aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorKentaro Takeda <takedakn@nttdata.co.jp>2009-02-05 03:18:16 -0500
committerJames Morris <jmorris@namei.org>2009-02-11 23:15:05 -0500
commitf7433243770c77979c396b4c7449a10e9b3521db (patch)
tree8bcb3d92ddb65b73f1802c5476d75f92814477d8 /security
parent26a2a1c9eb88d9aca8891575b3b986812e073872 (diff)
LSM adapter functions.
DAC's permissions and TOMOYO's permissions are not one-to-one mapping. Regarding DAC, there are "read", "write", "execute" permissions. Regarding TOMOYO, there are "allow_read", "allow_write", "allow_read/write", "allow_execute", "allow_create", "allow_unlink", "allow_mkdir", "allow_rmdir", "allow_mkfifo", "allow_mksock", "allow_mkblock", "allow_mkchar", "allow_truncate", "allow_symlink", "allow_rewrite", "allow_link", "allow_rename" permissions. +----------------------------------+----------------------------------+ | requested operation | required TOMOYO's permission | +----------------------------------+----------------------------------+ | sys_open(O_RDONLY) | allow_read | +----------------------------------+----------------------------------+ | sys_open(O_WRONLY) | allow_write | +----------------------------------+----------------------------------+ | sys_open(O_RDWR) | allow_read/write | +----------------------------------+----------------------------------+ | open_exec() from do_execve() | allow_execute | +----------------------------------+----------------------------------+ | open_exec() from !do_execve() | allow_read | +----------------------------------+----------------------------------+ | sys_read() | (none) | +----------------------------------+----------------------------------+ | sys_write() | (none) | +----------------------------------+----------------------------------+ | sys_mmap() | (none) | +----------------------------------+----------------------------------+ | sys_uselib() | allow_read | +----------------------------------+----------------------------------+ | sys_open(O_CREAT) | allow_create | +----------------------------------+----------------------------------+ | sys_open(O_TRUNC) | allow_truncate | +----------------------------------+----------------------------------+ | sys_truncate() | allow_truncate | +----------------------------------+----------------------------------+ | sys_ftruncate() | allow_truncate | +----------------------------------+----------------------------------+ | sys_open() without O_APPEND | allow_rewrite | +----------------------------------+----------------------------------+ | setfl() without O_APPEND | allow_rewrite | +----------------------------------+----------------------------------+ | sys_sysctl() for writing | allow_write | +----------------------------------+----------------------------------+ | sys_sysctl() for reading | allow_read | +----------------------------------+----------------------------------+ | sys_unlink() | allow_unlink | +----------------------------------+----------------------------------+ | sys_mknod(S_IFREG) | allow_create | +----------------------------------+----------------------------------+ | sys_mknod(0) | allow_create | +----------------------------------+----------------------------------+ | sys_mknod(S_IFIFO) | allow_mkfifo | +----------------------------------+----------------------------------+ | sys_mknod(S_IFSOCK) | allow_mksock | +----------------------------------+----------------------------------+ | sys_bind(AF_UNIX) | allow_mksock | +----------------------------------+----------------------------------+ | sys_mknod(S_IFBLK) | allow_mkblock | +----------------------------------+----------------------------------+ | sys_mknod(S_IFCHR) | allow_mkchar | +----------------------------------+----------------------------------+ | sys_symlink() | allow_symlink | +----------------------------------+----------------------------------+ | sys_mkdir() | allow_mkdir | +----------------------------------+----------------------------------+ | sys_rmdir() | allow_rmdir | +----------------------------------+----------------------------------+ | sys_link() | allow_link | +----------------------------------+----------------------------------+ | sys_rename() | allow_rename | +----------------------------------+----------------------------------+ TOMOYO requires "allow_execute" permission of a pathname passed to do_execve() but does not require "allow_read" permission of that pathname. Let's consider 3 patterns (statically linked, dynamically linked, shell script). This description is to some degree simplified. $ cat hello.c #include <stdio.h> int main() { printf("Hello\n"); return 0; } $ cat hello.sh #! /bin/sh echo "Hello" $ gcc -static -o hello-static hello.c $ gcc -o hello-dynamic hello.c $ chmod 755 hello.sh Case 1 -- Executing hello-static from bash. (1) The bash process calls fork() and the child process requests do_execve("hello-static"). (2) The kernel checks "allow_execute hello-static" from "bash" domain. (3) The kernel calculates "bash hello-static" as the domain to transit to. (4) The kernel overwrites the child process by "hello-static". (5) The child process transits to "bash hello-static" domain. (6) The "hello-static" starts and finishes. Case 2 -- Executing hello-dynamic from bash. (1) The bash process calls fork() and the child process requests do_execve("hello-dynamic"). (2) The kernel checks "allow_execute hello-dynamic" from "bash" domain. (3) The kernel calculates "bash hello-dynamic" as the domain to transit to. (4) The kernel checks "allow_read ld-linux.so" from "bash hello-dynamic" domain. I think permission to access ld-linux.so should be charged hello-dynamic program, for "hello-dynamic needs ld-linux.so" is not a fault of bash program. (5) The kernel overwrites the child process by "hello-dynamic". (6) The child process transits to "bash hello-dynamic" domain. (7) The "hello-dynamic" starts and finishes. Case 3 -- Executing hello.sh from bash. (1) The bash process calls fork() and the child process requests do_execve("hello.sh"). (2) The kernel checks "allow_execute hello.sh" from "bash" domain. (3) The kernel calculates "bash hello.sh" as the domain to transit to. (4) The kernel checks "allow_read /bin/sh" from "bash hello.sh" domain. I think permission to access /bin/sh should be charged hello.sh program, for "hello.sh needs /bin/sh" is not a fault of bash program. (5) The kernel overwrites the child process by "/bin/sh". (6) The child process transits to "bash hello.sh" domain. (7) The "/bin/sh" requests open("hello.sh"). (8) The kernel checks "allow_read hello.sh" from "bash hello.sh" domain. (9) The "/bin/sh" starts and finishes. Whether a file is interpreted as a program or not depends on an application. The kernel cannot know whether the file is interpreted as a program or not. Thus, TOMOYO treats "hello-static" "hello-dynamic" "ld-linux.so" "hello.sh" "/bin/sh" equally as merely files; no distinction between executable and non-executable. Therefore, TOMOYO doesn't check DAC's execute permission. TOMOYO checks "allow_read" permission instead. Calling do_execve() is a bold gesture that an old program's instance (i.e. current process) is ready to be overwritten by a new program and is ready to transfer control to the new program. To split purview of programs, TOMOYO requires "allow_execute" permission of the new program against the old program's instance and performs domain transition. If do_execve() succeeds, the old program is no longer responsible against the consequence of the new program's behavior. Only the new program is responsible for all consequences. But TOMOYO doesn't require "allow_read" permission of the new program. If TOMOYO requires "allow_read" permission of the new program, TOMOYO will allow an attacker (who hijacked the old program's instance) to open the new program and steal data from the new program. Requiring "allow_read" permission will widen purview of the old program. Not requiring "allow_read" permission of the new program against the old program's instance is my design for reducing purview of the old program. To be able to know whether the current process is in do_execve() or not, I want to add in_execve flag to "task_struct". Signed-off-by: Kentaro Takeda <takedakn@nttdata.co.jp> Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Signed-off-by: Toshiharu Harada <haradats@nttdata.co.jp> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security')
-rw-r--r--security/tomoyo/tomoyo.c293
-rw-r--r--security/tomoyo/tomoyo.h106
2 files changed, 399 insertions, 0 deletions
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
new file mode 100644
index 000000000000..f3ab20758c0f
--- /dev/null
+++ b/security/tomoyo/tomoyo.c
@@ -0,0 +1,293 @@
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-pre 2009/02/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 /*
31 * Do only if this function is called for the first time of an execve
32 * operation.
33 */
34 if (bprm->cred_prepared)
35 return 0;
36 /*
37 * Load policy if /sbin/tomoyo-init exists and /sbin/init is requested
38 * for the first time.
39 */
40 if (!tomoyo_policy_loaded)
41 tomoyo_load_policy(bprm->filename);
42 /*
43 * Tell tomoyo_bprm_check_security() is called for the first time of an
44 * execve operation.
45 */
46 bprm->cred->security = NULL;
47 return 0;
48}
49
50static int tomoyo_bprm_check_security(struct linux_binprm *bprm)
51{
52 struct tomoyo_domain_info *domain = bprm->cred->security;
53
54 /*
55 * Execute permission is checked against pathname passed to do_execve()
56 * using current domain.
57 */
58 if (!domain) {
59 struct tomoyo_domain_info *next_domain = NULL;
60 int retval = tomoyo_find_next_domain(bprm, &next_domain);
61
62 if (!retval)
63 bprm->cred->security = next_domain;
64 return retval;
65 }
66 /*
67 * Read permission is checked against interpreters using next domain.
68 * '1' is the result of open_to_namei_flags(O_RDONLY).
69 */
70 return tomoyo_check_open_permission(domain, &bprm->file->f_path, 1);
71}
72
73#ifdef CONFIG_SYSCTL
74
75static int tomoyo_prepend(char **buffer, int *buflen, const char *str)
76{
77 int namelen = strlen(str);
78
79 if (*buflen < namelen)
80 return -ENOMEM;
81 *buflen -= namelen;
82 *buffer -= namelen;
83 memcpy(*buffer, str, namelen);
84 return 0;
85}
86
87/**
88 * tomoyo_sysctl_path - return the realpath of a ctl_table.
89 * @table: pointer to "struct ctl_table".
90 *
91 * Returns realpath(3) of the @table on success.
92 * Returns NULL on failure.
93 *
94 * This function uses tomoyo_alloc(), so the caller must call tomoyo_free()
95 * if this function didn't return NULL.
96 */
97static char *tomoyo_sysctl_path(struct ctl_table *table)
98{
99 int buflen = TOMOYO_MAX_PATHNAME_LEN;
100 char *buf = tomoyo_alloc(buflen);
101 char *end = buf + buflen;
102 int error = -ENOMEM;
103
104 if (!buf)
105 return NULL;
106
107 *--end = '\0';
108 buflen--;
109 while (table) {
110 char buf[32];
111 const char *sp = table->procname;
112
113 if (!sp) {
114 memset(buf, 0, sizeof(buf));
115 snprintf(buf, sizeof(buf) - 1, "=%d=", table->ctl_name);
116 sp = buf;
117 }
118 if (tomoyo_prepend(&end, &buflen, sp) ||
119 tomoyo_prepend(&end, &buflen, "/"))
120 goto out;
121 table = table->parent;
122 }
123 if (tomoyo_prepend(&end, &buflen, "/proc/sys"))
124 goto out;
125 error = tomoyo_encode(buf, end - buf, end);
126 out:
127 if (!error)
128 return buf;
129 tomoyo_free(buf);
130 return NULL;
131}
132
133static int tomoyo_sysctl(struct ctl_table *table, int op)
134{
135 int error;
136 char *name;
137
138 op &= MAY_READ | MAY_WRITE;
139 if (!op)
140 return 0;
141 name = tomoyo_sysctl_path(table);
142 if (!name)
143 return -ENOMEM;
144 error = tomoyo_check_file_perm(tomoyo_domain(), name, op);
145 tomoyo_free(name);
146 return error;
147}
148#endif
149
150static int tomoyo_path_truncate(struct path *path, loff_t length,
151 unsigned int time_attrs)
152{
153 return tomoyo_check_1path_perm(tomoyo_domain(),
154 TOMOYO_TYPE_TRUNCATE_ACL,
155 path);
156}
157
158static int tomoyo_path_unlink(struct path *parent, struct dentry *dentry)
159{
160 struct path path = { parent->mnt, dentry };
161 return tomoyo_check_1path_perm(tomoyo_domain(),
162 TOMOYO_TYPE_UNLINK_ACL,
163 &path);
164}
165
166static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry,
167 int mode)
168{
169 struct path path = { parent->mnt, dentry };
170 return tomoyo_check_1path_perm(tomoyo_domain(),
171 TOMOYO_TYPE_MKDIR_ACL,
172 &path);
173}
174
175static int tomoyo_path_rmdir(struct path *parent, struct dentry *dentry)
176{
177 struct path path = { parent->mnt, dentry };
178 return tomoyo_check_1path_perm(tomoyo_domain(),
179 TOMOYO_TYPE_RMDIR_ACL,
180 &path);
181}
182
183static int tomoyo_path_symlink(struct path *parent, struct dentry *dentry,
184 const char *old_name)
185{
186 struct path path = { parent->mnt, dentry };
187 return tomoyo_check_1path_perm(tomoyo_domain(),
188 TOMOYO_TYPE_SYMLINK_ACL,
189 &path);
190}
191
192static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry,
193 int mode, unsigned int dev)
194{
195 struct path path = { parent->mnt, dentry };
196 int type = TOMOYO_TYPE_CREATE_ACL;
197
198 switch (mode & S_IFMT) {
199 case S_IFCHR:
200 type = TOMOYO_TYPE_MKCHAR_ACL;
201 break;
202 case S_IFBLK:
203 type = TOMOYO_TYPE_MKBLOCK_ACL;
204 break;
205 case S_IFIFO:
206 type = TOMOYO_TYPE_MKFIFO_ACL;
207 break;
208 case S_IFSOCK:
209 type = TOMOYO_TYPE_MKSOCK_ACL;
210 break;
211 }
212 return tomoyo_check_1path_perm(tomoyo_domain(),
213 type, &path);
214}
215
216static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir,
217 struct dentry *new_dentry)
218{
219 struct path path1 = { new_dir->mnt, old_dentry };
220 struct path path2 = { new_dir->mnt, new_dentry };
221 return tomoyo_check_2path_perm(tomoyo_domain(),
222 TOMOYO_TYPE_LINK_ACL,
223 &path1, &path2);
224}
225
226static int tomoyo_path_rename(struct path *old_parent,
227 struct dentry *old_dentry,
228 struct path *new_parent,
229 struct dentry *new_dentry)
230{
231 struct path path1 = { old_parent->mnt, old_dentry };
232 struct path path2 = { new_parent->mnt, new_dentry };
233 return tomoyo_check_2path_perm(tomoyo_domain(),
234 TOMOYO_TYPE_RENAME_ACL,
235 &path1, &path2);
236}
237
238static int tomoyo_file_fcntl(struct file *file, unsigned int cmd,
239 unsigned long arg)
240{
241 if (cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND))
242 return tomoyo_check_rewrite_permission(tomoyo_domain(), file);
243 return 0;
244}
245
246static int tomoyo_dentry_open(struct file *f, const struct cred *cred)
247{
248 int flags = f->f_flags;
249
250 if ((flags + 1) & O_ACCMODE)
251 flags++;
252 flags |= f->f_flags & (O_APPEND | O_TRUNC);
253 /* Don't check read permission here if called from do_execve(). */
254 if (current->in_execve)
255 return 0;
256 return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, flags);
257}
258
259static struct security_operations tomoyo_security_ops = {
260 .name = "tomoyo",
261 .cred_prepare = tomoyo_cred_prepare,
262 .bprm_set_creds = tomoyo_bprm_set_creds,
263 .bprm_check_security = tomoyo_bprm_check_security,
264#ifdef CONFIG_SYSCTL
265 .sysctl = tomoyo_sysctl,
266#endif
267 .file_fcntl = tomoyo_file_fcntl,
268 .dentry_open = tomoyo_dentry_open,
269 .path_truncate = tomoyo_path_truncate,
270 .path_unlink = tomoyo_path_unlink,
271 .path_mkdir = tomoyo_path_mkdir,
272 .path_rmdir = tomoyo_path_rmdir,
273 .path_symlink = tomoyo_path_symlink,
274 .path_mknod = tomoyo_path_mknod,
275 .path_link = tomoyo_path_link,
276 .path_rename = tomoyo_path_rename,
277};
278
279static int __init tomoyo_init(void)
280{
281 struct cred *cred = (struct cred *) current_cred();
282
283 if (!security_module_enable(&tomoyo_security_ops))
284 return 0;
285 /* register ourselves with the security framework */
286 if (register_security(&tomoyo_security_ops))
287 panic("Failure registering TOMOYO Linux");
288 printk(KERN_INFO "TOMOYO Linux initialized\n");
289 cred->security = &tomoyo_kernel_domain;
290 return 0;
291}
292
293security_initcall(tomoyo_init);
diff --git a/security/tomoyo/tomoyo.h b/security/tomoyo/tomoyo.h
new file mode 100644
index 000000000000..a0c8f6e0bea4
--- /dev/null
+++ b/security/tomoyo/tomoyo.h
@@ -0,0 +1,106 @@
1/*
2 * security/tomoyo/tomoyo.h
3 *
4 * Implementation of the Domain-Based Mandatory Access Control.
5 *
6 * Copyright (C) 2005-2009 NTT DATA CORPORATION
7 *
8 * Version: 2.2.0-pre 2009/02/01
9 *
10 */
11
12#ifndef _SECURITY_TOMOYO_TOMOYO_H
13#define _SECURITY_TOMOYO_TOMOYO_H
14
15struct tomoyo_path_info;
16struct path;
17struct inode;
18struct linux_binprm;
19struct pt_regs;
20struct tomoyo_page_buffer;
21
22int tomoyo_check_file_perm(struct tomoyo_domain_info *domain,
23 const char *filename, const u8 perm);
24int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain,
25 const struct tomoyo_path_info *filename,
26 struct tomoyo_page_buffer *buf);
27int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
28 struct path *path, const int flag);
29int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain,
30 const u8 operation, struct path *path);
31int tomoyo_check_2path_perm(struct tomoyo_domain_info *domain,
32 const u8 operation, struct path *path1,
33 struct path *path2);
34int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain,
35 struct file *filp);
36int tomoyo_find_next_domain(struct linux_binprm *bprm,
37 struct tomoyo_domain_info **next_domain);
38
39/* Index numbers for Access Controls. */
40
41#define TOMOYO_TYPE_SINGLE_PATH_ACL 0
42#define TOMOYO_TYPE_DOUBLE_PATH_ACL 1
43
44/* Index numbers for File Controls. */
45
46/*
47 * TYPE_READ_WRITE_ACL is special. TYPE_READ_WRITE_ACL is automatically set
48 * if both TYPE_READ_ACL and TYPE_WRITE_ACL are set. Both TYPE_READ_ACL and
49 * TYPE_WRITE_ACL are automatically set if TYPE_READ_WRITE_ACL is set.
50 * TYPE_READ_WRITE_ACL is automatically cleared if either TYPE_READ_ACL or
51 * TYPE_WRITE_ACL is cleared. Both TYPE_READ_ACL and TYPE_WRITE_ACL are
52 * automatically cleared if TYPE_READ_WRITE_ACL is cleared.
53 */
54
55#define TOMOYO_TYPE_READ_WRITE_ACL 0
56#define TOMOYO_TYPE_EXECUTE_ACL 1
57#define TOMOYO_TYPE_READ_ACL 2
58#define TOMOYO_TYPE_WRITE_ACL 3
59#define TOMOYO_TYPE_CREATE_ACL 4
60#define TOMOYO_TYPE_UNLINK_ACL 5
61#define TOMOYO_TYPE_MKDIR_ACL 6
62#define TOMOYO_TYPE_RMDIR_ACL 7
63#define TOMOYO_TYPE_MKFIFO_ACL 8
64#define TOMOYO_TYPE_MKSOCK_ACL 9
65#define TOMOYO_TYPE_MKBLOCK_ACL 10
66#define TOMOYO_TYPE_MKCHAR_ACL 11
67#define TOMOYO_TYPE_TRUNCATE_ACL 12
68#define TOMOYO_TYPE_SYMLINK_ACL 13
69#define TOMOYO_TYPE_REWRITE_ACL 14
70#define TOMOYO_MAX_SINGLE_PATH_OPERATION 15
71
72#define TOMOYO_TYPE_LINK_ACL 0
73#define TOMOYO_TYPE_RENAME_ACL 1
74#define TOMOYO_MAX_DOUBLE_PATH_OPERATION 2
75
76#define TOMOYO_DOMAINPOLICY 0
77#define TOMOYO_EXCEPTIONPOLICY 1
78#define TOMOYO_DOMAIN_STATUS 2
79#define TOMOYO_PROCESS_STATUS 3
80#define TOMOYO_MEMINFO 4
81#define TOMOYO_SELFDOMAIN 5
82#define TOMOYO_VERSION 6
83#define TOMOYO_PROFILE 7
84#define TOMOYO_MANAGER 8
85
86extern struct tomoyo_domain_info tomoyo_kernel_domain;
87
88static inline struct tomoyo_domain_info *tomoyo_domain(void)
89{
90 return current_cred()->security;
91}
92
93/* Caller holds tasklist_lock spinlock. */
94static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct
95 *task)
96{
97 /***** CRITICAL SECTION START *****/
98 const struct cred *cred = get_task_cred(task);
99 struct tomoyo_domain_info *domain = cred->security;
100
101 put_cred(cred);
102 return domain;
103 /***** CRITICAL SECTION END *****/
104}
105
106#endif /* !defined(_SECURITY_TOMOYO_TOMOYO_H) */