tomoyo.c revision b1338d199dda6681d9af0297928af0a7eb9cba7b
1/*
2 * security/tomoyo/tomoyo.c
3 *
4 * LSM hooks for TOMOYO Linux.
5 *
6 * Copyright (C) 2005-2009  NTT DATA CORPORATION
7 *
8 * Version: 2.2.0   2009/04/01
9 *
10 */
11
12#include <linux/security.h>
13#include "common.h"
14#include "tomoyo.h"
15#include "realpath.h"
16
17static int tomoyo_cred_prepare(struct cred *new, const struct cred *old,
18			       gfp_t gfp)
19{
20	/*
21	 * Since "struct tomoyo_domain_info *" is a sharable pointer,
22	 * we don't need to duplicate.
23	 */
24	new->security = old->security;
25	return 0;
26}
27
28static int tomoyo_bprm_set_creds(struct linux_binprm *bprm)
29{
30	int rc;
31
32	rc = cap_bprm_set_creds(bprm);
33	if (rc)
34		return rc;
35
36	/*
37	 * Do only if this function is called for the first time of an execve
38	 * operation.
39	 */
40	if (bprm->cred_prepared)
41		return 0;
42	/*
43	 * Load policy if /sbin/tomoyo-init exists and /sbin/init is requested
44	 * for the first time.
45	 */
46	if (!tomoyo_policy_loaded)
47		tomoyo_load_policy(bprm->filename);
48	/*
49	 * Tell tomoyo_bprm_check_security() is called for the first time of an
50	 * execve operation.
51	 */
52	bprm->cred->security = NULL;
53	return 0;
54}
55
56static int tomoyo_bprm_check_security(struct linux_binprm *bprm)
57{
58	struct tomoyo_domain_info *domain = bprm->cred->security;
59
60	/*
61	 * Execute permission is checked against pathname passed to do_execve()
62	 * using current domain.
63	 */
64	if (!domain) {
65		struct tomoyo_domain_info *next_domain = NULL;
66		int retval = tomoyo_find_next_domain(bprm, &next_domain);
67
68		if (!retval)
69			bprm->cred->security = next_domain;
70		return retval;
71	}
72	/*
73	 * Read permission is checked against interpreters using next domain.
74	 * '1' is the result of open_to_namei_flags(O_RDONLY).
75	 */
76	return tomoyo_check_open_permission(domain, &bprm->file->f_path, 1);
77}
78
79#ifdef CONFIG_SYSCTL
80
81static int tomoyo_prepend(char **buffer, int *buflen, const char *str)
82{
83	int namelen = strlen(str);
84
85	if (*buflen < namelen)
86		return -ENOMEM;
87	*buflen -= namelen;
88	*buffer -= namelen;
89	memcpy(*buffer, str, namelen);
90	return 0;
91}
92
93/**
94 * tomoyo_sysctl_path - return the realpath of a ctl_table.
95 * @table: pointer to "struct ctl_table".
96 *
97 * Returns realpath(3) of the @table on success.
98 * Returns NULL on failure.
99 *
100 * This function uses tomoyo_alloc(), so the caller must call tomoyo_free()
101 * if this function didn't return NULL.
102 */
103static char *tomoyo_sysctl_path(struct ctl_table *table)
104{
105	int buflen = TOMOYO_MAX_PATHNAME_LEN;
106	char *buf = tomoyo_alloc(buflen);
107	char *end = buf + buflen;
108	int error = -ENOMEM;
109
110	if (!buf)
111		return NULL;
112
113	*--end = '\0';
114	buflen--;
115	while (table) {
116		char num[32];
117		const char *sp = table->procname;
118
119		if (!sp) {
120			memset(num, 0, sizeof(num));
121			snprintf(num, sizeof(num) - 1, "=%d=", table->ctl_name);
122			sp = num;
123		}
124		if (tomoyo_prepend(&end, &buflen, sp) ||
125		    tomoyo_prepend(&end, &buflen, "/"))
126			goto out;
127		table = table->parent;
128	}
129	if (tomoyo_prepend(&end, &buflen, "/proc/sys"))
130		goto out;
131	error = tomoyo_encode(buf, end - buf, end);
132 out:
133	if (!error)
134		return buf;
135	tomoyo_free(buf);
136	return NULL;
137}
138
139static int tomoyo_sysctl(struct ctl_table *table, int op)
140{
141	int error;
142	char *name;
143
144	op &= MAY_READ | MAY_WRITE;
145	if (!op)
146		return 0;
147	name = tomoyo_sysctl_path(table);
148	if (!name)
149		return -ENOMEM;
150	error = tomoyo_check_file_perm(tomoyo_domain(), name, op);
151	tomoyo_free(name);
152	return error;
153}
154#endif
155
156static int tomoyo_path_truncate(struct path *path, loff_t length,
157				unsigned int time_attrs)
158{
159	return tomoyo_check_1path_perm(tomoyo_domain(),
160				       TOMOYO_TYPE_TRUNCATE_ACL,
161				       path);
162}
163
164static int tomoyo_path_unlink(struct path *parent, struct dentry *dentry)
165{
166	struct path path = { parent->mnt, dentry };
167	return tomoyo_check_1path_perm(tomoyo_domain(),
168				       TOMOYO_TYPE_UNLINK_ACL,
169				       &path);
170}
171
172static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry,
173			     int mode)
174{
175	struct path path = { parent->mnt, dentry };
176	return tomoyo_check_1path_perm(tomoyo_domain(),
177				       TOMOYO_TYPE_MKDIR_ACL,
178				       &path);
179}
180
181static int tomoyo_path_rmdir(struct path *parent, struct dentry *dentry)
182{
183	struct path path = { parent->mnt, dentry };
184	return tomoyo_check_1path_perm(tomoyo_domain(),
185				       TOMOYO_TYPE_RMDIR_ACL,
186				       &path);
187}
188
189static int tomoyo_path_symlink(struct path *parent, struct dentry *dentry,
190			       const char *old_name)
191{
192	struct path path = { parent->mnt, dentry };
193	return tomoyo_check_1path_perm(tomoyo_domain(),
194				       TOMOYO_TYPE_SYMLINK_ACL,
195				       &path);
196}
197
198static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry,
199			     int mode, unsigned int dev)
200{
201	struct path path = { parent->mnt, dentry };
202	int type = TOMOYO_TYPE_CREATE_ACL;
203
204	switch (mode & S_IFMT) {
205	case S_IFCHR:
206		type = TOMOYO_TYPE_MKCHAR_ACL;
207		break;
208	case S_IFBLK:
209		type = TOMOYO_TYPE_MKBLOCK_ACL;
210		break;
211	case S_IFIFO:
212		type = TOMOYO_TYPE_MKFIFO_ACL;
213		break;
214	case S_IFSOCK:
215		type = TOMOYO_TYPE_MKSOCK_ACL;
216		break;
217	}
218	return tomoyo_check_1path_perm(tomoyo_domain(),
219				       type, &path);
220}
221
222static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir,
223			    struct dentry *new_dentry)
224{
225	struct path path1 = { new_dir->mnt, old_dentry };
226	struct path path2 = { new_dir->mnt, new_dentry };
227	return tomoyo_check_2path_perm(tomoyo_domain(),
228				       TOMOYO_TYPE_LINK_ACL,
229				       &path1, &path2);
230}
231
232static int tomoyo_path_rename(struct path *old_parent,
233			      struct dentry *old_dentry,
234			      struct path *new_parent,
235			      struct dentry *new_dentry)
236{
237	struct path path1 = { old_parent->mnt, old_dentry };
238	struct path path2 = { new_parent->mnt, new_dentry };
239	return tomoyo_check_2path_perm(tomoyo_domain(),
240				       TOMOYO_TYPE_RENAME_ACL,
241				       &path1, &path2);
242}
243
244static int tomoyo_file_fcntl(struct file *file, unsigned int cmd,
245			     unsigned long arg)
246{
247	if (cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND))
248		return tomoyo_check_rewrite_permission(tomoyo_domain(), file);
249	return 0;
250}
251
252static int tomoyo_dentry_open(struct file *f, const struct cred *cred)
253{
254	int flags = f->f_flags;
255
256	if ((flags + 1) & O_ACCMODE)
257		flags++;
258	flags |= f->f_flags & (O_APPEND | O_TRUNC);
259	/* Don't check read permission here if called from do_execve(). */
260	if (current->in_execve)
261		return 0;
262	return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, flags);
263}
264
265static struct security_operations tomoyo_security_ops = {
266	.name                = "tomoyo",
267	.cred_prepare        = tomoyo_cred_prepare,
268	.bprm_set_creds      = tomoyo_bprm_set_creds,
269	.bprm_check_security = tomoyo_bprm_check_security,
270#ifdef CONFIG_SYSCTL
271	.sysctl              = tomoyo_sysctl,
272#endif
273	.file_fcntl          = tomoyo_file_fcntl,
274	.dentry_open         = tomoyo_dentry_open,
275	.path_truncate       = tomoyo_path_truncate,
276	.path_unlink         = tomoyo_path_unlink,
277	.path_mkdir          = tomoyo_path_mkdir,
278	.path_rmdir          = tomoyo_path_rmdir,
279	.path_symlink        = tomoyo_path_symlink,
280	.path_mknod          = tomoyo_path_mknod,
281	.path_link           = tomoyo_path_link,
282	.path_rename         = tomoyo_path_rename,
283};
284
285static int __init tomoyo_init(void)
286{
287	struct cred *cred = (struct cred *) current_cred();
288
289	if (!security_module_enable(&tomoyo_security_ops))
290		return 0;
291	/* register ourselves with the security framework */
292	if (register_security(&tomoyo_security_ops))
293		panic("Failure registering TOMOYO Linux");
294	printk(KERN_INFO "TOMOYO Linux initialized\n");
295	cred->security = &tomoyo_kernel_domain;
296	tomoyo_realpath_init();
297	return 0;
298}
299
300security_initcall(tomoyo_init);
301