diff options
-rw-r--r-- | security/tomoyo/common.c | 69 | ||||
-rw-r--r-- | security/tomoyo/common.h | 133 | ||||
-rw-r--r-- | security/tomoyo/domain.c | 192 | ||||
-rw-r--r-- | security/tomoyo/file.c | 121 | ||||
-rw-r--r-- | security/tomoyo/realpath.c | 19 | ||||
-rw-r--r-- | security/tomoyo/tomoyo.c | 4 |
6 files changed, 504 insertions, 34 deletions
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index a44f655b3913..fdd1f4b8c448 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
@@ -28,7 +28,13 @@ static const char *tomoyo_mode_2[4] = { | |||
28 | "disabled", "enabled", "enabled", "enabled" | 28 | "disabled", "enabled", "enabled", "enabled" |
29 | }; | 29 | }; |
30 | 30 | ||
31 | /* Table for profile. */ | 31 | /* |
32 | * tomoyo_control_array is a static data which contains | ||
33 | * | ||
34 | * (1) functionality name used by /sys/kernel/security/tomoyo/profile . | ||
35 | * (2) initial values for "struct tomoyo_profile". | ||
36 | * (3) max values for "struct tomoyo_profile". | ||
37 | */ | ||
32 | static struct { | 38 | static struct { |
33 | const char *keyword; | 39 | const char *keyword; |
34 | unsigned int current_value; | 40 | unsigned int current_value; |
@@ -39,7 +45,13 @@ static struct { | |||
39 | [TOMOYO_VERBOSE] = { "TOMOYO_VERBOSE", 1, 1 }, | 45 | [TOMOYO_VERBOSE] = { "TOMOYO_VERBOSE", 1, 1 }, |
40 | }; | 46 | }; |
41 | 47 | ||
42 | /* Profile table. Memory is allocated as needed. */ | 48 | /* |
49 | * tomoyo_profile is a structure which is used for holding the mode of access | ||
50 | * controls. TOMOYO has 4 modes: disabled, learning, permissive, enforcing. | ||
51 | * An administrator can define up to 256 profiles. | ||
52 | * The ->profile of "struct tomoyo_domain_info" is used for remembering | ||
53 | * the profile's number (0 - 255) assigned to that domain. | ||
54 | */ | ||
43 | static struct tomoyo_profile { | 55 | static struct tomoyo_profile { |
44 | unsigned int value[TOMOYO_MAX_CONTROL_INDEX]; | 56 | unsigned int value[TOMOYO_MAX_CONTROL_INDEX]; |
45 | const struct tomoyo_path_info *comment; | 57 | const struct tomoyo_path_info *comment; |
@@ -1006,7 +1018,19 @@ static int tomoyo_read_profile(struct tomoyo_io_buffer *head) | |||
1006 | return 0; | 1018 | return 0; |
1007 | } | 1019 | } |
1008 | 1020 | ||
1009 | /* Structure for policy manager. */ | 1021 | /* |
1022 | * tomoyo_policy_manager_entry is a structure which is used for holding list of | ||
1023 | * domainnames or programs which are permitted to modify configuration via | ||
1024 | * /sys/kernel/security/tomoyo/ interface. | ||
1025 | * It has following fields. | ||
1026 | * | ||
1027 | * (1) "list" which is linked to tomoyo_policy_manager_list . | ||
1028 | * (2) "manager" is a domainname or a program's pathname. | ||
1029 | * (3) "is_domain" is a bool which is true if "manager" is a domainname, false | ||
1030 | * otherwise. | ||
1031 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
1032 | * otherwise. | ||
1033 | */ | ||
1010 | struct tomoyo_policy_manager_entry { | 1034 | struct tomoyo_policy_manager_entry { |
1011 | struct list_head list; | 1035 | struct list_head list; |
1012 | /* A path to program or a domainname. */ | 1036 | /* A path to program or a domainname. */ |
@@ -1015,7 +1039,36 @@ struct tomoyo_policy_manager_entry { | |||
1015 | bool is_deleted; /* True if this entry is deleted. */ | 1039 | bool is_deleted; /* True if this entry is deleted. */ |
1016 | }; | 1040 | }; |
1017 | 1041 | ||
1018 | /* The list for "struct tomoyo_policy_manager_entry". */ | 1042 | /* |
1043 | * tomoyo_policy_manager_list is used for holding list of domainnames or | ||
1044 | * programs which are permitted to modify configuration via | ||
1045 | * /sys/kernel/security/tomoyo/ interface. | ||
1046 | * | ||
1047 | * An entry is added by | ||
1048 | * | ||
1049 | * # echo '<kernel> /sbin/mingetty /bin/login /bin/bash' > \ | ||
1050 | * /sys/kernel/security/tomoyo/manager | ||
1051 | * (if you want to specify by a domainname) | ||
1052 | * | ||
1053 | * or | ||
1054 | * | ||
1055 | * # echo '/usr/lib/ccs/editpolicy' > /sys/kernel/security/tomoyo/manager | ||
1056 | * (if you want to specify by a program's location) | ||
1057 | * | ||
1058 | * and is deleted by | ||
1059 | * | ||
1060 | * # echo 'delete <kernel> /sbin/mingetty /bin/login /bin/bash' > \ | ||
1061 | * /sys/kernel/security/tomoyo/manager | ||
1062 | * | ||
1063 | * or | ||
1064 | * | ||
1065 | * # echo 'delete /usr/lib/ccs/editpolicy' > \ | ||
1066 | * /sys/kernel/security/tomoyo/manager | ||
1067 | * | ||
1068 | * and all entries are retrieved by | ||
1069 | * | ||
1070 | * # cat /sys/kernel/security/tomoyo/manager | ||
1071 | */ | ||
1019 | static LIST_HEAD(tomoyo_policy_manager_list); | 1072 | static LIST_HEAD(tomoyo_policy_manager_list); |
1020 | static DECLARE_RWSEM(tomoyo_policy_manager_list_lock); | 1073 | static DECLARE_RWSEM(tomoyo_policy_manager_list_lock); |
1021 | 1074 | ||
@@ -2124,7 +2177,13 @@ static ssize_t tomoyo_write(struct file *file, const char __user *buf, | |||
2124 | return tomoyo_write_control(file, buf, count); | 2177 | return tomoyo_write_control(file, buf, count); |
2125 | } | 2178 | } |
2126 | 2179 | ||
2127 | /* Operations for /sys/kernel/security/tomoyo/ interface. */ | 2180 | /* |
2181 | * tomoyo_operations is a "struct file_operations" which is used for handling | ||
2182 | * /sys/kernel/security/tomoyo/ interface. | ||
2183 | * | ||
2184 | * Some files under /sys/kernel/security/tomoyo/ directory accept open(O_RDWR). | ||
2185 | * See tomoyo_io_buffer for internals. | ||
2186 | */ | ||
2128 | static const struct file_operations tomoyo_operations = { | 2187 | static const struct file_operations tomoyo_operations = { |
2129 | .open = tomoyo_open, | 2188 | .open = tomoyo_open, |
2130 | .release = tomoyo_release, | 2189 | .release = tomoyo_release, |
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index d8b95047cb9d..6d6ba09af457 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h | |||
@@ -26,12 +26,40 @@ | |||
26 | struct dentry; | 26 | struct dentry; |
27 | struct vfsmount; | 27 | struct vfsmount; |
28 | 28 | ||
29 | /* Temporary buffer for holding pathnames. */ | 29 | /* |
30 | * tomoyo_page_buffer is a structure which is used for holding a pathname | ||
31 | * obtained from "struct dentry" and "struct vfsmount" pair. | ||
32 | * As of now, it is 4096 bytes. If users complain that 4096 bytes is too small | ||
33 | * (because TOMOYO escapes non ASCII printable characters using \ooo format), | ||
34 | * we will make the buffer larger. | ||
35 | */ | ||
30 | struct tomoyo_page_buffer { | 36 | struct tomoyo_page_buffer { |
31 | char buffer[4096]; | 37 | char buffer[4096]; |
32 | }; | 38 | }; |
33 | 39 | ||
34 | /* Structure for holding a token. */ | 40 | /* |
41 | * tomoyo_path_info is a structure which is used for holding a string data | ||
42 | * used by TOMOYO. | ||
43 | * This structure has several fields for supporting pattern matching. | ||
44 | * | ||
45 | * (1) "name" is the '\0' terminated string data. | ||
46 | * (2) "hash" is full_name_hash(name, strlen(name)). | ||
47 | * This allows tomoyo_pathcmp() to compare by hash before actually compare | ||
48 | * using strcmp(). | ||
49 | * (3) "const_len" is the length of the initial segment of "name" which | ||
50 | * consists entirely of non wildcard characters. In other words, the length | ||
51 | * which we can compare two strings using strncmp(). | ||
52 | * (4) "is_dir" is a bool which is true if "name" ends with "/", | ||
53 | * false otherwise. | ||
54 | * TOMOYO distinguishes directory and non-directory. A directory ends with | ||
55 | * "/" and non-directory does not end with "/". | ||
56 | * (5) "is_patterned" is a bool which is true if "name" contains wildcard | ||
57 | * characters, false otherwise. This allows TOMOYO to use "hash" and | ||
58 | * strcmp() for string comparison if "is_patterned" is false. | ||
59 | * (6) "depth" is calculated using the number of "/" characters in "name". | ||
60 | * This allows TOMOYO to avoid comparing two pathnames which never match | ||
61 | * (e.g. whether "/var/www/html/index.html" matches "/tmp/sh-thd-\$"). | ||
62 | */ | ||
35 | struct tomoyo_path_info { | 63 | struct tomoyo_path_info { |
36 | const char *name; | 64 | const char *name; |
37 | u32 hash; /* = full_name_hash(name, strlen(name)) */ | 65 | u32 hash; /* = full_name_hash(name, strlen(name)) */ |
@@ -50,7 +78,20 @@ struct tomoyo_path_info { | |||
50 | */ | 78 | */ |
51 | #define TOMOYO_MAX_PATHNAME_LEN 4000 | 79 | #define TOMOYO_MAX_PATHNAME_LEN 4000 |
52 | 80 | ||
53 | /* Structure for holding requested pathname. */ | 81 | /* |
82 | * tomoyo_path_info_with_data is a structure which is used for holding a | ||
83 | * pathname obtained from "struct dentry" and "struct vfsmount" pair. | ||
84 | * | ||
85 | * "struct tomoyo_path_info_with_data" consists of "struct tomoyo_path_info" | ||
86 | * and buffer for the pathname, while "struct tomoyo_page_buffer" consists of | ||
87 | * buffer for the pathname only. | ||
88 | * | ||
89 | * "struct tomoyo_path_info_with_data" is intended to allow TOMOYO to release | ||
90 | * both "struct tomoyo_path_info" and buffer for the pathname by single kfree() | ||
91 | * so that we don't need to return two pointers to the caller. If the caller | ||
92 | * puts "struct tomoyo_path_info" on stack memory, we will be able to remove | ||
93 | * "struct tomoyo_path_info_with_data". | ||
94 | */ | ||
54 | struct tomoyo_path_info_with_data { | 95 | struct tomoyo_path_info_with_data { |
55 | /* Keep "head" first, for this pointer is passed to tomoyo_free(). */ | 96 | /* Keep "head" first, for this pointer is passed to tomoyo_free(). */ |
56 | struct tomoyo_path_info head; | 97 | struct tomoyo_path_info head; |
@@ -60,7 +101,15 @@ struct tomoyo_path_info_with_data { | |||
60 | }; | 101 | }; |
61 | 102 | ||
62 | /* | 103 | /* |
63 | * Common header for holding ACL entries. | 104 | * tomoyo_acl_info is a structure which is used for holding |
105 | * | ||
106 | * (1) "list" which is linked to the ->acl_info_list of | ||
107 | * "struct tomoyo_domain_info" | ||
108 | * (2) "type" which tells | ||
109 | * (a) type & 0x7F : type of the entry (either | ||
110 | * "struct tomoyo_single_path_acl_record" or | ||
111 | * "struct tomoyo_double_path_acl_record") | ||
112 | * (b) type & 0x80 : whether the entry is marked as "deleted". | ||
64 | * | 113 | * |
65 | * Packing "struct tomoyo_acl_info" allows | 114 | * Packing "struct tomoyo_acl_info" allows |
66 | * "struct tomoyo_single_path_acl_record" to embed "u16" and | 115 | * "struct tomoyo_single_path_acl_record" to embed "u16" and |
@@ -80,7 +129,28 @@ struct tomoyo_acl_info { | |||
80 | /* This ACL entry is deleted. */ | 129 | /* This ACL entry is deleted. */ |
81 | #define TOMOYO_ACL_DELETED 0x80 | 130 | #define TOMOYO_ACL_DELETED 0x80 |
82 | 131 | ||
83 | /* Structure for domain information. */ | 132 | /* |
133 | * tomoyo_domain_info is a structure which is used for holding permissions | ||
134 | * (e.g. "allow_read /lib/libc-2.5.so") given to each domain. | ||
135 | * It has following fields. | ||
136 | * | ||
137 | * (1) "list" which is linked to tomoyo_domain_list . | ||
138 | * (2) "acl_info_list" which is linked to "struct tomoyo_acl_info". | ||
139 | * (3) "domainname" which holds the name of the domain. | ||
140 | * (4) "profile" which remembers profile number assigned to this domain. | ||
141 | * (5) "is_deleted" is a bool which is true if this domain is marked as | ||
142 | * "deleted", false otherwise. | ||
143 | * (6) "quota_warned" is a bool which is used for suppressing warning message | ||
144 | * when learning mode learned too much entries. | ||
145 | * (7) "flags" which remembers this domain's attributes. | ||
146 | * | ||
147 | * A domain's lifecycle is an analogy of files on / directory. | ||
148 | * Multiple domains with the same domainname cannot be created (as with | ||
149 | * creating files with the same filename fails with -EEXIST). | ||
150 | * If a process reached a domain, that process can reside in that domain after | ||
151 | * that domain is marked as "deleted" (as with a process can access an already | ||
152 | * open()ed file after that file was unlink()ed). | ||
153 | */ | ||
84 | struct tomoyo_domain_info { | 154 | struct tomoyo_domain_info { |
85 | struct list_head list; | 155 | struct list_head list; |
86 | struct list_head acl_info_list; | 156 | struct list_head acl_info_list; |
@@ -107,10 +177,18 @@ struct tomoyo_domain_info { | |||
107 | #define TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED 2 | 177 | #define TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED 2 |
108 | 178 | ||
109 | /* | 179 | /* |
110 | * Structure for "allow_read/write", "allow_execute", "allow_read", | 180 | * tomoyo_single_path_acl_record is a structure which is used for holding an |
111 | * "allow_write", "allow_create", "allow_unlink", "allow_mkdir", "allow_rmdir", | 181 | * entry with one pathname operation (e.g. open(), mkdir()). |
112 | * "allow_mkfifo", "allow_mksock", "allow_mkblock", "allow_mkchar", | 182 | * It has following fields. |
113 | * "allow_truncate", "allow_symlink" and "allow_rewrite" directive. | 183 | * |
184 | * (1) "head" which is a "struct tomoyo_acl_info". | ||
185 | * (2) "perm" which is a bitmask of permitted operations. | ||
186 | * (3) "filename" is the pathname. | ||
187 | * | ||
188 | * Directives held by this structure are "allow_read/write", "allow_execute", | ||
189 | * "allow_read", "allow_write", "allow_create", "allow_unlink", "allow_mkdir", | ||
190 | * "allow_rmdir", "allow_mkfifo", "allow_mksock", "allow_mkblock", | ||
191 | * "allow_mkchar", "allow_truncate", "allow_symlink" and "allow_rewrite". | ||
114 | */ | 192 | */ |
115 | struct tomoyo_single_path_acl_record { | 193 | struct tomoyo_single_path_acl_record { |
116 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_SINGLE_PATH_ACL */ | 194 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_SINGLE_PATH_ACL */ |
@@ -119,7 +197,18 @@ struct tomoyo_single_path_acl_record { | |||
119 | const struct tomoyo_path_info *filename; | 197 | const struct tomoyo_path_info *filename; |
120 | }; | 198 | }; |
121 | 199 | ||
122 | /* Structure for "allow_rename" and "allow_link" directive. */ | 200 | /* |
201 | * tomoyo_double_path_acl_record is a structure which is used for holding an | ||
202 | * entry with two pathnames operation (i.e. link() and rename()). | ||
203 | * It has following fields. | ||
204 | * | ||
205 | * (1) "head" which is a "struct tomoyo_acl_info". | ||
206 | * (2) "perm" which is a bitmask of permitted operations. | ||
207 | * (3) "filename1" is the source/old pathname. | ||
208 | * (4) "filename2" is the destination/new pathname. | ||
209 | * | ||
210 | * Directives held by this structure are "allow_rename" and "allow_link". | ||
211 | */ | ||
123 | struct tomoyo_double_path_acl_record { | 212 | struct tomoyo_double_path_acl_record { |
124 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_DOUBLE_PATH_ACL */ | 213 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_DOUBLE_PATH_ACL */ |
125 | u8 perm; | 214 | u8 perm; |
@@ -152,7 +241,29 @@ struct tomoyo_double_path_acl_record { | |||
152 | #define TOMOYO_VERBOSE 2 | 241 | #define TOMOYO_VERBOSE 2 |
153 | #define TOMOYO_MAX_CONTROL_INDEX 3 | 242 | #define TOMOYO_MAX_CONTROL_INDEX 3 |
154 | 243 | ||
155 | /* Structure for reading/writing policy via securityfs interfaces. */ | 244 | /* |
245 | * tomoyo_io_buffer is a structure which is used for reading and modifying | ||
246 | * configuration via /sys/kernel/security/tomoyo/ interface. | ||
247 | * It has many fields. ->read_var1 , ->read_var2 , ->write_var1 are used as | ||
248 | * cursors. | ||
249 | * | ||
250 | * Since the content of /sys/kernel/security/tomoyo/domain_policy is a list of | ||
251 | * "struct tomoyo_domain_info" entries and each "struct tomoyo_domain_info" | ||
252 | * entry has a list of "struct tomoyo_acl_info", we need two cursors when | ||
253 | * reading (one is for traversing tomoyo_domain_list and the other is for | ||
254 | * traversing "struct tomoyo_acl_info"->acl_info_list ). | ||
255 | * | ||
256 | * If a line written to /sys/kernel/security/tomoyo/domain_policy starts with | ||
257 | * "select ", TOMOYO seeks the cursor ->read_var1 and ->write_var1 to the | ||
258 | * domain with the domainname specified by the rest of that line (NULL is set | ||
259 | * if seek failed). | ||
260 | * If a line written to /sys/kernel/security/tomoyo/domain_policy starts with | ||
261 | * "delete ", TOMOYO deletes an entry or a domain specified by the rest of that | ||
262 | * line (->write_var1 is set to NULL if a domain was deleted). | ||
263 | * If a line written to /sys/kernel/security/tomoyo/domain_policy starts with | ||
264 | * neither "select " nor "delete ", an entry or a domain specified by that line | ||
265 | * is appended. | ||
266 | */ | ||
156 | struct tomoyo_io_buffer { | 267 | struct tomoyo_io_buffer { |
157 | int (*read) (struct tomoyo_io_buffer *); | 268 | int (*read) (struct tomoyo_io_buffer *); |
158 | int (*write) (struct tomoyo_io_buffer *); | 269 | int (*write) (struct tomoyo_io_buffer *); |
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index eb75401fd6b0..1d8b16960576 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c | |||
@@ -19,11 +19,63 @@ | |||
19 | /* The initial domain. */ | 19 | /* The initial domain. */ |
20 | struct tomoyo_domain_info tomoyo_kernel_domain; | 20 | struct tomoyo_domain_info tomoyo_kernel_domain; |
21 | 21 | ||
22 | /* The list for "struct tomoyo_domain_info". */ | 22 | /* |
23 | * tomoyo_domain_list is used for holding list of domains. | ||
24 | * The ->acl_info_list of "struct tomoyo_domain_info" is used for holding | ||
25 | * permissions (e.g. "allow_read /lib/libc-2.5.so") given to each domain. | ||
26 | * | ||
27 | * An entry is added by | ||
28 | * | ||
29 | * # ( echo "<kernel>"; echo "allow_execute /sbin/init" ) > \ | ||
30 | * /sys/kernel/security/tomoyo/domain_policy | ||
31 | * | ||
32 | * and is deleted by | ||
33 | * | ||
34 | * # ( echo "<kernel>"; echo "delete allow_execute /sbin/init" ) > \ | ||
35 | * /sys/kernel/security/tomoyo/domain_policy | ||
36 | * | ||
37 | * and all entries are retrieved by | ||
38 | * | ||
39 | * # cat /sys/kernel/security/tomoyo/domain_policy | ||
40 | * | ||
41 | * A domain is added by | ||
42 | * | ||
43 | * # echo "<kernel>" > /sys/kernel/security/tomoyo/domain_policy | ||
44 | * | ||
45 | * and is deleted by | ||
46 | * | ||
47 | * # echo "delete <kernel>" > /sys/kernel/security/tomoyo/domain_policy | ||
48 | * | ||
49 | * and all domains are retrieved by | ||
50 | * | ||
51 | * # grep '^<kernel>' /sys/kernel/security/tomoyo/domain_policy | ||
52 | * | ||
53 | * Normally, a domainname is monotonically getting longer because a domainname | ||
54 | * which the process will belong to if an execve() operation succeeds is | ||
55 | * defined as a concatenation of "current domainname" + "pathname passed to | ||
56 | * execve()". | ||
57 | * See tomoyo_domain_initializer_list and tomoyo_domain_keeper_list for | ||
58 | * exceptions. | ||
59 | */ | ||
23 | LIST_HEAD(tomoyo_domain_list); | 60 | LIST_HEAD(tomoyo_domain_list); |
24 | DECLARE_RWSEM(tomoyo_domain_list_lock); | 61 | DECLARE_RWSEM(tomoyo_domain_list_lock); |
25 | 62 | ||
26 | /* Structure for "initialize_domain" and "no_initialize_domain" keyword. */ | 63 | /* |
64 | * tomoyo_domain_initializer_entry is a structure which is used for holding | ||
65 | * "initialize_domain" and "no_initialize_domain" entries. | ||
66 | * It has following fields. | ||
67 | * | ||
68 | * (1) "list" which is linked to tomoyo_domain_initializer_list . | ||
69 | * (2) "domainname" which is "a domainname" or "the last component of a | ||
70 | * domainname". This field is NULL if "from" clause is not specified. | ||
71 | * (3) "program" which is a program's pathname. | ||
72 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
73 | * otherwise. | ||
74 | * (5) "is_not" is a bool which is true if "no_initialize_domain", false | ||
75 | * otherwise. | ||
76 | * (6) "is_last_name" is a bool which is true if "domainname" is "the last | ||
77 | * component of a domainname", false otherwise. | ||
78 | */ | ||
27 | struct tomoyo_domain_initializer_entry { | 79 | struct tomoyo_domain_initializer_entry { |
28 | struct list_head list; | 80 | struct list_head list; |
29 | const struct tomoyo_path_info *domainname; /* This may be NULL */ | 81 | const struct tomoyo_path_info *domainname; /* This may be NULL */ |
@@ -34,7 +86,23 @@ struct tomoyo_domain_initializer_entry { | |||
34 | bool is_last_name; | 86 | bool is_last_name; |
35 | }; | 87 | }; |
36 | 88 | ||
37 | /* Structure for "keep_domain" and "no_keep_domain" keyword. */ | 89 | /* |
90 | * tomoyo_domain_keeper_entry is a structure which is used for holding | ||
91 | * "keep_domain" and "no_keep_domain" entries. | ||
92 | * It has following fields. | ||
93 | * | ||
94 | * (1) "list" which is linked to tomoyo_domain_keeper_list . | ||
95 | * (2) "domainname" which is "a domainname" or "the last component of a | ||
96 | * domainname". | ||
97 | * (3) "program" which is a program's pathname. | ||
98 | * This field is NULL if "from" clause is not specified. | ||
99 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
100 | * otherwise. | ||
101 | * (5) "is_not" is a bool which is true if "no_initialize_domain", false | ||
102 | * otherwise. | ||
103 | * (6) "is_last_name" is a bool which is true if "domainname" is "the last | ||
104 | * component of a domainname", false otherwise. | ||
105 | */ | ||
38 | struct tomoyo_domain_keeper_entry { | 106 | struct tomoyo_domain_keeper_entry { |
39 | struct list_head list; | 107 | struct list_head list; |
40 | const struct tomoyo_path_info *domainname; | 108 | const struct tomoyo_path_info *domainname; |
@@ -45,7 +113,16 @@ struct tomoyo_domain_keeper_entry { | |||
45 | bool is_last_name; | 113 | bool is_last_name; |
46 | }; | 114 | }; |
47 | 115 | ||
48 | /* Structure for "alias" keyword. */ | 116 | /* |
117 | * tomoyo_alias_entry is a structure which is used for holding "alias" entries. | ||
118 | * It has following fields. | ||
119 | * | ||
120 | * (1) "list" which is linked to tomoyo_alias_list . | ||
121 | * (2) "original_name" which is a dereferenced pathname. | ||
122 | * (3) "aliased_name" which is a symlink's pathname. | ||
123 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
124 | * otherwise. | ||
125 | */ | ||
49 | struct tomoyo_alias_entry { | 126 | struct tomoyo_alias_entry { |
50 | struct list_head list; | 127 | struct list_head list; |
51 | const struct tomoyo_path_info *original_name; | 128 | const struct tomoyo_path_info *original_name; |
@@ -92,7 +169,42 @@ const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain) | |||
92 | return cp0; | 169 | return cp0; |
93 | } | 170 | } |
94 | 171 | ||
95 | /* The list for "struct tomoyo_domain_initializer_entry". */ | 172 | /* |
173 | * tomoyo_domain_initializer_list is used for holding list of programs which | ||
174 | * triggers reinitialization of domainname. Normally, a domainname is | ||
175 | * monotonically getting longer. But sometimes, we restart daemon programs. | ||
176 | * It would be convenient for us that "a daemon started upon system boot" and | ||
177 | * "the daemon restarted from console" belong to the same domain. Thus, TOMOYO | ||
178 | * provides a way to shorten domainnames. | ||
179 | * | ||
180 | * An entry is added by | ||
181 | * | ||
182 | * # echo 'initialize_domain /usr/sbin/httpd' > \ | ||
183 | * /sys/kernel/security/tomoyo/exception_policy | ||
184 | * | ||
185 | * and is deleted by | ||
186 | * | ||
187 | * # echo 'delete initialize_domain /usr/sbin/httpd' > \ | ||
188 | * /sys/kernel/security/tomoyo/exception_policy | ||
189 | * | ||
190 | * and all entries are retrieved by | ||
191 | * | ||
192 | * # grep ^initialize_domain /sys/kernel/security/tomoyo/exception_policy | ||
193 | * | ||
194 | * In the example above, /usr/sbin/httpd will belong to | ||
195 | * "<kernel> /usr/sbin/httpd" domain. | ||
196 | * | ||
197 | * You may specify a domainname using "from" keyword. | ||
198 | * "initialize_domain /usr/sbin/httpd from <kernel> /etc/rc.d/init.d/httpd" | ||
199 | * will cause "/usr/sbin/httpd" executed from "<kernel> /etc/rc.d/init.d/httpd" | ||
200 | * domain to belong to "<kernel> /usr/sbin/httpd" domain. | ||
201 | * | ||
202 | * You may add "no_" prefix to "initialize_domain". | ||
203 | * "initialize_domain /usr/sbin/httpd" and | ||
204 | * "no_initialize_domain /usr/sbin/httpd from <kernel> /etc/rc.d/init.d/httpd" | ||
205 | * will cause "/usr/sbin/httpd" to belong to "<kernel> /usr/sbin/httpd" domain | ||
206 | * unless executed from "<kernel> /etc/rc.d/init.d/httpd" domain. | ||
207 | */ | ||
96 | static LIST_HEAD(tomoyo_domain_initializer_list); | 208 | static LIST_HEAD(tomoyo_domain_initializer_list); |
97 | static DECLARE_RWSEM(tomoyo_domain_initializer_list_lock); | 209 | static DECLARE_RWSEM(tomoyo_domain_initializer_list_lock); |
98 | 210 | ||
@@ -268,7 +380,44 @@ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * | |||
268 | return flag; | 380 | return flag; |
269 | } | 381 | } |
270 | 382 | ||
271 | /* The list for "struct tomoyo_domain_keeper_entry". */ | 383 | /* |
384 | * tomoyo_domain_keeper_list is used for holding list of domainnames which | ||
385 | * suppresses domain transition. Normally, a domainname is monotonically | ||
386 | * getting longer. But sometimes, we want to suppress domain transition. | ||
387 | * It would be convenient for us that programs executed from a login session | ||
388 | * belong to the same domain. Thus, TOMOYO provides a way to suppress domain | ||
389 | * transition. | ||
390 | * | ||
391 | * An entry is added by | ||
392 | * | ||
393 | * # echo 'keep_domain <kernel> /usr/sbin/sshd /bin/bash' > \ | ||
394 | * /sys/kernel/security/tomoyo/exception_policy | ||
395 | * | ||
396 | * and is deleted by | ||
397 | * | ||
398 | * # echo 'delete keep_domain <kernel> /usr/sbin/sshd /bin/bash' > \ | ||
399 | * /sys/kernel/security/tomoyo/exception_policy | ||
400 | * | ||
401 | * and all entries are retrieved by | ||
402 | * | ||
403 | * # grep ^keep_domain /sys/kernel/security/tomoyo/exception_policy | ||
404 | * | ||
405 | * In the example above, any process which belongs to | ||
406 | * "<kernel> /usr/sbin/sshd /bin/bash" domain will remain in that domain, | ||
407 | * unless explicitly specified by "initialize_domain" or "no_keep_domain". | ||
408 | * | ||
409 | * You may specify a program using "from" keyword. | ||
410 | * "keep_domain /bin/pwd from <kernel> /usr/sbin/sshd /bin/bash" | ||
411 | * will cause "/bin/pwd" executed from "<kernel> /usr/sbin/sshd /bin/bash" | ||
412 | * domain to remain in "<kernel> /usr/sbin/sshd /bin/bash" domain. | ||
413 | * | ||
414 | * You may add "no_" prefix to "keep_domain". | ||
415 | * "keep_domain <kernel> /usr/sbin/sshd /bin/bash" and | ||
416 | * "no_keep_domain /usr/bin/passwd from <kernel> /usr/sbin/sshd /bin/bash" will | ||
417 | * cause "/usr/bin/passwd" to belong to | ||
418 | * "<kernel> /usr/sbin/sshd /bin/bash /usr/bin/passwd" domain, unless | ||
419 | * explicitly specified by "initialize_domain". | ||
420 | */ | ||
272 | static LIST_HEAD(tomoyo_domain_keeper_list); | 421 | static LIST_HEAD(tomoyo_domain_keeper_list); |
273 | static DECLARE_RWSEM(tomoyo_domain_keeper_list_lock); | 422 | static DECLARE_RWSEM(tomoyo_domain_keeper_list_lock); |
274 | 423 | ||
@@ -437,7 +586,36 @@ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, | |||
437 | return flag; | 586 | return flag; |
438 | } | 587 | } |
439 | 588 | ||
440 | /* The list for "struct tomoyo_alias_entry". */ | 589 | /* |
590 | * tomoyo_alias_list is used for holding list of symlink's pathnames which are | ||
591 | * allowed to be passed to an execve() request. Normally, the domainname which | ||
592 | * the current process will belong to after execve() succeeds is calculated | ||
593 | * using dereferenced pathnames. But some programs behave differently depending | ||
594 | * on the name passed to argv[0]. For busybox, calculating domainname using | ||
595 | * dereferenced pathnames will cause all programs in the busybox to belong to | ||
596 | * the same domain. Thus, TOMOYO provides a way to allow use of symlink's | ||
597 | * pathname for checking execve()'s permission and calculating domainname which | ||
598 | * the current process will belong to after execve() succeeds. | ||
599 | * | ||
600 | * An entry is added by | ||
601 | * | ||
602 | * # echo 'alias /bin/busybox /bin/cat' > \ | ||
603 | * /sys/kernel/security/tomoyo/exception_policy | ||
604 | * | ||
605 | * and is deleted by | ||
606 | * | ||
607 | * # echo 'delete alias /bin/busybox /bin/cat' > \ | ||
608 | * /sys/kernel/security/tomoyo/exception_policy | ||
609 | * | ||
610 | * and all entries are retrieved by | ||
611 | * | ||
612 | * # grep ^alias /sys/kernel/security/tomoyo/exception_policy | ||
613 | * | ||
614 | * In the example above, if /bin/cat is a symlink to /bin/busybox and execution | ||
615 | * of /bin/cat is requested, permission is checked for /bin/cat rather than | ||
616 | * /bin/busybox and domainname which the current process will belong to after | ||
617 | * execve() succeeds is calculated using /bin/cat rather than /bin/busybox . | ||
618 | */ | ||
441 | static LIST_HEAD(tomoyo_alias_list); | 619 | static LIST_HEAD(tomoyo_alias_list); |
442 | static DECLARE_RWSEM(tomoyo_alias_list_lock); | 620 | static DECLARE_RWSEM(tomoyo_alias_list_lock); |
443 | 621 | ||
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index ab0cd3538510..5ae3a571559f 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c | |||
@@ -14,21 +14,50 @@ | |||
14 | #include "realpath.h" | 14 | #include "realpath.h" |
15 | #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) | 15 | #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) |
16 | 16 | ||
17 | /* Structure for "allow_read" keyword. */ | 17 | /* |
18 | * tomoyo_globally_readable_file_entry is a structure which is used for holding | ||
19 | * "allow_read" entries. | ||
20 | * It has following fields. | ||
21 | * | ||
22 | * (1) "list" which is linked to tomoyo_globally_readable_list . | ||
23 | * (2) "filename" is a pathname which is allowed to open(O_RDONLY). | ||
24 | * (3) "is_deleted" is a bool which is true if marked as deleted, false | ||
25 | * otherwise. | ||
26 | */ | ||
18 | struct tomoyo_globally_readable_file_entry { | 27 | struct tomoyo_globally_readable_file_entry { |
19 | struct list_head list; | 28 | struct list_head list; |
20 | const struct tomoyo_path_info *filename; | 29 | const struct tomoyo_path_info *filename; |
21 | bool is_deleted; | 30 | bool is_deleted; |
22 | }; | 31 | }; |
23 | 32 | ||
24 | /* Structure for "file_pattern" keyword. */ | 33 | /* |
34 | * tomoyo_pattern_entry is a structure which is used for holding | ||
35 | * "tomoyo_pattern_list" entries. | ||
36 | * It has following fields. | ||
37 | * | ||
38 | * (1) "list" which is linked to tomoyo_pattern_list . | ||
39 | * (2) "pattern" is a pathname pattern which is used for converting pathnames | ||
40 | * to pathname patterns during learning mode. | ||
41 | * (3) "is_deleted" is a bool which is true if marked as deleted, false | ||
42 | * otherwise. | ||
43 | */ | ||
25 | struct tomoyo_pattern_entry { | 44 | struct tomoyo_pattern_entry { |
26 | struct list_head list; | 45 | struct list_head list; |
27 | const struct tomoyo_path_info *pattern; | 46 | const struct tomoyo_path_info *pattern; |
28 | bool is_deleted; | 47 | bool is_deleted; |
29 | }; | 48 | }; |
30 | 49 | ||
31 | /* Structure for "deny_rewrite" keyword. */ | 50 | /* |
51 | * tomoyo_no_rewrite_entry is a structure which is used for holding | ||
52 | * "deny_rewrite" entries. | ||
53 | * It has following fields. | ||
54 | * | ||
55 | * (1) "list" which is linked to tomoyo_no_rewrite_list . | ||
56 | * (2) "pattern" is a pathname which is by default not permitted to modify | ||
57 | * already existing content. | ||
58 | * (3) "is_deleted" is a bool which is true if marked as deleted, false | ||
59 | * otherwise. | ||
60 | */ | ||
32 | struct tomoyo_no_rewrite_entry { | 61 | struct tomoyo_no_rewrite_entry { |
33 | struct list_head list; | 62 | struct list_head list; |
34 | const struct tomoyo_path_info *pattern; | 63 | const struct tomoyo_path_info *pattern; |
@@ -141,7 +170,31 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, | |||
141 | struct tomoyo_domain_info * | 170 | struct tomoyo_domain_info * |
142 | const domain, const bool is_delete); | 171 | const domain, const bool is_delete); |
143 | 172 | ||
144 | /* The list for "struct tomoyo_globally_readable_file_entry". */ | 173 | /* |
174 | * tomoyo_globally_readable_list is used for holding list of pathnames which | ||
175 | * are by default allowed to be open()ed for reading by any process. | ||
176 | * | ||
177 | * An entry is added by | ||
178 | * | ||
179 | * # echo 'allow_read /lib/libc-2.5.so' > \ | ||
180 | * /sys/kernel/security/tomoyo/exception_policy | ||
181 | * | ||
182 | * and is deleted by | ||
183 | * | ||
184 | * # echo 'delete allow_read /lib/libc-2.5.so' > \ | ||
185 | * /sys/kernel/security/tomoyo/exception_policy | ||
186 | * | ||
187 | * and all entries are retrieved by | ||
188 | * | ||
189 | * # grep ^allow_read /sys/kernel/security/tomoyo/exception_policy | ||
190 | * | ||
191 | * In the example above, any process is allowed to | ||
192 | * open("/lib/libc-2.5.so", O_RDONLY). | ||
193 | * One exception is, if the domain which current process belongs to is marked | ||
194 | * as "ignore_global_allow_read", current process can't do so unless explicitly | ||
195 | * given "allow_read /lib/libc-2.5.so" to the domain which current process | ||
196 | * belongs to. | ||
197 | */ | ||
145 | static LIST_HEAD(tomoyo_globally_readable_list); | 198 | static LIST_HEAD(tomoyo_globally_readable_list); |
146 | static DECLARE_RWSEM(tomoyo_globally_readable_list_lock); | 199 | static DECLARE_RWSEM(tomoyo_globally_readable_list_lock); |
147 | 200 | ||
@@ -256,7 +309,35 @@ bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) | |||
256 | return done; | 309 | return done; |
257 | } | 310 | } |
258 | 311 | ||
259 | /* The list for "struct tomoyo_pattern_entry". */ | 312 | /* tomoyo_pattern_list is used for holding list of pathnames which are used for |
313 | * converting pathnames to pathname patterns during learning mode. | ||
314 | * | ||
315 | * An entry is added by | ||
316 | * | ||
317 | * # echo 'file_pattern /proc/\$/mounts' > \ | ||
318 | * /sys/kernel/security/tomoyo/exception_policy | ||
319 | * | ||
320 | * and is deleted by | ||
321 | * | ||
322 | * # echo 'delete file_pattern /proc/\$/mounts' > \ | ||
323 | * /sys/kernel/security/tomoyo/exception_policy | ||
324 | * | ||
325 | * and all entries are retrieved by | ||
326 | * | ||
327 | * # grep ^file_pattern /sys/kernel/security/tomoyo/exception_policy | ||
328 | * | ||
329 | * In the example above, if a process which belongs to a domain which is in | ||
330 | * learning mode requested open("/proc/1/mounts", O_RDONLY), | ||
331 | * "allow_read /proc/\$/mounts" is automatically added to the domain which that | ||
332 | * process belongs to. | ||
333 | * | ||
334 | * It is not a desirable behavior that we have to use /proc/\$/ instead of | ||
335 | * /proc/self/ when current process needs to access only current process's | ||
336 | * information. As of now, LSM version of TOMOYO is using __d_path() for | ||
337 | * calculating pathname. Non LSM version of TOMOYO is using its own function | ||
338 | * which pretends as if /proc/self/ is not a symlink; so that we can forbid | ||
339 | * current process from accessing other process's information. | ||
340 | */ | ||
260 | static LIST_HEAD(tomoyo_pattern_list); | 341 | static LIST_HEAD(tomoyo_pattern_list); |
261 | static DECLARE_RWSEM(tomoyo_pattern_list_lock); | 342 | static DECLARE_RWSEM(tomoyo_pattern_list_lock); |
262 | 343 | ||
@@ -377,7 +458,35 @@ bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) | |||
377 | return done; | 458 | return done; |
378 | } | 459 | } |
379 | 460 | ||
380 | /* The list for "struct tomoyo_no_rewrite_entry". */ | 461 | /* |
462 | * tomoyo_no_rewrite_list is used for holding list of pathnames which are by | ||
463 | * default forbidden to modify already written content of a file. | ||
464 | * | ||
465 | * An entry is added by | ||
466 | * | ||
467 | * # echo 'deny_rewrite /var/log/messages' > \ | ||
468 | * /sys/kernel/security/tomoyo/exception_policy | ||
469 | * | ||
470 | * and is deleted by | ||
471 | * | ||
472 | * # echo 'delete deny_rewrite /var/log/messages' > \ | ||
473 | * /sys/kernel/security/tomoyo/exception_policy | ||
474 | * | ||
475 | * and all entries are retrieved by | ||
476 | * | ||
477 | * # grep ^deny_rewrite /sys/kernel/security/tomoyo/exception_policy | ||
478 | * | ||
479 | * In the example above, if a process requested to rewrite /var/log/messages , | ||
480 | * the process can't rewrite unless the domain which that process belongs to | ||
481 | * has "allow_rewrite /var/log/messages" entry. | ||
482 | * | ||
483 | * It is not a desirable behavior that we have to add "\040(deleted)" suffix | ||
484 | * when we want to allow rewriting already unlink()ed file. As of now, | ||
485 | * LSM version of TOMOYO is using __d_path() for calculating pathname. | ||
486 | * Non LSM version of TOMOYO is using its own function which doesn't append | ||
487 | * " (deleted)" suffix if the file is already unlink()ed; so that we don't | ||
488 | * need to worry whether the file is already unlink()ed or not. | ||
489 | */ | ||
381 | static LIST_HEAD(tomoyo_no_rewrite_list); | 490 | static LIST_HEAD(tomoyo_no_rewrite_list); |
382 | static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock); | 491 | static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock); |
383 | 492 | ||
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index 3948f6b56ae2..5f2e33263371 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c | |||
@@ -265,7 +265,16 @@ static unsigned int tomoyo_quota_for_savename; | |||
265 | */ | 265 | */ |
266 | #define TOMOYO_MAX_HASH 256 | 266 | #define TOMOYO_MAX_HASH 256 |
267 | 267 | ||
268 | /* Structure for string data. */ | 268 | /* |
269 | * tomoyo_name_entry is a structure which is used for linking | ||
270 | * "struct tomoyo_path_info" into tomoyo_name_list . | ||
271 | * | ||
272 | * Since tomoyo_name_list manages a list of strings which are shared by | ||
273 | * multiple processes (whereas "struct tomoyo_path_info" inside | ||
274 | * "struct tomoyo_path_info_with_data" is not shared), a reference counter will | ||
275 | * be added to "struct tomoyo_name_entry" rather than "struct tomoyo_path_info" | ||
276 | * when TOMOYO starts supporting garbage collector. | ||
277 | */ | ||
269 | struct tomoyo_name_entry { | 278 | struct tomoyo_name_entry { |
270 | struct list_head list; | 279 | struct list_head list; |
271 | struct tomoyo_path_info entry; | 280 | struct tomoyo_path_info entry; |
@@ -279,10 +288,10 @@ struct tomoyo_free_memory_block_list { | |||
279 | }; | 288 | }; |
280 | 289 | ||
281 | /* | 290 | /* |
282 | * The list for "struct tomoyo_name_entry". | 291 | * tomoyo_name_list is used for holding string data used by TOMOYO. |
283 | * | 292 | * Since same string data is likely used for multiple times (e.g. |
284 | * This list is updated only inside tomoyo_save_name(), thus | 293 | * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of |
285 | * no global mutex exists. | 294 | * "const struct tomoyo_path_info *". |
286 | */ | 295 | */ |
287 | static struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; | 296 | static struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; |
288 | 297 | ||
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index e42be5c4f055..3194d09fe0f4 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c | |||
@@ -262,6 +262,10 @@ static int tomoyo_dentry_open(struct file *f, const struct cred *cred) | |||
262 | return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, flags); | 262 | return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, flags); |
263 | } | 263 | } |
264 | 264 | ||
265 | /* | ||
266 | * tomoyo_security_ops is a "struct security_operations" which is used for | ||
267 | * registering TOMOYO. | ||
268 | */ | ||
265 | static struct security_operations tomoyo_security_ops = { | 269 | static struct security_operations tomoyo_security_ops = { |
266 | .name = "tomoyo", | 270 | .name = "tomoyo", |
267 | .cred_prepare = tomoyo_cred_prepare, | 271 | .cred_prepare = tomoyo_cred_prepare, |