Commit 0f2a55d5bb2372058275b0b343d90dd5d640d045
Committed by
James Morris
1 parent
c920669345
Exists in
master
and in
6 other branches
TOMOYO: Update kernel-doc.
Update comments for scripts/kernel-doc and fix some of errors reported by scripts/checkpatch.pl . Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Signed-off-by: James Morris <jmorris@namei.org>
Showing 13 changed files with 269 additions and 62 deletions Inline Diff
- security/tomoyo/audit.c
- security/tomoyo/common.c
- security/tomoyo/domain.c
- security/tomoyo/file.c
- security/tomoyo/gc.c
- security/tomoyo/group.c
- security/tomoyo/load_policy.c
- security/tomoyo/memory.c
- security/tomoyo/mount.c
- security/tomoyo/realpath.c
- security/tomoyo/securityfs_if.c
- security/tomoyo/tomoyo.c
- security/tomoyo/util.c
security/tomoyo/audit.c
1 | /* | 1 | /* |
2 | * security/tomoyo/audit.c | 2 | * security/tomoyo/audit.c |
3 | * | 3 | * |
4 | * Pathname restriction functions. | 4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION |
5 | * | ||
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
7 | */ | 5 | */ |
8 | 6 | ||
9 | #include "common.h" | 7 | #include "common.h" |
10 | #include <linux/slab.h> | 8 | #include <linux/slab.h> |
11 | 9 | ||
12 | /** | 10 | /** |
13 | * tomoyo_print_bprm - Print "struct linux_binprm" for auditing. | 11 | * tomoyo_print_bprm - Print "struct linux_binprm" for auditing. |
14 | * | 12 | * |
15 | * @bprm: Pointer to "struct linux_binprm". | 13 | * @bprm: Pointer to "struct linux_binprm". |
16 | * @dump: Pointer to "struct tomoyo_page_dump". | 14 | * @dump: Pointer to "struct tomoyo_page_dump". |
17 | * | 15 | * |
18 | * Returns the contents of @bprm on success, NULL otherwise. | 16 | * Returns the contents of @bprm on success, NULL otherwise. |
19 | * | 17 | * |
20 | * This function uses kzalloc(), so caller must kfree() if this function | 18 | * This function uses kzalloc(), so caller must kfree() if this function |
21 | * didn't return NULL. | 19 | * didn't return NULL. |
22 | */ | 20 | */ |
23 | static char *tomoyo_print_bprm(struct linux_binprm *bprm, | 21 | static char *tomoyo_print_bprm(struct linux_binprm *bprm, |
24 | struct tomoyo_page_dump *dump) | 22 | struct tomoyo_page_dump *dump) |
25 | { | 23 | { |
26 | static const int tomoyo_buffer_len = 4096 * 2; | 24 | static const int tomoyo_buffer_len = 4096 * 2; |
27 | char *buffer = kzalloc(tomoyo_buffer_len, GFP_NOFS); | 25 | char *buffer = kzalloc(tomoyo_buffer_len, GFP_NOFS); |
28 | char *cp; | 26 | char *cp; |
29 | char *last_start; | 27 | char *last_start; |
30 | int len; | 28 | int len; |
31 | unsigned long pos = bprm->p; | 29 | unsigned long pos = bprm->p; |
32 | int offset = pos % PAGE_SIZE; | 30 | int offset = pos % PAGE_SIZE; |
33 | int argv_count = bprm->argc; | 31 | int argv_count = bprm->argc; |
34 | int envp_count = bprm->envc; | 32 | int envp_count = bprm->envc; |
35 | bool truncated = false; | 33 | bool truncated = false; |
36 | if (!buffer) | 34 | if (!buffer) |
37 | return NULL; | 35 | return NULL; |
38 | len = snprintf(buffer, tomoyo_buffer_len - 1, "argv[]={ "); | 36 | len = snprintf(buffer, tomoyo_buffer_len - 1, "argv[]={ "); |
39 | cp = buffer + len; | 37 | cp = buffer + len; |
40 | if (!argv_count) { | 38 | if (!argv_count) { |
41 | memmove(cp, "} envp[]={ ", 11); | 39 | memmove(cp, "} envp[]={ ", 11); |
42 | cp += 11; | 40 | cp += 11; |
43 | } | 41 | } |
44 | last_start = cp; | 42 | last_start = cp; |
45 | while (argv_count || envp_count) { | 43 | while (argv_count || envp_count) { |
46 | if (!tomoyo_dump_page(bprm, pos, dump)) | 44 | if (!tomoyo_dump_page(bprm, pos, dump)) |
47 | goto out; | 45 | goto out; |
48 | pos += PAGE_SIZE - offset; | 46 | pos += PAGE_SIZE - offset; |
49 | /* Read. */ | 47 | /* Read. */ |
50 | while (offset < PAGE_SIZE) { | 48 | while (offset < PAGE_SIZE) { |
51 | const char *kaddr = dump->data; | 49 | const char *kaddr = dump->data; |
52 | const unsigned char c = kaddr[offset++]; | 50 | const unsigned char c = kaddr[offset++]; |
53 | if (cp == last_start) | 51 | if (cp == last_start) |
54 | *cp++ = '"'; | 52 | *cp++ = '"'; |
55 | if (cp >= buffer + tomoyo_buffer_len - 32) { | 53 | if (cp >= buffer + tomoyo_buffer_len - 32) { |
56 | /* Reserve some room for "..." string. */ | 54 | /* Reserve some room for "..." string. */ |
57 | truncated = true; | 55 | truncated = true; |
58 | } else if (c == '\\') { | 56 | } else if (c == '\\') { |
59 | *cp++ = '\\'; | 57 | *cp++ = '\\'; |
60 | *cp++ = '\\'; | 58 | *cp++ = '\\'; |
61 | } else if (c > ' ' && c < 127) { | 59 | } else if (c > ' ' && c < 127) { |
62 | *cp++ = c; | 60 | *cp++ = c; |
63 | } else if (!c) { | 61 | } else if (!c) { |
64 | *cp++ = '"'; | 62 | *cp++ = '"'; |
65 | *cp++ = ' '; | 63 | *cp++ = ' '; |
66 | last_start = cp; | 64 | last_start = cp; |
67 | } else { | 65 | } else { |
68 | *cp++ = '\\'; | 66 | *cp++ = '\\'; |
69 | *cp++ = (c >> 6) + '0'; | 67 | *cp++ = (c >> 6) + '0'; |
70 | *cp++ = ((c >> 3) & 7) + '0'; | 68 | *cp++ = ((c >> 3) & 7) + '0'; |
71 | *cp++ = (c & 7) + '0'; | 69 | *cp++ = (c & 7) + '0'; |
72 | } | 70 | } |
73 | if (c) | 71 | if (c) |
74 | continue; | 72 | continue; |
75 | if (argv_count) { | 73 | if (argv_count) { |
76 | if (--argv_count == 0) { | 74 | if (--argv_count == 0) { |
77 | if (truncated) { | 75 | if (truncated) { |
78 | cp = last_start; | 76 | cp = last_start; |
79 | memmove(cp, "... ", 4); | 77 | memmove(cp, "... ", 4); |
80 | cp += 4; | 78 | cp += 4; |
81 | } | 79 | } |
82 | memmove(cp, "} envp[]={ ", 11); | 80 | memmove(cp, "} envp[]={ ", 11); |
83 | cp += 11; | 81 | cp += 11; |
84 | last_start = cp; | 82 | last_start = cp; |
85 | truncated = false; | 83 | truncated = false; |
86 | } | 84 | } |
87 | } else if (envp_count) { | 85 | } else if (envp_count) { |
88 | if (--envp_count == 0) { | 86 | if (--envp_count == 0) { |
89 | if (truncated) { | 87 | if (truncated) { |
90 | cp = last_start; | 88 | cp = last_start; |
91 | memmove(cp, "... ", 4); | 89 | memmove(cp, "... ", 4); |
92 | cp += 4; | 90 | cp += 4; |
93 | } | 91 | } |
94 | } | 92 | } |
95 | } | 93 | } |
96 | if (!argv_count && !envp_count) | 94 | if (!argv_count && !envp_count) |
97 | break; | 95 | break; |
98 | } | 96 | } |
99 | offset = 0; | 97 | offset = 0; |
100 | } | 98 | } |
101 | *cp++ = '}'; | 99 | *cp++ = '}'; |
102 | *cp = '\0'; | 100 | *cp = '\0'; |
103 | return buffer; | 101 | return buffer; |
104 | out: | 102 | out: |
105 | snprintf(buffer, tomoyo_buffer_len - 1, | 103 | snprintf(buffer, tomoyo_buffer_len - 1, |
106 | "argv[]={ ... } envp[]= { ... }"); | 104 | "argv[]={ ... } envp[]= { ... }"); |
107 | return buffer; | 105 | return buffer; |
108 | } | 106 | } |
109 | 107 | ||
110 | /** | 108 | /** |
111 | * tomoyo_filetype - Get string representation of file type. | 109 | * tomoyo_filetype - Get string representation of file type. |
112 | * | 110 | * |
113 | * @mode: Mode value for stat(). | 111 | * @mode: Mode value for stat(). |
114 | * | 112 | * |
115 | * Returns file type string. | 113 | * Returns file type string. |
116 | */ | 114 | */ |
117 | static inline const char *tomoyo_filetype(const mode_t mode) | 115 | static inline const char *tomoyo_filetype(const mode_t mode) |
118 | { | 116 | { |
119 | switch (mode & S_IFMT) { | 117 | switch (mode & S_IFMT) { |
120 | case S_IFREG: | 118 | case S_IFREG: |
121 | case 0: | 119 | case 0: |
122 | return tomoyo_condition_keyword[TOMOYO_TYPE_IS_FILE]; | 120 | return tomoyo_condition_keyword[TOMOYO_TYPE_IS_FILE]; |
123 | case S_IFDIR: | 121 | case S_IFDIR: |
124 | return tomoyo_condition_keyword[TOMOYO_TYPE_IS_DIRECTORY]; | 122 | return tomoyo_condition_keyword[TOMOYO_TYPE_IS_DIRECTORY]; |
125 | case S_IFLNK: | 123 | case S_IFLNK: |
126 | return tomoyo_condition_keyword[TOMOYO_TYPE_IS_SYMLINK]; | 124 | return tomoyo_condition_keyword[TOMOYO_TYPE_IS_SYMLINK]; |
127 | case S_IFIFO: | 125 | case S_IFIFO: |
128 | return tomoyo_condition_keyword[TOMOYO_TYPE_IS_FIFO]; | 126 | return tomoyo_condition_keyword[TOMOYO_TYPE_IS_FIFO]; |
129 | case S_IFSOCK: | 127 | case S_IFSOCK: |
130 | return tomoyo_condition_keyword[TOMOYO_TYPE_IS_SOCKET]; | 128 | return tomoyo_condition_keyword[TOMOYO_TYPE_IS_SOCKET]; |
131 | case S_IFBLK: | 129 | case S_IFBLK: |
132 | return tomoyo_condition_keyword[TOMOYO_TYPE_IS_BLOCK_DEV]; | 130 | return tomoyo_condition_keyword[TOMOYO_TYPE_IS_BLOCK_DEV]; |
133 | case S_IFCHR: | 131 | case S_IFCHR: |
134 | return tomoyo_condition_keyword[TOMOYO_TYPE_IS_CHAR_DEV]; | 132 | return tomoyo_condition_keyword[TOMOYO_TYPE_IS_CHAR_DEV]; |
135 | } | 133 | } |
136 | return "unknown"; /* This should not happen. */ | 134 | return "unknown"; /* This should not happen. */ |
137 | } | 135 | } |
138 | 136 | ||
139 | /** | 137 | /** |
140 | * tomoyo_print_header - Get header line of audit log. | 138 | * tomoyo_print_header - Get header line of audit log. |
141 | * | 139 | * |
142 | * @r: Pointer to "struct tomoyo_request_info". | 140 | * @r: Pointer to "struct tomoyo_request_info". |
143 | * | 141 | * |
144 | * Returns string representation. | 142 | * Returns string representation. |
145 | * | 143 | * |
146 | * This function uses kmalloc(), so caller must kfree() if this function | 144 | * This function uses kmalloc(), so caller must kfree() if this function |
147 | * didn't return NULL. | 145 | * didn't return NULL. |
148 | */ | 146 | */ |
149 | static char *tomoyo_print_header(struct tomoyo_request_info *r) | 147 | static char *tomoyo_print_header(struct tomoyo_request_info *r) |
150 | { | 148 | { |
151 | struct tomoyo_time stamp; | 149 | struct tomoyo_time stamp; |
152 | const pid_t gpid = task_pid_nr(current); | 150 | const pid_t gpid = task_pid_nr(current); |
153 | struct tomoyo_obj_info *obj = r->obj; | 151 | struct tomoyo_obj_info *obj = r->obj; |
154 | static const int tomoyo_buffer_len = 4096; | 152 | static const int tomoyo_buffer_len = 4096; |
155 | char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS); | 153 | char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS); |
156 | int pos; | 154 | int pos; |
157 | u8 i; | 155 | u8 i; |
158 | if (!buffer) | 156 | if (!buffer) |
159 | return NULL; | 157 | return NULL; |
160 | { | 158 | { |
161 | struct timeval tv; | 159 | struct timeval tv; |
162 | do_gettimeofday(&tv); | 160 | do_gettimeofday(&tv); |
163 | tomoyo_convert_time(tv.tv_sec, &stamp); | 161 | tomoyo_convert_time(tv.tv_sec, &stamp); |
164 | } | 162 | } |
165 | pos = snprintf(buffer, tomoyo_buffer_len - 1, | 163 | pos = snprintf(buffer, tomoyo_buffer_len - 1, |
166 | "#%04u/%02u/%02u %02u:%02u:%02u# profile=%u mode=%s " | 164 | "#%04u/%02u/%02u %02u:%02u:%02u# profile=%u mode=%s " |
167 | "granted=%s (global-pid=%u) task={ pid=%u ppid=%u " | 165 | "granted=%s (global-pid=%u) task={ pid=%u ppid=%u " |
168 | "uid=%u gid=%u euid=%u egid=%u suid=%u sgid=%u " | 166 | "uid=%u gid=%u euid=%u egid=%u suid=%u sgid=%u " |
169 | "fsuid=%u fsgid=%u }", stamp.year, stamp.month, | 167 | "fsuid=%u fsgid=%u }", stamp.year, stamp.month, |
170 | stamp.day, stamp.hour, stamp.min, stamp.sec, r->profile, | 168 | stamp.day, stamp.hour, stamp.min, stamp.sec, r->profile, |
171 | tomoyo_mode[r->mode], tomoyo_yesno(r->granted), gpid, | 169 | tomoyo_mode[r->mode], tomoyo_yesno(r->granted), gpid, |
172 | tomoyo_sys_getpid(), tomoyo_sys_getppid(), | 170 | tomoyo_sys_getpid(), tomoyo_sys_getppid(), |
173 | current_uid(), current_gid(), current_euid(), | 171 | current_uid(), current_gid(), current_euid(), |
174 | current_egid(), current_suid(), current_sgid(), | 172 | current_egid(), current_suid(), current_sgid(), |
175 | current_fsuid(), current_fsgid()); | 173 | current_fsuid(), current_fsgid()); |
176 | if (!obj) | 174 | if (!obj) |
177 | goto no_obj_info; | 175 | goto no_obj_info; |
178 | if (!obj->validate_done) { | 176 | if (!obj->validate_done) { |
179 | tomoyo_get_attributes(obj); | 177 | tomoyo_get_attributes(obj); |
180 | obj->validate_done = true; | 178 | obj->validate_done = true; |
181 | } | 179 | } |
182 | for (i = 0; i < TOMOYO_MAX_PATH_STAT; i++) { | 180 | for (i = 0; i < TOMOYO_MAX_PATH_STAT; i++) { |
183 | struct tomoyo_mini_stat *stat; | 181 | struct tomoyo_mini_stat *stat; |
184 | unsigned int dev; | 182 | unsigned int dev; |
185 | mode_t mode; | 183 | mode_t mode; |
186 | if (!obj->stat_valid[i]) | 184 | if (!obj->stat_valid[i]) |
187 | continue; | 185 | continue; |
188 | stat = &obj->stat[i]; | 186 | stat = &obj->stat[i]; |
189 | dev = stat->dev; | 187 | dev = stat->dev; |
190 | mode = stat->mode; | 188 | mode = stat->mode; |
191 | if (i & 1) { | 189 | if (i & 1) { |
192 | pos += snprintf(buffer + pos, | 190 | pos += snprintf(buffer + pos, |
193 | tomoyo_buffer_len - 1 - pos, | 191 | tomoyo_buffer_len - 1 - pos, |
194 | " path%u.parent={ uid=%u gid=%u " | 192 | " path%u.parent={ uid=%u gid=%u " |
195 | "ino=%lu perm=0%o }", (i >> 1) + 1, | 193 | "ino=%lu perm=0%o }", (i >> 1) + 1, |
196 | stat->uid, stat->gid, (unsigned long) | 194 | stat->uid, stat->gid, (unsigned long) |
197 | stat->ino, stat->mode & S_IALLUGO); | 195 | stat->ino, stat->mode & S_IALLUGO); |
198 | continue; | 196 | continue; |
199 | } | 197 | } |
200 | pos += snprintf(buffer + pos, tomoyo_buffer_len - 1 - pos, | 198 | pos += snprintf(buffer + pos, tomoyo_buffer_len - 1 - pos, |
201 | " path%u={ uid=%u gid=%u ino=%lu major=%u" | 199 | " path%u={ uid=%u gid=%u ino=%lu major=%u" |
202 | " minor=%u perm=0%o type=%s", (i >> 1) + 1, | 200 | " minor=%u perm=0%o type=%s", (i >> 1) + 1, |
203 | stat->uid, stat->gid, (unsigned long) | 201 | stat->uid, stat->gid, (unsigned long) |
204 | stat->ino, MAJOR(dev), MINOR(dev), | 202 | stat->ino, MAJOR(dev), MINOR(dev), |
205 | mode & S_IALLUGO, tomoyo_filetype(mode)); | 203 | mode & S_IALLUGO, tomoyo_filetype(mode)); |
206 | if (S_ISCHR(mode) || S_ISBLK(mode)) { | 204 | if (S_ISCHR(mode) || S_ISBLK(mode)) { |
207 | dev = stat->rdev; | 205 | dev = stat->rdev; |
208 | pos += snprintf(buffer + pos, | 206 | pos += snprintf(buffer + pos, |
209 | tomoyo_buffer_len - 1 - pos, | 207 | tomoyo_buffer_len - 1 - pos, |
210 | " dev_major=%u dev_minor=%u", | 208 | " dev_major=%u dev_minor=%u", |
211 | MAJOR(dev), MINOR(dev)); | 209 | MAJOR(dev), MINOR(dev)); |
212 | } | 210 | } |
213 | pos += snprintf(buffer + pos, tomoyo_buffer_len - 1 - pos, | 211 | pos += snprintf(buffer + pos, tomoyo_buffer_len - 1 - pos, |
214 | " }"); | 212 | " }"); |
215 | } | 213 | } |
216 | no_obj_info: | 214 | no_obj_info: |
217 | if (pos < tomoyo_buffer_len - 1) | 215 | if (pos < tomoyo_buffer_len - 1) |
218 | return buffer; | 216 | return buffer; |
219 | kfree(buffer); | 217 | kfree(buffer); |
220 | return NULL; | 218 | return NULL; |
221 | } | 219 | } |
222 | 220 | ||
223 | /** | 221 | /** |
224 | * tomoyo_init_log - Allocate buffer for audit logs. | 222 | * tomoyo_init_log - Allocate buffer for audit logs. |
225 | * | 223 | * |
226 | * @r: Pointer to "struct tomoyo_request_info". | 224 | * @r: Pointer to "struct tomoyo_request_info". |
227 | * @len: Buffer size needed for @fmt and @args. | 225 | * @len: Buffer size needed for @fmt and @args. |
228 | * @fmt: The printf()'s format string. | 226 | * @fmt: The printf()'s format string. |
229 | * @args: va_list structure for @fmt. | 227 | * @args: va_list structure for @fmt. |
230 | * | 228 | * |
231 | * Returns pointer to allocated memory. | 229 | * Returns pointer to allocated memory. |
232 | * | 230 | * |
233 | * This function uses kzalloc(), so caller must kfree() if this function | 231 | * This function uses kzalloc(), so caller must kfree() if this function |
234 | * didn't return NULL. | 232 | * didn't return NULL. |
235 | */ | 233 | */ |
236 | char *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt, | 234 | char *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt, |
237 | va_list args) | 235 | va_list args) |
238 | { | 236 | { |
239 | char *buf = NULL; | 237 | char *buf = NULL; |
240 | char *bprm_info = NULL; | 238 | char *bprm_info = NULL; |
241 | const char *header = NULL; | 239 | const char *header = NULL; |
242 | char *realpath = NULL; | 240 | char *realpath = NULL; |
243 | const char *symlink = NULL; | 241 | const char *symlink = NULL; |
244 | int pos; | 242 | int pos; |
245 | const char *domainname = r->domain->domainname->name; | 243 | const char *domainname = r->domain->domainname->name; |
246 | header = tomoyo_print_header(r); | 244 | header = tomoyo_print_header(r); |
247 | if (!header) | 245 | if (!header) |
248 | return NULL; | 246 | return NULL; |
249 | /* +10 is for '\n' etc. and '\0'. */ | 247 | /* +10 is for '\n' etc. and '\0'. */ |
250 | len += strlen(domainname) + strlen(header) + 10; | 248 | len += strlen(domainname) + strlen(header) + 10; |
251 | if (r->ee) { | 249 | if (r->ee) { |
252 | struct file *file = r->ee->bprm->file; | 250 | struct file *file = r->ee->bprm->file; |
253 | realpath = tomoyo_realpath_from_path(&file->f_path); | 251 | realpath = tomoyo_realpath_from_path(&file->f_path); |
254 | bprm_info = tomoyo_print_bprm(r->ee->bprm, &r->ee->dump); | 252 | bprm_info = tomoyo_print_bprm(r->ee->bprm, &r->ee->dump); |
255 | if (!realpath || !bprm_info) | 253 | if (!realpath || !bprm_info) |
256 | goto out; | 254 | goto out; |
257 | /* +80 is for " exec={ realpath=\"%s\" argc=%d envc=%d %s }" */ | 255 | /* +80 is for " exec={ realpath=\"%s\" argc=%d envc=%d %s }" */ |
258 | len += strlen(realpath) + 80 + strlen(bprm_info); | 256 | len += strlen(realpath) + 80 + strlen(bprm_info); |
259 | } else if (r->obj && r->obj->symlink_target) { | 257 | } else if (r->obj && r->obj->symlink_target) { |
260 | symlink = r->obj->symlink_target->name; | 258 | symlink = r->obj->symlink_target->name; |
261 | /* +18 is for " symlink.target=\"%s\"" */ | 259 | /* +18 is for " symlink.target=\"%s\"" */ |
262 | len += 18 + strlen(symlink); | 260 | len += 18 + strlen(symlink); |
263 | } | 261 | } |
264 | len = tomoyo_round2(len); | 262 | len = tomoyo_round2(len); |
265 | buf = kzalloc(len, GFP_NOFS); | 263 | buf = kzalloc(len, GFP_NOFS); |
266 | if (!buf) | 264 | if (!buf) |
267 | goto out; | 265 | goto out; |
268 | len--; | 266 | len--; |
269 | pos = snprintf(buf, len, "%s", header); | 267 | pos = snprintf(buf, len, "%s", header); |
270 | if (realpath) { | 268 | if (realpath) { |
271 | struct linux_binprm *bprm = r->ee->bprm; | 269 | struct linux_binprm *bprm = r->ee->bprm; |
272 | pos += snprintf(buf + pos, len - pos, | 270 | pos += snprintf(buf + pos, len - pos, |
273 | " exec={ realpath=\"%s\" argc=%d envc=%d %s }", | 271 | " exec={ realpath=\"%s\" argc=%d envc=%d %s }", |
274 | realpath, bprm->argc, bprm->envc, bprm_info); | 272 | realpath, bprm->argc, bprm->envc, bprm_info); |
275 | } else if (symlink) | 273 | } else if (symlink) |
276 | pos += snprintf(buf + pos, len - pos, " symlink.target=\"%s\"", | 274 | pos += snprintf(buf + pos, len - pos, " symlink.target=\"%s\"", |
277 | symlink); | 275 | symlink); |
278 | pos += snprintf(buf + pos, len - pos, "\n%s\n", domainname); | 276 | pos += snprintf(buf + pos, len - pos, "\n%s\n", domainname); |
279 | vsnprintf(buf + pos, len - pos, fmt, args); | 277 | vsnprintf(buf + pos, len - pos, fmt, args); |
280 | out: | 278 | out: |
281 | kfree(realpath); | 279 | kfree(realpath); |
282 | kfree(bprm_info); | 280 | kfree(bprm_info); |
283 | kfree(header); | 281 | kfree(header); |
284 | return buf; | 282 | return buf; |
285 | } | 283 | } |
286 | 284 | ||
287 | /* Wait queue for /sys/kernel/security/tomoyo/audit. */ | 285 | /* Wait queue for /sys/kernel/security/tomoyo/audit. */ |
288 | static DECLARE_WAIT_QUEUE_HEAD(tomoyo_log_wait); | 286 | static DECLARE_WAIT_QUEUE_HEAD(tomoyo_log_wait); |
289 | 287 | ||
290 | /* Structure for audit log. */ | 288 | /* Structure for audit log. */ |
291 | struct tomoyo_log { | 289 | struct tomoyo_log { |
292 | struct list_head list; | 290 | struct list_head list; |
293 | char *log; | 291 | char *log; |
294 | int size; | 292 | int size; |
295 | }; | 293 | }; |
296 | 294 | ||
297 | /* The list for "struct tomoyo_log". */ | 295 | /* The list for "struct tomoyo_log". */ |
298 | static LIST_HEAD(tomoyo_log); | 296 | static LIST_HEAD(tomoyo_log); |
299 | 297 | ||
300 | /* Lock for "struct list_head tomoyo_log". */ | 298 | /* Lock for "struct list_head tomoyo_log". */ |
301 | static DEFINE_SPINLOCK(tomoyo_log_lock); | 299 | static DEFINE_SPINLOCK(tomoyo_log_lock); |
302 | 300 | ||
303 | /* Length of "stuct list_head tomoyo_log". */ | 301 | /* Length of "stuct list_head tomoyo_log". */ |
304 | static unsigned int tomoyo_log_count; | 302 | static unsigned int tomoyo_log_count; |
305 | 303 | ||
306 | /** | 304 | /** |
307 | * tomoyo_get_audit - Get audit mode. | 305 | * tomoyo_get_audit - Get audit mode. |
308 | * | 306 | * |
309 | * @ns: Pointer to "struct tomoyo_policy_namespace". | 307 | * @ns: Pointer to "struct tomoyo_policy_namespace". |
310 | * @profile: Profile number. | 308 | * @profile: Profile number. |
311 | * @index: Index number of functionality. | 309 | * @index: Index number of functionality. |
312 | * @is_granted: True if granted log, false otherwise. | 310 | * @is_granted: True if granted log, false otherwise. |
313 | * | 311 | * |
314 | * Returns true if this request should be audited, false otherwise. | 312 | * Returns true if this request should be audited, false otherwise. |
315 | */ | 313 | */ |
316 | static bool tomoyo_get_audit(const struct tomoyo_policy_namespace *ns, | 314 | static bool tomoyo_get_audit(const struct tomoyo_policy_namespace *ns, |
317 | const u8 profile, const u8 index, | 315 | const u8 profile, const u8 index, |
318 | const bool is_granted) | 316 | const bool is_granted) |
319 | { | 317 | { |
320 | u8 mode; | 318 | u8 mode; |
321 | const u8 category = tomoyo_index2category[index] + | 319 | const u8 category = tomoyo_index2category[index] + |
322 | TOMOYO_MAX_MAC_INDEX; | 320 | TOMOYO_MAX_MAC_INDEX; |
323 | struct tomoyo_profile *p; | 321 | struct tomoyo_profile *p; |
324 | if (!tomoyo_policy_loaded) | 322 | if (!tomoyo_policy_loaded) |
325 | return false; | 323 | return false; |
326 | p = tomoyo_profile(ns, profile); | 324 | p = tomoyo_profile(ns, profile); |
327 | if (tomoyo_log_count >= p->pref[TOMOYO_PREF_MAX_AUDIT_LOG]) | 325 | if (tomoyo_log_count >= p->pref[TOMOYO_PREF_MAX_AUDIT_LOG]) |
328 | return false; | 326 | return false; |
329 | mode = p->config[index]; | 327 | mode = p->config[index]; |
330 | if (mode == TOMOYO_CONFIG_USE_DEFAULT) | 328 | if (mode == TOMOYO_CONFIG_USE_DEFAULT) |
331 | mode = p->config[category]; | 329 | mode = p->config[category]; |
332 | if (mode == TOMOYO_CONFIG_USE_DEFAULT) | 330 | if (mode == TOMOYO_CONFIG_USE_DEFAULT) |
333 | mode = p->default_config; | 331 | mode = p->default_config; |
334 | if (is_granted) | 332 | if (is_granted) |
335 | return mode & TOMOYO_CONFIG_WANT_GRANT_LOG; | 333 | return mode & TOMOYO_CONFIG_WANT_GRANT_LOG; |
336 | return mode & TOMOYO_CONFIG_WANT_REJECT_LOG; | 334 | return mode & TOMOYO_CONFIG_WANT_REJECT_LOG; |
337 | } | 335 | } |
338 | 336 | ||
339 | /** | 337 | /** |
340 | * tomoyo_write_log2 - Write an audit log. | 338 | * tomoyo_write_log2 - Write an audit log. |
341 | * | 339 | * |
342 | * @r: Pointer to "struct tomoyo_request_info". | 340 | * @r: Pointer to "struct tomoyo_request_info". |
343 | * @len: Buffer size needed for @fmt and @args. | 341 | * @len: Buffer size needed for @fmt and @args. |
344 | * @fmt: The printf()'s format string. | 342 | * @fmt: The printf()'s format string. |
345 | * @args: va_list structure for @fmt. | 343 | * @args: va_list structure for @fmt. |
346 | * | 344 | * |
347 | * Returns nothing. | 345 | * Returns nothing. |
348 | */ | 346 | */ |
349 | void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt, | 347 | void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt, |
350 | va_list args) | 348 | va_list args) |
351 | { | 349 | { |
352 | char *buf; | 350 | char *buf; |
353 | struct tomoyo_log *entry; | 351 | struct tomoyo_log *entry; |
354 | bool quota_exceeded = false; | 352 | bool quota_exceeded = false; |
355 | if (!tomoyo_get_audit(r->domain->ns, r->profile, r->type, r->granted)) | 353 | if (!tomoyo_get_audit(r->domain->ns, r->profile, r->type, r->granted)) |
356 | goto out; | 354 | goto out; |
357 | buf = tomoyo_init_log(r, len, fmt, args); | 355 | buf = tomoyo_init_log(r, len, fmt, args); |
358 | if (!buf) | 356 | if (!buf) |
359 | goto out; | 357 | goto out; |
360 | entry = kzalloc(sizeof(*entry), GFP_NOFS); | 358 | entry = kzalloc(sizeof(*entry), GFP_NOFS); |
361 | if (!entry) { | 359 | if (!entry) { |
362 | kfree(buf); | 360 | kfree(buf); |
363 | goto out; | 361 | goto out; |
364 | } | 362 | } |
365 | entry->log = buf; | 363 | entry->log = buf; |
366 | len = tomoyo_round2(strlen(buf) + 1); | 364 | len = tomoyo_round2(strlen(buf) + 1); |
367 | /* | 365 | /* |
368 | * The entry->size is used for memory quota checks. | 366 | * The entry->size is used for memory quota checks. |
369 | * Don't go beyond strlen(entry->log). | 367 | * Don't go beyond strlen(entry->log). |
370 | */ | 368 | */ |
371 | entry->size = len + tomoyo_round2(sizeof(*entry)); | 369 | entry->size = len + tomoyo_round2(sizeof(*entry)); |
372 | spin_lock(&tomoyo_log_lock); | 370 | spin_lock(&tomoyo_log_lock); |
373 | if (tomoyo_memory_quota[TOMOYO_MEMORY_AUDIT] && | 371 | if (tomoyo_memory_quota[TOMOYO_MEMORY_AUDIT] && |
374 | tomoyo_memory_used[TOMOYO_MEMORY_AUDIT] + entry->size >= | 372 | tomoyo_memory_used[TOMOYO_MEMORY_AUDIT] + entry->size >= |
375 | tomoyo_memory_quota[TOMOYO_MEMORY_AUDIT]) { | 373 | tomoyo_memory_quota[TOMOYO_MEMORY_AUDIT]) { |
376 | quota_exceeded = true; | 374 | quota_exceeded = true; |
377 | } else { | 375 | } else { |
378 | tomoyo_memory_used[TOMOYO_MEMORY_AUDIT] += entry->size; | 376 | tomoyo_memory_used[TOMOYO_MEMORY_AUDIT] += entry->size; |
379 | list_add_tail(&entry->list, &tomoyo_log); | 377 | list_add_tail(&entry->list, &tomoyo_log); |
380 | tomoyo_log_count++; | 378 | tomoyo_log_count++; |
381 | } | 379 | } |
382 | spin_unlock(&tomoyo_log_lock); | 380 | spin_unlock(&tomoyo_log_lock); |
383 | if (quota_exceeded) { | 381 | if (quota_exceeded) { |
384 | kfree(buf); | 382 | kfree(buf); |
385 | kfree(entry); | 383 | kfree(entry); |
386 | goto out; | 384 | goto out; |
387 | } | 385 | } |
388 | wake_up(&tomoyo_log_wait); | 386 | wake_up(&tomoyo_log_wait); |
389 | out: | 387 | out: |
390 | return; | 388 | return; |
391 | } | 389 | } |
392 | 390 | ||
393 | /** | 391 | /** |
394 | * tomoyo_write_log - Write an audit log. | 392 | * tomoyo_write_log - Write an audit log. |
395 | * | 393 | * |
396 | * @r: Pointer to "struct tomoyo_request_info". | 394 | * @r: Pointer to "struct tomoyo_request_info". |
397 | * @fmt: The printf()'s format string, followed by parameters. | 395 | * @fmt: The printf()'s format string, followed by parameters. |
398 | * | 396 | * |
399 | * Returns nothing. | 397 | * Returns nothing. |
400 | */ | 398 | */ |
401 | void tomoyo_write_log(struct tomoyo_request_info *r, const char *fmt, ...) | 399 | void tomoyo_write_log(struct tomoyo_request_info *r, const char *fmt, ...) |
402 | { | 400 | { |
403 | va_list args; | 401 | va_list args; |
404 | int len; | 402 | int len; |
405 | va_start(args, fmt); | 403 | va_start(args, fmt); |
406 | len = vsnprintf((char *) &len, 1, fmt, args) + 1; | 404 | len = vsnprintf((char *) &len, 1, fmt, args) + 1; |
407 | va_end(args); | 405 | va_end(args); |
408 | va_start(args, fmt); | 406 | va_start(args, fmt); |
409 | tomoyo_write_log2(r, len, fmt, args); | 407 | tomoyo_write_log2(r, len, fmt, args); |
410 | va_end(args); | 408 | va_end(args); |
411 | } | 409 | } |
412 | 410 | ||
413 | /** | 411 | /** |
414 | * tomoyo_read_log - Read an audit log. | 412 | * tomoyo_read_log - Read an audit log. |
415 | * | 413 | * |
416 | * @head: Pointer to "struct tomoyo_io_buffer". | 414 | * @head: Pointer to "struct tomoyo_io_buffer". |
417 | * | 415 | * |
418 | * Returns nothing. | 416 | * Returns nothing. |
419 | */ | 417 | */ |
420 | void tomoyo_read_log(struct tomoyo_io_buffer *head) | 418 | void tomoyo_read_log(struct tomoyo_io_buffer *head) |
421 | { | 419 | { |
422 | struct tomoyo_log *ptr = NULL; | 420 | struct tomoyo_log *ptr = NULL; |
423 | if (head->r.w_pos) | 421 | if (head->r.w_pos) |
424 | return; | 422 | return; |
425 | kfree(head->read_buf); | 423 | kfree(head->read_buf); |
426 | head->read_buf = NULL; | 424 | head->read_buf = NULL; |
427 | spin_lock(&tomoyo_log_lock); | 425 | spin_lock(&tomoyo_log_lock); |
428 | if (!list_empty(&tomoyo_log)) { | 426 | if (!list_empty(&tomoyo_log)) { |
429 | ptr = list_entry(tomoyo_log.next, typeof(*ptr), list); | 427 | ptr = list_entry(tomoyo_log.next, typeof(*ptr), list); |
430 | list_del(&ptr->list); | 428 | list_del(&ptr->list); |
431 | tomoyo_log_count--; | 429 | tomoyo_log_count--; |
432 | tomoyo_memory_used[TOMOYO_MEMORY_AUDIT] -= ptr->size; | 430 | tomoyo_memory_used[TOMOYO_MEMORY_AUDIT] -= ptr->size; |
433 | } | 431 | } |
434 | spin_unlock(&tomoyo_log_lock); | 432 | spin_unlock(&tomoyo_log_lock); |
435 | if (ptr) { | 433 | if (ptr) { |
436 | head->read_buf = ptr->log; | 434 | head->read_buf = ptr->log; |
437 | head->r.w[head->r.w_pos++] = head->read_buf; | 435 | head->r.w[head->r.w_pos++] = head->read_buf; |
438 | kfree(ptr); | 436 | kfree(ptr); |
439 | } | 437 | } |
440 | } | 438 | } |
441 | 439 | ||
442 | /** | 440 | /** |
443 | * tomoyo_poll_log - Wait for an audit log. | 441 | * tomoyo_poll_log - Wait for an audit log. |
444 | * | 442 | * |
445 | * @file: Pointer to "struct file". | 443 | * @file: Pointer to "struct file". |
446 | * @wait: Pointer to "poll_table". | 444 | * @wait: Pointer to "poll_table". |
447 | * | 445 | * |
448 | * Returns POLLIN | POLLRDNORM when ready to read an audit log. | 446 | * Returns POLLIN | POLLRDNORM when ready to read an audit log. |
449 | */ | 447 | */ |
450 | int tomoyo_poll_log(struct file *file, poll_table *wait) | 448 | int tomoyo_poll_log(struct file *file, poll_table *wait) |
451 | { | 449 | { |
452 | if (tomoyo_log_count) | 450 | if (tomoyo_log_count) |
453 | return POLLIN | POLLRDNORM; | 451 | return POLLIN | POLLRDNORM; |
454 | poll_wait(file, &tomoyo_log_wait, wait); | 452 | poll_wait(file, &tomoyo_log_wait, wait); |
455 | if (tomoyo_log_count) | 453 | if (tomoyo_log_count) |
456 | return POLLIN | POLLRDNORM; | 454 | return POLLIN | POLLRDNORM; |
457 | return 0; | 455 | return 0; |
458 | } | 456 | } |
459 | 457 |
security/tomoyo/common.c
1 | /* | 1 | /* |
2 | * security/tomoyo/common.c | 2 | * security/tomoyo/common.c |
3 | * | 3 | * |
4 | * Common functions for TOMOYO. | 4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION |
5 | * | ||
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
7 | */ | 5 | */ |
8 | 6 | ||
9 | #include <linux/uaccess.h> | 7 | #include <linux/uaccess.h> |
10 | #include <linux/slab.h> | 8 | #include <linux/slab.h> |
11 | #include <linux/security.h> | 9 | #include <linux/security.h> |
12 | #include "common.h" | 10 | #include "common.h" |
13 | 11 | ||
14 | /* String table for operation mode. */ | 12 | /* String table for operation mode. */ |
15 | const char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE] = { | 13 | const char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE] = { |
16 | [TOMOYO_CONFIG_DISABLED] = "disabled", | 14 | [TOMOYO_CONFIG_DISABLED] = "disabled", |
17 | [TOMOYO_CONFIG_LEARNING] = "learning", | 15 | [TOMOYO_CONFIG_LEARNING] = "learning", |
18 | [TOMOYO_CONFIG_PERMISSIVE] = "permissive", | 16 | [TOMOYO_CONFIG_PERMISSIVE] = "permissive", |
19 | [TOMOYO_CONFIG_ENFORCING] = "enforcing" | 17 | [TOMOYO_CONFIG_ENFORCING] = "enforcing" |
20 | }; | 18 | }; |
21 | 19 | ||
22 | /* String table for /sys/kernel/security/tomoyo/profile */ | 20 | /* String table for /sys/kernel/security/tomoyo/profile */ |
23 | const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX | 21 | const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX |
24 | + TOMOYO_MAX_MAC_CATEGORY_INDEX] = { | 22 | + TOMOYO_MAX_MAC_CATEGORY_INDEX] = { |
25 | [TOMOYO_MAC_FILE_EXECUTE] = "execute", | 23 | [TOMOYO_MAC_FILE_EXECUTE] = "execute", |
26 | [TOMOYO_MAC_FILE_OPEN] = "open", | 24 | [TOMOYO_MAC_FILE_OPEN] = "open", |
27 | [TOMOYO_MAC_FILE_CREATE] = "create", | 25 | [TOMOYO_MAC_FILE_CREATE] = "create", |
28 | [TOMOYO_MAC_FILE_UNLINK] = "unlink", | 26 | [TOMOYO_MAC_FILE_UNLINK] = "unlink", |
29 | [TOMOYO_MAC_FILE_GETATTR] = "getattr", | 27 | [TOMOYO_MAC_FILE_GETATTR] = "getattr", |
30 | [TOMOYO_MAC_FILE_MKDIR] = "mkdir", | 28 | [TOMOYO_MAC_FILE_MKDIR] = "mkdir", |
31 | [TOMOYO_MAC_FILE_RMDIR] = "rmdir", | 29 | [TOMOYO_MAC_FILE_RMDIR] = "rmdir", |
32 | [TOMOYO_MAC_FILE_MKFIFO] = "mkfifo", | 30 | [TOMOYO_MAC_FILE_MKFIFO] = "mkfifo", |
33 | [TOMOYO_MAC_FILE_MKSOCK] = "mksock", | 31 | [TOMOYO_MAC_FILE_MKSOCK] = "mksock", |
34 | [TOMOYO_MAC_FILE_TRUNCATE] = "truncate", | 32 | [TOMOYO_MAC_FILE_TRUNCATE] = "truncate", |
35 | [TOMOYO_MAC_FILE_SYMLINK] = "symlink", | 33 | [TOMOYO_MAC_FILE_SYMLINK] = "symlink", |
36 | [TOMOYO_MAC_FILE_MKBLOCK] = "mkblock", | 34 | [TOMOYO_MAC_FILE_MKBLOCK] = "mkblock", |
37 | [TOMOYO_MAC_FILE_MKCHAR] = "mkchar", | 35 | [TOMOYO_MAC_FILE_MKCHAR] = "mkchar", |
38 | [TOMOYO_MAC_FILE_LINK] = "link", | 36 | [TOMOYO_MAC_FILE_LINK] = "link", |
39 | [TOMOYO_MAC_FILE_RENAME] = "rename", | 37 | [TOMOYO_MAC_FILE_RENAME] = "rename", |
40 | [TOMOYO_MAC_FILE_CHMOD] = "chmod", | 38 | [TOMOYO_MAC_FILE_CHMOD] = "chmod", |
41 | [TOMOYO_MAC_FILE_CHOWN] = "chown", | 39 | [TOMOYO_MAC_FILE_CHOWN] = "chown", |
42 | [TOMOYO_MAC_FILE_CHGRP] = "chgrp", | 40 | [TOMOYO_MAC_FILE_CHGRP] = "chgrp", |
43 | [TOMOYO_MAC_FILE_IOCTL] = "ioctl", | 41 | [TOMOYO_MAC_FILE_IOCTL] = "ioctl", |
44 | [TOMOYO_MAC_FILE_CHROOT] = "chroot", | 42 | [TOMOYO_MAC_FILE_CHROOT] = "chroot", |
45 | [TOMOYO_MAC_FILE_MOUNT] = "mount", | 43 | [TOMOYO_MAC_FILE_MOUNT] = "mount", |
46 | [TOMOYO_MAC_FILE_UMOUNT] = "unmount", | 44 | [TOMOYO_MAC_FILE_UMOUNT] = "unmount", |
47 | [TOMOYO_MAC_FILE_PIVOT_ROOT] = "pivot_root", | 45 | [TOMOYO_MAC_FILE_PIVOT_ROOT] = "pivot_root", |
48 | [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_FILE] = "file", | 46 | [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_FILE] = "file", |
49 | }; | 47 | }; |
50 | 48 | ||
51 | /* String table for conditions. */ | 49 | /* String table for conditions. */ |
52 | const char * const tomoyo_condition_keyword[TOMOYO_MAX_CONDITION_KEYWORD] = { | 50 | const char * const tomoyo_condition_keyword[TOMOYO_MAX_CONDITION_KEYWORD] = { |
53 | [TOMOYO_TASK_UID] = "task.uid", | 51 | [TOMOYO_TASK_UID] = "task.uid", |
54 | [TOMOYO_TASK_EUID] = "task.euid", | 52 | [TOMOYO_TASK_EUID] = "task.euid", |
55 | [TOMOYO_TASK_SUID] = "task.suid", | 53 | [TOMOYO_TASK_SUID] = "task.suid", |
56 | [TOMOYO_TASK_FSUID] = "task.fsuid", | 54 | [TOMOYO_TASK_FSUID] = "task.fsuid", |
57 | [TOMOYO_TASK_GID] = "task.gid", | 55 | [TOMOYO_TASK_GID] = "task.gid", |
58 | [TOMOYO_TASK_EGID] = "task.egid", | 56 | [TOMOYO_TASK_EGID] = "task.egid", |
59 | [TOMOYO_TASK_SGID] = "task.sgid", | 57 | [TOMOYO_TASK_SGID] = "task.sgid", |
60 | [TOMOYO_TASK_FSGID] = "task.fsgid", | 58 | [TOMOYO_TASK_FSGID] = "task.fsgid", |
61 | [TOMOYO_TASK_PID] = "task.pid", | 59 | [TOMOYO_TASK_PID] = "task.pid", |
62 | [TOMOYO_TASK_PPID] = "task.ppid", | 60 | [TOMOYO_TASK_PPID] = "task.ppid", |
63 | [TOMOYO_EXEC_ARGC] = "exec.argc", | 61 | [TOMOYO_EXEC_ARGC] = "exec.argc", |
64 | [TOMOYO_EXEC_ENVC] = "exec.envc", | 62 | [TOMOYO_EXEC_ENVC] = "exec.envc", |
65 | [TOMOYO_TYPE_IS_SOCKET] = "socket", | 63 | [TOMOYO_TYPE_IS_SOCKET] = "socket", |
66 | [TOMOYO_TYPE_IS_SYMLINK] = "symlink", | 64 | [TOMOYO_TYPE_IS_SYMLINK] = "symlink", |
67 | [TOMOYO_TYPE_IS_FILE] = "file", | 65 | [TOMOYO_TYPE_IS_FILE] = "file", |
68 | [TOMOYO_TYPE_IS_BLOCK_DEV] = "block", | 66 | [TOMOYO_TYPE_IS_BLOCK_DEV] = "block", |
69 | [TOMOYO_TYPE_IS_DIRECTORY] = "directory", | 67 | [TOMOYO_TYPE_IS_DIRECTORY] = "directory", |
70 | [TOMOYO_TYPE_IS_CHAR_DEV] = "char", | 68 | [TOMOYO_TYPE_IS_CHAR_DEV] = "char", |
71 | [TOMOYO_TYPE_IS_FIFO] = "fifo", | 69 | [TOMOYO_TYPE_IS_FIFO] = "fifo", |
72 | [TOMOYO_MODE_SETUID] = "setuid", | 70 | [TOMOYO_MODE_SETUID] = "setuid", |
73 | [TOMOYO_MODE_SETGID] = "setgid", | 71 | [TOMOYO_MODE_SETGID] = "setgid", |
74 | [TOMOYO_MODE_STICKY] = "sticky", | 72 | [TOMOYO_MODE_STICKY] = "sticky", |
75 | [TOMOYO_MODE_OWNER_READ] = "owner_read", | 73 | [TOMOYO_MODE_OWNER_READ] = "owner_read", |
76 | [TOMOYO_MODE_OWNER_WRITE] = "owner_write", | 74 | [TOMOYO_MODE_OWNER_WRITE] = "owner_write", |
77 | [TOMOYO_MODE_OWNER_EXECUTE] = "owner_execute", | 75 | [TOMOYO_MODE_OWNER_EXECUTE] = "owner_execute", |
78 | [TOMOYO_MODE_GROUP_READ] = "group_read", | 76 | [TOMOYO_MODE_GROUP_READ] = "group_read", |
79 | [TOMOYO_MODE_GROUP_WRITE] = "group_write", | 77 | [TOMOYO_MODE_GROUP_WRITE] = "group_write", |
80 | [TOMOYO_MODE_GROUP_EXECUTE] = "group_execute", | 78 | [TOMOYO_MODE_GROUP_EXECUTE] = "group_execute", |
81 | [TOMOYO_MODE_OTHERS_READ] = "others_read", | 79 | [TOMOYO_MODE_OTHERS_READ] = "others_read", |
82 | [TOMOYO_MODE_OTHERS_WRITE] = "others_write", | 80 | [TOMOYO_MODE_OTHERS_WRITE] = "others_write", |
83 | [TOMOYO_MODE_OTHERS_EXECUTE] = "others_execute", | 81 | [TOMOYO_MODE_OTHERS_EXECUTE] = "others_execute", |
84 | [TOMOYO_EXEC_REALPATH] = "exec.realpath", | 82 | [TOMOYO_EXEC_REALPATH] = "exec.realpath", |
85 | [TOMOYO_SYMLINK_TARGET] = "symlink.target", | 83 | [TOMOYO_SYMLINK_TARGET] = "symlink.target", |
86 | [TOMOYO_PATH1_UID] = "path1.uid", | 84 | [TOMOYO_PATH1_UID] = "path1.uid", |
87 | [TOMOYO_PATH1_GID] = "path1.gid", | 85 | [TOMOYO_PATH1_GID] = "path1.gid", |
88 | [TOMOYO_PATH1_INO] = "path1.ino", | 86 | [TOMOYO_PATH1_INO] = "path1.ino", |
89 | [TOMOYO_PATH1_MAJOR] = "path1.major", | 87 | [TOMOYO_PATH1_MAJOR] = "path1.major", |
90 | [TOMOYO_PATH1_MINOR] = "path1.minor", | 88 | [TOMOYO_PATH1_MINOR] = "path1.minor", |
91 | [TOMOYO_PATH1_PERM] = "path1.perm", | 89 | [TOMOYO_PATH1_PERM] = "path1.perm", |
92 | [TOMOYO_PATH1_TYPE] = "path1.type", | 90 | [TOMOYO_PATH1_TYPE] = "path1.type", |
93 | [TOMOYO_PATH1_DEV_MAJOR] = "path1.dev_major", | 91 | [TOMOYO_PATH1_DEV_MAJOR] = "path1.dev_major", |
94 | [TOMOYO_PATH1_DEV_MINOR] = "path1.dev_minor", | 92 | [TOMOYO_PATH1_DEV_MINOR] = "path1.dev_minor", |
95 | [TOMOYO_PATH2_UID] = "path2.uid", | 93 | [TOMOYO_PATH2_UID] = "path2.uid", |
96 | [TOMOYO_PATH2_GID] = "path2.gid", | 94 | [TOMOYO_PATH2_GID] = "path2.gid", |
97 | [TOMOYO_PATH2_INO] = "path2.ino", | 95 | [TOMOYO_PATH2_INO] = "path2.ino", |
98 | [TOMOYO_PATH2_MAJOR] = "path2.major", | 96 | [TOMOYO_PATH2_MAJOR] = "path2.major", |
99 | [TOMOYO_PATH2_MINOR] = "path2.minor", | 97 | [TOMOYO_PATH2_MINOR] = "path2.minor", |
100 | [TOMOYO_PATH2_PERM] = "path2.perm", | 98 | [TOMOYO_PATH2_PERM] = "path2.perm", |
101 | [TOMOYO_PATH2_TYPE] = "path2.type", | 99 | [TOMOYO_PATH2_TYPE] = "path2.type", |
102 | [TOMOYO_PATH2_DEV_MAJOR] = "path2.dev_major", | 100 | [TOMOYO_PATH2_DEV_MAJOR] = "path2.dev_major", |
103 | [TOMOYO_PATH2_DEV_MINOR] = "path2.dev_minor", | 101 | [TOMOYO_PATH2_DEV_MINOR] = "path2.dev_minor", |
104 | [TOMOYO_PATH1_PARENT_UID] = "path1.parent.uid", | 102 | [TOMOYO_PATH1_PARENT_UID] = "path1.parent.uid", |
105 | [TOMOYO_PATH1_PARENT_GID] = "path1.parent.gid", | 103 | [TOMOYO_PATH1_PARENT_GID] = "path1.parent.gid", |
106 | [TOMOYO_PATH1_PARENT_INO] = "path1.parent.ino", | 104 | [TOMOYO_PATH1_PARENT_INO] = "path1.parent.ino", |
107 | [TOMOYO_PATH1_PARENT_PERM] = "path1.parent.perm", | 105 | [TOMOYO_PATH1_PARENT_PERM] = "path1.parent.perm", |
108 | [TOMOYO_PATH2_PARENT_UID] = "path2.parent.uid", | 106 | [TOMOYO_PATH2_PARENT_UID] = "path2.parent.uid", |
109 | [TOMOYO_PATH2_PARENT_GID] = "path2.parent.gid", | 107 | [TOMOYO_PATH2_PARENT_GID] = "path2.parent.gid", |
110 | [TOMOYO_PATH2_PARENT_INO] = "path2.parent.ino", | 108 | [TOMOYO_PATH2_PARENT_INO] = "path2.parent.ino", |
111 | [TOMOYO_PATH2_PARENT_PERM] = "path2.parent.perm", | 109 | [TOMOYO_PATH2_PARENT_PERM] = "path2.parent.perm", |
112 | }; | 110 | }; |
113 | 111 | ||
114 | /* String table for PREFERENCE keyword. */ | 112 | /* String table for PREFERENCE keyword. */ |
115 | static const char * const tomoyo_pref_keywords[TOMOYO_MAX_PREF] = { | 113 | static const char * const tomoyo_pref_keywords[TOMOYO_MAX_PREF] = { |
116 | [TOMOYO_PREF_MAX_AUDIT_LOG] = "max_audit_log", | 114 | [TOMOYO_PREF_MAX_AUDIT_LOG] = "max_audit_log", |
117 | [TOMOYO_PREF_MAX_LEARNING_ENTRY] = "max_learning_entry", | 115 | [TOMOYO_PREF_MAX_LEARNING_ENTRY] = "max_learning_entry", |
118 | }; | 116 | }; |
119 | 117 | ||
120 | /* String table for path operation. */ | 118 | /* String table for path operation. */ |
121 | const char * const tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = { | 119 | const char * const tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = { |
122 | [TOMOYO_TYPE_EXECUTE] = "execute", | 120 | [TOMOYO_TYPE_EXECUTE] = "execute", |
123 | [TOMOYO_TYPE_READ] = "read", | 121 | [TOMOYO_TYPE_READ] = "read", |
124 | [TOMOYO_TYPE_WRITE] = "write", | 122 | [TOMOYO_TYPE_WRITE] = "write", |
125 | [TOMOYO_TYPE_APPEND] = "append", | 123 | [TOMOYO_TYPE_APPEND] = "append", |
126 | [TOMOYO_TYPE_UNLINK] = "unlink", | 124 | [TOMOYO_TYPE_UNLINK] = "unlink", |
127 | [TOMOYO_TYPE_GETATTR] = "getattr", | 125 | [TOMOYO_TYPE_GETATTR] = "getattr", |
128 | [TOMOYO_TYPE_RMDIR] = "rmdir", | 126 | [TOMOYO_TYPE_RMDIR] = "rmdir", |
129 | [TOMOYO_TYPE_TRUNCATE] = "truncate", | 127 | [TOMOYO_TYPE_TRUNCATE] = "truncate", |
130 | [TOMOYO_TYPE_SYMLINK] = "symlink", | 128 | [TOMOYO_TYPE_SYMLINK] = "symlink", |
131 | [TOMOYO_TYPE_CHROOT] = "chroot", | 129 | [TOMOYO_TYPE_CHROOT] = "chroot", |
132 | [TOMOYO_TYPE_UMOUNT] = "unmount", | 130 | [TOMOYO_TYPE_UMOUNT] = "unmount", |
133 | }; | 131 | }; |
134 | 132 | ||
135 | /* String table for categories. */ | 133 | /* String table for categories. */ |
136 | static const char * const tomoyo_category_keywords | 134 | static const char * const tomoyo_category_keywords |
137 | [TOMOYO_MAX_MAC_CATEGORY_INDEX] = { | 135 | [TOMOYO_MAX_MAC_CATEGORY_INDEX] = { |
138 | [TOMOYO_MAC_CATEGORY_FILE] = "file", | 136 | [TOMOYO_MAC_CATEGORY_FILE] = "file", |
139 | }; | 137 | }; |
140 | 138 | ||
141 | /* Permit policy management by non-root user? */ | 139 | /* Permit policy management by non-root user? */ |
142 | static bool tomoyo_manage_by_non_root; | 140 | static bool tomoyo_manage_by_non_root; |
143 | 141 | ||
144 | /* Utility functions. */ | 142 | /* Utility functions. */ |
145 | 143 | ||
146 | /** | 144 | /** |
147 | * tomoyo_yesno - Return "yes" or "no". | 145 | * tomoyo_yesno - Return "yes" or "no". |
148 | * | 146 | * |
149 | * @value: Bool value. | 147 | * @value: Bool value. |
150 | */ | 148 | */ |
151 | const char *tomoyo_yesno(const unsigned int value) | 149 | const char *tomoyo_yesno(const unsigned int value) |
152 | { | 150 | { |
153 | return value ? "yes" : "no"; | 151 | return value ? "yes" : "no"; |
154 | } | 152 | } |
155 | 153 | ||
156 | /** | 154 | /** |
157 | * tomoyo_addprintf - strncat()-like-snprintf(). | 155 | * tomoyo_addprintf - strncat()-like-snprintf(). |
158 | * | 156 | * |
159 | * @buffer: Buffer to write to. Must be '\0'-terminated. | 157 | * @buffer: Buffer to write to. Must be '\0'-terminated. |
160 | * @len: Size of @buffer. | 158 | * @len: Size of @buffer. |
161 | * @fmt: The printf()'s format string, followed by parameters. | 159 | * @fmt: The printf()'s format string, followed by parameters. |
162 | * | 160 | * |
163 | * Returns nothing. | 161 | * Returns nothing. |
164 | */ | 162 | */ |
165 | static void tomoyo_addprintf(char *buffer, int len, const char *fmt, ...) | 163 | static void tomoyo_addprintf(char *buffer, int len, const char *fmt, ...) |
166 | { | 164 | { |
167 | va_list args; | 165 | va_list args; |
168 | const int pos = strlen(buffer); | 166 | const int pos = strlen(buffer); |
169 | va_start(args, fmt); | 167 | va_start(args, fmt); |
170 | vsnprintf(buffer + pos, len - pos - 1, fmt, args); | 168 | vsnprintf(buffer + pos, len - pos - 1, fmt, args); |
171 | va_end(args); | 169 | va_end(args); |
172 | } | 170 | } |
173 | 171 | ||
174 | /** | 172 | /** |
175 | * tomoyo_flush - Flush queued string to userspace's buffer. | 173 | * tomoyo_flush - Flush queued string to userspace's buffer. |
176 | * | 174 | * |
177 | * @head: Pointer to "struct tomoyo_io_buffer". | 175 | * @head: Pointer to "struct tomoyo_io_buffer". |
178 | * | 176 | * |
179 | * Returns true if all data was flushed, false otherwise. | 177 | * Returns true if all data was flushed, false otherwise. |
180 | */ | 178 | */ |
181 | static bool tomoyo_flush(struct tomoyo_io_buffer *head) | 179 | static bool tomoyo_flush(struct tomoyo_io_buffer *head) |
182 | { | 180 | { |
183 | while (head->r.w_pos) { | 181 | while (head->r.w_pos) { |
184 | const char *w = head->r.w[0]; | 182 | const char *w = head->r.w[0]; |
185 | size_t len = strlen(w); | 183 | size_t len = strlen(w); |
186 | if (len) { | 184 | if (len) { |
187 | if (len > head->read_user_buf_avail) | 185 | if (len > head->read_user_buf_avail) |
188 | len = head->read_user_buf_avail; | 186 | len = head->read_user_buf_avail; |
189 | if (!len) | 187 | if (!len) |
190 | return false; | 188 | return false; |
191 | if (copy_to_user(head->read_user_buf, w, len)) | 189 | if (copy_to_user(head->read_user_buf, w, len)) |
192 | return false; | 190 | return false; |
193 | head->read_user_buf_avail -= len; | 191 | head->read_user_buf_avail -= len; |
194 | head->read_user_buf += len; | 192 | head->read_user_buf += len; |
195 | w += len; | 193 | w += len; |
196 | } | 194 | } |
197 | head->r.w[0] = w; | 195 | head->r.w[0] = w; |
198 | if (*w) | 196 | if (*w) |
199 | return false; | 197 | return false; |
200 | /* Add '\0' for audit logs and query. */ | 198 | /* Add '\0' for audit logs and query. */ |
201 | if (head->poll) { | 199 | if (head->poll) { |
202 | if (!head->read_user_buf_avail || | 200 | if (!head->read_user_buf_avail || |
203 | copy_to_user(head->read_user_buf, "", 1)) | 201 | copy_to_user(head->read_user_buf, "", 1)) |
204 | return false; | 202 | return false; |
205 | head->read_user_buf_avail--; | 203 | head->read_user_buf_avail--; |
206 | head->read_user_buf++; | 204 | head->read_user_buf++; |
207 | } | 205 | } |
208 | head->r.w_pos--; | 206 | head->r.w_pos--; |
209 | for (len = 0; len < head->r.w_pos; len++) | 207 | for (len = 0; len < head->r.w_pos; len++) |
210 | head->r.w[len] = head->r.w[len + 1]; | 208 | head->r.w[len] = head->r.w[len + 1]; |
211 | } | 209 | } |
212 | head->r.avail = 0; | 210 | head->r.avail = 0; |
213 | return true; | 211 | return true; |
214 | } | 212 | } |
215 | 213 | ||
216 | /** | 214 | /** |
217 | * tomoyo_set_string - Queue string to "struct tomoyo_io_buffer" structure. | 215 | * tomoyo_set_string - Queue string to "struct tomoyo_io_buffer" structure. |
218 | * | 216 | * |
219 | * @head: Pointer to "struct tomoyo_io_buffer". | 217 | * @head: Pointer to "struct tomoyo_io_buffer". |
220 | * @string: String to print. | 218 | * @string: String to print. |
221 | * | 219 | * |
222 | * Note that @string has to be kept valid until @head is kfree()d. | 220 | * Note that @string has to be kept valid until @head is kfree()d. |
223 | * This means that char[] allocated on stack memory cannot be passed to | 221 | * This means that char[] allocated on stack memory cannot be passed to |
224 | * this function. Use tomoyo_io_printf() for char[] allocated on stack memory. | 222 | * this function. Use tomoyo_io_printf() for char[] allocated on stack memory. |
225 | */ | 223 | */ |
226 | static void tomoyo_set_string(struct tomoyo_io_buffer *head, const char *string) | 224 | static void tomoyo_set_string(struct tomoyo_io_buffer *head, const char *string) |
227 | { | 225 | { |
228 | if (head->r.w_pos < TOMOYO_MAX_IO_READ_QUEUE) { | 226 | if (head->r.w_pos < TOMOYO_MAX_IO_READ_QUEUE) { |
229 | head->r.w[head->r.w_pos++] = string; | 227 | head->r.w[head->r.w_pos++] = string; |
230 | tomoyo_flush(head); | 228 | tomoyo_flush(head); |
231 | } else | 229 | } else |
232 | WARN_ON(1); | 230 | WARN_ON(1); |
233 | } | 231 | } |
234 | 232 | ||
235 | /** | 233 | /** |
236 | * tomoyo_io_printf - printf() to "struct tomoyo_io_buffer" structure. | 234 | * tomoyo_io_printf - printf() to "struct tomoyo_io_buffer" structure. |
237 | * | 235 | * |
238 | * @head: Pointer to "struct tomoyo_io_buffer". | 236 | * @head: Pointer to "struct tomoyo_io_buffer". |
239 | * @fmt: The printf()'s format string, followed by parameters. | 237 | * @fmt: The printf()'s format string, followed by parameters. |
240 | */ | 238 | */ |
241 | void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) | 239 | void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) |
242 | { | 240 | { |
243 | va_list args; | 241 | va_list args; |
244 | size_t len; | 242 | size_t len; |
245 | size_t pos = head->r.avail; | 243 | size_t pos = head->r.avail; |
246 | int size = head->readbuf_size - pos; | 244 | int size = head->readbuf_size - pos; |
247 | if (size <= 0) | 245 | if (size <= 0) |
248 | return; | 246 | return; |
249 | va_start(args, fmt); | 247 | va_start(args, fmt); |
250 | len = vsnprintf(head->read_buf + pos, size, fmt, args) + 1; | 248 | len = vsnprintf(head->read_buf + pos, size, fmt, args) + 1; |
251 | va_end(args); | 249 | va_end(args); |
252 | if (pos + len >= head->readbuf_size) { | 250 | if (pos + len >= head->readbuf_size) { |
253 | WARN_ON(1); | 251 | WARN_ON(1); |
254 | return; | 252 | return; |
255 | } | 253 | } |
256 | head->r.avail += len; | 254 | head->r.avail += len; |
257 | tomoyo_set_string(head, head->read_buf + pos); | 255 | tomoyo_set_string(head, head->read_buf + pos); |
258 | } | 256 | } |
259 | 257 | ||
260 | /** | 258 | /** |
261 | * tomoyo_set_space - Put a space to "struct tomoyo_io_buffer" structure. | 259 | * tomoyo_set_space - Put a space to "struct tomoyo_io_buffer" structure. |
262 | * | 260 | * |
263 | * @head: Pointer to "struct tomoyo_io_buffer". | 261 | * @head: Pointer to "struct tomoyo_io_buffer". |
264 | * | 262 | * |
265 | * Returns nothing. | 263 | * Returns nothing. |
266 | */ | 264 | */ |
267 | static void tomoyo_set_space(struct tomoyo_io_buffer *head) | 265 | static void tomoyo_set_space(struct tomoyo_io_buffer *head) |
268 | { | 266 | { |
269 | tomoyo_set_string(head, " "); | 267 | tomoyo_set_string(head, " "); |
270 | } | 268 | } |
271 | 269 | ||
272 | /** | 270 | /** |
273 | * tomoyo_set_lf - Put a line feed to "struct tomoyo_io_buffer" structure. | 271 | * tomoyo_set_lf - Put a line feed to "struct tomoyo_io_buffer" structure. |
274 | * | 272 | * |
275 | * @head: Pointer to "struct tomoyo_io_buffer". | 273 | * @head: Pointer to "struct tomoyo_io_buffer". |
276 | * | 274 | * |
277 | * Returns nothing. | 275 | * Returns nothing. |
278 | */ | 276 | */ |
279 | static bool tomoyo_set_lf(struct tomoyo_io_buffer *head) | 277 | static bool tomoyo_set_lf(struct tomoyo_io_buffer *head) |
280 | { | 278 | { |
281 | tomoyo_set_string(head, "\n"); | 279 | tomoyo_set_string(head, "\n"); |
282 | return !head->r.w_pos; | 280 | return !head->r.w_pos; |
283 | } | 281 | } |
284 | 282 | ||
285 | /** | 283 | /** |
286 | * tomoyo_set_slash - Put a shash to "struct tomoyo_io_buffer" structure. | 284 | * tomoyo_set_slash - Put a shash to "struct tomoyo_io_buffer" structure. |
287 | * | 285 | * |
288 | * @head: Pointer to "struct tomoyo_io_buffer". | 286 | * @head: Pointer to "struct tomoyo_io_buffer". |
289 | * | 287 | * |
290 | * Returns nothing. | 288 | * Returns nothing. |
291 | */ | 289 | */ |
292 | static void tomoyo_set_slash(struct tomoyo_io_buffer *head) | 290 | static void tomoyo_set_slash(struct tomoyo_io_buffer *head) |
293 | { | 291 | { |
294 | tomoyo_set_string(head, "/"); | 292 | tomoyo_set_string(head, "/"); |
295 | } | 293 | } |
296 | 294 | ||
297 | /* List of namespaces. */ | 295 | /* List of namespaces. */ |
298 | LIST_HEAD(tomoyo_namespace_list); | 296 | LIST_HEAD(tomoyo_namespace_list); |
299 | /* True if namespace other than tomoyo_kernel_namespace is defined. */ | 297 | /* True if namespace other than tomoyo_kernel_namespace is defined. */ |
300 | static bool tomoyo_namespace_enabled; | 298 | static bool tomoyo_namespace_enabled; |
301 | 299 | ||
302 | /** | 300 | /** |
303 | * tomoyo_init_policy_namespace - Initialize namespace. | 301 | * tomoyo_init_policy_namespace - Initialize namespace. |
304 | * | 302 | * |
305 | * @ns: Pointer to "struct tomoyo_policy_namespace". | 303 | * @ns: Pointer to "struct tomoyo_policy_namespace". |
306 | * | 304 | * |
307 | * Returns nothing. | 305 | * Returns nothing. |
308 | */ | 306 | */ |
309 | void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns) | 307 | void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns) |
310 | { | 308 | { |
311 | unsigned int idx; | 309 | unsigned int idx; |
312 | for (idx = 0; idx < TOMOYO_MAX_ACL_GROUPS; idx++) | 310 | for (idx = 0; idx < TOMOYO_MAX_ACL_GROUPS; idx++) |
313 | INIT_LIST_HEAD(&ns->acl_group[idx]); | 311 | INIT_LIST_HEAD(&ns->acl_group[idx]); |
314 | for (idx = 0; idx < TOMOYO_MAX_GROUP; idx++) | 312 | for (idx = 0; idx < TOMOYO_MAX_GROUP; idx++) |
315 | INIT_LIST_HEAD(&ns->group_list[idx]); | 313 | INIT_LIST_HEAD(&ns->group_list[idx]); |
316 | for (idx = 0; idx < TOMOYO_MAX_POLICY; idx++) | 314 | for (idx = 0; idx < TOMOYO_MAX_POLICY; idx++) |
317 | INIT_LIST_HEAD(&ns->policy_list[idx]); | 315 | INIT_LIST_HEAD(&ns->policy_list[idx]); |
318 | ns->profile_version = 20100903; | 316 | ns->profile_version = 20100903; |
319 | tomoyo_namespace_enabled = !list_empty(&tomoyo_namespace_list); | 317 | tomoyo_namespace_enabled = !list_empty(&tomoyo_namespace_list); |
320 | list_add_tail_rcu(&ns->namespace_list, &tomoyo_namespace_list); | 318 | list_add_tail_rcu(&ns->namespace_list, &tomoyo_namespace_list); |
321 | } | 319 | } |
322 | 320 | ||
323 | /** | 321 | /** |
324 | * tomoyo_print_namespace - Print namespace header. | 322 | * tomoyo_print_namespace - Print namespace header. |
325 | * | 323 | * |
326 | * @head: Pointer to "struct tomoyo_io_buffer". | 324 | * @head: Pointer to "struct tomoyo_io_buffer". |
327 | * | 325 | * |
328 | * Returns nothing. | 326 | * Returns nothing. |
329 | */ | 327 | */ |
330 | static void tomoyo_print_namespace(struct tomoyo_io_buffer *head) | 328 | static void tomoyo_print_namespace(struct tomoyo_io_buffer *head) |
331 | { | 329 | { |
332 | if (!tomoyo_namespace_enabled) | 330 | if (!tomoyo_namespace_enabled) |
333 | return; | 331 | return; |
334 | tomoyo_set_string(head, | 332 | tomoyo_set_string(head, |
335 | container_of(head->r.ns, | 333 | container_of(head->r.ns, |
336 | struct tomoyo_policy_namespace, | 334 | struct tomoyo_policy_namespace, |
337 | namespace_list)->name); | 335 | namespace_list)->name); |
338 | tomoyo_set_space(head); | 336 | tomoyo_set_space(head); |
339 | } | 337 | } |
340 | 338 | ||
341 | /** | 339 | /** |
342 | * tomoyo_print_name_union - Print a tomoyo_name_union. | 340 | * tomoyo_print_name_union - Print a tomoyo_name_union. |
343 | * | 341 | * |
344 | * @head: Pointer to "struct tomoyo_io_buffer". | 342 | * @head: Pointer to "struct tomoyo_io_buffer". |
345 | * @ptr: Pointer to "struct tomoyo_name_union". | 343 | * @ptr: Pointer to "struct tomoyo_name_union". |
346 | */ | 344 | */ |
347 | static void tomoyo_print_name_union(struct tomoyo_io_buffer *head, | 345 | static void tomoyo_print_name_union(struct tomoyo_io_buffer *head, |
348 | const struct tomoyo_name_union *ptr) | 346 | const struct tomoyo_name_union *ptr) |
349 | { | 347 | { |
350 | tomoyo_set_space(head); | 348 | tomoyo_set_space(head); |
351 | if (ptr->group) { | 349 | if (ptr->group) { |
352 | tomoyo_set_string(head, "@"); | 350 | tomoyo_set_string(head, "@"); |
353 | tomoyo_set_string(head, ptr->group->group_name->name); | 351 | tomoyo_set_string(head, ptr->group->group_name->name); |
354 | } else { | 352 | } else { |
355 | tomoyo_set_string(head, ptr->filename->name); | 353 | tomoyo_set_string(head, ptr->filename->name); |
356 | } | 354 | } |
357 | } | 355 | } |
358 | 356 | ||
359 | /** | 357 | /** |
360 | * tomoyo_print_name_union_quoted - Print a tomoyo_name_union with a quote. | 358 | * tomoyo_print_name_union_quoted - Print a tomoyo_name_union with a quote. |
361 | * | 359 | * |
362 | * @head: Pointer to "struct tomoyo_io_buffer". | 360 | * @head: Pointer to "struct tomoyo_io_buffer". |
363 | * @ptr: Pointer to "struct tomoyo_name_union". | 361 | * @ptr: Pointer to "struct tomoyo_name_union". |
364 | * | 362 | * |
365 | * Returns nothing. | 363 | * Returns nothing. |
366 | */ | 364 | */ |
367 | static void tomoyo_print_name_union_quoted(struct tomoyo_io_buffer *head, | 365 | static void tomoyo_print_name_union_quoted(struct tomoyo_io_buffer *head, |
368 | const struct tomoyo_name_union *ptr) | 366 | const struct tomoyo_name_union *ptr) |
369 | { | 367 | { |
370 | if (ptr->group) { | 368 | if (ptr->group) { |
371 | tomoyo_set_string(head, "@"); | 369 | tomoyo_set_string(head, "@"); |
372 | tomoyo_set_string(head, ptr->group->group_name->name); | 370 | tomoyo_set_string(head, ptr->group->group_name->name); |
373 | } else { | 371 | } else { |
374 | tomoyo_set_string(head, "\""); | 372 | tomoyo_set_string(head, "\""); |
375 | tomoyo_set_string(head, ptr->filename->name); | 373 | tomoyo_set_string(head, ptr->filename->name); |
376 | tomoyo_set_string(head, "\""); | 374 | tomoyo_set_string(head, "\""); |
377 | } | 375 | } |
378 | } | 376 | } |
379 | 377 | ||
380 | /** | 378 | /** |
381 | * tomoyo_print_number_union_nospace - Print a tomoyo_number_union without a space. | 379 | * tomoyo_print_number_union_nospace - Print a tomoyo_number_union without a space. |
382 | * | 380 | * |
383 | * @head: Pointer to "struct tomoyo_io_buffer". | 381 | * @head: Pointer to "struct tomoyo_io_buffer". |
384 | * @ptr: Pointer to "struct tomoyo_number_union". | 382 | * @ptr: Pointer to "struct tomoyo_number_union". |
385 | * | 383 | * |
386 | * Returns nothing. | 384 | * Returns nothing. |
387 | */ | 385 | */ |
388 | static void tomoyo_print_number_union_nospace | 386 | static void tomoyo_print_number_union_nospace |
389 | (struct tomoyo_io_buffer *head, const struct tomoyo_number_union *ptr) | 387 | (struct tomoyo_io_buffer *head, const struct tomoyo_number_union *ptr) |
390 | { | 388 | { |
391 | if (ptr->group) { | 389 | if (ptr->group) { |
392 | tomoyo_set_string(head, "@"); | 390 | tomoyo_set_string(head, "@"); |
393 | tomoyo_set_string(head, ptr->group->group_name->name); | 391 | tomoyo_set_string(head, ptr->group->group_name->name); |
394 | } else { | 392 | } else { |
395 | int i; | 393 | int i; |
396 | unsigned long min = ptr->values[0]; | 394 | unsigned long min = ptr->values[0]; |
397 | const unsigned long max = ptr->values[1]; | 395 | const unsigned long max = ptr->values[1]; |
398 | u8 min_type = ptr->value_type[0]; | 396 | u8 min_type = ptr->value_type[0]; |
399 | const u8 max_type = ptr->value_type[1]; | 397 | const u8 max_type = ptr->value_type[1]; |
400 | char buffer[128]; | 398 | char buffer[128]; |
401 | buffer[0] = '\0'; | 399 | buffer[0] = '\0'; |
402 | for (i = 0; i < 2; i++) { | 400 | for (i = 0; i < 2; i++) { |
403 | switch (min_type) { | 401 | switch (min_type) { |
404 | case TOMOYO_VALUE_TYPE_HEXADECIMAL: | 402 | case TOMOYO_VALUE_TYPE_HEXADECIMAL: |
405 | tomoyo_addprintf(buffer, sizeof(buffer), | 403 | tomoyo_addprintf(buffer, sizeof(buffer), |
406 | "0x%lX", min); | 404 | "0x%lX", min); |
407 | break; | 405 | break; |
408 | case TOMOYO_VALUE_TYPE_OCTAL: | 406 | case TOMOYO_VALUE_TYPE_OCTAL: |
409 | tomoyo_addprintf(buffer, sizeof(buffer), | 407 | tomoyo_addprintf(buffer, sizeof(buffer), |
410 | "0%lo", min); | 408 | "0%lo", min); |
411 | break; | 409 | break; |
412 | default: | 410 | default: |
413 | tomoyo_addprintf(buffer, sizeof(buffer), "%lu", | 411 | tomoyo_addprintf(buffer, sizeof(buffer), "%lu", |
414 | min); | 412 | min); |
415 | break; | 413 | break; |
416 | } | 414 | } |
417 | if (min == max && min_type == max_type) | 415 | if (min == max && min_type == max_type) |
418 | break; | 416 | break; |
419 | tomoyo_addprintf(buffer, sizeof(buffer), "-"); | 417 | tomoyo_addprintf(buffer, sizeof(buffer), "-"); |
420 | min_type = max_type; | 418 | min_type = max_type; |
421 | min = max; | 419 | min = max; |
422 | } | 420 | } |
423 | tomoyo_io_printf(head, "%s", buffer); | 421 | tomoyo_io_printf(head, "%s", buffer); |
424 | } | 422 | } |
425 | } | 423 | } |
426 | 424 | ||
427 | /** | 425 | /** |
428 | * tomoyo_print_number_union - Print a tomoyo_number_union. | 426 | * tomoyo_print_number_union - Print a tomoyo_number_union. |
429 | * | 427 | * |
430 | * @head: Pointer to "struct tomoyo_io_buffer". | 428 | * @head: Pointer to "struct tomoyo_io_buffer". |
431 | * @ptr: Pointer to "struct tomoyo_number_union". | 429 | * @ptr: Pointer to "struct tomoyo_number_union". |
432 | * | 430 | * |
433 | * Returns nothing. | 431 | * Returns nothing. |
434 | */ | 432 | */ |
435 | static void tomoyo_print_number_union(struct tomoyo_io_buffer *head, | 433 | static void tomoyo_print_number_union(struct tomoyo_io_buffer *head, |
436 | const struct tomoyo_number_union *ptr) | 434 | const struct tomoyo_number_union *ptr) |
437 | { | 435 | { |
438 | tomoyo_set_space(head); | 436 | tomoyo_set_space(head); |
439 | tomoyo_print_number_union_nospace(head, ptr); | 437 | tomoyo_print_number_union_nospace(head, ptr); |
440 | } | 438 | } |
441 | 439 | ||
442 | /** | 440 | /** |
443 | * tomoyo_assign_profile - Create a new profile. | 441 | * tomoyo_assign_profile - Create a new profile. |
444 | * | 442 | * |
445 | * @ns: Pointer to "struct tomoyo_policy_namespace". | 443 | * @ns: Pointer to "struct tomoyo_policy_namespace". |
446 | * @profile: Profile number to create. | 444 | * @profile: Profile number to create. |
447 | * | 445 | * |
448 | * Returns pointer to "struct tomoyo_profile" on success, NULL otherwise. | 446 | * Returns pointer to "struct tomoyo_profile" on success, NULL otherwise. |
449 | */ | 447 | */ |
450 | static struct tomoyo_profile *tomoyo_assign_profile | 448 | static struct tomoyo_profile *tomoyo_assign_profile |
451 | (struct tomoyo_policy_namespace *ns, const unsigned int profile) | 449 | (struct tomoyo_policy_namespace *ns, const unsigned int profile) |
452 | { | 450 | { |
453 | struct tomoyo_profile *ptr; | 451 | struct tomoyo_profile *ptr; |
454 | struct tomoyo_profile *entry; | 452 | struct tomoyo_profile *entry; |
455 | if (profile >= TOMOYO_MAX_PROFILES) | 453 | if (profile >= TOMOYO_MAX_PROFILES) |
456 | return NULL; | 454 | return NULL; |
457 | ptr = ns->profile_ptr[profile]; | 455 | ptr = ns->profile_ptr[profile]; |
458 | if (ptr) | 456 | if (ptr) |
459 | return ptr; | 457 | return ptr; |
460 | entry = kzalloc(sizeof(*entry), GFP_NOFS); | 458 | entry = kzalloc(sizeof(*entry), GFP_NOFS); |
461 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 459 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
462 | goto out; | 460 | goto out; |
463 | ptr = ns->profile_ptr[profile]; | 461 | ptr = ns->profile_ptr[profile]; |
464 | if (!ptr && tomoyo_memory_ok(entry)) { | 462 | if (!ptr && tomoyo_memory_ok(entry)) { |
465 | ptr = entry; | 463 | ptr = entry; |
466 | ptr->default_config = TOMOYO_CONFIG_DISABLED | | 464 | ptr->default_config = TOMOYO_CONFIG_DISABLED | |
467 | TOMOYO_CONFIG_WANT_GRANT_LOG | | 465 | TOMOYO_CONFIG_WANT_GRANT_LOG | |
468 | TOMOYO_CONFIG_WANT_REJECT_LOG; | 466 | TOMOYO_CONFIG_WANT_REJECT_LOG; |
469 | memset(ptr->config, TOMOYO_CONFIG_USE_DEFAULT, | 467 | memset(ptr->config, TOMOYO_CONFIG_USE_DEFAULT, |
470 | sizeof(ptr->config)); | 468 | sizeof(ptr->config)); |
471 | ptr->pref[TOMOYO_PREF_MAX_AUDIT_LOG] = 1024; | 469 | ptr->pref[TOMOYO_PREF_MAX_AUDIT_LOG] = 1024; |
472 | ptr->pref[TOMOYO_PREF_MAX_LEARNING_ENTRY] = 2048; | 470 | ptr->pref[TOMOYO_PREF_MAX_LEARNING_ENTRY] = 2048; |
473 | mb(); /* Avoid out-of-order execution. */ | 471 | mb(); /* Avoid out-of-order execution. */ |
474 | ns->profile_ptr[profile] = ptr; | 472 | ns->profile_ptr[profile] = ptr; |
475 | entry = NULL; | 473 | entry = NULL; |
476 | } | 474 | } |
477 | mutex_unlock(&tomoyo_policy_lock); | 475 | mutex_unlock(&tomoyo_policy_lock); |
478 | out: | 476 | out: |
479 | kfree(entry); | 477 | kfree(entry); |
480 | return ptr; | 478 | return ptr; |
481 | } | 479 | } |
482 | 480 | ||
483 | /** | 481 | /** |
484 | * tomoyo_profile - Find a profile. | 482 | * tomoyo_profile - Find a profile. |
485 | * | 483 | * |
486 | * @ns: Pointer to "struct tomoyo_policy_namespace". | 484 | * @ns: Pointer to "struct tomoyo_policy_namespace". |
487 | * @profile: Profile number to find. | 485 | * @profile: Profile number to find. |
488 | * | 486 | * |
489 | * Returns pointer to "struct tomoyo_profile". | 487 | * Returns pointer to "struct tomoyo_profile". |
490 | */ | 488 | */ |
491 | struct tomoyo_profile *tomoyo_profile(const struct tomoyo_policy_namespace *ns, | 489 | struct tomoyo_profile *tomoyo_profile(const struct tomoyo_policy_namespace *ns, |
492 | const u8 profile) | 490 | const u8 profile) |
493 | { | 491 | { |
494 | static struct tomoyo_profile tomoyo_null_profile; | 492 | static struct tomoyo_profile tomoyo_null_profile; |
495 | struct tomoyo_profile *ptr = ns->profile_ptr[profile]; | 493 | struct tomoyo_profile *ptr = ns->profile_ptr[profile]; |
496 | if (!ptr) | 494 | if (!ptr) |
497 | ptr = &tomoyo_null_profile; | 495 | ptr = &tomoyo_null_profile; |
498 | return ptr; | 496 | return ptr; |
499 | } | 497 | } |
500 | 498 | ||
501 | /** | 499 | /** |
502 | * tomoyo_find_yesno - Find values for specified keyword. | 500 | * tomoyo_find_yesno - Find values for specified keyword. |
503 | * | 501 | * |
504 | * @string: String to check. | 502 | * @string: String to check. |
505 | * @find: Name of keyword. | 503 | * @find: Name of keyword. |
506 | * | 504 | * |
507 | * Returns 1 if "@find=yes" was found, 0 if "@find=no" was found, -1 otherwise. | 505 | * Returns 1 if "@find=yes" was found, 0 if "@find=no" was found, -1 otherwise. |
508 | */ | 506 | */ |
509 | static s8 tomoyo_find_yesno(const char *string, const char *find) | 507 | static s8 tomoyo_find_yesno(const char *string, const char *find) |
510 | { | 508 | { |
511 | const char *cp = strstr(string, find); | 509 | const char *cp = strstr(string, find); |
512 | if (cp) { | 510 | if (cp) { |
513 | cp += strlen(find); | 511 | cp += strlen(find); |
514 | if (!strncmp(cp, "=yes", 4)) | 512 | if (!strncmp(cp, "=yes", 4)) |
515 | return 1; | 513 | return 1; |
516 | else if (!strncmp(cp, "=no", 3)) | 514 | else if (!strncmp(cp, "=no", 3)) |
517 | return 0; | 515 | return 0; |
518 | } | 516 | } |
519 | return -1; | 517 | return -1; |
520 | } | 518 | } |
521 | 519 | ||
522 | /** | 520 | /** |
523 | * tomoyo_set_uint - Set value for specified preference. | 521 | * tomoyo_set_uint - Set value for specified preference. |
524 | * | 522 | * |
525 | * @i: Pointer to "unsigned int". | 523 | * @i: Pointer to "unsigned int". |
526 | * @string: String to check. | 524 | * @string: String to check. |
527 | * @find: Name of keyword. | 525 | * @find: Name of keyword. |
528 | * | 526 | * |
529 | * Returns nothing. | 527 | * Returns nothing. |
530 | */ | 528 | */ |
531 | static void tomoyo_set_uint(unsigned int *i, const char *string, | 529 | static void tomoyo_set_uint(unsigned int *i, const char *string, |
532 | const char *find) | 530 | const char *find) |
533 | { | 531 | { |
534 | const char *cp = strstr(string, find); | 532 | const char *cp = strstr(string, find); |
535 | if (cp) | 533 | if (cp) |
536 | sscanf(cp + strlen(find), "=%u", i); | 534 | sscanf(cp + strlen(find), "=%u", i); |
537 | } | 535 | } |
538 | 536 | ||
539 | /** | 537 | /** |
540 | * tomoyo_set_mode - Set mode for specified profile. | 538 | * tomoyo_set_mode - Set mode for specified profile. |
541 | * | 539 | * |
542 | * @name: Name of functionality. | 540 | * @name: Name of functionality. |
543 | * @value: Mode for @name. | 541 | * @value: Mode for @name. |
544 | * @profile: Pointer to "struct tomoyo_profile". | 542 | * @profile: Pointer to "struct tomoyo_profile". |
545 | * | 543 | * |
546 | * Returns 0 on success, negative value otherwise. | 544 | * Returns 0 on success, negative value otherwise. |
547 | */ | 545 | */ |
548 | static int tomoyo_set_mode(char *name, const char *value, | 546 | static int tomoyo_set_mode(char *name, const char *value, |
549 | struct tomoyo_profile *profile) | 547 | struct tomoyo_profile *profile) |
550 | { | 548 | { |
551 | u8 i; | 549 | u8 i; |
552 | u8 config; | 550 | u8 config; |
553 | if (!strcmp(name, "CONFIG")) { | 551 | if (!strcmp(name, "CONFIG")) { |
554 | i = TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX; | 552 | i = TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX; |
555 | config = profile->default_config; | 553 | config = profile->default_config; |
556 | } else if (tomoyo_str_starts(&name, "CONFIG::")) { | 554 | } else if (tomoyo_str_starts(&name, "CONFIG::")) { |
557 | config = 0; | 555 | config = 0; |
558 | for (i = 0; i < TOMOYO_MAX_MAC_INDEX | 556 | for (i = 0; i < TOMOYO_MAX_MAC_INDEX |
559 | + TOMOYO_MAX_MAC_CATEGORY_INDEX; i++) { | 557 | + TOMOYO_MAX_MAC_CATEGORY_INDEX; i++) { |
560 | int len = 0; | 558 | int len = 0; |
561 | if (i < TOMOYO_MAX_MAC_INDEX) { | 559 | if (i < TOMOYO_MAX_MAC_INDEX) { |
562 | const u8 c = tomoyo_index2category[i]; | 560 | const u8 c = tomoyo_index2category[i]; |
563 | const char *category = | 561 | const char *category = |
564 | tomoyo_category_keywords[c]; | 562 | tomoyo_category_keywords[c]; |
565 | len = strlen(category); | 563 | len = strlen(category); |
566 | if (strncmp(name, category, len) || | 564 | if (strncmp(name, category, len) || |
567 | name[len++] != ':' || name[len++] != ':') | 565 | name[len++] != ':' || name[len++] != ':') |
568 | continue; | 566 | continue; |
569 | } | 567 | } |
570 | if (strcmp(name + len, tomoyo_mac_keywords[i])) | 568 | if (strcmp(name + len, tomoyo_mac_keywords[i])) |
571 | continue; | 569 | continue; |
572 | config = profile->config[i]; | 570 | config = profile->config[i]; |
573 | break; | 571 | break; |
574 | } | 572 | } |
575 | if (i == TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX) | 573 | if (i == TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX) |
576 | return -EINVAL; | 574 | return -EINVAL; |
577 | } else { | 575 | } else { |
578 | return -EINVAL; | 576 | return -EINVAL; |
579 | } | 577 | } |
580 | if (strstr(value, "use_default")) { | 578 | if (strstr(value, "use_default")) { |
581 | config = TOMOYO_CONFIG_USE_DEFAULT; | 579 | config = TOMOYO_CONFIG_USE_DEFAULT; |
582 | } else { | 580 | } else { |
583 | u8 mode; | 581 | u8 mode; |
584 | for (mode = 0; mode < 4; mode++) | 582 | for (mode = 0; mode < 4; mode++) |
585 | if (strstr(value, tomoyo_mode[mode])) | 583 | if (strstr(value, tomoyo_mode[mode])) |
586 | /* | 584 | /* |
587 | * Update lower 3 bits in order to distinguish | 585 | * Update lower 3 bits in order to distinguish |
588 | * 'config' from 'TOMOYO_CONFIG_USE_DEAFULT'. | 586 | * 'config' from 'TOMOYO_CONFIG_USE_DEAFULT'. |
589 | */ | 587 | */ |
590 | config = (config & ~7) | mode; | 588 | config = (config & ~7) | mode; |
591 | if (config != TOMOYO_CONFIG_USE_DEFAULT) { | 589 | if (config != TOMOYO_CONFIG_USE_DEFAULT) { |
592 | switch (tomoyo_find_yesno(value, "grant_log")) { | 590 | switch (tomoyo_find_yesno(value, "grant_log")) { |
593 | case 1: | 591 | case 1: |
594 | config |= TOMOYO_CONFIG_WANT_GRANT_LOG; | 592 | config |= TOMOYO_CONFIG_WANT_GRANT_LOG; |
595 | break; | 593 | break; |
596 | case 0: | 594 | case 0: |
597 | config &= ~TOMOYO_CONFIG_WANT_GRANT_LOG; | 595 | config &= ~TOMOYO_CONFIG_WANT_GRANT_LOG; |
598 | break; | 596 | break; |
599 | } | 597 | } |
600 | switch (tomoyo_find_yesno(value, "reject_log")) { | 598 | switch (tomoyo_find_yesno(value, "reject_log")) { |
601 | case 1: | 599 | case 1: |
602 | config |= TOMOYO_CONFIG_WANT_REJECT_LOG; | 600 | config |= TOMOYO_CONFIG_WANT_REJECT_LOG; |
603 | break; | 601 | break; |
604 | case 0: | 602 | case 0: |
605 | config &= ~TOMOYO_CONFIG_WANT_REJECT_LOG; | 603 | config &= ~TOMOYO_CONFIG_WANT_REJECT_LOG; |
606 | break; | 604 | break; |
607 | } | 605 | } |
608 | } | 606 | } |
609 | } | 607 | } |
610 | if (i < TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX) | 608 | if (i < TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX) |
611 | profile->config[i] = config; | 609 | profile->config[i] = config; |
612 | else if (config != TOMOYO_CONFIG_USE_DEFAULT) | 610 | else if (config != TOMOYO_CONFIG_USE_DEFAULT) |
613 | profile->default_config = config; | 611 | profile->default_config = config; |
614 | return 0; | 612 | return 0; |
615 | } | 613 | } |
616 | 614 | ||
617 | /** | 615 | /** |
618 | * tomoyo_write_profile - Write profile table. | 616 | * tomoyo_write_profile - Write profile table. |
619 | * | 617 | * |
620 | * @head: Pointer to "struct tomoyo_io_buffer". | 618 | * @head: Pointer to "struct tomoyo_io_buffer". |
621 | * | 619 | * |
622 | * Returns 0 on success, negative value otherwise. | 620 | * Returns 0 on success, negative value otherwise. |
623 | */ | 621 | */ |
624 | static int tomoyo_write_profile(struct tomoyo_io_buffer *head) | 622 | static int tomoyo_write_profile(struct tomoyo_io_buffer *head) |
625 | { | 623 | { |
626 | char *data = head->write_buf; | 624 | char *data = head->write_buf; |
627 | unsigned int i; | 625 | unsigned int i; |
628 | char *cp; | 626 | char *cp; |
629 | struct tomoyo_profile *profile; | 627 | struct tomoyo_profile *profile; |
630 | if (sscanf(data, "PROFILE_VERSION=%u", &head->w.ns->profile_version) | 628 | if (sscanf(data, "PROFILE_VERSION=%u", &head->w.ns->profile_version) |
631 | == 1) | 629 | == 1) |
632 | return 0; | 630 | return 0; |
633 | i = simple_strtoul(data, &cp, 10); | 631 | i = simple_strtoul(data, &cp, 10); |
634 | if (*cp != '-') | 632 | if (*cp != '-') |
635 | return -EINVAL; | 633 | return -EINVAL; |
636 | data = cp + 1; | 634 | data = cp + 1; |
637 | profile = tomoyo_assign_profile(head->w.ns, i); | 635 | profile = tomoyo_assign_profile(head->w.ns, i); |
638 | if (!profile) | 636 | if (!profile) |
639 | return -EINVAL; | 637 | return -EINVAL; |
640 | cp = strchr(data, '='); | 638 | cp = strchr(data, '='); |
641 | if (!cp) | 639 | if (!cp) |
642 | return -EINVAL; | 640 | return -EINVAL; |
643 | *cp++ = '\0'; | 641 | *cp++ = '\0'; |
644 | if (!strcmp(data, "COMMENT")) { | 642 | if (!strcmp(data, "COMMENT")) { |
645 | static DEFINE_SPINLOCK(lock); | 643 | static DEFINE_SPINLOCK(lock); |
646 | const struct tomoyo_path_info *new_comment | 644 | const struct tomoyo_path_info *new_comment |
647 | = tomoyo_get_name(cp); | 645 | = tomoyo_get_name(cp); |
648 | const struct tomoyo_path_info *old_comment; | 646 | const struct tomoyo_path_info *old_comment; |
649 | if (!new_comment) | 647 | if (!new_comment) |
650 | return -ENOMEM; | 648 | return -ENOMEM; |
651 | spin_lock(&lock); | 649 | spin_lock(&lock); |
652 | old_comment = profile->comment; | 650 | old_comment = profile->comment; |
653 | profile->comment = new_comment; | 651 | profile->comment = new_comment; |
654 | spin_unlock(&lock); | 652 | spin_unlock(&lock); |
655 | tomoyo_put_name(old_comment); | 653 | tomoyo_put_name(old_comment); |
656 | return 0; | 654 | return 0; |
657 | } | 655 | } |
658 | if (!strcmp(data, "PREFERENCE")) { | 656 | if (!strcmp(data, "PREFERENCE")) { |
659 | for (i = 0; i < TOMOYO_MAX_PREF; i++) | 657 | for (i = 0; i < TOMOYO_MAX_PREF; i++) |
660 | tomoyo_set_uint(&profile->pref[i], cp, | 658 | tomoyo_set_uint(&profile->pref[i], cp, |
661 | tomoyo_pref_keywords[i]); | 659 | tomoyo_pref_keywords[i]); |
662 | return 0; | 660 | return 0; |
663 | } | 661 | } |
664 | return tomoyo_set_mode(data, cp, profile); | 662 | return tomoyo_set_mode(data, cp, profile); |
665 | } | 663 | } |
666 | 664 | ||
667 | /** | 665 | /** |
668 | * tomoyo_print_config - Print mode for specified functionality. | 666 | * tomoyo_print_config - Print mode for specified functionality. |
669 | * | 667 | * |
670 | * @head: Pointer to "struct tomoyo_io_buffer". | 668 | * @head: Pointer to "struct tomoyo_io_buffer". |
671 | * @config: Mode for that functionality. | 669 | * @config: Mode for that functionality. |
672 | * | 670 | * |
673 | * Returns nothing. | 671 | * Returns nothing. |
674 | * | 672 | * |
675 | * Caller prints functionality's name. | 673 | * Caller prints functionality's name. |
676 | */ | 674 | */ |
677 | static void tomoyo_print_config(struct tomoyo_io_buffer *head, const u8 config) | 675 | static void tomoyo_print_config(struct tomoyo_io_buffer *head, const u8 config) |
678 | { | 676 | { |
679 | tomoyo_io_printf(head, "={ mode=%s grant_log=%s reject_log=%s }\n", | 677 | tomoyo_io_printf(head, "={ mode=%s grant_log=%s reject_log=%s }\n", |
680 | tomoyo_mode[config & 3], | 678 | tomoyo_mode[config & 3], |
681 | tomoyo_yesno(config & TOMOYO_CONFIG_WANT_GRANT_LOG), | 679 | tomoyo_yesno(config & TOMOYO_CONFIG_WANT_GRANT_LOG), |
682 | tomoyo_yesno(config & TOMOYO_CONFIG_WANT_REJECT_LOG)); | 680 | tomoyo_yesno(config & TOMOYO_CONFIG_WANT_REJECT_LOG)); |
683 | } | 681 | } |
684 | 682 | ||
685 | /** | 683 | /** |
686 | * tomoyo_read_profile - Read profile table. | 684 | * tomoyo_read_profile - Read profile table. |
687 | * | 685 | * |
688 | * @head: Pointer to "struct tomoyo_io_buffer". | 686 | * @head: Pointer to "struct tomoyo_io_buffer". |
689 | * | 687 | * |
690 | * Returns nothing. | 688 | * Returns nothing. |
691 | */ | 689 | */ |
692 | static void tomoyo_read_profile(struct tomoyo_io_buffer *head) | 690 | static void tomoyo_read_profile(struct tomoyo_io_buffer *head) |
693 | { | 691 | { |
694 | u8 index; | 692 | u8 index; |
695 | struct tomoyo_policy_namespace *ns = | 693 | struct tomoyo_policy_namespace *ns = |
696 | container_of(head->r.ns, typeof(*ns), namespace_list); | 694 | container_of(head->r.ns, typeof(*ns), namespace_list); |
697 | const struct tomoyo_profile *profile; | 695 | const struct tomoyo_profile *profile; |
698 | if (head->r.eof) | 696 | if (head->r.eof) |
699 | return; | 697 | return; |
700 | next: | 698 | next: |
701 | index = head->r.index; | 699 | index = head->r.index; |
702 | profile = ns->profile_ptr[index]; | 700 | profile = ns->profile_ptr[index]; |
703 | switch (head->r.step) { | 701 | switch (head->r.step) { |
704 | case 0: | 702 | case 0: |
705 | tomoyo_print_namespace(head); | 703 | tomoyo_print_namespace(head); |
706 | tomoyo_io_printf(head, "PROFILE_VERSION=%u\n", | 704 | tomoyo_io_printf(head, "PROFILE_VERSION=%u\n", |
707 | ns->profile_version); | 705 | ns->profile_version); |
708 | head->r.step++; | 706 | head->r.step++; |
709 | break; | 707 | break; |
710 | case 1: | 708 | case 1: |
711 | for ( ; head->r.index < TOMOYO_MAX_PROFILES; | 709 | for ( ; head->r.index < TOMOYO_MAX_PROFILES; |
712 | head->r.index++) | 710 | head->r.index++) |
713 | if (ns->profile_ptr[head->r.index]) | 711 | if (ns->profile_ptr[head->r.index]) |
714 | break; | 712 | break; |
715 | if (head->r.index == TOMOYO_MAX_PROFILES) | 713 | if (head->r.index == TOMOYO_MAX_PROFILES) |
716 | return; | 714 | return; |
717 | head->r.step++; | 715 | head->r.step++; |
718 | break; | 716 | break; |
719 | case 2: | 717 | case 2: |
720 | { | 718 | { |
721 | u8 i; | 719 | u8 i; |
722 | const struct tomoyo_path_info *comment = | 720 | const struct tomoyo_path_info *comment = |
723 | profile->comment; | 721 | profile->comment; |
724 | tomoyo_print_namespace(head); | 722 | tomoyo_print_namespace(head); |
725 | tomoyo_io_printf(head, "%u-COMMENT=", index); | 723 | tomoyo_io_printf(head, "%u-COMMENT=", index); |
726 | tomoyo_set_string(head, comment ? comment->name : ""); | 724 | tomoyo_set_string(head, comment ? comment->name : ""); |
727 | tomoyo_set_lf(head); | 725 | tomoyo_set_lf(head); |
728 | tomoyo_io_printf(head, "%u-PREFERENCE={ ", index); | 726 | tomoyo_io_printf(head, "%u-PREFERENCE={ ", index); |
729 | for (i = 0; i < TOMOYO_MAX_PREF; i++) | 727 | for (i = 0; i < TOMOYO_MAX_PREF; i++) |
730 | tomoyo_io_printf(head, "%s=%u ", | 728 | tomoyo_io_printf(head, "%s=%u ", |
731 | tomoyo_pref_keywords[i], | 729 | tomoyo_pref_keywords[i], |
732 | profile->pref[i]); | 730 | profile->pref[i]); |
733 | tomoyo_set_string(head, "}\n"); | 731 | tomoyo_set_string(head, "}\n"); |
734 | head->r.step++; | 732 | head->r.step++; |
735 | } | 733 | } |
736 | break; | 734 | break; |
737 | case 3: | 735 | case 3: |
738 | { | 736 | { |
739 | tomoyo_print_namespace(head); | 737 | tomoyo_print_namespace(head); |
740 | tomoyo_io_printf(head, "%u-%s", index, "CONFIG"); | 738 | tomoyo_io_printf(head, "%u-%s", index, "CONFIG"); |
741 | tomoyo_print_config(head, profile->default_config); | 739 | tomoyo_print_config(head, profile->default_config); |
742 | head->r.bit = 0; | 740 | head->r.bit = 0; |
743 | head->r.step++; | 741 | head->r.step++; |
744 | } | 742 | } |
745 | break; | 743 | break; |
746 | case 4: | 744 | case 4: |
747 | for ( ; head->r.bit < TOMOYO_MAX_MAC_INDEX | 745 | for ( ; head->r.bit < TOMOYO_MAX_MAC_INDEX |
748 | + TOMOYO_MAX_MAC_CATEGORY_INDEX; head->r.bit++) { | 746 | + TOMOYO_MAX_MAC_CATEGORY_INDEX; head->r.bit++) { |
749 | const u8 i = head->r.bit; | 747 | const u8 i = head->r.bit; |
750 | const u8 config = profile->config[i]; | 748 | const u8 config = profile->config[i]; |
751 | if (config == TOMOYO_CONFIG_USE_DEFAULT) | 749 | if (config == TOMOYO_CONFIG_USE_DEFAULT) |
752 | continue; | 750 | continue; |
753 | tomoyo_print_namespace(head); | 751 | tomoyo_print_namespace(head); |
754 | if (i < TOMOYO_MAX_MAC_INDEX) | 752 | if (i < TOMOYO_MAX_MAC_INDEX) |
755 | tomoyo_io_printf(head, "%u-CONFIG::%s::%s", | 753 | tomoyo_io_printf(head, "%u-CONFIG::%s::%s", |
756 | index, | 754 | index, |
757 | tomoyo_category_keywords | 755 | tomoyo_category_keywords |
758 | [tomoyo_index2category[i]], | 756 | [tomoyo_index2category[i]], |
759 | tomoyo_mac_keywords[i]); | 757 | tomoyo_mac_keywords[i]); |
760 | else | 758 | else |
761 | tomoyo_io_printf(head, "%u-CONFIG::%s", index, | 759 | tomoyo_io_printf(head, "%u-CONFIG::%s", index, |
762 | tomoyo_mac_keywords[i]); | 760 | tomoyo_mac_keywords[i]); |
763 | tomoyo_print_config(head, config); | 761 | tomoyo_print_config(head, config); |
764 | head->r.bit++; | 762 | head->r.bit++; |
765 | break; | 763 | break; |
766 | } | 764 | } |
767 | if (head->r.bit == TOMOYO_MAX_MAC_INDEX | 765 | if (head->r.bit == TOMOYO_MAX_MAC_INDEX |
768 | + TOMOYO_MAX_MAC_CATEGORY_INDEX) { | 766 | + TOMOYO_MAX_MAC_CATEGORY_INDEX) { |
769 | head->r.index++; | 767 | head->r.index++; |
770 | head->r.step = 1; | 768 | head->r.step = 1; |
771 | } | 769 | } |
772 | break; | 770 | break; |
773 | } | 771 | } |
774 | if (tomoyo_flush(head)) | 772 | if (tomoyo_flush(head)) |
775 | goto next; | 773 | goto next; |
776 | } | 774 | } |
777 | 775 | ||
776 | /** | ||
777 | * tomoyo_same_manager - Check for duplicated "struct tomoyo_manager" entry. | ||
778 | * | ||
779 | * @a: Pointer to "struct tomoyo_acl_head". | ||
780 | * @b: Pointer to "struct tomoyo_acl_head". | ||
781 | * | ||
782 | * Returns true if @a == @b, false otherwise. | ||
783 | */ | ||
778 | static bool tomoyo_same_manager(const struct tomoyo_acl_head *a, | 784 | static bool tomoyo_same_manager(const struct tomoyo_acl_head *a, |
779 | const struct tomoyo_acl_head *b) | 785 | const struct tomoyo_acl_head *b) |
780 | { | 786 | { |
781 | return container_of(a, struct tomoyo_manager, head)->manager == | 787 | return container_of(a, struct tomoyo_manager, head)->manager == |
782 | container_of(b, struct tomoyo_manager, head)->manager; | 788 | container_of(b, struct tomoyo_manager, head)->manager; |
783 | } | 789 | } |
784 | 790 | ||
785 | /** | 791 | /** |
786 | * tomoyo_update_manager_entry - Add a manager entry. | 792 | * tomoyo_update_manager_entry - Add a manager entry. |
787 | * | 793 | * |
788 | * @manager: The path to manager or the domainnamme. | 794 | * @manager: The path to manager or the domainnamme. |
789 | * @is_delete: True if it is a delete request. | 795 | * @is_delete: True if it is a delete request. |
790 | * | 796 | * |
791 | * Returns 0 on success, negative value otherwise. | 797 | * Returns 0 on success, negative value otherwise. |
792 | * | 798 | * |
793 | * Caller holds tomoyo_read_lock(). | 799 | * Caller holds tomoyo_read_lock(). |
794 | */ | 800 | */ |
795 | static int tomoyo_update_manager_entry(const char *manager, | 801 | static int tomoyo_update_manager_entry(const char *manager, |
796 | const bool is_delete) | 802 | const bool is_delete) |
797 | { | 803 | { |
798 | struct tomoyo_manager e = { }; | 804 | struct tomoyo_manager e = { }; |
799 | struct tomoyo_acl_param param = { | 805 | struct tomoyo_acl_param param = { |
800 | /* .ns = &tomoyo_kernel_namespace, */ | 806 | /* .ns = &tomoyo_kernel_namespace, */ |
801 | .is_delete = is_delete, | 807 | .is_delete = is_delete, |
802 | .list = &tomoyo_kernel_namespace. | 808 | .list = &tomoyo_kernel_namespace. |
803 | policy_list[TOMOYO_ID_MANAGER], | 809 | policy_list[TOMOYO_ID_MANAGER], |
804 | }; | 810 | }; |
805 | int error = is_delete ? -ENOENT : -ENOMEM; | 811 | int error = is_delete ? -ENOENT : -ENOMEM; |
806 | if (tomoyo_domain_def(manager)) { | 812 | if (tomoyo_domain_def(manager)) { |
807 | if (!tomoyo_correct_domain(manager)) | 813 | if (!tomoyo_correct_domain(manager)) |
808 | return -EINVAL; | 814 | return -EINVAL; |
809 | e.is_domain = true; | 815 | e.is_domain = true; |
810 | } else { | 816 | } else { |
811 | if (!tomoyo_correct_path(manager)) | 817 | if (!tomoyo_correct_path(manager)) |
812 | return -EINVAL; | 818 | return -EINVAL; |
813 | } | 819 | } |
814 | e.manager = tomoyo_get_name(manager); | 820 | e.manager = tomoyo_get_name(manager); |
815 | if (e.manager) { | 821 | if (e.manager) { |
816 | error = tomoyo_update_policy(&e.head, sizeof(e), ¶m, | 822 | error = tomoyo_update_policy(&e.head, sizeof(e), ¶m, |
817 | tomoyo_same_manager); | 823 | tomoyo_same_manager); |
818 | tomoyo_put_name(e.manager); | 824 | tomoyo_put_name(e.manager); |
819 | } | 825 | } |
820 | return error; | 826 | return error; |
821 | } | 827 | } |
822 | 828 | ||
823 | /** | 829 | /** |
824 | * tomoyo_write_manager - Write manager policy. | 830 | * tomoyo_write_manager - Write manager policy. |
825 | * | 831 | * |
826 | * @head: Pointer to "struct tomoyo_io_buffer". | 832 | * @head: Pointer to "struct tomoyo_io_buffer". |
827 | * | 833 | * |
828 | * Returns 0 on success, negative value otherwise. | 834 | * Returns 0 on success, negative value otherwise. |
829 | * | 835 | * |
830 | * Caller holds tomoyo_read_lock(). | 836 | * Caller holds tomoyo_read_lock(). |
831 | */ | 837 | */ |
832 | static int tomoyo_write_manager(struct tomoyo_io_buffer *head) | 838 | static int tomoyo_write_manager(struct tomoyo_io_buffer *head) |
833 | { | 839 | { |
834 | char *data = head->write_buf; | 840 | char *data = head->write_buf; |
835 | 841 | ||
836 | if (!strcmp(data, "manage_by_non_root")) { | 842 | if (!strcmp(data, "manage_by_non_root")) { |
837 | tomoyo_manage_by_non_root = !head->w.is_delete; | 843 | tomoyo_manage_by_non_root = !head->w.is_delete; |
838 | return 0; | 844 | return 0; |
839 | } | 845 | } |
840 | return tomoyo_update_manager_entry(data, head->w.is_delete); | 846 | return tomoyo_update_manager_entry(data, head->w.is_delete); |
841 | } | 847 | } |
842 | 848 | ||
843 | /** | 849 | /** |
844 | * tomoyo_read_manager - Read manager policy. | 850 | * tomoyo_read_manager - Read manager policy. |
845 | * | 851 | * |
846 | * @head: Pointer to "struct tomoyo_io_buffer". | 852 | * @head: Pointer to "struct tomoyo_io_buffer". |
847 | * | 853 | * |
848 | * Caller holds tomoyo_read_lock(). | 854 | * Caller holds tomoyo_read_lock(). |
849 | */ | 855 | */ |
850 | static void tomoyo_read_manager(struct tomoyo_io_buffer *head) | 856 | static void tomoyo_read_manager(struct tomoyo_io_buffer *head) |
851 | { | 857 | { |
852 | if (head->r.eof) | 858 | if (head->r.eof) |
853 | return; | 859 | return; |
854 | list_for_each_cookie(head->r.acl, &tomoyo_kernel_namespace. | 860 | list_for_each_cookie(head->r.acl, &tomoyo_kernel_namespace. |
855 | policy_list[TOMOYO_ID_MANAGER]) { | 861 | policy_list[TOMOYO_ID_MANAGER]) { |
856 | struct tomoyo_manager *ptr = | 862 | struct tomoyo_manager *ptr = |
857 | list_entry(head->r.acl, typeof(*ptr), head.list); | 863 | list_entry(head->r.acl, typeof(*ptr), head.list); |
858 | if (ptr->head.is_deleted) | 864 | if (ptr->head.is_deleted) |
859 | continue; | 865 | continue; |
860 | if (!tomoyo_flush(head)) | 866 | if (!tomoyo_flush(head)) |
861 | return; | 867 | return; |
862 | tomoyo_set_string(head, ptr->manager->name); | 868 | tomoyo_set_string(head, ptr->manager->name); |
863 | tomoyo_set_lf(head); | 869 | tomoyo_set_lf(head); |
864 | } | 870 | } |
865 | head->r.eof = true; | 871 | head->r.eof = true; |
866 | } | 872 | } |
867 | 873 | ||
868 | /** | 874 | /** |
869 | * tomoyo_manager - Check whether the current process is a policy manager. | 875 | * tomoyo_manager - Check whether the current process is a policy manager. |
870 | * | 876 | * |
871 | * Returns true if the current process is permitted to modify policy | 877 | * Returns true if the current process is permitted to modify policy |
872 | * via /sys/kernel/security/tomoyo/ interface. | 878 | * via /sys/kernel/security/tomoyo/ interface. |
873 | * | 879 | * |
874 | * Caller holds tomoyo_read_lock(). | 880 | * Caller holds tomoyo_read_lock(). |
875 | */ | 881 | */ |
876 | static bool tomoyo_manager(void) | 882 | static bool tomoyo_manager(void) |
877 | { | 883 | { |
878 | struct tomoyo_manager *ptr; | 884 | struct tomoyo_manager *ptr; |
879 | const char *exe; | 885 | const char *exe; |
880 | const struct task_struct *task = current; | 886 | const struct task_struct *task = current; |
881 | const struct tomoyo_path_info *domainname = tomoyo_domain()->domainname; | 887 | const struct tomoyo_path_info *domainname = tomoyo_domain()->domainname; |
882 | bool found = false; | 888 | bool found = false; |
883 | 889 | ||
884 | if (!tomoyo_policy_loaded) | 890 | if (!tomoyo_policy_loaded) |
885 | return true; | 891 | return true; |
886 | if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid)) | 892 | if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid)) |
887 | return false; | 893 | return false; |
888 | list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace. | 894 | list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace. |
889 | policy_list[TOMOYO_ID_MANAGER], head.list) { | 895 | policy_list[TOMOYO_ID_MANAGER], head.list) { |
890 | if (!ptr->head.is_deleted && ptr->is_domain | 896 | if (!ptr->head.is_deleted && ptr->is_domain |
891 | && !tomoyo_pathcmp(domainname, ptr->manager)) { | 897 | && !tomoyo_pathcmp(domainname, ptr->manager)) { |
892 | found = true; | 898 | found = true; |
893 | break; | 899 | break; |
894 | } | 900 | } |
895 | } | 901 | } |
896 | if (found) | 902 | if (found) |
897 | return true; | 903 | return true; |
898 | exe = tomoyo_get_exe(); | 904 | exe = tomoyo_get_exe(); |
899 | if (!exe) | 905 | if (!exe) |
900 | return false; | 906 | return false; |
901 | list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace. | 907 | list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace. |
902 | policy_list[TOMOYO_ID_MANAGER], head.list) { | 908 | policy_list[TOMOYO_ID_MANAGER], head.list) { |
903 | if (!ptr->head.is_deleted && !ptr->is_domain | 909 | if (!ptr->head.is_deleted && !ptr->is_domain |
904 | && !strcmp(exe, ptr->manager->name)) { | 910 | && !strcmp(exe, ptr->manager->name)) { |
905 | found = true; | 911 | found = true; |
906 | break; | 912 | break; |
907 | } | 913 | } |
908 | } | 914 | } |
909 | if (!found) { /* Reduce error messages. */ | 915 | if (!found) { /* Reduce error messages. */ |
910 | static pid_t last_pid; | 916 | static pid_t last_pid; |
911 | const pid_t pid = current->pid; | 917 | const pid_t pid = current->pid; |
912 | if (last_pid != pid) { | 918 | if (last_pid != pid) { |
913 | printk(KERN_WARNING "%s ( %s ) is not permitted to " | 919 | printk(KERN_WARNING "%s ( %s ) is not permitted to " |
914 | "update policies.\n", domainname->name, exe); | 920 | "update policies.\n", domainname->name, exe); |
915 | last_pid = pid; | 921 | last_pid = pid; |
916 | } | 922 | } |
917 | } | 923 | } |
918 | kfree(exe); | 924 | kfree(exe); |
919 | return found; | 925 | return found; |
920 | } | 926 | } |
921 | 927 | ||
922 | /** | 928 | /** |
923 | * tomoyo_select_domain - Parse select command. | 929 | * tomoyo_select_domain - Parse select command. |
924 | * | 930 | * |
925 | * @head: Pointer to "struct tomoyo_io_buffer". | 931 | * @head: Pointer to "struct tomoyo_io_buffer". |
926 | * @data: String to parse. | 932 | * @data: String to parse. |
927 | * | 933 | * |
928 | * Returns true on success, false otherwise. | 934 | * Returns true on success, false otherwise. |
929 | * | 935 | * |
930 | * Caller holds tomoyo_read_lock(). | 936 | * Caller holds tomoyo_read_lock(). |
931 | */ | 937 | */ |
932 | static bool tomoyo_select_domain(struct tomoyo_io_buffer *head, | 938 | static bool tomoyo_select_domain(struct tomoyo_io_buffer *head, |
933 | const char *data) | 939 | const char *data) |
934 | { | 940 | { |
935 | unsigned int pid; | 941 | unsigned int pid; |
936 | struct tomoyo_domain_info *domain = NULL; | 942 | struct tomoyo_domain_info *domain = NULL; |
937 | bool global_pid = false; | 943 | bool global_pid = false; |
938 | if (strncmp(data, "select ", 7)) | 944 | if (strncmp(data, "select ", 7)) |
939 | return false; | 945 | return false; |
940 | data += 7; | 946 | data += 7; |
941 | if (sscanf(data, "pid=%u", &pid) == 1 || | 947 | if (sscanf(data, "pid=%u", &pid) == 1 || |
942 | (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) { | 948 | (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) { |
943 | struct task_struct *p; | 949 | struct task_struct *p; |
944 | rcu_read_lock(); | 950 | rcu_read_lock(); |
945 | read_lock(&tasklist_lock); | 951 | read_lock(&tasklist_lock); |
946 | if (global_pid) | 952 | if (global_pid) |
947 | p = find_task_by_pid_ns(pid, &init_pid_ns); | 953 | p = find_task_by_pid_ns(pid, &init_pid_ns); |
948 | else | 954 | else |
949 | p = find_task_by_vpid(pid); | 955 | p = find_task_by_vpid(pid); |
950 | if (p) | 956 | if (p) |
951 | domain = tomoyo_real_domain(p); | 957 | domain = tomoyo_real_domain(p); |
952 | read_unlock(&tasklist_lock); | 958 | read_unlock(&tasklist_lock); |
953 | rcu_read_unlock(); | 959 | rcu_read_unlock(); |
954 | } else if (!strncmp(data, "domain=", 7)) { | 960 | } else if (!strncmp(data, "domain=", 7)) { |
955 | if (tomoyo_domain_def(data + 7)) | 961 | if (tomoyo_domain_def(data + 7)) |
956 | domain = tomoyo_find_domain(data + 7); | 962 | domain = tomoyo_find_domain(data + 7); |
957 | } else | 963 | } else |
958 | return false; | 964 | return false; |
959 | head->w.domain = domain; | 965 | head->w.domain = domain; |
960 | /* Accessing read_buf is safe because head->io_sem is held. */ | 966 | /* Accessing read_buf is safe because head->io_sem is held. */ |
961 | if (!head->read_buf) | 967 | if (!head->read_buf) |
962 | return true; /* Do nothing if open(O_WRONLY). */ | 968 | return true; /* Do nothing if open(O_WRONLY). */ |
963 | memset(&head->r, 0, sizeof(head->r)); | 969 | memset(&head->r, 0, sizeof(head->r)); |
964 | head->r.print_this_domain_only = true; | 970 | head->r.print_this_domain_only = true; |
965 | if (domain) | 971 | if (domain) |
966 | head->r.domain = &domain->list; | 972 | head->r.domain = &domain->list; |
967 | else | 973 | else |
968 | head->r.eof = 1; | 974 | head->r.eof = 1; |
969 | tomoyo_io_printf(head, "# select %s\n", data); | 975 | tomoyo_io_printf(head, "# select %s\n", data); |
970 | if (domain && domain->is_deleted) | 976 | if (domain && domain->is_deleted) |
971 | tomoyo_io_printf(head, "# This is a deleted domain.\n"); | 977 | tomoyo_io_printf(head, "# This is a deleted domain.\n"); |
972 | return true; | 978 | return true; |
973 | } | 979 | } |
974 | 980 | ||
975 | /** | 981 | /** |
976 | * tomoyo_delete_domain - Delete a domain. | 982 | * tomoyo_delete_domain - Delete a domain. |
977 | * | 983 | * |
978 | * @domainname: The name of domain. | 984 | * @domainname: The name of domain. |
979 | * | 985 | * |
980 | * Returns 0. | 986 | * Returns 0. |
981 | * | 987 | * |
982 | * Caller holds tomoyo_read_lock(). | 988 | * Caller holds tomoyo_read_lock(). |
983 | */ | 989 | */ |
984 | static int tomoyo_delete_domain(char *domainname) | 990 | static int tomoyo_delete_domain(char *domainname) |
985 | { | 991 | { |
986 | struct tomoyo_domain_info *domain; | 992 | struct tomoyo_domain_info *domain; |
987 | struct tomoyo_path_info name; | 993 | struct tomoyo_path_info name; |
988 | 994 | ||
989 | name.name = domainname; | 995 | name.name = domainname; |
990 | tomoyo_fill_path_info(&name); | 996 | tomoyo_fill_path_info(&name); |
991 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 997 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
992 | return 0; | 998 | return 0; |
993 | /* Is there an active domain? */ | 999 | /* Is there an active domain? */ |
994 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { | 1000 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { |
995 | /* Never delete tomoyo_kernel_domain */ | 1001 | /* Never delete tomoyo_kernel_domain */ |
996 | if (domain == &tomoyo_kernel_domain) | 1002 | if (domain == &tomoyo_kernel_domain) |
997 | continue; | 1003 | continue; |
998 | if (domain->is_deleted || | 1004 | if (domain->is_deleted || |
999 | tomoyo_pathcmp(domain->domainname, &name)) | 1005 | tomoyo_pathcmp(domain->domainname, &name)) |
1000 | continue; | 1006 | continue; |
1001 | domain->is_deleted = true; | 1007 | domain->is_deleted = true; |
1002 | break; | 1008 | break; |
1003 | } | 1009 | } |
1004 | mutex_unlock(&tomoyo_policy_lock); | 1010 | mutex_unlock(&tomoyo_policy_lock); |
1005 | return 0; | 1011 | return 0; |
1006 | } | 1012 | } |
1007 | 1013 | ||
1008 | /** | 1014 | /** |
1009 | * tomoyo_write_domain2 - Write domain policy. | 1015 | * tomoyo_write_domain2 - Write domain policy. |
1010 | * | 1016 | * |
1011 | * @ns: Pointer to "struct tomoyo_policy_namespace". | 1017 | * @ns: Pointer to "struct tomoyo_policy_namespace". |
1012 | * @list: Pointer to "struct list_head". | 1018 | * @list: Pointer to "struct list_head". |
1013 | * @data: Policy to be interpreted. | 1019 | * @data: Policy to be interpreted. |
1014 | * @is_delete: True if it is a delete request. | 1020 | * @is_delete: True if it is a delete request. |
1015 | * | 1021 | * |
1016 | * Returns 0 on success, negative value otherwise. | 1022 | * Returns 0 on success, negative value otherwise. |
1017 | * | 1023 | * |
1018 | * Caller holds tomoyo_read_lock(). | 1024 | * Caller holds tomoyo_read_lock(). |
1019 | */ | 1025 | */ |
1020 | static int tomoyo_write_domain2(struct tomoyo_policy_namespace *ns, | 1026 | static int tomoyo_write_domain2(struct tomoyo_policy_namespace *ns, |
1021 | struct list_head *list, char *data, | 1027 | struct list_head *list, char *data, |
1022 | const bool is_delete) | 1028 | const bool is_delete) |
1023 | { | 1029 | { |
1024 | struct tomoyo_acl_param param = { | 1030 | struct tomoyo_acl_param param = { |
1025 | .ns = ns, | 1031 | .ns = ns, |
1026 | .list = list, | 1032 | .list = list, |
1027 | .data = data, | 1033 | .data = data, |
1028 | .is_delete = is_delete, | 1034 | .is_delete = is_delete, |
1029 | }; | 1035 | }; |
1030 | static const struct { | 1036 | static const struct { |
1031 | const char *keyword; | 1037 | const char *keyword; |
1032 | int (*write) (struct tomoyo_acl_param *); | 1038 | int (*write) (struct tomoyo_acl_param *); |
1033 | } tomoyo_callback[1] = { | 1039 | } tomoyo_callback[1] = { |
1034 | { "file ", tomoyo_write_file }, | 1040 | { "file ", tomoyo_write_file }, |
1035 | }; | 1041 | }; |
1036 | u8 i; | 1042 | u8 i; |
1037 | for (i = 0; i < 1; i++) { | 1043 | for (i = 0; i < 1; i++) { |
1038 | if (!tomoyo_str_starts(¶m.data, | 1044 | if (!tomoyo_str_starts(¶m.data, |
1039 | tomoyo_callback[i].keyword)) | 1045 | tomoyo_callback[i].keyword)) |
1040 | continue; | 1046 | continue; |
1041 | return tomoyo_callback[i].write(¶m); | 1047 | return tomoyo_callback[i].write(¶m); |
1042 | } | 1048 | } |
1043 | return -EINVAL; | 1049 | return -EINVAL; |
1044 | } | 1050 | } |
1045 | 1051 | ||
1046 | /* String table for domain flags. */ | 1052 | /* String table for domain flags. */ |
1047 | const char * const tomoyo_dif[TOMOYO_MAX_DOMAIN_INFO_FLAGS] = { | 1053 | const char * const tomoyo_dif[TOMOYO_MAX_DOMAIN_INFO_FLAGS] = { |
1048 | [TOMOYO_DIF_QUOTA_WARNED] = "quota_exceeded\n", | 1054 | [TOMOYO_DIF_QUOTA_WARNED] = "quota_exceeded\n", |
1049 | [TOMOYO_DIF_TRANSITION_FAILED] = "transition_failed\n", | 1055 | [TOMOYO_DIF_TRANSITION_FAILED] = "transition_failed\n", |
1050 | }; | 1056 | }; |
1051 | 1057 | ||
1052 | /** | 1058 | /** |
1053 | * tomoyo_write_domain - Write domain policy. | 1059 | * tomoyo_write_domain - Write domain policy. |
1054 | * | 1060 | * |
1055 | * @head: Pointer to "struct tomoyo_io_buffer". | 1061 | * @head: Pointer to "struct tomoyo_io_buffer". |
1056 | * | 1062 | * |
1057 | * Returns 0 on success, negative value otherwise. | 1063 | * Returns 0 on success, negative value otherwise. |
1058 | * | 1064 | * |
1059 | * Caller holds tomoyo_read_lock(). | 1065 | * Caller holds tomoyo_read_lock(). |
1060 | */ | 1066 | */ |
1061 | static int tomoyo_write_domain(struct tomoyo_io_buffer *head) | 1067 | static int tomoyo_write_domain(struct tomoyo_io_buffer *head) |
1062 | { | 1068 | { |
1063 | char *data = head->write_buf; | 1069 | char *data = head->write_buf; |
1064 | struct tomoyo_policy_namespace *ns; | 1070 | struct tomoyo_policy_namespace *ns; |
1065 | struct tomoyo_domain_info *domain = head->w.domain; | 1071 | struct tomoyo_domain_info *domain = head->w.domain; |
1066 | const bool is_delete = head->w.is_delete; | 1072 | const bool is_delete = head->w.is_delete; |
1067 | bool is_select = !is_delete && tomoyo_str_starts(&data, "select "); | 1073 | bool is_select = !is_delete && tomoyo_str_starts(&data, "select "); |
1068 | unsigned int profile; | 1074 | unsigned int profile; |
1069 | if (*data == '<') { | 1075 | if (*data == '<') { |
1070 | domain = NULL; | 1076 | domain = NULL; |
1071 | if (is_delete) | 1077 | if (is_delete) |
1072 | tomoyo_delete_domain(data); | 1078 | tomoyo_delete_domain(data); |
1073 | else if (is_select) | 1079 | else if (is_select) |
1074 | domain = tomoyo_find_domain(data); | 1080 | domain = tomoyo_find_domain(data); |
1075 | else | 1081 | else |
1076 | domain = tomoyo_assign_domain(data, false); | 1082 | domain = tomoyo_assign_domain(data, false); |
1077 | head->w.domain = domain; | 1083 | head->w.domain = domain; |
1078 | return 0; | 1084 | return 0; |
1079 | } | 1085 | } |
1080 | if (!domain) | 1086 | if (!domain) |
1081 | return -EINVAL; | 1087 | return -EINVAL; |
1082 | ns = domain->ns; | 1088 | ns = domain->ns; |
1083 | if (sscanf(data, "use_profile %u", &profile) == 1 | 1089 | if (sscanf(data, "use_profile %u", &profile) == 1 |
1084 | && profile < TOMOYO_MAX_PROFILES) { | 1090 | && profile < TOMOYO_MAX_PROFILES) { |
1085 | if (!tomoyo_policy_loaded || ns->profile_ptr[profile]) | 1091 | if (!tomoyo_policy_loaded || ns->profile_ptr[profile]) |
1086 | domain->profile = (u8) profile; | 1092 | domain->profile = (u8) profile; |
1087 | return 0; | 1093 | return 0; |
1088 | } | 1094 | } |
1089 | if (sscanf(data, "use_group %u\n", &profile) == 1 | 1095 | if (sscanf(data, "use_group %u\n", &profile) == 1 |
1090 | && profile < TOMOYO_MAX_ACL_GROUPS) { | 1096 | && profile < TOMOYO_MAX_ACL_GROUPS) { |
1091 | if (!is_delete) | 1097 | if (!is_delete) |
1092 | domain->group = (u8) profile; | 1098 | domain->group = (u8) profile; |
1093 | return 0; | 1099 | return 0; |
1094 | } | 1100 | } |
1095 | for (profile = 0; profile < TOMOYO_MAX_DOMAIN_INFO_FLAGS; profile++) { | 1101 | for (profile = 0; profile < TOMOYO_MAX_DOMAIN_INFO_FLAGS; profile++) { |
1096 | const char *cp = tomoyo_dif[profile]; | 1102 | const char *cp = tomoyo_dif[profile]; |
1097 | if (strncmp(data, cp, strlen(cp) - 1)) | 1103 | if (strncmp(data, cp, strlen(cp) - 1)) |
1098 | continue; | 1104 | continue; |
1099 | domain->flags[profile] = !is_delete; | 1105 | domain->flags[profile] = !is_delete; |
1100 | return 0; | 1106 | return 0; |
1101 | } | 1107 | } |
1102 | return tomoyo_write_domain2(ns, &domain->acl_info_list, data, | 1108 | return tomoyo_write_domain2(ns, &domain->acl_info_list, data, |
1103 | is_delete); | 1109 | is_delete); |
1104 | } | 1110 | } |
1105 | 1111 | ||
1106 | /** | 1112 | /** |
1107 | * tomoyo_print_condition - Print condition part. | 1113 | * tomoyo_print_condition - Print condition part. |
1108 | * | 1114 | * |
1109 | * @head: Pointer to "struct tomoyo_io_buffer". | 1115 | * @head: Pointer to "struct tomoyo_io_buffer". |
1110 | * @cond: Pointer to "struct tomoyo_condition". | 1116 | * @cond: Pointer to "struct tomoyo_condition". |
1111 | * | 1117 | * |
1112 | * Returns true on success, false otherwise. | 1118 | * Returns true on success, false otherwise. |
1113 | */ | 1119 | */ |
1114 | static bool tomoyo_print_condition(struct tomoyo_io_buffer *head, | 1120 | static bool tomoyo_print_condition(struct tomoyo_io_buffer *head, |
1115 | const struct tomoyo_condition *cond) | 1121 | const struct tomoyo_condition *cond) |
1116 | { | 1122 | { |
1117 | switch (head->r.cond_step) { | 1123 | switch (head->r.cond_step) { |
1118 | case 0: | 1124 | case 0: |
1119 | head->r.cond_index = 0; | 1125 | head->r.cond_index = 0; |
1120 | head->r.cond_step++; | 1126 | head->r.cond_step++; |
1121 | /* fall through */ | 1127 | /* fall through */ |
1122 | case 1: | 1128 | case 1: |
1123 | { | 1129 | { |
1124 | const u16 condc = cond->condc; | 1130 | const u16 condc = cond->condc; |
1125 | const struct tomoyo_condition_element *condp = | 1131 | const struct tomoyo_condition_element *condp = |
1126 | (typeof(condp)) (cond + 1); | 1132 | (typeof(condp)) (cond + 1); |
1127 | const struct tomoyo_number_union *numbers_p = | 1133 | const struct tomoyo_number_union *numbers_p = |
1128 | (typeof(numbers_p)) (condp + condc); | 1134 | (typeof(numbers_p)) (condp + condc); |
1129 | const struct tomoyo_name_union *names_p = | 1135 | const struct tomoyo_name_union *names_p = |
1130 | (typeof(names_p)) | 1136 | (typeof(names_p)) |
1131 | (numbers_p + cond->numbers_count); | 1137 | (numbers_p + cond->numbers_count); |
1132 | const struct tomoyo_argv *argv = | 1138 | const struct tomoyo_argv *argv = |
1133 | (typeof(argv)) (names_p + cond->names_count); | 1139 | (typeof(argv)) (names_p + cond->names_count); |
1134 | const struct tomoyo_envp *envp = | 1140 | const struct tomoyo_envp *envp = |
1135 | (typeof(envp)) (argv + cond->argc); | 1141 | (typeof(envp)) (argv + cond->argc); |
1136 | u16 skip; | 1142 | u16 skip; |
1137 | for (skip = 0; skip < head->r.cond_index; skip++) { | 1143 | for (skip = 0; skip < head->r.cond_index; skip++) { |
1138 | const u8 left = condp->left; | 1144 | const u8 left = condp->left; |
1139 | const u8 right = condp->right; | 1145 | const u8 right = condp->right; |
1140 | condp++; | 1146 | condp++; |
1141 | switch (left) { | 1147 | switch (left) { |
1142 | case TOMOYO_ARGV_ENTRY: | 1148 | case TOMOYO_ARGV_ENTRY: |
1143 | argv++; | 1149 | argv++; |
1144 | continue; | 1150 | continue; |
1145 | case TOMOYO_ENVP_ENTRY: | 1151 | case TOMOYO_ENVP_ENTRY: |
1146 | envp++; | 1152 | envp++; |
1147 | continue; | 1153 | continue; |
1148 | case TOMOYO_NUMBER_UNION: | 1154 | case TOMOYO_NUMBER_UNION: |
1149 | numbers_p++; | 1155 | numbers_p++; |
1150 | break; | 1156 | break; |
1151 | } | 1157 | } |
1152 | switch (right) { | 1158 | switch (right) { |
1153 | case TOMOYO_NAME_UNION: | 1159 | case TOMOYO_NAME_UNION: |
1154 | names_p++; | 1160 | names_p++; |
1155 | break; | 1161 | break; |
1156 | case TOMOYO_NUMBER_UNION: | 1162 | case TOMOYO_NUMBER_UNION: |
1157 | numbers_p++; | 1163 | numbers_p++; |
1158 | break; | 1164 | break; |
1159 | } | 1165 | } |
1160 | } | 1166 | } |
1161 | while (head->r.cond_index < condc) { | 1167 | while (head->r.cond_index < condc) { |
1162 | const u8 match = condp->equals; | 1168 | const u8 match = condp->equals; |
1163 | const u8 left = condp->left; | 1169 | const u8 left = condp->left; |
1164 | const u8 right = condp->right; | 1170 | const u8 right = condp->right; |
1165 | if (!tomoyo_flush(head)) | 1171 | if (!tomoyo_flush(head)) |
1166 | return false; | 1172 | return false; |
1167 | condp++; | 1173 | condp++; |
1168 | head->r.cond_index++; | 1174 | head->r.cond_index++; |
1169 | tomoyo_set_space(head); | 1175 | tomoyo_set_space(head); |
1170 | switch (left) { | 1176 | switch (left) { |
1171 | case TOMOYO_ARGV_ENTRY: | 1177 | case TOMOYO_ARGV_ENTRY: |
1172 | tomoyo_io_printf(head, | 1178 | tomoyo_io_printf(head, |
1173 | "exec.argv[%lu]%s=\"", | 1179 | "exec.argv[%lu]%s=\"", |
1174 | argv->index, argv-> | 1180 | argv->index, argv-> |
1175 | is_not ? "!" : ""); | 1181 | is_not ? "!" : ""); |
1176 | tomoyo_set_string(head, | 1182 | tomoyo_set_string(head, |
1177 | argv->value->name); | 1183 | argv->value->name); |
1178 | tomoyo_set_string(head, "\""); | 1184 | tomoyo_set_string(head, "\""); |
1179 | argv++; | 1185 | argv++; |
1180 | continue; | 1186 | continue; |
1181 | case TOMOYO_ENVP_ENTRY: | 1187 | case TOMOYO_ENVP_ENTRY: |
1182 | tomoyo_set_string(head, | 1188 | tomoyo_set_string(head, |
1183 | "exec.envp[\""); | 1189 | "exec.envp[\""); |
1184 | tomoyo_set_string(head, | 1190 | tomoyo_set_string(head, |
1185 | envp->name->name); | 1191 | envp->name->name); |
1186 | tomoyo_io_printf(head, "\"]%s=", envp-> | 1192 | tomoyo_io_printf(head, "\"]%s=", envp-> |
1187 | is_not ? "!" : ""); | 1193 | is_not ? "!" : ""); |
1188 | if (envp->value) { | 1194 | if (envp->value) { |
1189 | tomoyo_set_string(head, "\""); | 1195 | tomoyo_set_string(head, "\""); |
1190 | tomoyo_set_string(head, envp-> | 1196 | tomoyo_set_string(head, envp-> |
1191 | value->name); | 1197 | value->name); |
1192 | tomoyo_set_string(head, "\""); | 1198 | tomoyo_set_string(head, "\""); |
1193 | } else { | 1199 | } else { |
1194 | tomoyo_set_string(head, | 1200 | tomoyo_set_string(head, |
1195 | "NULL"); | 1201 | "NULL"); |
1196 | } | 1202 | } |
1197 | envp++; | 1203 | envp++; |
1198 | continue; | 1204 | continue; |
1199 | case TOMOYO_NUMBER_UNION: | 1205 | case TOMOYO_NUMBER_UNION: |
1200 | tomoyo_print_number_union_nospace | 1206 | tomoyo_print_number_union_nospace |
1201 | (head, numbers_p++); | 1207 | (head, numbers_p++); |
1202 | break; | 1208 | break; |
1203 | default: | 1209 | default: |
1204 | tomoyo_set_string(head, | 1210 | tomoyo_set_string(head, |
1205 | tomoyo_condition_keyword[left]); | 1211 | tomoyo_condition_keyword[left]); |
1206 | break; | 1212 | break; |
1207 | } | 1213 | } |
1208 | tomoyo_set_string(head, match ? "=" : "!="); | 1214 | tomoyo_set_string(head, match ? "=" : "!="); |
1209 | switch (right) { | 1215 | switch (right) { |
1210 | case TOMOYO_NAME_UNION: | 1216 | case TOMOYO_NAME_UNION: |
1211 | tomoyo_print_name_union_quoted | 1217 | tomoyo_print_name_union_quoted |
1212 | (head, names_p++); | 1218 | (head, names_p++); |
1213 | break; | 1219 | break; |
1214 | case TOMOYO_NUMBER_UNION: | 1220 | case TOMOYO_NUMBER_UNION: |
1215 | tomoyo_print_number_union_nospace | 1221 | tomoyo_print_number_union_nospace |
1216 | (head, numbers_p++); | 1222 | (head, numbers_p++); |
1217 | break; | 1223 | break; |
1218 | default: | 1224 | default: |
1219 | tomoyo_set_string(head, | 1225 | tomoyo_set_string(head, |
1220 | tomoyo_condition_keyword[right]); | 1226 | tomoyo_condition_keyword[right]); |
1221 | break; | 1227 | break; |
1222 | } | 1228 | } |
1223 | } | 1229 | } |
1224 | } | 1230 | } |
1225 | head->r.cond_step++; | 1231 | head->r.cond_step++; |
1226 | /* fall through */ | 1232 | /* fall through */ |
1227 | case 2: | 1233 | case 2: |
1228 | if (!tomoyo_flush(head)) | 1234 | if (!tomoyo_flush(head)) |
1229 | break; | 1235 | break; |
1230 | head->r.cond_step++; | 1236 | head->r.cond_step++; |
1231 | /* fall through */ | 1237 | /* fall through */ |
1232 | case 3: | 1238 | case 3: |
1233 | tomoyo_set_lf(head); | 1239 | tomoyo_set_lf(head); |
1234 | return true; | 1240 | return true; |
1235 | } | 1241 | } |
1236 | return false; | 1242 | return false; |
1237 | } | 1243 | } |
1238 | 1244 | ||
1239 | /** | 1245 | /** |
1240 | * tomoyo_set_group - Print "acl_group " header keyword and category name. | 1246 | * tomoyo_set_group - Print "acl_group " header keyword and category name. |
1241 | * | 1247 | * |
1242 | * @head: Pointer to "struct tomoyo_io_buffer". | 1248 | * @head: Pointer to "struct tomoyo_io_buffer". |
1243 | * @category: Category name. | 1249 | * @category: Category name. |
1244 | * | 1250 | * |
1245 | * Returns nothing. | 1251 | * Returns nothing. |
1246 | */ | 1252 | */ |
1247 | static void tomoyo_set_group(struct tomoyo_io_buffer *head, | 1253 | static void tomoyo_set_group(struct tomoyo_io_buffer *head, |
1248 | const char *category) | 1254 | const char *category) |
1249 | { | 1255 | { |
1250 | if (head->type == TOMOYO_EXCEPTIONPOLICY) { | 1256 | if (head->type == TOMOYO_EXCEPTIONPOLICY) { |
1251 | tomoyo_print_namespace(head); | 1257 | tomoyo_print_namespace(head); |
1252 | tomoyo_io_printf(head, "acl_group %u ", | 1258 | tomoyo_io_printf(head, "acl_group %u ", |
1253 | head->r.acl_group_index); | 1259 | head->r.acl_group_index); |
1254 | } | 1260 | } |
1255 | tomoyo_set_string(head, category); | 1261 | tomoyo_set_string(head, category); |
1256 | } | 1262 | } |
1257 | 1263 | ||
1258 | /** | 1264 | /** |
1259 | * tomoyo_print_entry - Print an ACL entry. | 1265 | * tomoyo_print_entry - Print an ACL entry. |
1260 | * | 1266 | * |
1261 | * @head: Pointer to "struct tomoyo_io_buffer". | 1267 | * @head: Pointer to "struct tomoyo_io_buffer". |
1262 | * @acl: Pointer to an ACL entry. | 1268 | * @acl: Pointer to an ACL entry. |
1263 | * | 1269 | * |
1264 | * Returns true on success, false otherwise. | 1270 | * Returns true on success, false otherwise. |
1265 | */ | 1271 | */ |
1266 | static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, | 1272 | static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, |
1267 | struct tomoyo_acl_info *acl) | 1273 | struct tomoyo_acl_info *acl) |
1268 | { | 1274 | { |
1269 | const u8 acl_type = acl->type; | 1275 | const u8 acl_type = acl->type; |
1270 | bool first = true; | 1276 | bool first = true; |
1271 | u8 bit; | 1277 | u8 bit; |
1272 | 1278 | ||
1273 | if (head->r.print_cond_part) | 1279 | if (head->r.print_cond_part) |
1274 | goto print_cond_part; | 1280 | goto print_cond_part; |
1275 | if (acl->is_deleted) | 1281 | if (acl->is_deleted) |
1276 | return true; | 1282 | return true; |
1277 | if (!tomoyo_flush(head)) | 1283 | if (!tomoyo_flush(head)) |
1278 | return false; | 1284 | return false; |
1279 | else if (acl_type == TOMOYO_TYPE_PATH_ACL) { | 1285 | else if (acl_type == TOMOYO_TYPE_PATH_ACL) { |
1280 | struct tomoyo_path_acl *ptr = | 1286 | struct tomoyo_path_acl *ptr = |
1281 | container_of(acl, typeof(*ptr), head); | 1287 | container_of(acl, typeof(*ptr), head); |
1282 | const u16 perm = ptr->perm; | 1288 | const u16 perm = ptr->perm; |
1283 | for (bit = 0; bit < TOMOYO_MAX_PATH_OPERATION; bit++) { | 1289 | for (bit = 0; bit < TOMOYO_MAX_PATH_OPERATION; bit++) { |
1284 | if (!(perm & (1 << bit))) | 1290 | if (!(perm & (1 << bit))) |
1285 | continue; | 1291 | continue; |
1286 | if (head->r.print_transition_related_only && | 1292 | if (head->r.print_transition_related_only && |
1287 | bit != TOMOYO_TYPE_EXECUTE) | 1293 | bit != TOMOYO_TYPE_EXECUTE) |
1288 | continue; | 1294 | continue; |
1289 | if (first) { | 1295 | if (first) { |
1290 | tomoyo_set_group(head, "file "); | 1296 | tomoyo_set_group(head, "file "); |
1291 | first = false; | 1297 | first = false; |
1292 | } else { | 1298 | } else { |
1293 | tomoyo_set_slash(head); | 1299 | tomoyo_set_slash(head); |
1294 | } | 1300 | } |
1295 | tomoyo_set_string(head, tomoyo_path_keyword[bit]); | 1301 | tomoyo_set_string(head, tomoyo_path_keyword[bit]); |
1296 | } | 1302 | } |
1297 | if (first) | 1303 | if (first) |
1298 | return true; | 1304 | return true; |
1299 | tomoyo_print_name_union(head, &ptr->name); | 1305 | tomoyo_print_name_union(head, &ptr->name); |
1300 | } else if (head->r.print_transition_related_only) { | 1306 | } else if (head->r.print_transition_related_only) { |
1301 | return true; | 1307 | return true; |
1302 | } else if (acl_type == TOMOYO_TYPE_PATH2_ACL) { | 1308 | } else if (acl_type == TOMOYO_TYPE_PATH2_ACL) { |
1303 | struct tomoyo_path2_acl *ptr = | 1309 | struct tomoyo_path2_acl *ptr = |
1304 | container_of(acl, typeof(*ptr), head); | 1310 | container_of(acl, typeof(*ptr), head); |
1305 | const u8 perm = ptr->perm; | 1311 | const u8 perm = ptr->perm; |
1306 | for (bit = 0; bit < TOMOYO_MAX_PATH2_OPERATION; bit++) { | 1312 | for (bit = 0; bit < TOMOYO_MAX_PATH2_OPERATION; bit++) { |
1307 | if (!(perm & (1 << bit))) | 1313 | if (!(perm & (1 << bit))) |
1308 | continue; | 1314 | continue; |
1309 | if (first) { | 1315 | if (first) { |
1310 | tomoyo_set_group(head, "file "); | 1316 | tomoyo_set_group(head, "file "); |
1311 | first = false; | 1317 | first = false; |
1312 | } else { | 1318 | } else { |
1313 | tomoyo_set_slash(head); | 1319 | tomoyo_set_slash(head); |
1314 | } | 1320 | } |
1315 | tomoyo_set_string(head, tomoyo_mac_keywords | 1321 | tomoyo_set_string(head, tomoyo_mac_keywords |
1316 | [tomoyo_pp2mac[bit]]); | 1322 | [tomoyo_pp2mac[bit]]); |
1317 | } | 1323 | } |
1318 | if (first) | 1324 | if (first) |
1319 | return true; | 1325 | return true; |
1320 | tomoyo_print_name_union(head, &ptr->name1); | 1326 | tomoyo_print_name_union(head, &ptr->name1); |
1321 | tomoyo_print_name_union(head, &ptr->name2); | 1327 | tomoyo_print_name_union(head, &ptr->name2); |
1322 | } else if (acl_type == TOMOYO_TYPE_PATH_NUMBER_ACL) { | 1328 | } else if (acl_type == TOMOYO_TYPE_PATH_NUMBER_ACL) { |
1323 | struct tomoyo_path_number_acl *ptr = | 1329 | struct tomoyo_path_number_acl *ptr = |
1324 | container_of(acl, typeof(*ptr), head); | 1330 | container_of(acl, typeof(*ptr), head); |
1325 | const u8 perm = ptr->perm; | 1331 | const u8 perm = ptr->perm; |
1326 | for (bit = 0; bit < TOMOYO_MAX_PATH_NUMBER_OPERATION; bit++) { | 1332 | for (bit = 0; bit < TOMOYO_MAX_PATH_NUMBER_OPERATION; bit++) { |
1327 | if (!(perm & (1 << bit))) | 1333 | if (!(perm & (1 << bit))) |
1328 | continue; | 1334 | continue; |
1329 | if (first) { | 1335 | if (first) { |
1330 | tomoyo_set_group(head, "file "); | 1336 | tomoyo_set_group(head, "file "); |
1331 | first = false; | 1337 | first = false; |
1332 | } else { | 1338 | } else { |
1333 | tomoyo_set_slash(head); | 1339 | tomoyo_set_slash(head); |
1334 | } | 1340 | } |
1335 | tomoyo_set_string(head, tomoyo_mac_keywords | 1341 | tomoyo_set_string(head, tomoyo_mac_keywords |
1336 | [tomoyo_pn2mac[bit]]); | 1342 | [tomoyo_pn2mac[bit]]); |
1337 | } | 1343 | } |
1338 | if (first) | 1344 | if (first) |
1339 | return true; | 1345 | return true; |
1340 | tomoyo_print_name_union(head, &ptr->name); | 1346 | tomoyo_print_name_union(head, &ptr->name); |
1341 | tomoyo_print_number_union(head, &ptr->number); | 1347 | tomoyo_print_number_union(head, &ptr->number); |
1342 | } else if (acl_type == TOMOYO_TYPE_MKDEV_ACL) { | 1348 | } else if (acl_type == TOMOYO_TYPE_MKDEV_ACL) { |
1343 | struct tomoyo_mkdev_acl *ptr = | 1349 | struct tomoyo_mkdev_acl *ptr = |
1344 | container_of(acl, typeof(*ptr), head); | 1350 | container_of(acl, typeof(*ptr), head); |
1345 | const u8 perm = ptr->perm; | 1351 | const u8 perm = ptr->perm; |
1346 | for (bit = 0; bit < TOMOYO_MAX_MKDEV_OPERATION; bit++) { | 1352 | for (bit = 0; bit < TOMOYO_MAX_MKDEV_OPERATION; bit++) { |
1347 | if (!(perm & (1 << bit))) | 1353 | if (!(perm & (1 << bit))) |
1348 | continue; | 1354 | continue; |
1349 | if (first) { | 1355 | if (first) { |
1350 | tomoyo_set_group(head, "file "); | 1356 | tomoyo_set_group(head, "file "); |
1351 | first = false; | 1357 | first = false; |
1352 | } else { | 1358 | } else { |
1353 | tomoyo_set_slash(head); | 1359 | tomoyo_set_slash(head); |
1354 | } | 1360 | } |
1355 | tomoyo_set_string(head, tomoyo_mac_keywords | 1361 | tomoyo_set_string(head, tomoyo_mac_keywords |
1356 | [tomoyo_pnnn2mac[bit]]); | 1362 | [tomoyo_pnnn2mac[bit]]); |
1357 | } | 1363 | } |
1358 | if (first) | 1364 | if (first) |
1359 | return true; | 1365 | return true; |
1360 | tomoyo_print_name_union(head, &ptr->name); | 1366 | tomoyo_print_name_union(head, &ptr->name); |
1361 | tomoyo_print_number_union(head, &ptr->mode); | 1367 | tomoyo_print_number_union(head, &ptr->mode); |
1362 | tomoyo_print_number_union(head, &ptr->major); | 1368 | tomoyo_print_number_union(head, &ptr->major); |
1363 | tomoyo_print_number_union(head, &ptr->minor); | 1369 | tomoyo_print_number_union(head, &ptr->minor); |
1364 | } else if (acl_type == TOMOYO_TYPE_MOUNT_ACL) { | 1370 | } else if (acl_type == TOMOYO_TYPE_MOUNT_ACL) { |
1365 | struct tomoyo_mount_acl *ptr = | 1371 | struct tomoyo_mount_acl *ptr = |
1366 | container_of(acl, typeof(*ptr), head); | 1372 | container_of(acl, typeof(*ptr), head); |
1367 | tomoyo_set_group(head, "file mount"); | 1373 | tomoyo_set_group(head, "file mount"); |
1368 | tomoyo_print_name_union(head, &ptr->dev_name); | 1374 | tomoyo_print_name_union(head, &ptr->dev_name); |
1369 | tomoyo_print_name_union(head, &ptr->dir_name); | 1375 | tomoyo_print_name_union(head, &ptr->dir_name); |
1370 | tomoyo_print_name_union(head, &ptr->fs_type); | 1376 | tomoyo_print_name_union(head, &ptr->fs_type); |
1371 | tomoyo_print_number_union(head, &ptr->flags); | 1377 | tomoyo_print_number_union(head, &ptr->flags); |
1372 | } | 1378 | } |
1373 | if (acl->cond) { | 1379 | if (acl->cond) { |
1374 | head->r.print_cond_part = true; | 1380 | head->r.print_cond_part = true; |
1375 | head->r.cond_step = 0; | 1381 | head->r.cond_step = 0; |
1376 | if (!tomoyo_flush(head)) | 1382 | if (!tomoyo_flush(head)) |
1377 | return false; | 1383 | return false; |
1378 | print_cond_part: | 1384 | print_cond_part: |
1379 | if (!tomoyo_print_condition(head, acl->cond)) | 1385 | if (!tomoyo_print_condition(head, acl->cond)) |
1380 | return false; | 1386 | return false; |
1381 | head->r.print_cond_part = false; | 1387 | head->r.print_cond_part = false; |
1382 | } else { | 1388 | } else { |
1383 | tomoyo_set_lf(head); | 1389 | tomoyo_set_lf(head); |
1384 | } | 1390 | } |
1385 | return true; | 1391 | return true; |
1386 | } | 1392 | } |
1387 | 1393 | ||
1388 | /** | 1394 | /** |
1389 | * tomoyo_read_domain2 - Read domain policy. | 1395 | * tomoyo_read_domain2 - Read domain policy. |
1390 | * | 1396 | * |
1391 | * @head: Pointer to "struct tomoyo_io_buffer". | 1397 | * @head: Pointer to "struct tomoyo_io_buffer". |
1392 | * @list: Pointer to "struct list_head". | 1398 | * @list: Pointer to "struct list_head". |
1393 | * | 1399 | * |
1394 | * Caller holds tomoyo_read_lock(). | 1400 | * Caller holds tomoyo_read_lock(). |
1395 | * | 1401 | * |
1396 | * Returns true on success, false otherwise. | 1402 | * Returns true on success, false otherwise. |
1397 | */ | 1403 | */ |
1398 | static bool tomoyo_read_domain2(struct tomoyo_io_buffer *head, | 1404 | static bool tomoyo_read_domain2(struct tomoyo_io_buffer *head, |
1399 | struct list_head *list) | 1405 | struct list_head *list) |
1400 | { | 1406 | { |
1401 | list_for_each_cookie(head->r.acl, list) { | 1407 | list_for_each_cookie(head->r.acl, list) { |
1402 | struct tomoyo_acl_info *ptr = | 1408 | struct tomoyo_acl_info *ptr = |
1403 | list_entry(head->r.acl, typeof(*ptr), list); | 1409 | list_entry(head->r.acl, typeof(*ptr), list); |
1404 | if (!tomoyo_print_entry(head, ptr)) | 1410 | if (!tomoyo_print_entry(head, ptr)) |
1405 | return false; | 1411 | return false; |
1406 | } | 1412 | } |
1407 | head->r.acl = NULL; | 1413 | head->r.acl = NULL; |
1408 | return true; | 1414 | return true; |
1409 | } | 1415 | } |
1410 | 1416 | ||
1411 | /** | 1417 | /** |
1412 | * tomoyo_read_domain - Read domain policy. | 1418 | * tomoyo_read_domain - Read domain policy. |
1413 | * | 1419 | * |
1414 | * @head: Pointer to "struct tomoyo_io_buffer". | 1420 | * @head: Pointer to "struct tomoyo_io_buffer". |
1415 | * | 1421 | * |
1416 | * Caller holds tomoyo_read_lock(). | 1422 | * Caller holds tomoyo_read_lock(). |
1417 | */ | 1423 | */ |
1418 | static void tomoyo_read_domain(struct tomoyo_io_buffer *head) | 1424 | static void tomoyo_read_domain(struct tomoyo_io_buffer *head) |
1419 | { | 1425 | { |
1420 | if (head->r.eof) | 1426 | if (head->r.eof) |
1421 | return; | 1427 | return; |
1422 | list_for_each_cookie(head->r.domain, &tomoyo_domain_list) { | 1428 | list_for_each_cookie(head->r.domain, &tomoyo_domain_list) { |
1423 | struct tomoyo_domain_info *domain = | 1429 | struct tomoyo_domain_info *domain = |
1424 | list_entry(head->r.domain, typeof(*domain), list); | 1430 | list_entry(head->r.domain, typeof(*domain), list); |
1425 | switch (head->r.step) { | 1431 | switch (head->r.step) { |
1426 | u8 i; | 1432 | u8 i; |
1427 | case 0: | 1433 | case 0: |
1428 | if (domain->is_deleted && | 1434 | if (domain->is_deleted && |
1429 | !head->r.print_this_domain_only) | 1435 | !head->r.print_this_domain_only) |
1430 | continue; | 1436 | continue; |
1431 | /* Print domainname and flags. */ | 1437 | /* Print domainname and flags. */ |
1432 | tomoyo_set_string(head, domain->domainname->name); | 1438 | tomoyo_set_string(head, domain->domainname->name); |
1433 | tomoyo_set_lf(head); | 1439 | tomoyo_set_lf(head); |
1434 | tomoyo_io_printf(head, "use_profile %u\n", | 1440 | tomoyo_io_printf(head, "use_profile %u\n", |
1435 | domain->profile); | 1441 | domain->profile); |
1436 | tomoyo_io_printf(head, "use_group %u\n", | 1442 | tomoyo_io_printf(head, "use_group %u\n", |
1437 | domain->group); | 1443 | domain->group); |
1438 | for (i = 0; i < TOMOYO_MAX_DOMAIN_INFO_FLAGS; i++) | 1444 | for (i = 0; i < TOMOYO_MAX_DOMAIN_INFO_FLAGS; i++) |
1439 | if (domain->flags[i]) | 1445 | if (domain->flags[i]) |
1440 | tomoyo_set_string(head, tomoyo_dif[i]); | 1446 | tomoyo_set_string(head, tomoyo_dif[i]); |
1441 | head->r.step++; | 1447 | head->r.step++; |
1442 | tomoyo_set_lf(head); | 1448 | tomoyo_set_lf(head); |
1443 | /* fall through */ | 1449 | /* fall through */ |
1444 | case 1: | 1450 | case 1: |
1445 | if (!tomoyo_read_domain2(head, &domain->acl_info_list)) | 1451 | if (!tomoyo_read_domain2(head, &domain->acl_info_list)) |
1446 | return; | 1452 | return; |
1447 | head->r.step++; | 1453 | head->r.step++; |
1448 | if (!tomoyo_set_lf(head)) | 1454 | if (!tomoyo_set_lf(head)) |
1449 | return; | 1455 | return; |
1450 | /* fall through */ | 1456 | /* fall through */ |
1451 | case 2: | 1457 | case 2: |
1452 | head->r.step = 0; | 1458 | head->r.step = 0; |
1453 | if (head->r.print_this_domain_only) | 1459 | if (head->r.print_this_domain_only) |
1454 | goto done; | 1460 | goto done; |
1455 | } | 1461 | } |
1456 | } | 1462 | } |
1457 | done: | 1463 | done: |
1458 | head->r.eof = true; | 1464 | head->r.eof = true; |
1459 | } | 1465 | } |
1460 | 1466 | ||
1461 | /** | 1467 | /** |
1462 | * tomoyo_write_pid: Specify PID to obtain domainname. | 1468 | * tomoyo_write_pid: Specify PID to obtain domainname. |
1463 | * | 1469 | * |
1464 | * @head: Pointer to "struct tomoyo_io_buffer". | 1470 | * @head: Pointer to "struct tomoyo_io_buffer". |
1465 | * | 1471 | * |
1466 | * Returns 0. | 1472 | * Returns 0. |
1467 | */ | 1473 | */ |
1468 | static int tomoyo_write_pid(struct tomoyo_io_buffer *head) | 1474 | static int tomoyo_write_pid(struct tomoyo_io_buffer *head) |
1469 | { | 1475 | { |
1470 | head->r.eof = false; | 1476 | head->r.eof = false; |
1471 | return 0; | 1477 | return 0; |
1472 | } | 1478 | } |
1473 | 1479 | ||
1474 | /** | 1480 | /** |
1475 | * tomoyo_read_pid - Get domainname of the specified PID. | 1481 | * tomoyo_read_pid - Get domainname of the specified PID. |
1476 | * | 1482 | * |
1477 | * @head: Pointer to "struct tomoyo_io_buffer". | 1483 | * @head: Pointer to "struct tomoyo_io_buffer". |
1478 | * | 1484 | * |
1479 | * Returns the domainname which the specified PID is in on success, | 1485 | * Returns the domainname which the specified PID is in on success, |
1480 | * empty string otherwise. | 1486 | * empty string otherwise. |
1481 | * The PID is specified by tomoyo_write_pid() so that the user can obtain | 1487 | * The PID is specified by tomoyo_write_pid() so that the user can obtain |
1482 | * using read()/write() interface rather than sysctl() interface. | 1488 | * using read()/write() interface rather than sysctl() interface. |
1483 | */ | 1489 | */ |
1484 | static void tomoyo_read_pid(struct tomoyo_io_buffer *head) | 1490 | static void tomoyo_read_pid(struct tomoyo_io_buffer *head) |
1485 | { | 1491 | { |
1486 | char *buf = head->write_buf; | 1492 | char *buf = head->write_buf; |
1487 | bool global_pid = false; | 1493 | bool global_pid = false; |
1488 | unsigned int pid; | 1494 | unsigned int pid; |
1489 | struct task_struct *p; | 1495 | struct task_struct *p; |
1490 | struct tomoyo_domain_info *domain = NULL; | 1496 | struct tomoyo_domain_info *domain = NULL; |
1491 | 1497 | ||
1492 | /* Accessing write_buf is safe because head->io_sem is held. */ | 1498 | /* Accessing write_buf is safe because head->io_sem is held. */ |
1493 | if (!buf) { | 1499 | if (!buf) { |
1494 | head->r.eof = true; | 1500 | head->r.eof = true; |
1495 | return; /* Do nothing if open(O_RDONLY). */ | 1501 | return; /* Do nothing if open(O_RDONLY). */ |
1496 | } | 1502 | } |
1497 | if (head->r.w_pos || head->r.eof) | 1503 | if (head->r.w_pos || head->r.eof) |
1498 | return; | 1504 | return; |
1499 | head->r.eof = true; | 1505 | head->r.eof = true; |
1500 | if (tomoyo_str_starts(&buf, "global-pid ")) | 1506 | if (tomoyo_str_starts(&buf, "global-pid ")) |
1501 | global_pid = true; | 1507 | global_pid = true; |
1502 | pid = (unsigned int) simple_strtoul(buf, NULL, 10); | 1508 | pid = (unsigned int) simple_strtoul(buf, NULL, 10); |
1503 | rcu_read_lock(); | 1509 | rcu_read_lock(); |
1504 | read_lock(&tasklist_lock); | 1510 | read_lock(&tasklist_lock); |
1505 | if (global_pid) | 1511 | if (global_pid) |
1506 | p = find_task_by_pid_ns(pid, &init_pid_ns); | 1512 | p = find_task_by_pid_ns(pid, &init_pid_ns); |
1507 | else | 1513 | else |
1508 | p = find_task_by_vpid(pid); | 1514 | p = find_task_by_vpid(pid); |
1509 | if (p) | 1515 | if (p) |
1510 | domain = tomoyo_real_domain(p); | 1516 | domain = tomoyo_real_domain(p); |
1511 | read_unlock(&tasklist_lock); | 1517 | read_unlock(&tasklist_lock); |
1512 | rcu_read_unlock(); | 1518 | rcu_read_unlock(); |
1513 | if (!domain) | 1519 | if (!domain) |
1514 | return; | 1520 | return; |
1515 | tomoyo_io_printf(head, "%u %u ", pid, domain->profile); | 1521 | tomoyo_io_printf(head, "%u %u ", pid, domain->profile); |
1516 | tomoyo_set_string(head, domain->domainname->name); | 1522 | tomoyo_set_string(head, domain->domainname->name); |
1517 | } | 1523 | } |
1518 | 1524 | ||
1525 | /* String table for domain transition control keywords. */ | ||
1519 | static const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = { | 1526 | static const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = { |
1520 | [TOMOYO_TRANSITION_CONTROL_NO_RESET] = "no_reset_domain ", | 1527 | [TOMOYO_TRANSITION_CONTROL_NO_RESET] = "no_reset_domain ", |
1521 | [TOMOYO_TRANSITION_CONTROL_RESET] = "reset_domain ", | 1528 | [TOMOYO_TRANSITION_CONTROL_RESET] = "reset_domain ", |
1522 | [TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE] = "no_initialize_domain ", | 1529 | [TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE] = "no_initialize_domain ", |
1523 | [TOMOYO_TRANSITION_CONTROL_INITIALIZE] = "initialize_domain ", | 1530 | [TOMOYO_TRANSITION_CONTROL_INITIALIZE] = "initialize_domain ", |
1524 | [TOMOYO_TRANSITION_CONTROL_NO_KEEP] = "no_keep_domain ", | 1531 | [TOMOYO_TRANSITION_CONTROL_NO_KEEP] = "no_keep_domain ", |
1525 | [TOMOYO_TRANSITION_CONTROL_KEEP] = "keep_domain ", | 1532 | [TOMOYO_TRANSITION_CONTROL_KEEP] = "keep_domain ", |
1526 | }; | 1533 | }; |
1527 | 1534 | ||
1535 | /* String table for grouping keywords. */ | ||
1528 | static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = { | 1536 | static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = { |
1529 | [TOMOYO_PATH_GROUP] = "path_group ", | 1537 | [TOMOYO_PATH_GROUP] = "path_group ", |
1530 | [TOMOYO_NUMBER_GROUP] = "number_group ", | 1538 | [TOMOYO_NUMBER_GROUP] = "number_group ", |
1531 | }; | 1539 | }; |
1532 | 1540 | ||
1533 | /** | 1541 | /** |
1534 | * tomoyo_write_exception - Write exception policy. | 1542 | * tomoyo_write_exception - Write exception policy. |
1535 | * | 1543 | * |
1536 | * @head: Pointer to "struct tomoyo_io_buffer". | 1544 | * @head: Pointer to "struct tomoyo_io_buffer". |
1537 | * | 1545 | * |
1538 | * Returns 0 on success, negative value otherwise. | 1546 | * Returns 0 on success, negative value otherwise. |
1539 | * | 1547 | * |
1540 | * Caller holds tomoyo_read_lock(). | 1548 | * Caller holds tomoyo_read_lock(). |
1541 | */ | 1549 | */ |
1542 | static int tomoyo_write_exception(struct tomoyo_io_buffer *head) | 1550 | static int tomoyo_write_exception(struct tomoyo_io_buffer *head) |
1543 | { | 1551 | { |
1544 | const bool is_delete = head->w.is_delete; | 1552 | const bool is_delete = head->w.is_delete; |
1545 | struct tomoyo_acl_param param = { | 1553 | struct tomoyo_acl_param param = { |
1546 | .ns = head->w.ns, | 1554 | .ns = head->w.ns, |
1547 | .is_delete = is_delete, | 1555 | .is_delete = is_delete, |
1548 | .data = head->write_buf, | 1556 | .data = head->write_buf, |
1549 | }; | 1557 | }; |
1550 | u8 i; | 1558 | u8 i; |
1551 | if (tomoyo_str_starts(¶m.data, "aggregator ")) | 1559 | if (tomoyo_str_starts(¶m.data, "aggregator ")) |
1552 | return tomoyo_write_aggregator(¶m); | 1560 | return tomoyo_write_aggregator(¶m); |
1553 | for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++) | 1561 | for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++) |
1554 | if (tomoyo_str_starts(¶m.data, tomoyo_transition_type[i])) | 1562 | if (tomoyo_str_starts(¶m.data, tomoyo_transition_type[i])) |
1555 | return tomoyo_write_transition_control(¶m, i); | 1563 | return tomoyo_write_transition_control(¶m, i); |
1556 | for (i = 0; i < TOMOYO_MAX_GROUP; i++) | 1564 | for (i = 0; i < TOMOYO_MAX_GROUP; i++) |
1557 | if (tomoyo_str_starts(¶m.data, tomoyo_group_name[i])) | 1565 | if (tomoyo_str_starts(¶m.data, tomoyo_group_name[i])) |
1558 | return tomoyo_write_group(¶m, i); | 1566 | return tomoyo_write_group(¶m, i); |
1559 | if (tomoyo_str_starts(¶m.data, "acl_group ")) { | 1567 | if (tomoyo_str_starts(¶m.data, "acl_group ")) { |
1560 | unsigned int group; | 1568 | unsigned int group; |
1561 | char *data; | 1569 | char *data; |
1562 | group = simple_strtoul(param.data, &data, 10); | 1570 | group = simple_strtoul(param.data, &data, 10); |
1563 | if (group < TOMOYO_MAX_ACL_GROUPS && *data++ == ' ') | 1571 | if (group < TOMOYO_MAX_ACL_GROUPS && *data++ == ' ') |
1564 | return tomoyo_write_domain2 | 1572 | return tomoyo_write_domain2 |
1565 | (head->w.ns, &head->w.ns->acl_group[group], | 1573 | (head->w.ns, &head->w.ns->acl_group[group], |
1566 | data, is_delete); | 1574 | data, is_delete); |
1567 | } | 1575 | } |
1568 | return -EINVAL; | 1576 | return -EINVAL; |
1569 | } | 1577 | } |
1570 | 1578 | ||
1571 | /** | 1579 | /** |
1572 | * tomoyo_read_group - Read "struct tomoyo_path_group"/"struct tomoyo_number_group" list. | 1580 | * tomoyo_read_group - Read "struct tomoyo_path_group"/"struct tomoyo_number_group" list. |
1573 | * | 1581 | * |
1574 | * @head: Pointer to "struct tomoyo_io_buffer". | 1582 | * @head: Pointer to "struct tomoyo_io_buffer". |
1575 | * @idx: Index number. | 1583 | * @idx: Index number. |
1576 | * | 1584 | * |
1577 | * Returns true on success, false otherwise. | 1585 | * Returns true on success, false otherwise. |
1578 | * | 1586 | * |
1579 | * Caller holds tomoyo_read_lock(). | 1587 | * Caller holds tomoyo_read_lock(). |
1580 | */ | 1588 | */ |
1581 | static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx) | 1589 | static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx) |
1582 | { | 1590 | { |
1583 | struct tomoyo_policy_namespace *ns = | 1591 | struct tomoyo_policy_namespace *ns = |
1584 | container_of(head->r.ns, typeof(*ns), namespace_list); | 1592 | container_of(head->r.ns, typeof(*ns), namespace_list); |
1585 | struct list_head *list = &ns->group_list[idx]; | 1593 | struct list_head *list = &ns->group_list[idx]; |
1586 | list_for_each_cookie(head->r.group, list) { | 1594 | list_for_each_cookie(head->r.group, list) { |
1587 | struct tomoyo_group *group = | 1595 | struct tomoyo_group *group = |
1588 | list_entry(head->r.group, typeof(*group), head.list); | 1596 | list_entry(head->r.group, typeof(*group), head.list); |
1589 | list_for_each_cookie(head->r.acl, &group->member_list) { | 1597 | list_for_each_cookie(head->r.acl, &group->member_list) { |
1590 | struct tomoyo_acl_head *ptr = | 1598 | struct tomoyo_acl_head *ptr = |
1591 | list_entry(head->r.acl, typeof(*ptr), list); | 1599 | list_entry(head->r.acl, typeof(*ptr), list); |
1592 | if (ptr->is_deleted) | 1600 | if (ptr->is_deleted) |
1593 | continue; | 1601 | continue; |
1594 | if (!tomoyo_flush(head)) | 1602 | if (!tomoyo_flush(head)) |
1595 | return false; | 1603 | return false; |
1596 | tomoyo_print_namespace(head); | 1604 | tomoyo_print_namespace(head); |
1597 | tomoyo_set_string(head, tomoyo_group_name[idx]); | 1605 | tomoyo_set_string(head, tomoyo_group_name[idx]); |
1598 | tomoyo_set_string(head, group->group_name->name); | 1606 | tomoyo_set_string(head, group->group_name->name); |
1599 | if (idx == TOMOYO_PATH_GROUP) { | 1607 | if (idx == TOMOYO_PATH_GROUP) { |
1600 | tomoyo_set_space(head); | 1608 | tomoyo_set_space(head); |
1601 | tomoyo_set_string(head, container_of | 1609 | tomoyo_set_string(head, container_of |
1602 | (ptr, struct tomoyo_path_group, | 1610 | (ptr, struct tomoyo_path_group, |
1603 | head)->member_name->name); | 1611 | head)->member_name->name); |
1604 | } else if (idx == TOMOYO_NUMBER_GROUP) { | 1612 | } else if (idx == TOMOYO_NUMBER_GROUP) { |
1605 | tomoyo_print_number_union(head, &container_of | 1613 | tomoyo_print_number_union(head, &container_of |
1606 | (ptr, | 1614 | (ptr, |
1607 | struct tomoyo_number_group, | 1615 | struct tomoyo_number_group, |
1608 | head)->number); | 1616 | head)->number); |
1609 | } | 1617 | } |
1610 | tomoyo_set_lf(head); | 1618 | tomoyo_set_lf(head); |
1611 | } | 1619 | } |
1612 | head->r.acl = NULL; | 1620 | head->r.acl = NULL; |
1613 | } | 1621 | } |
1614 | head->r.group = NULL; | 1622 | head->r.group = NULL; |
1615 | return true; | 1623 | return true; |
1616 | } | 1624 | } |
1617 | 1625 | ||
1618 | /** | 1626 | /** |
1619 | * tomoyo_read_policy - Read "struct tomoyo_..._entry" list. | 1627 | * tomoyo_read_policy - Read "struct tomoyo_..._entry" list. |
1620 | * | 1628 | * |
1621 | * @head: Pointer to "struct tomoyo_io_buffer". | 1629 | * @head: Pointer to "struct tomoyo_io_buffer". |
1622 | * @idx: Index number. | 1630 | * @idx: Index number. |
1623 | * | 1631 | * |
1624 | * Returns true on success, false otherwise. | 1632 | * Returns true on success, false otherwise. |
1625 | * | 1633 | * |
1626 | * Caller holds tomoyo_read_lock(). | 1634 | * Caller holds tomoyo_read_lock(). |
1627 | */ | 1635 | */ |
1628 | static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx) | 1636 | static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx) |
1629 | { | 1637 | { |
1630 | struct tomoyo_policy_namespace *ns = | 1638 | struct tomoyo_policy_namespace *ns = |
1631 | container_of(head->r.ns, typeof(*ns), namespace_list); | 1639 | container_of(head->r.ns, typeof(*ns), namespace_list); |
1632 | struct list_head *list = &ns->policy_list[idx]; | 1640 | struct list_head *list = &ns->policy_list[idx]; |
1633 | list_for_each_cookie(head->r.acl, list) { | 1641 | list_for_each_cookie(head->r.acl, list) { |
1634 | struct tomoyo_acl_head *acl = | 1642 | struct tomoyo_acl_head *acl = |
1635 | container_of(head->r.acl, typeof(*acl), list); | 1643 | container_of(head->r.acl, typeof(*acl), list); |
1636 | if (acl->is_deleted) | 1644 | if (acl->is_deleted) |
1637 | continue; | 1645 | continue; |
1638 | if (!tomoyo_flush(head)) | 1646 | if (!tomoyo_flush(head)) |
1639 | return false; | 1647 | return false; |
1640 | switch (idx) { | 1648 | switch (idx) { |
1641 | case TOMOYO_ID_TRANSITION_CONTROL: | 1649 | case TOMOYO_ID_TRANSITION_CONTROL: |
1642 | { | 1650 | { |
1643 | struct tomoyo_transition_control *ptr = | 1651 | struct tomoyo_transition_control *ptr = |
1644 | container_of(acl, typeof(*ptr), head); | 1652 | container_of(acl, typeof(*ptr), head); |
1645 | tomoyo_print_namespace(head); | 1653 | tomoyo_print_namespace(head); |
1646 | tomoyo_set_string(head, tomoyo_transition_type | 1654 | tomoyo_set_string(head, tomoyo_transition_type |
1647 | [ptr->type]); | 1655 | [ptr->type]); |
1648 | tomoyo_set_string(head, ptr->program ? | 1656 | tomoyo_set_string(head, ptr->program ? |
1649 | ptr->program->name : "any"); | 1657 | ptr->program->name : "any"); |
1650 | tomoyo_set_string(head, " from "); | 1658 | tomoyo_set_string(head, " from "); |
1651 | tomoyo_set_string(head, ptr->domainname ? | 1659 | tomoyo_set_string(head, ptr->domainname ? |
1652 | ptr->domainname->name : | 1660 | ptr->domainname->name : |
1653 | "any"); | 1661 | "any"); |
1654 | } | 1662 | } |
1655 | break; | 1663 | break; |
1656 | case TOMOYO_ID_AGGREGATOR: | 1664 | case TOMOYO_ID_AGGREGATOR: |
1657 | { | 1665 | { |
1658 | struct tomoyo_aggregator *ptr = | 1666 | struct tomoyo_aggregator *ptr = |
1659 | container_of(acl, typeof(*ptr), head); | 1667 | container_of(acl, typeof(*ptr), head); |
1660 | tomoyo_print_namespace(head); | 1668 | tomoyo_print_namespace(head); |
1661 | tomoyo_set_string(head, "aggregator "); | 1669 | tomoyo_set_string(head, "aggregator "); |
1662 | tomoyo_set_string(head, | 1670 | tomoyo_set_string(head, |
1663 | ptr->original_name->name); | 1671 | ptr->original_name->name); |
1664 | tomoyo_set_space(head); | 1672 | tomoyo_set_space(head); |
1665 | tomoyo_set_string(head, | 1673 | tomoyo_set_string(head, |
1666 | ptr->aggregated_name->name); | 1674 | ptr->aggregated_name->name); |
1667 | } | 1675 | } |
1668 | break; | 1676 | break; |
1669 | default: | 1677 | default: |
1670 | continue; | 1678 | continue; |
1671 | } | 1679 | } |
1672 | tomoyo_set_lf(head); | 1680 | tomoyo_set_lf(head); |
1673 | } | 1681 | } |
1674 | head->r.acl = NULL; | 1682 | head->r.acl = NULL; |
1675 | return true; | 1683 | return true; |
1676 | } | 1684 | } |
1677 | 1685 | ||
1678 | /** | 1686 | /** |
1679 | * tomoyo_read_exception - Read exception policy. | 1687 | * tomoyo_read_exception - Read exception policy. |
1680 | * | 1688 | * |
1681 | * @head: Pointer to "struct tomoyo_io_buffer". | 1689 | * @head: Pointer to "struct tomoyo_io_buffer". |
1682 | * | 1690 | * |
1683 | * Caller holds tomoyo_read_lock(). | 1691 | * Caller holds tomoyo_read_lock(). |
1684 | */ | 1692 | */ |
1685 | static void tomoyo_read_exception(struct tomoyo_io_buffer *head) | 1693 | static void tomoyo_read_exception(struct tomoyo_io_buffer *head) |
1686 | { | 1694 | { |
1687 | struct tomoyo_policy_namespace *ns = | 1695 | struct tomoyo_policy_namespace *ns = |
1688 | container_of(head->r.ns, typeof(*ns), namespace_list); | 1696 | container_of(head->r.ns, typeof(*ns), namespace_list); |
1689 | if (head->r.eof) | 1697 | if (head->r.eof) |
1690 | return; | 1698 | return; |
1691 | while (head->r.step < TOMOYO_MAX_POLICY && | 1699 | while (head->r.step < TOMOYO_MAX_POLICY && |
1692 | tomoyo_read_policy(head, head->r.step)) | 1700 | tomoyo_read_policy(head, head->r.step)) |
1693 | head->r.step++; | 1701 | head->r.step++; |
1694 | if (head->r.step < TOMOYO_MAX_POLICY) | 1702 | if (head->r.step < TOMOYO_MAX_POLICY) |
1695 | return; | 1703 | return; |
1696 | while (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP && | 1704 | while (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP && |
1697 | tomoyo_read_group(head, head->r.step - TOMOYO_MAX_POLICY)) | 1705 | tomoyo_read_group(head, head->r.step - TOMOYO_MAX_POLICY)) |
1698 | head->r.step++; | 1706 | head->r.step++; |
1699 | if (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP) | 1707 | if (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP) |
1700 | return; | 1708 | return; |
1701 | while (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP | 1709 | while (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP |
1702 | + TOMOYO_MAX_ACL_GROUPS) { | 1710 | + TOMOYO_MAX_ACL_GROUPS) { |
1703 | head->r.acl_group_index = head->r.step - TOMOYO_MAX_POLICY | 1711 | head->r.acl_group_index = head->r.step - TOMOYO_MAX_POLICY |
1704 | - TOMOYO_MAX_GROUP; | 1712 | - TOMOYO_MAX_GROUP; |
1705 | if (!tomoyo_read_domain2(head, &ns->acl_group | 1713 | if (!tomoyo_read_domain2(head, &ns->acl_group |
1706 | [head->r.acl_group_index])) | 1714 | [head->r.acl_group_index])) |
1707 | return; | 1715 | return; |
1708 | head->r.step++; | 1716 | head->r.step++; |
1709 | } | 1717 | } |
1710 | head->r.eof = true; | 1718 | head->r.eof = true; |
1711 | } | 1719 | } |
1712 | 1720 | ||
1713 | /* Wait queue for kernel -> userspace notification. */ | 1721 | /* Wait queue for kernel -> userspace notification. */ |
1714 | static DECLARE_WAIT_QUEUE_HEAD(tomoyo_query_wait); | 1722 | static DECLARE_WAIT_QUEUE_HEAD(tomoyo_query_wait); |
1715 | /* Wait queue for userspace -> kernel notification. */ | 1723 | /* Wait queue for userspace -> kernel notification. */ |
1716 | static DECLARE_WAIT_QUEUE_HEAD(tomoyo_answer_wait); | 1724 | static DECLARE_WAIT_QUEUE_HEAD(tomoyo_answer_wait); |
1717 | 1725 | ||
1718 | /* Structure for query. */ | 1726 | /* Structure for query. */ |
1719 | struct tomoyo_query { | 1727 | struct tomoyo_query { |
1720 | struct list_head list; | 1728 | struct list_head list; |
1721 | char *query; | 1729 | char *query; |
1722 | size_t query_len; | 1730 | size_t query_len; |
1723 | unsigned int serial; | 1731 | unsigned int serial; |
1724 | u8 timer; | 1732 | u8 timer; |
1725 | u8 answer; | 1733 | u8 answer; |
1726 | u8 retry; | 1734 | u8 retry; |
1727 | }; | 1735 | }; |
1728 | 1736 | ||
1729 | /* The list for "struct tomoyo_query". */ | 1737 | /* The list for "struct tomoyo_query". */ |
1730 | static LIST_HEAD(tomoyo_query_list); | 1738 | static LIST_HEAD(tomoyo_query_list); |
1731 | 1739 | ||
1732 | /* Lock for manipulating tomoyo_query_list. */ | 1740 | /* Lock for manipulating tomoyo_query_list. */ |
1733 | static DEFINE_SPINLOCK(tomoyo_query_list_lock); | 1741 | static DEFINE_SPINLOCK(tomoyo_query_list_lock); |
1734 | 1742 | ||
1735 | /* | 1743 | /* |
1736 | * Number of "struct file" referring /sys/kernel/security/tomoyo/query | 1744 | * Number of "struct file" referring /sys/kernel/security/tomoyo/query |
1737 | * interface. | 1745 | * interface. |
1738 | */ | 1746 | */ |
1739 | static atomic_t tomoyo_query_observers = ATOMIC_INIT(0); | 1747 | static atomic_t tomoyo_query_observers = ATOMIC_INIT(0); |
1740 | 1748 | ||
1741 | /** | 1749 | /** |
1742 | * tomoyo_truncate - Truncate a line. | 1750 | * tomoyo_truncate - Truncate a line. |
1743 | * | 1751 | * |
1744 | * @str: String to truncate. | 1752 | * @str: String to truncate. |
1745 | * | 1753 | * |
1746 | * Returns length of truncated @str. | 1754 | * Returns length of truncated @str. |
1747 | */ | 1755 | */ |
1748 | static int tomoyo_truncate(char *str) | 1756 | static int tomoyo_truncate(char *str) |
1749 | { | 1757 | { |
1750 | char *start = str; | 1758 | char *start = str; |
1751 | while (*(unsigned char *) str > (unsigned char) ' ') | 1759 | while (*(unsigned char *) str > (unsigned char) ' ') |
1752 | str++; | 1760 | str++; |
1753 | *str = '\0'; | 1761 | *str = '\0'; |
1754 | return strlen(start) + 1; | 1762 | return strlen(start) + 1; |
1755 | } | 1763 | } |
1756 | 1764 | ||
1757 | /** | 1765 | /** |
1758 | * tomoyo_add_entry - Add an ACL to current thread's domain. Used by learning mode. | 1766 | * tomoyo_add_entry - Add an ACL to current thread's domain. Used by learning mode. |
1759 | * | 1767 | * |
1760 | * @domain: Pointer to "struct tomoyo_domain_info". | 1768 | * @domain: Pointer to "struct tomoyo_domain_info". |
1761 | * @header: Lines containing ACL. | 1769 | * @header: Lines containing ACL. |
1762 | * | 1770 | * |
1763 | * Returns nothing. | 1771 | * Returns nothing. |
1764 | */ | 1772 | */ |
1765 | static void tomoyo_add_entry(struct tomoyo_domain_info *domain, char *header) | 1773 | static void tomoyo_add_entry(struct tomoyo_domain_info *domain, char *header) |
1766 | { | 1774 | { |
1767 | char *buffer; | 1775 | char *buffer; |
1768 | char *realpath = NULL; | 1776 | char *realpath = NULL; |
1769 | char *argv0 = NULL; | 1777 | char *argv0 = NULL; |
1770 | char *symlink = NULL; | 1778 | char *symlink = NULL; |
1771 | char *cp = strchr(header, '\n'); | 1779 | char *cp = strchr(header, '\n'); |
1772 | int len; | 1780 | int len; |
1773 | if (!cp) | 1781 | if (!cp) |
1774 | return; | 1782 | return; |
1775 | cp = strchr(cp + 1, '\n'); | 1783 | cp = strchr(cp + 1, '\n'); |
1776 | if (!cp) | 1784 | if (!cp) |
1777 | return; | 1785 | return; |
1778 | *cp++ = '\0'; | 1786 | *cp++ = '\0'; |
1779 | len = strlen(cp) + 1; | 1787 | len = strlen(cp) + 1; |
1780 | /* strstr() will return NULL if ordering is wrong. */ | 1788 | /* strstr() will return NULL if ordering is wrong. */ |
1781 | if (*cp == 'f') { | 1789 | if (*cp == 'f') { |
1782 | argv0 = strstr(header, " argv[]={ \""); | 1790 | argv0 = strstr(header, " argv[]={ \""); |
1783 | if (argv0) { | 1791 | if (argv0) { |
1784 | argv0 += 10; | 1792 | argv0 += 10; |
1785 | len += tomoyo_truncate(argv0) + 14; | 1793 | len += tomoyo_truncate(argv0) + 14; |
1786 | } | 1794 | } |
1787 | realpath = strstr(header, " exec={ realpath=\""); | 1795 | realpath = strstr(header, " exec={ realpath=\""); |
1788 | if (realpath) { | 1796 | if (realpath) { |
1789 | realpath += 8; | 1797 | realpath += 8; |
1790 | len += tomoyo_truncate(realpath) + 6; | 1798 | len += tomoyo_truncate(realpath) + 6; |
1791 | } | 1799 | } |
1792 | symlink = strstr(header, " symlink.target=\""); | 1800 | symlink = strstr(header, " symlink.target=\""); |
1793 | if (symlink) | 1801 | if (symlink) |
1794 | len += tomoyo_truncate(symlink + 1) + 1; | 1802 | len += tomoyo_truncate(symlink + 1) + 1; |
1795 | } | 1803 | } |
1796 | buffer = kmalloc(len, GFP_NOFS); | 1804 | buffer = kmalloc(len, GFP_NOFS); |
1797 | if (!buffer) | 1805 | if (!buffer) |
1798 | return; | 1806 | return; |
1799 | snprintf(buffer, len - 1, "%s", cp); | 1807 | snprintf(buffer, len - 1, "%s", cp); |
1800 | if (realpath) | 1808 | if (realpath) |
1801 | tomoyo_addprintf(buffer, len, " exec.%s", realpath); | 1809 | tomoyo_addprintf(buffer, len, " exec.%s", realpath); |
1802 | if (argv0) | 1810 | if (argv0) |
1803 | tomoyo_addprintf(buffer, len, " exec.argv[0]=%s", argv0); | 1811 | tomoyo_addprintf(buffer, len, " exec.argv[0]=%s", argv0); |
1804 | if (symlink) | 1812 | if (symlink) |
1805 | tomoyo_addprintf(buffer, len, "%s", symlink); | 1813 | tomoyo_addprintf(buffer, len, "%s", symlink); |
1806 | tomoyo_normalize_line(buffer); | 1814 | tomoyo_normalize_line(buffer); |
1807 | if (!tomoyo_write_domain2(domain->ns, &domain->acl_info_list, buffer, | 1815 | if (!tomoyo_write_domain2(domain->ns, &domain->acl_info_list, buffer, |
1808 | false)) | 1816 | false)) |
1809 | tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES); | 1817 | tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES); |
1810 | kfree(buffer); | 1818 | kfree(buffer); |
1811 | } | 1819 | } |
1812 | 1820 | ||
1813 | /** | 1821 | /** |
1814 | * tomoyo_supervisor - Ask for the supervisor's decision. | 1822 | * tomoyo_supervisor - Ask for the supervisor's decision. |
1815 | * | 1823 | * |
1816 | * @r: Pointer to "struct tomoyo_request_info". | 1824 | * @r: Pointer to "struct tomoyo_request_info". |
1817 | * @fmt: The printf()'s format string, followed by parameters. | 1825 | * @fmt: The printf()'s format string, followed by parameters. |
1818 | * | 1826 | * |
1819 | * Returns 0 if the supervisor decided to permit the access request which | 1827 | * Returns 0 if the supervisor decided to permit the access request which |
1820 | * violated the policy in enforcing mode, TOMOYO_RETRY_REQUEST if the | 1828 | * violated the policy in enforcing mode, TOMOYO_RETRY_REQUEST if the |
1821 | * supervisor decided to retry the access request which violated the policy in | 1829 | * supervisor decided to retry the access request which violated the policy in |
1822 | * enforcing mode, 0 if it is not in enforcing mode, -EPERM otherwise. | 1830 | * enforcing mode, 0 if it is not in enforcing mode, -EPERM otherwise. |
1823 | */ | 1831 | */ |
1824 | int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...) | 1832 | int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...) |
1825 | { | 1833 | { |
1826 | va_list args; | 1834 | va_list args; |
1827 | int error; | 1835 | int error; |
1828 | int len; | 1836 | int len; |
1829 | static unsigned int tomoyo_serial; | 1837 | static unsigned int tomoyo_serial; |
1830 | struct tomoyo_query entry = { }; | 1838 | struct tomoyo_query entry = { }; |
1831 | bool quota_exceeded = false; | 1839 | bool quota_exceeded = false; |
1832 | va_start(args, fmt); | 1840 | va_start(args, fmt); |
1833 | len = vsnprintf((char *) &len, 1, fmt, args) + 1; | 1841 | len = vsnprintf((char *) &len, 1, fmt, args) + 1; |
1834 | va_end(args); | 1842 | va_end(args); |
1835 | /* Write /sys/kernel/security/tomoyo/audit. */ | 1843 | /* Write /sys/kernel/security/tomoyo/audit. */ |
1836 | va_start(args, fmt); | 1844 | va_start(args, fmt); |
1837 | tomoyo_write_log2(r, len, fmt, args); | 1845 | tomoyo_write_log2(r, len, fmt, args); |
1838 | va_end(args); | 1846 | va_end(args); |
1839 | /* Nothing more to do if granted. */ | 1847 | /* Nothing more to do if granted. */ |
1840 | if (r->granted) | 1848 | if (r->granted) |
1841 | return 0; | 1849 | return 0; |
1842 | if (r->mode) | 1850 | if (r->mode) |
1843 | tomoyo_update_stat(r->mode); | 1851 | tomoyo_update_stat(r->mode); |
1844 | switch (r->mode) { | 1852 | switch (r->mode) { |
1845 | case TOMOYO_CONFIG_ENFORCING: | 1853 | case TOMOYO_CONFIG_ENFORCING: |
1846 | error = -EPERM; | 1854 | error = -EPERM; |
1847 | if (atomic_read(&tomoyo_query_observers)) | 1855 | if (atomic_read(&tomoyo_query_observers)) |
1848 | break; | 1856 | break; |
1849 | goto out; | 1857 | goto out; |
1850 | case TOMOYO_CONFIG_LEARNING: | 1858 | case TOMOYO_CONFIG_LEARNING: |
1851 | error = 0; | 1859 | error = 0; |
1852 | /* Check max_learning_entry parameter. */ | 1860 | /* Check max_learning_entry parameter. */ |
1853 | if (tomoyo_domain_quota_is_ok(r)) | 1861 | if (tomoyo_domain_quota_is_ok(r)) |
1854 | break; | 1862 | break; |
1855 | /* fall through */ | 1863 | /* fall through */ |
1856 | default: | 1864 | default: |
1857 | return 0; | 1865 | return 0; |
1858 | } | 1866 | } |
1859 | /* Get message. */ | 1867 | /* Get message. */ |
1860 | va_start(args, fmt); | 1868 | va_start(args, fmt); |
1861 | entry.query = tomoyo_init_log(r, len, fmt, args); | 1869 | entry.query = tomoyo_init_log(r, len, fmt, args); |
1862 | va_end(args); | 1870 | va_end(args); |
1863 | if (!entry.query) | 1871 | if (!entry.query) |
1864 | goto out; | 1872 | goto out; |
1865 | entry.query_len = strlen(entry.query) + 1; | 1873 | entry.query_len = strlen(entry.query) + 1; |
1866 | if (!error) { | 1874 | if (!error) { |
1867 | tomoyo_add_entry(r->domain, entry.query); | 1875 | tomoyo_add_entry(r->domain, entry.query); |
1868 | goto out; | 1876 | goto out; |
1869 | } | 1877 | } |
1870 | len = tomoyo_round2(entry.query_len); | 1878 | len = tomoyo_round2(entry.query_len); |
1871 | spin_lock(&tomoyo_query_list_lock); | 1879 | spin_lock(&tomoyo_query_list_lock); |
1872 | if (tomoyo_memory_quota[TOMOYO_MEMORY_QUERY] && | 1880 | if (tomoyo_memory_quota[TOMOYO_MEMORY_QUERY] && |
1873 | tomoyo_memory_used[TOMOYO_MEMORY_QUERY] + len | 1881 | tomoyo_memory_used[TOMOYO_MEMORY_QUERY] + len |
1874 | >= tomoyo_memory_quota[TOMOYO_MEMORY_QUERY]) { | 1882 | >= tomoyo_memory_quota[TOMOYO_MEMORY_QUERY]) { |
1875 | quota_exceeded = true; | 1883 | quota_exceeded = true; |
1876 | } else { | 1884 | } else { |
1877 | entry.serial = tomoyo_serial++; | 1885 | entry.serial = tomoyo_serial++; |
1878 | entry.retry = r->retry; | 1886 | entry.retry = r->retry; |
1879 | tomoyo_memory_used[TOMOYO_MEMORY_QUERY] += len; | 1887 | tomoyo_memory_used[TOMOYO_MEMORY_QUERY] += len; |
1880 | list_add_tail(&entry.list, &tomoyo_query_list); | 1888 | list_add_tail(&entry.list, &tomoyo_query_list); |
1881 | } | 1889 | } |
1882 | spin_unlock(&tomoyo_query_list_lock); | 1890 | spin_unlock(&tomoyo_query_list_lock); |
1883 | if (quota_exceeded) | 1891 | if (quota_exceeded) |
1884 | goto out; | 1892 | goto out; |
1885 | /* Give 10 seconds for supervisor's opinion. */ | 1893 | /* Give 10 seconds for supervisor's opinion. */ |
1886 | while (entry.timer < 10) { | 1894 | while (entry.timer < 10) { |
1887 | wake_up_all(&tomoyo_query_wait); | 1895 | wake_up_all(&tomoyo_query_wait); |
1888 | if (wait_event_interruptible_timeout | 1896 | if (wait_event_interruptible_timeout |
1889 | (tomoyo_answer_wait, entry.answer || | 1897 | (tomoyo_answer_wait, entry.answer || |
1890 | !atomic_read(&tomoyo_query_observers), HZ)) | 1898 | !atomic_read(&tomoyo_query_observers), HZ)) |
1891 | break; | 1899 | break; |
1892 | else | 1900 | else |
1893 | entry.timer++; | 1901 | entry.timer++; |
1894 | } | 1902 | } |
1895 | spin_lock(&tomoyo_query_list_lock); | 1903 | spin_lock(&tomoyo_query_list_lock); |
1896 | list_del(&entry.list); | 1904 | list_del(&entry.list); |
1897 | tomoyo_memory_used[TOMOYO_MEMORY_QUERY] -= len; | 1905 | tomoyo_memory_used[TOMOYO_MEMORY_QUERY] -= len; |
1898 | spin_unlock(&tomoyo_query_list_lock); | 1906 | spin_unlock(&tomoyo_query_list_lock); |
1899 | switch (entry.answer) { | 1907 | switch (entry.answer) { |
1900 | case 3: /* Asked to retry by administrator. */ | 1908 | case 3: /* Asked to retry by administrator. */ |
1901 | error = TOMOYO_RETRY_REQUEST; | 1909 | error = TOMOYO_RETRY_REQUEST; |
1902 | r->retry++; | 1910 | r->retry++; |
1903 | break; | 1911 | break; |
1904 | case 1: | 1912 | case 1: |
1905 | /* Granted by administrator. */ | 1913 | /* Granted by administrator. */ |
1906 | error = 0; | 1914 | error = 0; |
1907 | break; | 1915 | break; |
1908 | default: | 1916 | default: |
1909 | /* Timed out or rejected by administrator. */ | 1917 | /* Timed out or rejected by administrator. */ |
1910 | break; | 1918 | break; |
1911 | } | 1919 | } |
1912 | out: | 1920 | out: |
1913 | kfree(entry.query); | 1921 | kfree(entry.query); |
1914 | return error; | 1922 | return error; |
1915 | } | 1923 | } |
1916 | 1924 | ||
1917 | /** | 1925 | /** |
1918 | * tomoyo_poll_query - poll() for /sys/kernel/security/tomoyo/query. | 1926 | * tomoyo_poll_query - poll() for /sys/kernel/security/tomoyo/query. |
1919 | * | 1927 | * |
1920 | * @file: Pointer to "struct file". | 1928 | * @file: Pointer to "struct file". |
1921 | * @wait: Pointer to "poll_table". | 1929 | * @wait: Pointer to "poll_table". |
1922 | * | 1930 | * |
1923 | * Returns POLLIN | POLLRDNORM when ready to read, 0 otherwise. | 1931 | * Returns POLLIN | POLLRDNORM when ready to read, 0 otherwise. |
1924 | * | 1932 | * |
1925 | * Waits for access requests which violated policy in enforcing mode. | 1933 | * Waits for access requests which violated policy in enforcing mode. |
1926 | */ | 1934 | */ |
1927 | static int tomoyo_poll_query(struct file *file, poll_table *wait) | 1935 | static int tomoyo_poll_query(struct file *file, poll_table *wait) |
1928 | { | 1936 | { |
1929 | struct list_head *tmp; | 1937 | struct list_head *tmp; |
1930 | bool found = false; | 1938 | bool found = false; |
1931 | u8 i; | 1939 | u8 i; |
1932 | for (i = 0; i < 2; i++) { | 1940 | for (i = 0; i < 2; i++) { |
1933 | spin_lock(&tomoyo_query_list_lock); | 1941 | spin_lock(&tomoyo_query_list_lock); |
1934 | list_for_each(tmp, &tomoyo_query_list) { | 1942 | list_for_each(tmp, &tomoyo_query_list) { |
1935 | struct tomoyo_query *ptr = | 1943 | struct tomoyo_query *ptr = |
1936 | list_entry(tmp, typeof(*ptr), list); | 1944 | list_entry(tmp, typeof(*ptr), list); |
1937 | if (ptr->answer) | 1945 | if (ptr->answer) |
1938 | continue; | 1946 | continue; |
1939 | found = true; | 1947 | found = true; |
1940 | break; | 1948 | break; |
1941 | } | 1949 | } |
1942 | spin_unlock(&tomoyo_query_list_lock); | 1950 | spin_unlock(&tomoyo_query_list_lock); |
1943 | if (found) | 1951 | if (found) |
1944 | return POLLIN | POLLRDNORM; | 1952 | return POLLIN | POLLRDNORM; |
1945 | if (i) | 1953 | if (i) |
1946 | break; | 1954 | break; |
1947 | poll_wait(file, &tomoyo_query_wait, wait); | 1955 | poll_wait(file, &tomoyo_query_wait, wait); |
1948 | } | 1956 | } |
1949 | return 0; | 1957 | return 0; |
1950 | } | 1958 | } |
1951 | 1959 | ||
1952 | /** | 1960 | /** |
1953 | * tomoyo_read_query - Read access requests which violated policy in enforcing mode. | 1961 | * tomoyo_read_query - Read access requests which violated policy in enforcing mode. |
1954 | * | 1962 | * |
1955 | * @head: Pointer to "struct tomoyo_io_buffer". | 1963 | * @head: Pointer to "struct tomoyo_io_buffer". |
1956 | */ | 1964 | */ |
1957 | static void tomoyo_read_query(struct tomoyo_io_buffer *head) | 1965 | static void tomoyo_read_query(struct tomoyo_io_buffer *head) |
1958 | { | 1966 | { |
1959 | struct list_head *tmp; | 1967 | struct list_head *tmp; |
1960 | unsigned int pos = 0; | 1968 | unsigned int pos = 0; |
1961 | size_t len = 0; | 1969 | size_t len = 0; |
1962 | char *buf; | 1970 | char *buf; |
1963 | if (head->r.w_pos) | 1971 | if (head->r.w_pos) |
1964 | return; | 1972 | return; |
1965 | if (head->read_buf) { | 1973 | if (head->read_buf) { |
1966 | kfree(head->read_buf); | 1974 | kfree(head->read_buf); |
1967 | head->read_buf = NULL; | 1975 | head->read_buf = NULL; |
1968 | } | 1976 | } |
1969 | spin_lock(&tomoyo_query_list_lock); | 1977 | spin_lock(&tomoyo_query_list_lock); |
1970 | list_for_each(tmp, &tomoyo_query_list) { | 1978 | list_for_each(tmp, &tomoyo_query_list) { |
1971 | struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list); | 1979 | struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list); |
1972 | if (ptr->answer) | 1980 | if (ptr->answer) |
1973 | continue; | 1981 | continue; |
1974 | if (pos++ != head->r.query_index) | 1982 | if (pos++ != head->r.query_index) |
1975 | continue; | 1983 | continue; |
1976 | len = ptr->query_len; | 1984 | len = ptr->query_len; |
1977 | break; | 1985 | break; |
1978 | } | 1986 | } |
1979 | spin_unlock(&tomoyo_query_list_lock); | 1987 | spin_unlock(&tomoyo_query_list_lock); |
1980 | if (!len) { | 1988 | if (!len) { |
1981 | head->r.query_index = 0; | 1989 | head->r.query_index = 0; |
1982 | return; | 1990 | return; |
1983 | } | 1991 | } |
1984 | buf = kzalloc(len + 32, GFP_NOFS); | 1992 | buf = kzalloc(len + 32, GFP_NOFS); |
1985 | if (!buf) | 1993 | if (!buf) |
1986 | return; | 1994 | return; |
1987 | pos = 0; | 1995 | pos = 0; |
1988 | spin_lock(&tomoyo_query_list_lock); | 1996 | spin_lock(&tomoyo_query_list_lock); |
1989 | list_for_each(tmp, &tomoyo_query_list) { | 1997 | list_for_each(tmp, &tomoyo_query_list) { |
1990 | struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list); | 1998 | struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list); |
1991 | if (ptr->answer) | 1999 | if (ptr->answer) |
1992 | continue; | 2000 | continue; |
1993 | if (pos++ != head->r.query_index) | 2001 | if (pos++ != head->r.query_index) |
1994 | continue; | 2002 | continue; |
1995 | /* | 2003 | /* |
1996 | * Some query can be skipped because tomoyo_query_list | 2004 | * Some query can be skipped because tomoyo_query_list |
1997 | * can change, but I don't care. | 2005 | * can change, but I don't care. |
1998 | */ | 2006 | */ |
1999 | if (len == ptr->query_len) | 2007 | if (len == ptr->query_len) |
2000 | snprintf(buf, len + 31, "Q%u-%hu\n%s", ptr->serial, | 2008 | snprintf(buf, len + 31, "Q%u-%hu\n%s", ptr->serial, |
2001 | ptr->retry, ptr->query); | 2009 | ptr->retry, ptr->query); |
2002 | break; | 2010 | break; |
2003 | } | 2011 | } |
2004 | spin_unlock(&tomoyo_query_list_lock); | 2012 | spin_unlock(&tomoyo_query_list_lock); |
2005 | if (buf[0]) { | 2013 | if (buf[0]) { |
2006 | head->read_buf = buf; | 2014 | head->read_buf = buf; |
2007 | head->r.w[head->r.w_pos++] = buf; | 2015 | head->r.w[head->r.w_pos++] = buf; |
2008 | head->r.query_index++; | 2016 | head->r.query_index++; |
2009 | } else { | 2017 | } else { |
2010 | kfree(buf); | 2018 | kfree(buf); |
2011 | } | 2019 | } |
2012 | } | 2020 | } |
2013 | 2021 | ||
2014 | /** | 2022 | /** |
2015 | * tomoyo_write_answer - Write the supervisor's decision. | 2023 | * tomoyo_write_answer - Write the supervisor's decision. |
2016 | * | 2024 | * |
2017 | * @head: Pointer to "struct tomoyo_io_buffer". | 2025 | * @head: Pointer to "struct tomoyo_io_buffer". |
2018 | * | 2026 | * |
2019 | * Returns 0 on success, -EINVAL otherwise. | 2027 | * Returns 0 on success, -EINVAL otherwise. |
2020 | */ | 2028 | */ |
2021 | static int tomoyo_write_answer(struct tomoyo_io_buffer *head) | 2029 | static int tomoyo_write_answer(struct tomoyo_io_buffer *head) |
2022 | { | 2030 | { |
2023 | char *data = head->write_buf; | 2031 | char *data = head->write_buf; |
2024 | struct list_head *tmp; | 2032 | struct list_head *tmp; |
2025 | unsigned int serial; | 2033 | unsigned int serial; |
2026 | unsigned int answer; | 2034 | unsigned int answer; |
2027 | spin_lock(&tomoyo_query_list_lock); | 2035 | spin_lock(&tomoyo_query_list_lock); |
2028 | list_for_each(tmp, &tomoyo_query_list) { | 2036 | list_for_each(tmp, &tomoyo_query_list) { |
2029 | struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list); | 2037 | struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list); |
2030 | ptr->timer = 0; | 2038 | ptr->timer = 0; |
2031 | } | 2039 | } |
2032 | spin_unlock(&tomoyo_query_list_lock); | 2040 | spin_unlock(&tomoyo_query_list_lock); |
2033 | if (sscanf(data, "A%u=%u", &serial, &answer) != 2) | 2041 | if (sscanf(data, "A%u=%u", &serial, &answer) != 2) |
2034 | return -EINVAL; | 2042 | return -EINVAL; |
2035 | spin_lock(&tomoyo_query_list_lock); | 2043 | spin_lock(&tomoyo_query_list_lock); |
2036 | list_for_each(tmp, &tomoyo_query_list) { | 2044 | list_for_each(tmp, &tomoyo_query_list) { |
2037 | struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list); | 2045 | struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list); |
2038 | if (ptr->serial != serial) | 2046 | if (ptr->serial != serial) |
2039 | continue; | 2047 | continue; |
2040 | if (!ptr->answer) | 2048 | if (!ptr->answer) |
2041 | ptr->answer = answer; | 2049 | ptr->answer = answer; |
2042 | break; | 2050 | break; |
2043 | } | 2051 | } |
2044 | spin_unlock(&tomoyo_query_list_lock); | 2052 | spin_unlock(&tomoyo_query_list_lock); |
2045 | return 0; | 2053 | return 0; |
2046 | } | 2054 | } |
2047 | 2055 | ||
2048 | /** | 2056 | /** |
2049 | * tomoyo_read_version: Get version. | 2057 | * tomoyo_read_version: Get version. |
2050 | * | 2058 | * |
2051 | * @head: Pointer to "struct tomoyo_io_buffer". | 2059 | * @head: Pointer to "struct tomoyo_io_buffer". |
2052 | * | 2060 | * |
2053 | * Returns version information. | 2061 | * Returns version information. |
2054 | */ | 2062 | */ |
2055 | static void tomoyo_read_version(struct tomoyo_io_buffer *head) | 2063 | static void tomoyo_read_version(struct tomoyo_io_buffer *head) |
2056 | { | 2064 | { |
2057 | if (!head->r.eof) { | 2065 | if (!head->r.eof) { |
2058 | tomoyo_io_printf(head, "2.4.0"); | 2066 | tomoyo_io_printf(head, "2.4.0"); |
2059 | head->r.eof = true; | 2067 | head->r.eof = true; |
2060 | } | 2068 | } |
2061 | } | 2069 | } |
2062 | 2070 | ||
2063 | /** | 2071 | /** |
2064 | * tomoyo_read_self_domain - Get the current process's domainname. | 2072 | * tomoyo_read_self_domain - Get the current process's domainname. |
2065 | * | 2073 | * |
2066 | * @head: Pointer to "struct tomoyo_io_buffer". | 2074 | * @head: Pointer to "struct tomoyo_io_buffer". |
2067 | * | 2075 | * |
2068 | * Returns the current process's domainname. | 2076 | * Returns the current process's domainname. |
2069 | */ | 2077 | */ |
2070 | static void tomoyo_read_self_domain(struct tomoyo_io_buffer *head) | 2078 | static void tomoyo_read_self_domain(struct tomoyo_io_buffer *head) |
2071 | { | 2079 | { |
2072 | if (!head->r.eof) { | 2080 | if (!head->r.eof) { |
2073 | /* | 2081 | /* |
2074 | * tomoyo_domain()->domainname != NULL | 2082 | * tomoyo_domain()->domainname != NULL |
2075 | * because every process belongs to a domain and | 2083 | * because every process belongs to a domain and |
2076 | * the domain's name cannot be NULL. | 2084 | * the domain's name cannot be NULL. |
2077 | */ | 2085 | */ |
2078 | tomoyo_io_printf(head, "%s", tomoyo_domain()->domainname->name); | 2086 | tomoyo_io_printf(head, "%s", tomoyo_domain()->domainname->name); |
2079 | head->r.eof = true; | 2087 | head->r.eof = true; |
2080 | } | 2088 | } |
2081 | } | 2089 | } |
2082 | 2090 | ||
2083 | /* String table for /sys/kernel/security/tomoyo/stat interface. */ | 2091 | /* String table for /sys/kernel/security/tomoyo/stat interface. */ |
2084 | static const char * const tomoyo_policy_headers[TOMOYO_MAX_POLICY_STAT] = { | 2092 | static const char * const tomoyo_policy_headers[TOMOYO_MAX_POLICY_STAT] = { |
2085 | [TOMOYO_STAT_POLICY_UPDATES] = "update:", | 2093 | [TOMOYO_STAT_POLICY_UPDATES] = "update:", |
2086 | [TOMOYO_STAT_POLICY_LEARNING] = "violation in learning mode:", | 2094 | [TOMOYO_STAT_POLICY_LEARNING] = "violation in learning mode:", |
2087 | [TOMOYO_STAT_POLICY_PERMISSIVE] = "violation in permissive mode:", | 2095 | [TOMOYO_STAT_POLICY_PERMISSIVE] = "violation in permissive mode:", |
2088 | [TOMOYO_STAT_POLICY_ENFORCING] = "violation in enforcing mode:", | 2096 | [TOMOYO_STAT_POLICY_ENFORCING] = "violation in enforcing mode:", |
2089 | }; | 2097 | }; |
2090 | 2098 | ||
2091 | /* String table for /sys/kernel/security/tomoyo/stat interface. */ | 2099 | /* String table for /sys/kernel/security/tomoyo/stat interface. */ |
2092 | static const char * const tomoyo_memory_headers[TOMOYO_MAX_MEMORY_STAT] = { | 2100 | static const char * const tomoyo_memory_headers[TOMOYO_MAX_MEMORY_STAT] = { |
2093 | [TOMOYO_MEMORY_POLICY] = "policy:", | 2101 | [TOMOYO_MEMORY_POLICY] = "policy:", |
2094 | [TOMOYO_MEMORY_AUDIT] = "audit log:", | 2102 | [TOMOYO_MEMORY_AUDIT] = "audit log:", |
2095 | [TOMOYO_MEMORY_QUERY] = "query message:", | 2103 | [TOMOYO_MEMORY_QUERY] = "query message:", |
2096 | }; | 2104 | }; |
2097 | 2105 | ||
2098 | /* Timestamp counter for last updated. */ | 2106 | /* Timestamp counter for last updated. */ |
2099 | static unsigned int tomoyo_stat_updated[TOMOYO_MAX_POLICY_STAT]; | 2107 | static unsigned int tomoyo_stat_updated[TOMOYO_MAX_POLICY_STAT]; |
2100 | /* Counter for number of updates. */ | 2108 | /* Counter for number of updates. */ |
2101 | static unsigned int tomoyo_stat_modified[TOMOYO_MAX_POLICY_STAT]; | 2109 | static unsigned int tomoyo_stat_modified[TOMOYO_MAX_POLICY_STAT]; |
2102 | 2110 | ||
2103 | /** | 2111 | /** |
2104 | * tomoyo_update_stat - Update statistic counters. | 2112 | * tomoyo_update_stat - Update statistic counters. |
2105 | * | 2113 | * |
2106 | * @index: Index for policy type. | 2114 | * @index: Index for policy type. |
2107 | * | 2115 | * |
2108 | * Returns nothing. | 2116 | * Returns nothing. |
2109 | */ | 2117 | */ |
2110 | void tomoyo_update_stat(const u8 index) | 2118 | void tomoyo_update_stat(const u8 index) |
2111 | { | 2119 | { |
2112 | struct timeval tv; | 2120 | struct timeval tv; |
2113 | do_gettimeofday(&tv); | 2121 | do_gettimeofday(&tv); |
2114 | /* | 2122 | /* |
2115 | * I don't use atomic operations because race condition is not fatal. | 2123 | * I don't use atomic operations because race condition is not fatal. |
2116 | */ | 2124 | */ |
2117 | tomoyo_stat_updated[index]++; | 2125 | tomoyo_stat_updated[index]++; |
2118 | tomoyo_stat_modified[index] = tv.tv_sec; | 2126 | tomoyo_stat_modified[index] = tv.tv_sec; |
2119 | } | 2127 | } |
2120 | 2128 | ||
2121 | /** | 2129 | /** |
2122 | * tomoyo_read_stat - Read statistic data. | 2130 | * tomoyo_read_stat - Read statistic data. |
2123 | * | 2131 | * |
2124 | * @head: Pointer to "struct tomoyo_io_buffer". | 2132 | * @head: Pointer to "struct tomoyo_io_buffer". |
2125 | * | 2133 | * |
2126 | * Returns nothing. | 2134 | * Returns nothing. |
2127 | */ | 2135 | */ |
2128 | static void tomoyo_read_stat(struct tomoyo_io_buffer *head) | 2136 | static void tomoyo_read_stat(struct tomoyo_io_buffer *head) |
2129 | { | 2137 | { |
2130 | u8 i; | 2138 | u8 i; |
2131 | unsigned int total = 0; | 2139 | unsigned int total = 0; |
2132 | if (head->r.eof) | 2140 | if (head->r.eof) |
2133 | return; | 2141 | return; |
2134 | for (i = 0; i < TOMOYO_MAX_POLICY_STAT; i++) { | 2142 | for (i = 0; i < TOMOYO_MAX_POLICY_STAT; i++) { |
2135 | tomoyo_io_printf(head, "Policy %-30s %10u", | 2143 | tomoyo_io_printf(head, "Policy %-30s %10u", |
2136 | tomoyo_policy_headers[i], | 2144 | tomoyo_policy_headers[i], |
2137 | tomoyo_stat_updated[i]); | 2145 | tomoyo_stat_updated[i]); |
2138 | if (tomoyo_stat_modified[i]) { | 2146 | if (tomoyo_stat_modified[i]) { |
2139 | struct tomoyo_time stamp; | 2147 | struct tomoyo_time stamp; |
2140 | tomoyo_convert_time(tomoyo_stat_modified[i], &stamp); | 2148 | tomoyo_convert_time(tomoyo_stat_modified[i], &stamp); |
2141 | tomoyo_io_printf(head, " (Last: %04u/%02u/%02u " | 2149 | tomoyo_io_printf(head, " (Last: %04u/%02u/%02u " |
2142 | "%02u:%02u:%02u)", | 2150 | "%02u:%02u:%02u)", |
2143 | stamp.year, stamp.month, stamp.day, | 2151 | stamp.year, stamp.month, stamp.day, |
2144 | stamp.hour, stamp.min, stamp.sec); | 2152 | stamp.hour, stamp.min, stamp.sec); |
2145 | } | 2153 | } |
2146 | tomoyo_set_lf(head); | 2154 | tomoyo_set_lf(head); |
2147 | } | 2155 | } |
2148 | for (i = 0; i < TOMOYO_MAX_MEMORY_STAT; i++) { | 2156 | for (i = 0; i < TOMOYO_MAX_MEMORY_STAT; i++) { |
2149 | unsigned int used = tomoyo_memory_used[i]; | 2157 | unsigned int used = tomoyo_memory_used[i]; |
2150 | total += used; | 2158 | total += used; |
2151 | tomoyo_io_printf(head, "Memory used by %-22s %10u", | 2159 | tomoyo_io_printf(head, "Memory used by %-22s %10u", |
2152 | tomoyo_memory_headers[i], used); | 2160 | tomoyo_memory_headers[i], used); |
2153 | used = tomoyo_memory_quota[i]; | 2161 | used = tomoyo_memory_quota[i]; |
2154 | if (used) | 2162 | if (used) |
2155 | tomoyo_io_printf(head, " (Quota: %10u)", used); | 2163 | tomoyo_io_printf(head, " (Quota: %10u)", used); |
2156 | tomoyo_set_lf(head); | 2164 | tomoyo_set_lf(head); |
2157 | } | 2165 | } |
2158 | tomoyo_io_printf(head, "Total memory used: %10u\n", | 2166 | tomoyo_io_printf(head, "Total memory used: %10u\n", |
2159 | total); | 2167 | total); |
2160 | head->r.eof = true; | 2168 | head->r.eof = true; |
2161 | } | 2169 | } |
2162 | 2170 | ||
2163 | /** | 2171 | /** |
2164 | * tomoyo_write_stat - Set memory quota. | 2172 | * tomoyo_write_stat - Set memory quota. |
2165 | * | 2173 | * |
2166 | * @head: Pointer to "struct tomoyo_io_buffer". | 2174 | * @head: Pointer to "struct tomoyo_io_buffer". |
2167 | * | 2175 | * |
2168 | * Returns 0. | 2176 | * Returns 0. |
2169 | */ | 2177 | */ |
2170 | static int tomoyo_write_stat(struct tomoyo_io_buffer *head) | 2178 | static int tomoyo_write_stat(struct tomoyo_io_buffer *head) |
2171 | { | 2179 | { |
2172 | char *data = head->write_buf; | 2180 | char *data = head->write_buf; |
2173 | u8 i; | 2181 | u8 i; |
2174 | if (tomoyo_str_starts(&data, "Memory used by ")) | 2182 | if (tomoyo_str_starts(&data, "Memory used by ")) |
2175 | for (i = 0; i < TOMOYO_MAX_MEMORY_STAT; i++) | 2183 | for (i = 0; i < TOMOYO_MAX_MEMORY_STAT; i++) |
2176 | if (tomoyo_str_starts(&data, tomoyo_memory_headers[i])) | 2184 | if (tomoyo_str_starts(&data, tomoyo_memory_headers[i])) |
2177 | sscanf(data, "%u", &tomoyo_memory_quota[i]); | 2185 | sscanf(data, "%u", &tomoyo_memory_quota[i]); |
2178 | return 0; | 2186 | return 0; |
2179 | } | 2187 | } |
2180 | 2188 | ||
2181 | /** | 2189 | /** |
2182 | * tomoyo_open_control - open() for /sys/kernel/security/tomoyo/ interface. | 2190 | * tomoyo_open_control - open() for /sys/kernel/security/tomoyo/ interface. |
2183 | * | 2191 | * |
2184 | * @type: Type of interface. | 2192 | * @type: Type of interface. |
2185 | * @file: Pointer to "struct file". | 2193 | * @file: Pointer to "struct file". |
2186 | * | 2194 | * |
2187 | * Returns 0 on success, negative value otherwise. | 2195 | * Returns 0 on success, negative value otherwise. |
2188 | */ | 2196 | */ |
2189 | int tomoyo_open_control(const u8 type, struct file *file) | 2197 | int tomoyo_open_control(const u8 type, struct file *file) |
2190 | { | 2198 | { |
2191 | struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_NOFS); | 2199 | struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_NOFS); |
2192 | 2200 | ||
2193 | if (!head) | 2201 | if (!head) |
2194 | return -ENOMEM; | 2202 | return -ENOMEM; |
2195 | mutex_init(&head->io_sem); | 2203 | mutex_init(&head->io_sem); |
2196 | head->type = type; | 2204 | head->type = type; |
2197 | switch (type) { | 2205 | switch (type) { |
2198 | case TOMOYO_DOMAINPOLICY: | 2206 | case TOMOYO_DOMAINPOLICY: |
2199 | /* /sys/kernel/security/tomoyo/domain_policy */ | 2207 | /* /sys/kernel/security/tomoyo/domain_policy */ |
2200 | head->write = tomoyo_write_domain; | 2208 | head->write = tomoyo_write_domain; |
2201 | head->read = tomoyo_read_domain; | 2209 | head->read = tomoyo_read_domain; |
2202 | break; | 2210 | break; |
2203 | case TOMOYO_EXCEPTIONPOLICY: | 2211 | case TOMOYO_EXCEPTIONPOLICY: |
2204 | /* /sys/kernel/security/tomoyo/exception_policy */ | 2212 | /* /sys/kernel/security/tomoyo/exception_policy */ |
2205 | head->write = tomoyo_write_exception; | 2213 | head->write = tomoyo_write_exception; |
2206 | head->read = tomoyo_read_exception; | 2214 | head->read = tomoyo_read_exception; |
2207 | break; | 2215 | break; |
2208 | case TOMOYO_AUDIT: | 2216 | case TOMOYO_AUDIT: |
2209 | /* /sys/kernel/security/tomoyo/audit */ | 2217 | /* /sys/kernel/security/tomoyo/audit */ |
2210 | head->poll = tomoyo_poll_log; | 2218 | head->poll = tomoyo_poll_log; |
2211 | head->read = tomoyo_read_log; | 2219 | head->read = tomoyo_read_log; |
2212 | break; | 2220 | break; |
2213 | case TOMOYO_SELFDOMAIN: | 2221 | case TOMOYO_SELFDOMAIN: |
2214 | /* /sys/kernel/security/tomoyo/self_domain */ | 2222 | /* /sys/kernel/security/tomoyo/self_domain */ |
2215 | head->read = tomoyo_read_self_domain; | 2223 | head->read = tomoyo_read_self_domain; |
2216 | break; | 2224 | break; |
2217 | case TOMOYO_PROCESS_STATUS: | 2225 | case TOMOYO_PROCESS_STATUS: |
2218 | /* /sys/kernel/security/tomoyo/.process_status */ | 2226 | /* /sys/kernel/security/tomoyo/.process_status */ |
2219 | head->write = tomoyo_write_pid; | 2227 | head->write = tomoyo_write_pid; |
2220 | head->read = tomoyo_read_pid; | 2228 | head->read = tomoyo_read_pid; |
2221 | break; | 2229 | break; |
2222 | case TOMOYO_VERSION: | 2230 | case TOMOYO_VERSION: |
2223 | /* /sys/kernel/security/tomoyo/version */ | 2231 | /* /sys/kernel/security/tomoyo/version */ |
2224 | head->read = tomoyo_read_version; | 2232 | head->read = tomoyo_read_version; |
2225 | head->readbuf_size = 128; | 2233 | head->readbuf_size = 128; |
2226 | break; | 2234 | break; |
2227 | case TOMOYO_STAT: | 2235 | case TOMOYO_STAT: |
2228 | /* /sys/kernel/security/tomoyo/stat */ | 2236 | /* /sys/kernel/security/tomoyo/stat */ |
2229 | head->write = tomoyo_write_stat; | 2237 | head->write = tomoyo_write_stat; |
2230 | head->read = tomoyo_read_stat; | 2238 | head->read = tomoyo_read_stat; |
2231 | head->readbuf_size = 1024; | 2239 | head->readbuf_size = 1024; |
2232 | break; | 2240 | break; |
2233 | case TOMOYO_PROFILE: | 2241 | case TOMOYO_PROFILE: |
2234 | /* /sys/kernel/security/tomoyo/profile */ | 2242 | /* /sys/kernel/security/tomoyo/profile */ |
2235 | head->write = tomoyo_write_profile; | 2243 | head->write = tomoyo_write_profile; |
2236 | head->read = tomoyo_read_profile; | 2244 | head->read = tomoyo_read_profile; |
2237 | break; | 2245 | break; |
2238 | case TOMOYO_QUERY: /* /sys/kernel/security/tomoyo/query */ | 2246 | case TOMOYO_QUERY: /* /sys/kernel/security/tomoyo/query */ |
2239 | head->poll = tomoyo_poll_query; | 2247 | head->poll = tomoyo_poll_query; |
2240 | head->write = tomoyo_write_answer; | 2248 | head->write = tomoyo_write_answer; |
2241 | head->read = tomoyo_read_query; | 2249 | head->read = tomoyo_read_query; |
2242 | break; | 2250 | break; |
2243 | case TOMOYO_MANAGER: | 2251 | case TOMOYO_MANAGER: |
2244 | /* /sys/kernel/security/tomoyo/manager */ | 2252 | /* /sys/kernel/security/tomoyo/manager */ |
2245 | head->write = tomoyo_write_manager; | 2253 | head->write = tomoyo_write_manager; |
2246 | head->read = tomoyo_read_manager; | 2254 | head->read = tomoyo_read_manager; |
2247 | break; | 2255 | break; |
2248 | } | 2256 | } |
2249 | if (!(file->f_mode & FMODE_READ)) { | 2257 | if (!(file->f_mode & FMODE_READ)) { |
2250 | /* | 2258 | /* |
2251 | * No need to allocate read_buf since it is not opened | 2259 | * No need to allocate read_buf since it is not opened |
2252 | * for reading. | 2260 | * for reading. |
2253 | */ | 2261 | */ |
2254 | head->read = NULL; | 2262 | head->read = NULL; |
2255 | head->poll = NULL; | 2263 | head->poll = NULL; |
2256 | } else if (!head->poll) { | 2264 | } else if (!head->poll) { |
2257 | /* Don't allocate read_buf for poll() access. */ | 2265 | /* Don't allocate read_buf for poll() access. */ |
2258 | if (!head->readbuf_size) | 2266 | if (!head->readbuf_size) |
2259 | head->readbuf_size = 4096 * 2; | 2267 | head->readbuf_size = 4096 * 2; |
2260 | head->read_buf = kzalloc(head->readbuf_size, GFP_NOFS); | 2268 | head->read_buf = kzalloc(head->readbuf_size, GFP_NOFS); |
2261 | if (!head->read_buf) { | 2269 | if (!head->read_buf) { |
2262 | kfree(head); | 2270 | kfree(head); |
2263 | return -ENOMEM; | 2271 | return -ENOMEM; |
2264 | } | 2272 | } |
2265 | } | 2273 | } |
2266 | if (!(file->f_mode & FMODE_WRITE)) { | 2274 | if (!(file->f_mode & FMODE_WRITE)) { |
2267 | /* | 2275 | /* |
2268 | * No need to allocate write_buf since it is not opened | 2276 | * No need to allocate write_buf since it is not opened |
2269 | * for writing. | 2277 | * for writing. |
2270 | */ | 2278 | */ |
2271 | head->write = NULL; | 2279 | head->write = NULL; |
2272 | } else if (head->write) { | 2280 | } else if (head->write) { |
2273 | head->writebuf_size = 4096 * 2; | 2281 | head->writebuf_size = 4096 * 2; |
2274 | head->write_buf = kzalloc(head->writebuf_size, GFP_NOFS); | 2282 | head->write_buf = kzalloc(head->writebuf_size, GFP_NOFS); |
2275 | if (!head->write_buf) { | 2283 | if (!head->write_buf) { |
2276 | kfree(head->read_buf); | 2284 | kfree(head->read_buf); |
2277 | kfree(head); | 2285 | kfree(head); |
2278 | return -ENOMEM; | 2286 | return -ENOMEM; |
2279 | } | 2287 | } |
2280 | } | 2288 | } |
2281 | /* | 2289 | /* |
2282 | * If the file is /sys/kernel/security/tomoyo/query , increment the | 2290 | * If the file is /sys/kernel/security/tomoyo/query , increment the |
2283 | * observer counter. | 2291 | * observer counter. |
2284 | * The obserber counter is used by tomoyo_supervisor() to see if | 2292 | * The obserber counter is used by tomoyo_supervisor() to see if |
2285 | * there is some process monitoring /sys/kernel/security/tomoyo/query. | 2293 | * there is some process monitoring /sys/kernel/security/tomoyo/query. |
2286 | */ | 2294 | */ |
2287 | if (type == TOMOYO_QUERY) | 2295 | if (type == TOMOYO_QUERY) |
2288 | atomic_inc(&tomoyo_query_observers); | 2296 | atomic_inc(&tomoyo_query_observers); |
2289 | file->private_data = head; | 2297 | file->private_data = head; |
2290 | tomoyo_notify_gc(head, true); | 2298 | tomoyo_notify_gc(head, true); |
2291 | return 0; | 2299 | return 0; |
2292 | } | 2300 | } |
2293 | 2301 | ||
2294 | /** | 2302 | /** |
2295 | * tomoyo_poll_control - poll() for /sys/kernel/security/tomoyo/ interface. | 2303 | * tomoyo_poll_control - poll() for /sys/kernel/security/tomoyo/ interface. |
2296 | * | 2304 | * |
2297 | * @file: Pointer to "struct file". | 2305 | * @file: Pointer to "struct file". |
2298 | * @wait: Pointer to "poll_table". | 2306 | * @wait: Pointer to "poll_table". |
2299 | * | 2307 | * |
2300 | * Waits for read readiness. | 2308 | * Waits for read readiness. |
2301 | * /sys/kernel/security/tomoyo/query is handled by /usr/sbin/tomoyo-queryd and | 2309 | * /sys/kernel/security/tomoyo/query is handled by /usr/sbin/tomoyo-queryd and |
2302 | * /sys/kernel/security/tomoyo/audit is handled by /usr/sbin/tomoyo-auditd. | 2310 | * /sys/kernel/security/tomoyo/audit is handled by /usr/sbin/tomoyo-auditd. |
2303 | */ | 2311 | */ |
2304 | int tomoyo_poll_control(struct file *file, poll_table *wait) | 2312 | int tomoyo_poll_control(struct file *file, poll_table *wait) |
2305 | { | 2313 | { |
2306 | struct tomoyo_io_buffer *head = file->private_data; | 2314 | struct tomoyo_io_buffer *head = file->private_data; |
2307 | if (!head->poll) | 2315 | if (!head->poll) |
2308 | return -ENOSYS; | 2316 | return -ENOSYS; |
2309 | return head->poll(file, wait); | 2317 | return head->poll(file, wait); |
2310 | } | 2318 | } |
2311 | 2319 | ||
2312 | /** | 2320 | /** |
2313 | * tomoyo_set_namespace_cursor - Set namespace to read. | 2321 | * tomoyo_set_namespace_cursor - Set namespace to read. |
2314 | * | 2322 | * |
2315 | * @head: Pointer to "struct tomoyo_io_buffer". | 2323 | * @head: Pointer to "struct tomoyo_io_buffer". |
2316 | * | 2324 | * |
2317 | * Returns nothing. | 2325 | * Returns nothing. |
2318 | */ | 2326 | */ |
2319 | static inline void tomoyo_set_namespace_cursor(struct tomoyo_io_buffer *head) | 2327 | static inline void tomoyo_set_namespace_cursor(struct tomoyo_io_buffer *head) |
2320 | { | 2328 | { |
2321 | struct list_head *ns; | 2329 | struct list_head *ns; |
2322 | if (head->type != TOMOYO_EXCEPTIONPOLICY && | 2330 | if (head->type != TOMOYO_EXCEPTIONPOLICY && |
2323 | head->type != TOMOYO_PROFILE) | 2331 | head->type != TOMOYO_PROFILE) |
2324 | return; | 2332 | return; |
2325 | /* | 2333 | /* |
2326 | * If this is the first read, or reading previous namespace finished | 2334 | * If this is the first read, or reading previous namespace finished |
2327 | * and has more namespaces to read, update the namespace cursor. | 2335 | * and has more namespaces to read, update the namespace cursor. |
2328 | */ | 2336 | */ |
2329 | ns = head->r.ns; | 2337 | ns = head->r.ns; |
2330 | if (!ns || (head->r.eof && ns->next != &tomoyo_namespace_list)) { | 2338 | if (!ns || (head->r.eof && ns->next != &tomoyo_namespace_list)) { |
2331 | /* Clearing is OK because tomoyo_flush() returned true. */ | 2339 | /* Clearing is OK because tomoyo_flush() returned true. */ |
2332 | memset(&head->r, 0, sizeof(head->r)); | 2340 | memset(&head->r, 0, sizeof(head->r)); |
2333 | head->r.ns = ns ? ns->next : tomoyo_namespace_list.next; | 2341 | head->r.ns = ns ? ns->next : tomoyo_namespace_list.next; |
2334 | } | 2342 | } |
2335 | } | 2343 | } |
2336 | 2344 | ||
2337 | /** | 2345 | /** |
2338 | * tomoyo_has_more_namespace - Check for unread namespaces. | 2346 | * tomoyo_has_more_namespace - Check for unread namespaces. |
2339 | * | 2347 | * |
2340 | * @head: Pointer to "struct tomoyo_io_buffer". | 2348 | * @head: Pointer to "struct tomoyo_io_buffer". |
2341 | * | 2349 | * |
2342 | * Returns true if we have more entries to print, false otherwise. | 2350 | * Returns true if we have more entries to print, false otherwise. |
2343 | */ | 2351 | */ |
2344 | static inline bool tomoyo_has_more_namespace(struct tomoyo_io_buffer *head) | 2352 | static inline bool tomoyo_has_more_namespace(struct tomoyo_io_buffer *head) |
2345 | { | 2353 | { |
2346 | return (head->type == TOMOYO_EXCEPTIONPOLICY || | 2354 | return (head->type == TOMOYO_EXCEPTIONPOLICY || |
2347 | head->type == TOMOYO_PROFILE) && head->r.eof && | 2355 | head->type == TOMOYO_PROFILE) && head->r.eof && |
2348 | head->r.ns->next != &tomoyo_namespace_list; | 2356 | head->r.ns->next != &tomoyo_namespace_list; |
2349 | } | 2357 | } |
2350 | 2358 | ||
2351 | /** | 2359 | /** |
2352 | * tomoyo_read_control - read() for /sys/kernel/security/tomoyo/ interface. | 2360 | * tomoyo_read_control - read() for /sys/kernel/security/tomoyo/ interface. |
2353 | * | 2361 | * |
2354 | * @head: Pointer to "struct tomoyo_io_buffer". | 2362 | * @head: Pointer to "struct tomoyo_io_buffer". |
2355 | * @buffer: Poiner to buffer to write to. | 2363 | * @buffer: Poiner to buffer to write to. |
2356 | * @buffer_len: Size of @buffer. | 2364 | * @buffer_len: Size of @buffer. |
2357 | * | 2365 | * |
2358 | * Returns bytes read on success, negative value otherwise. | 2366 | * Returns bytes read on success, negative value otherwise. |
2359 | */ | 2367 | */ |
2360 | ssize_t tomoyo_read_control(struct tomoyo_io_buffer *head, char __user *buffer, | 2368 | ssize_t tomoyo_read_control(struct tomoyo_io_buffer *head, char __user *buffer, |
2361 | const int buffer_len) | 2369 | const int buffer_len) |
2362 | { | 2370 | { |
2363 | int len; | 2371 | int len; |
2364 | int idx; | 2372 | int idx; |
2365 | 2373 | ||
2366 | if (!head->read) | 2374 | if (!head->read) |
2367 | return -ENOSYS; | 2375 | return -ENOSYS; |
2368 | if (mutex_lock_interruptible(&head->io_sem)) | 2376 | if (mutex_lock_interruptible(&head->io_sem)) |
2369 | return -EINTR; | 2377 | return -EINTR; |
2370 | head->read_user_buf = buffer; | 2378 | head->read_user_buf = buffer; |
2371 | head->read_user_buf_avail = buffer_len; | 2379 | head->read_user_buf_avail = buffer_len; |
2372 | idx = tomoyo_read_lock(); | 2380 | idx = tomoyo_read_lock(); |
2373 | if (tomoyo_flush(head)) | 2381 | if (tomoyo_flush(head)) |
2374 | /* Call the policy handler. */ | 2382 | /* Call the policy handler. */ |
2375 | do { | 2383 | do { |
2376 | tomoyo_set_namespace_cursor(head); | 2384 | tomoyo_set_namespace_cursor(head); |
2377 | head->read(head); | 2385 | head->read(head); |
2378 | } while (tomoyo_flush(head) && | 2386 | } while (tomoyo_flush(head) && |
2379 | tomoyo_has_more_namespace(head)); | 2387 | tomoyo_has_more_namespace(head)); |
2380 | tomoyo_read_unlock(idx); | 2388 | tomoyo_read_unlock(idx); |
2381 | len = head->read_user_buf - buffer; | 2389 | len = head->read_user_buf - buffer; |
2382 | mutex_unlock(&head->io_sem); | 2390 | mutex_unlock(&head->io_sem); |
2383 | return len; | 2391 | return len; |
2384 | } | 2392 | } |
2385 | 2393 | ||
2386 | /** | 2394 | /** |
2387 | * tomoyo_parse_policy - Parse a policy line. | 2395 | * tomoyo_parse_policy - Parse a policy line. |
2388 | * | 2396 | * |
2389 | * @head: Poiter to "struct tomoyo_io_buffer". | 2397 | * @head: Poiter to "struct tomoyo_io_buffer". |
2390 | * @line: Line to parse. | 2398 | * @line: Line to parse. |
2391 | * | 2399 | * |
2392 | * Returns 0 on success, negative value otherwise. | 2400 | * Returns 0 on success, negative value otherwise. |
2393 | * | 2401 | * |
2394 | * Caller holds tomoyo_read_lock(). | 2402 | * Caller holds tomoyo_read_lock(). |
2395 | */ | 2403 | */ |
2396 | static int tomoyo_parse_policy(struct tomoyo_io_buffer *head, char *line) | 2404 | static int tomoyo_parse_policy(struct tomoyo_io_buffer *head, char *line) |
2397 | { | 2405 | { |
2398 | /* Delete request? */ | 2406 | /* Delete request? */ |
2399 | head->w.is_delete = !strncmp(line, "delete ", 7); | 2407 | head->w.is_delete = !strncmp(line, "delete ", 7); |
2400 | if (head->w.is_delete) | 2408 | if (head->w.is_delete) |
2401 | memmove(line, line + 7, strlen(line + 7) + 1); | 2409 | memmove(line, line + 7, strlen(line + 7) + 1); |
2402 | /* Selecting namespace to update. */ | 2410 | /* Selecting namespace to update. */ |
2403 | if (head->type == TOMOYO_EXCEPTIONPOLICY || | 2411 | if (head->type == TOMOYO_EXCEPTIONPOLICY || |
2404 | head->type == TOMOYO_PROFILE) { | 2412 | head->type == TOMOYO_PROFILE) { |
2405 | if (*line == '<') { | 2413 | if (*line == '<') { |
2406 | char *cp = strchr(line, ' '); | 2414 | char *cp = strchr(line, ' '); |
2407 | if (cp) { | 2415 | if (cp) { |
2408 | *cp++ = '\0'; | 2416 | *cp++ = '\0'; |
2409 | head->w.ns = tomoyo_assign_namespace(line); | 2417 | head->w.ns = tomoyo_assign_namespace(line); |
2410 | memmove(line, cp, strlen(cp) + 1); | 2418 | memmove(line, cp, strlen(cp) + 1); |
2411 | } else | 2419 | } else |
2412 | head->w.ns = NULL; | 2420 | head->w.ns = NULL; |
2413 | } else | 2421 | } else |
2414 | head->w.ns = &tomoyo_kernel_namespace; | 2422 | head->w.ns = &tomoyo_kernel_namespace; |
2415 | /* Don't allow updating if namespace is invalid. */ | 2423 | /* Don't allow updating if namespace is invalid. */ |
2416 | if (!head->w.ns) | 2424 | if (!head->w.ns) |
2417 | return -ENOENT; | 2425 | return -ENOENT; |
2418 | } | 2426 | } |
2419 | /* Do the update. */ | 2427 | /* Do the update. */ |
2420 | return head->write(head); | 2428 | return head->write(head); |
2421 | } | 2429 | } |
2422 | 2430 | ||
2423 | /** | 2431 | /** |
2424 | * tomoyo_write_control - write() for /sys/kernel/security/tomoyo/ interface. | 2432 | * tomoyo_write_control - write() for /sys/kernel/security/tomoyo/ interface. |
2425 | * | 2433 | * |
2426 | * @head: Pointer to "struct tomoyo_io_buffer". | 2434 | * @head: Pointer to "struct tomoyo_io_buffer". |
2427 | * @buffer: Pointer to buffer to read from. | 2435 | * @buffer: Pointer to buffer to read from. |
2428 | * @buffer_len: Size of @buffer. | 2436 | * @buffer_len: Size of @buffer. |
2429 | * | 2437 | * |
2430 | * Returns @buffer_len on success, negative value otherwise. | 2438 | * Returns @buffer_len on success, negative value otherwise. |
2431 | */ | 2439 | */ |
2432 | ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head, | 2440 | ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head, |
2433 | const char __user *buffer, const int buffer_len) | 2441 | const char __user *buffer, const int buffer_len) |
2434 | { | 2442 | { |
2435 | int error = buffer_len; | 2443 | int error = buffer_len; |
2436 | size_t avail_len = buffer_len; | 2444 | size_t avail_len = buffer_len; |
2437 | char *cp0 = head->write_buf; | 2445 | char *cp0 = head->write_buf; |
2438 | int idx; | 2446 | int idx; |
2439 | if (!head->write) | 2447 | if (!head->write) |
2440 | return -ENOSYS; | 2448 | return -ENOSYS; |
2441 | if (!access_ok(VERIFY_READ, buffer, buffer_len)) | 2449 | if (!access_ok(VERIFY_READ, buffer, buffer_len)) |
2442 | return -EFAULT; | 2450 | return -EFAULT; |
2443 | if (mutex_lock_interruptible(&head->io_sem)) | 2451 | if (mutex_lock_interruptible(&head->io_sem)) |
2444 | return -EINTR; | 2452 | return -EINTR; |
2445 | idx = tomoyo_read_lock(); | 2453 | idx = tomoyo_read_lock(); |
2446 | /* Read a line and dispatch it to the policy handler. */ | 2454 | /* Read a line and dispatch it to the policy handler. */ |
2447 | while (avail_len > 0) { | 2455 | while (avail_len > 0) { |
2448 | char c; | 2456 | char c; |
2449 | if (head->w.avail >= head->writebuf_size - 1) { | 2457 | if (head->w.avail >= head->writebuf_size - 1) { |
2450 | const int len = head->writebuf_size * 2; | 2458 | const int len = head->writebuf_size * 2; |
2451 | char *cp = kzalloc(len, GFP_NOFS); | 2459 | char *cp = kzalloc(len, GFP_NOFS); |
2452 | if (!cp) { | 2460 | if (!cp) { |
2453 | error = -ENOMEM; | 2461 | error = -ENOMEM; |
2454 | break; | 2462 | break; |
2455 | } | 2463 | } |
2456 | memmove(cp, cp0, head->w.avail); | 2464 | memmove(cp, cp0, head->w.avail); |
2457 | kfree(cp0); | 2465 | kfree(cp0); |
2458 | head->write_buf = cp; | 2466 | head->write_buf = cp; |
2459 | cp0 = cp; | 2467 | cp0 = cp; |
2460 | head->writebuf_size = len; | 2468 | head->writebuf_size = len; |
2461 | } | 2469 | } |
2462 | if (get_user(c, buffer)) { | 2470 | if (get_user(c, buffer)) { |
2463 | error = -EFAULT; | 2471 | error = -EFAULT; |
2464 | break; | 2472 | break; |
2465 | } | 2473 | } |
2466 | buffer++; | 2474 | buffer++; |
2467 | avail_len--; | 2475 | avail_len--; |
2468 | cp0[head->w.avail++] = c; | 2476 | cp0[head->w.avail++] = c; |
2469 | if (c != '\n') | 2477 | if (c != '\n') |
2470 | continue; | 2478 | continue; |
2471 | cp0[head->w.avail - 1] = '\0'; | 2479 | cp0[head->w.avail - 1] = '\0'; |
2472 | head->w.avail = 0; | 2480 | head->w.avail = 0; |
2473 | tomoyo_normalize_line(cp0); | 2481 | tomoyo_normalize_line(cp0); |
2474 | if (!strcmp(cp0, "reset")) { | 2482 | if (!strcmp(cp0, "reset")) { |
2475 | head->w.ns = &tomoyo_kernel_namespace; | 2483 | head->w.ns = &tomoyo_kernel_namespace; |
2476 | head->w.domain = NULL; | 2484 | head->w.domain = NULL; |
2477 | memset(&head->r, 0, sizeof(head->r)); | 2485 | memset(&head->r, 0, sizeof(head->r)); |
2478 | continue; | 2486 | continue; |
2479 | } | 2487 | } |
2480 | /* Don't allow updating policies by non manager programs. */ | 2488 | /* Don't allow updating policies by non manager programs. */ |
2481 | switch (head->type) { | 2489 | switch (head->type) { |
2482 | case TOMOYO_PROCESS_STATUS: | 2490 | case TOMOYO_PROCESS_STATUS: |
2483 | /* This does not write anything. */ | 2491 | /* This does not write anything. */ |
2484 | break; | 2492 | break; |
2485 | case TOMOYO_DOMAINPOLICY: | 2493 | case TOMOYO_DOMAINPOLICY: |
2486 | if (tomoyo_select_domain(head, cp0)) | 2494 | if (tomoyo_select_domain(head, cp0)) |
2487 | continue; | 2495 | continue; |
2488 | /* fall through */ | 2496 | /* fall through */ |
2489 | case TOMOYO_EXCEPTIONPOLICY: | 2497 | case TOMOYO_EXCEPTIONPOLICY: |
2490 | if (!strcmp(cp0, "select transition_only")) { | 2498 | if (!strcmp(cp0, "select transition_only")) { |
2491 | head->r.print_transition_related_only = true; | 2499 | head->r.print_transition_related_only = true; |
2492 | continue; | 2500 | continue; |
2493 | } | 2501 | } |
2494 | /* fall through */ | 2502 | /* fall through */ |
2495 | default: | 2503 | default: |
2496 | if (!tomoyo_manager()) { | 2504 | if (!tomoyo_manager()) { |
2497 | error = -EPERM; | 2505 | error = -EPERM; |
2498 | goto out; | 2506 | goto out; |
2499 | } | 2507 | } |
2500 | } | 2508 | } |
2501 | switch (tomoyo_parse_policy(head, cp0)) { | 2509 | switch (tomoyo_parse_policy(head, cp0)) { |
2502 | case -EPERM: | 2510 | case -EPERM: |
2503 | error = -EPERM; | 2511 | error = -EPERM; |
2504 | goto out; | 2512 | goto out; |
2505 | case 0: | 2513 | case 0: |
2506 | switch (head->type) { | 2514 | switch (head->type) { |
2507 | case TOMOYO_DOMAINPOLICY: | 2515 | case TOMOYO_DOMAINPOLICY: |
2508 | case TOMOYO_EXCEPTIONPOLICY: | 2516 | case TOMOYO_EXCEPTIONPOLICY: |
2509 | case TOMOYO_STAT: | 2517 | case TOMOYO_STAT: |
2510 | case TOMOYO_PROFILE: | 2518 | case TOMOYO_PROFILE: |
2511 | case TOMOYO_MANAGER: | 2519 | case TOMOYO_MANAGER: |
2512 | tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES); | 2520 | tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES); |
2513 | break; | 2521 | break; |
2514 | default: | 2522 | default: |
2515 | break; | 2523 | break; |
2516 | } | 2524 | } |
2517 | break; | 2525 | break; |
2518 | } | 2526 | } |
2519 | } | 2527 | } |
2520 | out: | 2528 | out: |
2521 | tomoyo_read_unlock(idx); | 2529 | tomoyo_read_unlock(idx); |
2522 | mutex_unlock(&head->io_sem); | 2530 | mutex_unlock(&head->io_sem); |
2523 | return error; | 2531 | return error; |
2524 | } | 2532 | } |
2525 | 2533 | ||
2526 | /** | 2534 | /** |
2527 | * tomoyo_close_control - close() for /sys/kernel/security/tomoyo/ interface. | 2535 | * tomoyo_close_control - close() for /sys/kernel/security/tomoyo/ interface. |
2528 | * | 2536 | * |
2529 | * @head: Pointer to "struct tomoyo_io_buffer". | 2537 | * @head: Pointer to "struct tomoyo_io_buffer". |
2530 | * | 2538 | * |
2531 | * Returns 0. | 2539 | * Returns 0. |
2532 | */ | 2540 | */ |
2533 | int tomoyo_close_control(struct tomoyo_io_buffer *head) | 2541 | int tomoyo_close_control(struct tomoyo_io_buffer *head) |
2534 | { | 2542 | { |
2535 | /* | 2543 | /* |
2536 | * If the file is /sys/kernel/security/tomoyo/query , decrement the | 2544 | * If the file is /sys/kernel/security/tomoyo/query , decrement the |
2537 | * observer counter. | 2545 | * observer counter. |
2538 | */ | 2546 | */ |
2539 | if (head->type == TOMOYO_QUERY && | 2547 | if (head->type == TOMOYO_QUERY && |
2540 | atomic_dec_and_test(&tomoyo_query_observers)) | 2548 | atomic_dec_and_test(&tomoyo_query_observers)) |
2541 | wake_up_all(&tomoyo_answer_wait); | 2549 | wake_up_all(&tomoyo_answer_wait); |
2542 | tomoyo_notify_gc(head, false); | 2550 | tomoyo_notify_gc(head, false); |
2543 | return 0; | 2551 | return 0; |
2544 | } | 2552 | } |
2545 | 2553 | ||
2546 | /** | 2554 | /** |
2547 | * tomoyo_check_profile - Check all profiles currently assigned to domains are defined. | 2555 | * tomoyo_check_profile - Check all profiles currently assigned to domains are defined. |
2548 | */ | 2556 | */ |
2549 | void tomoyo_check_profile(void) | 2557 | void tomoyo_check_profile(void) |
2550 | { | 2558 | { |
2551 | struct tomoyo_domain_info *domain; | 2559 | struct tomoyo_domain_info *domain; |
2552 | const int idx = tomoyo_read_lock(); | 2560 | const int idx = tomoyo_read_lock(); |
2553 | tomoyo_policy_loaded = true; | 2561 | tomoyo_policy_loaded = true; |
2554 | printk(KERN_INFO "TOMOYO: 2.4.0\n"); | 2562 | printk(KERN_INFO "TOMOYO: 2.4.0\n"); |
2555 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { | 2563 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { |
2556 | const u8 profile = domain->profile; | 2564 | const u8 profile = domain->profile; |
2557 | const struct tomoyo_policy_namespace *ns = domain->ns; | 2565 | const struct tomoyo_policy_namespace *ns = domain->ns; |
2558 | if (ns->profile_version != 20100903) | 2566 | if (ns->profile_version != 20100903) |
2559 | printk(KERN_ERR | 2567 | printk(KERN_ERR |
2560 | "Profile version %u is not supported.\n", | 2568 | "Profile version %u is not supported.\n", |
2561 | ns->profile_version); | 2569 | ns->profile_version); |
2562 | else if (!ns->profile_ptr[profile]) | 2570 | else if (!ns->profile_ptr[profile]) |
2563 | printk(KERN_ERR | 2571 | printk(KERN_ERR |
2564 | "Profile %u (used by '%s') is not defined.\n", | 2572 | "Profile %u (used by '%s') is not defined.\n", |
2565 | profile, domain->domainname->name); | 2573 | profile, domain->domainname->name); |
2566 | else | 2574 | else |
2567 | continue; | 2575 | continue; |
2568 | printk(KERN_ERR | 2576 | printk(KERN_ERR |
2569 | "Userland tools for TOMOYO 2.4 must be installed and " | 2577 | "Userland tools for TOMOYO 2.4 must be installed and " |
2570 | "policy must be initialized.\n"); | 2578 | "policy must be initialized.\n"); |
2571 | printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.4/ " | 2579 | printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.4/ " |
2572 | "for more information.\n"); | 2580 | "for more information.\n"); |
2573 | panic("STOP!"); | 2581 | panic("STOP!"); |
2574 | } | 2582 | } |
2575 | tomoyo_read_unlock(idx); | 2583 | tomoyo_read_unlock(idx); |
2576 | printk(KERN_INFO "Mandatory Access Control activated.\n"); | 2584 | printk(KERN_INFO "Mandatory Access Control activated.\n"); |
2577 | } | 2585 | } |
2578 | 2586 | ||
2579 | /** | 2587 | /** |
2580 | * tomoyo_load_builtin_policy - Load built-in policy. | 2588 | * tomoyo_load_builtin_policy - Load built-in policy. |
2581 | * | 2589 | * |
2582 | * Returns nothing. | 2590 | * Returns nothing. |
2583 | */ | 2591 | */ |
2584 | void __init tomoyo_load_builtin_policy(void) | 2592 | void __init tomoyo_load_builtin_policy(void) |
2585 | { | 2593 | { |
2586 | /* | 2594 | /* |
2587 | * This include file is manually created and contains built-in policy | 2595 | * This include file is manually created and contains built-in policy |
2588 | * named "tomoyo_builtin_profile", "tomoyo_builtin_exception_policy", | 2596 | * named "tomoyo_builtin_profile", "tomoyo_builtin_exception_policy", |
2589 | * "tomoyo_builtin_domain_policy", "tomoyo_builtin_manager", | 2597 | * "tomoyo_builtin_domain_policy", "tomoyo_builtin_manager", |
2590 | * "tomoyo_builtin_stat" in the form of "static char [] __initdata". | 2598 | * "tomoyo_builtin_stat" in the form of "static char [] __initdata". |
2591 | */ | 2599 | */ |
2592 | #include "builtin-policy.h" | 2600 | #include "builtin-policy.h" |
2593 | u8 i; | 2601 | u8 i; |
2594 | const int idx = tomoyo_read_lock(); | 2602 | const int idx = tomoyo_read_lock(); |
2595 | for (i = 0; i < 5; i++) { | 2603 | for (i = 0; i < 5; i++) { |
2596 | struct tomoyo_io_buffer head = { }; | 2604 | struct tomoyo_io_buffer head = { }; |
2597 | char *start = ""; | 2605 | char *start = ""; |
2598 | switch (i) { | 2606 | switch (i) { |
2599 | case 0: | 2607 | case 0: |
2600 | start = tomoyo_builtin_profile; | 2608 | start = tomoyo_builtin_profile; |
2601 | head.type = TOMOYO_PROFILE; | 2609 | head.type = TOMOYO_PROFILE; |
2602 | head.write = tomoyo_write_profile; | 2610 | head.write = tomoyo_write_profile; |
2603 | break; | 2611 | break; |
2604 | case 1: | 2612 | case 1: |
2605 | start = tomoyo_builtin_exception_policy; | 2613 | start = tomoyo_builtin_exception_policy; |
2606 | head.type = TOMOYO_EXCEPTIONPOLICY; | 2614 | head.type = TOMOYO_EXCEPTIONPOLICY; |
2607 | head.write = tomoyo_write_exception; | 2615 | head.write = tomoyo_write_exception; |
2608 | break; | 2616 | break; |
2609 | case 2: | 2617 | case 2: |
2610 | start = tomoyo_builtin_domain_policy; | 2618 | start = tomoyo_builtin_domain_policy; |
2611 | head.type = TOMOYO_DOMAINPOLICY; | 2619 | head.type = TOMOYO_DOMAINPOLICY; |
2612 | head.write = tomoyo_write_domain; | 2620 | head.write = tomoyo_write_domain; |
2613 | break; | 2621 | break; |
2614 | case 3: | 2622 | case 3: |
2615 | start = tomoyo_builtin_manager; | 2623 | start = tomoyo_builtin_manager; |
2616 | head.type = TOMOYO_MANAGER; | 2624 | head.type = TOMOYO_MANAGER; |
2617 | head.write = tomoyo_write_manager; | 2625 | head.write = tomoyo_write_manager; |
2618 | break; | 2626 | break; |
2619 | case 4: | 2627 | case 4: |
2620 | start = tomoyo_builtin_stat; | 2628 | start = tomoyo_builtin_stat; |
2621 | head.type = TOMOYO_STAT; | 2629 | head.type = TOMOYO_STAT; |
2622 | head.write = tomoyo_write_stat; | 2630 | head.write = tomoyo_write_stat; |
2623 | break; | 2631 | break; |
2624 | } | 2632 | } |
2625 | while (1) { | 2633 | while (1) { |
2626 | char *end = strchr(start, '\n'); | 2634 | char *end = strchr(start, '\n'); |
2627 | if (!end) | 2635 | if (!end) |
2628 | break; | 2636 | break; |
2629 | *end = '\0'; | 2637 | *end = '\0'; |
2630 | tomoyo_normalize_line(start); | 2638 | tomoyo_normalize_line(start); |
2631 | head.write_buf = start; | 2639 | head.write_buf = start; |
2632 | tomoyo_parse_policy(&head, start); | 2640 | tomoyo_parse_policy(&head, start); |
2633 | start = end + 1; | 2641 | start = end + 1; |
2634 | } | 2642 | } |
2635 | } | 2643 | } |
2636 | tomoyo_read_unlock(idx); | 2644 | tomoyo_read_unlock(idx); |
2637 | #ifdef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER | 2645 | #ifdef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER |
2638 | tomoyo_check_profile(); | 2646 | tomoyo_check_profile(); |
2639 | #endif | 2647 | #endif |
security/tomoyo/domain.c
1 | /* | 1 | /* |
2 | * security/tomoyo/domain.c | 2 | * security/tomoyo/domain.c |
3 | * | 3 | * |
4 | * Domain transition functions for TOMOYO. | 4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION |
5 | * | ||
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
7 | */ | 5 | */ |
8 | 6 | ||
9 | #include "common.h" | 7 | #include "common.h" |
10 | #include <linux/binfmts.h> | 8 | #include <linux/binfmts.h> |
11 | #include <linux/slab.h> | 9 | #include <linux/slab.h> |
12 | 10 | ||
13 | /* Variables definitions.*/ | 11 | /* Variables definitions.*/ |
14 | 12 | ||
15 | /* The initial domain. */ | 13 | /* The initial domain. */ |
16 | struct tomoyo_domain_info tomoyo_kernel_domain; | 14 | struct tomoyo_domain_info tomoyo_kernel_domain; |
17 | 15 | ||
18 | /** | 16 | /** |
19 | * tomoyo_update_policy - Update an entry for exception policy. | 17 | * tomoyo_update_policy - Update an entry for exception policy. |
20 | * | 18 | * |
21 | * @new_entry: Pointer to "struct tomoyo_acl_info". | 19 | * @new_entry: Pointer to "struct tomoyo_acl_info". |
22 | * @size: Size of @new_entry in bytes. | 20 | * @size: Size of @new_entry in bytes. |
23 | * @param: Pointer to "struct tomoyo_acl_param". | 21 | * @param: Pointer to "struct tomoyo_acl_param". |
24 | * @check_duplicate: Callback function to find duplicated entry. | 22 | * @check_duplicate: Callback function to find duplicated entry. |
25 | * | 23 | * |
26 | * Returns 0 on success, negative value otherwise. | 24 | * Returns 0 on success, negative value otherwise. |
27 | * | 25 | * |
28 | * Caller holds tomoyo_read_lock(). | 26 | * Caller holds tomoyo_read_lock(). |
29 | */ | 27 | */ |
30 | int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size, | 28 | int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size, |
31 | struct tomoyo_acl_param *param, | 29 | struct tomoyo_acl_param *param, |
32 | bool (*check_duplicate) (const struct tomoyo_acl_head | 30 | bool (*check_duplicate) (const struct tomoyo_acl_head |
33 | *, | 31 | *, |
34 | const struct tomoyo_acl_head | 32 | const struct tomoyo_acl_head |
35 | *)) | 33 | *)) |
36 | { | 34 | { |
37 | int error = param->is_delete ? -ENOENT : -ENOMEM; | 35 | int error = param->is_delete ? -ENOENT : -ENOMEM; |
38 | struct tomoyo_acl_head *entry; | 36 | struct tomoyo_acl_head *entry; |
39 | struct list_head *list = param->list; | 37 | struct list_head *list = param->list; |
40 | 38 | ||
41 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 39 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
42 | return -ENOMEM; | 40 | return -ENOMEM; |
43 | list_for_each_entry_rcu(entry, list, list) { | 41 | list_for_each_entry_rcu(entry, list, list) { |
44 | if (!check_duplicate(entry, new_entry)) | 42 | if (!check_duplicate(entry, new_entry)) |
45 | continue; | 43 | continue; |
46 | entry->is_deleted = param->is_delete; | 44 | entry->is_deleted = param->is_delete; |
47 | error = 0; | 45 | error = 0; |
48 | break; | 46 | break; |
49 | } | 47 | } |
50 | if (error && !param->is_delete) { | 48 | if (error && !param->is_delete) { |
51 | entry = tomoyo_commit_ok(new_entry, size); | 49 | entry = tomoyo_commit_ok(new_entry, size); |
52 | if (entry) { | 50 | if (entry) { |
53 | list_add_tail_rcu(&entry->list, list); | 51 | list_add_tail_rcu(&entry->list, list); |
54 | error = 0; | 52 | error = 0; |
55 | } | 53 | } |
56 | } | 54 | } |
57 | mutex_unlock(&tomoyo_policy_lock); | 55 | mutex_unlock(&tomoyo_policy_lock); |
58 | return error; | 56 | return error; |
59 | } | 57 | } |
60 | 58 | ||
61 | /** | 59 | /** |
62 | * tomoyo_same_acl_head - Check for duplicated "struct tomoyo_acl_info" entry. | 60 | * tomoyo_same_acl_head - Check for duplicated "struct tomoyo_acl_info" entry. |
63 | * | 61 | * |
64 | * @a: Pointer to "struct tomoyo_acl_info". | 62 | * @a: Pointer to "struct tomoyo_acl_info". |
65 | * @b: Pointer to "struct tomoyo_acl_info". | 63 | * @b: Pointer to "struct tomoyo_acl_info". |
66 | * | 64 | * |
67 | * Returns true if @a == @b, false otherwise. | 65 | * Returns true if @a == @b, false otherwise. |
68 | */ | 66 | */ |
69 | static inline bool tomoyo_same_acl_head(const struct tomoyo_acl_info *a, | 67 | static inline bool tomoyo_same_acl_head(const struct tomoyo_acl_info *a, |
70 | const struct tomoyo_acl_info *b) | 68 | const struct tomoyo_acl_info *b) |
71 | { | 69 | { |
72 | return a->type == b->type && a->cond == b->cond; | 70 | return a->type == b->type && a->cond == b->cond; |
73 | } | 71 | } |
74 | 72 | ||
75 | /** | 73 | /** |
76 | * tomoyo_update_domain - Update an entry for domain policy. | 74 | * tomoyo_update_domain - Update an entry for domain policy. |
77 | * | 75 | * |
78 | * @new_entry: Pointer to "struct tomoyo_acl_info". | 76 | * @new_entry: Pointer to "struct tomoyo_acl_info". |
79 | * @size: Size of @new_entry in bytes. | 77 | * @size: Size of @new_entry in bytes. |
80 | * @param: Pointer to "struct tomoyo_acl_param". | 78 | * @param: Pointer to "struct tomoyo_acl_param". |
81 | * @check_duplicate: Callback function to find duplicated entry. | 79 | * @check_duplicate: Callback function to find duplicated entry. |
82 | * @merge_duplicate: Callback function to merge duplicated entry. | 80 | * @merge_duplicate: Callback function to merge duplicated entry. |
83 | * | 81 | * |
84 | * Returns 0 on success, negative value otherwise. | 82 | * Returns 0 on success, negative value otherwise. |
85 | * | 83 | * |
86 | * Caller holds tomoyo_read_lock(). | 84 | * Caller holds tomoyo_read_lock(). |
87 | */ | 85 | */ |
88 | int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, | 86 | int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, |
89 | struct tomoyo_acl_param *param, | 87 | struct tomoyo_acl_param *param, |
90 | bool (*check_duplicate) (const struct tomoyo_acl_info | 88 | bool (*check_duplicate) (const struct tomoyo_acl_info |
91 | *, | 89 | *, |
92 | const struct tomoyo_acl_info | 90 | const struct tomoyo_acl_info |
93 | *), | 91 | *), |
94 | bool (*merge_duplicate) (struct tomoyo_acl_info *, | 92 | bool (*merge_duplicate) (struct tomoyo_acl_info *, |
95 | struct tomoyo_acl_info *, | 93 | struct tomoyo_acl_info *, |
96 | const bool)) | 94 | const bool)) |
97 | { | 95 | { |
98 | const bool is_delete = param->is_delete; | 96 | const bool is_delete = param->is_delete; |
99 | int error = is_delete ? -ENOENT : -ENOMEM; | 97 | int error = is_delete ? -ENOENT : -ENOMEM; |
100 | struct tomoyo_acl_info *entry; | 98 | struct tomoyo_acl_info *entry; |
101 | struct list_head * const list = param->list; | 99 | struct list_head * const list = param->list; |
102 | 100 | ||
103 | if (param->data[0]) { | 101 | if (param->data[0]) { |
104 | new_entry->cond = tomoyo_get_condition(param); | 102 | new_entry->cond = tomoyo_get_condition(param); |
105 | if (!new_entry->cond) | 103 | if (!new_entry->cond) |
106 | return -EINVAL; | 104 | return -EINVAL; |
107 | } | 105 | } |
108 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 106 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
109 | goto out; | 107 | goto out; |
110 | list_for_each_entry_rcu(entry, list, list) { | 108 | list_for_each_entry_rcu(entry, list, list) { |
111 | if (!tomoyo_same_acl_head(entry, new_entry) || | 109 | if (!tomoyo_same_acl_head(entry, new_entry) || |
112 | !check_duplicate(entry, new_entry)) | 110 | !check_duplicate(entry, new_entry)) |
113 | continue; | 111 | continue; |
114 | if (merge_duplicate) | 112 | if (merge_duplicate) |
115 | entry->is_deleted = merge_duplicate(entry, new_entry, | 113 | entry->is_deleted = merge_duplicate(entry, new_entry, |
116 | is_delete); | 114 | is_delete); |
117 | else | 115 | else |
118 | entry->is_deleted = is_delete; | 116 | entry->is_deleted = is_delete; |
119 | error = 0; | 117 | error = 0; |
120 | break; | 118 | break; |
121 | } | 119 | } |
122 | if (error && !is_delete) { | 120 | if (error && !is_delete) { |
123 | entry = tomoyo_commit_ok(new_entry, size); | 121 | entry = tomoyo_commit_ok(new_entry, size); |
124 | if (entry) { | 122 | if (entry) { |
125 | list_add_tail_rcu(&entry->list, list); | 123 | list_add_tail_rcu(&entry->list, list); |
126 | error = 0; | 124 | error = 0; |
127 | } | 125 | } |
128 | } | 126 | } |
129 | mutex_unlock(&tomoyo_policy_lock); | 127 | mutex_unlock(&tomoyo_policy_lock); |
130 | out: | 128 | out: |
131 | tomoyo_put_condition(new_entry->cond); | 129 | tomoyo_put_condition(new_entry->cond); |
132 | return error; | 130 | return error; |
133 | } | 131 | } |
134 | 132 | ||
135 | /** | 133 | /** |
136 | * tomoyo_check_acl - Do permission check. | 134 | * tomoyo_check_acl - Do permission check. |
137 | * | 135 | * |
138 | * @r: Pointer to "struct tomoyo_request_info". | 136 | * @r: Pointer to "struct tomoyo_request_info". |
139 | * @check_entry: Callback function to check type specific parameters. | 137 | * @check_entry: Callback function to check type specific parameters. |
140 | * | 138 | * |
141 | * Returns 0 on success, negative value otherwise. | 139 | * Returns 0 on success, negative value otherwise. |
142 | * | 140 | * |
143 | * Caller holds tomoyo_read_lock(). | 141 | * Caller holds tomoyo_read_lock(). |
144 | */ | 142 | */ |
145 | void tomoyo_check_acl(struct tomoyo_request_info *r, | 143 | void tomoyo_check_acl(struct tomoyo_request_info *r, |
146 | bool (*check_entry) (struct tomoyo_request_info *, | 144 | bool (*check_entry) (struct tomoyo_request_info *, |
147 | const struct tomoyo_acl_info *)) | 145 | const struct tomoyo_acl_info *)) |
148 | { | 146 | { |
149 | const struct tomoyo_domain_info *domain = r->domain; | 147 | const struct tomoyo_domain_info *domain = r->domain; |
150 | struct tomoyo_acl_info *ptr; | 148 | struct tomoyo_acl_info *ptr; |
151 | bool retried = false; | 149 | bool retried = false; |
152 | const struct list_head *list = &domain->acl_info_list; | 150 | const struct list_head *list = &domain->acl_info_list; |
153 | 151 | ||
154 | retry: | 152 | retry: |
155 | list_for_each_entry_rcu(ptr, list, list) { | 153 | list_for_each_entry_rcu(ptr, list, list) { |
156 | if (ptr->is_deleted || ptr->type != r->param_type) | 154 | if (ptr->is_deleted || ptr->type != r->param_type) |
157 | continue; | 155 | continue; |
158 | if (!check_entry(r, ptr)) | 156 | if (!check_entry(r, ptr)) |
159 | continue; | 157 | continue; |
160 | if (!tomoyo_condition(r, ptr->cond)) | 158 | if (!tomoyo_condition(r, ptr->cond)) |
161 | continue; | 159 | continue; |
162 | r->granted = true; | 160 | r->granted = true; |
163 | return; | 161 | return; |
164 | } | 162 | } |
165 | if (!retried) { | 163 | if (!retried) { |
166 | retried = true; | 164 | retried = true; |
167 | list = &domain->ns->acl_group[domain->group]; | 165 | list = &domain->ns->acl_group[domain->group]; |
168 | goto retry; | 166 | goto retry; |
169 | } | 167 | } |
170 | r->granted = false; | 168 | r->granted = false; |
171 | } | 169 | } |
172 | 170 | ||
173 | /* The list for "struct tomoyo_domain_info". */ | 171 | /* The list for "struct tomoyo_domain_info". */ |
174 | LIST_HEAD(tomoyo_domain_list); | 172 | LIST_HEAD(tomoyo_domain_list); |
175 | 173 | ||
176 | /** | 174 | /** |
177 | * tomoyo_last_word - Get last component of a domainname. | 175 | * tomoyo_last_word - Get last component of a domainname. |
178 | * | 176 | * |
179 | * @name: Domainname to check. | 177 | * @name: Domainname to check. |
180 | * | 178 | * |
181 | * Returns the last word of @domainname. | 179 | * Returns the last word of @domainname. |
182 | */ | 180 | */ |
183 | static const char *tomoyo_last_word(const char *name) | 181 | static const char *tomoyo_last_word(const char *name) |
184 | { | 182 | { |
185 | const char *cp = strrchr(name, ' '); | 183 | const char *cp = strrchr(name, ' '); |
186 | if (cp) | 184 | if (cp) |
187 | return cp + 1; | 185 | return cp + 1; |
188 | return name; | 186 | return name; |
189 | } | 187 | } |
190 | 188 | ||
191 | /** | 189 | /** |
192 | * tomoyo_same_transition_control - Check for duplicated "struct tomoyo_transition_control" entry. | 190 | * tomoyo_same_transition_control - Check for duplicated "struct tomoyo_transition_control" entry. |
193 | * | 191 | * |
194 | * @a: Pointer to "struct tomoyo_acl_head". | 192 | * @a: Pointer to "struct tomoyo_acl_head". |
195 | * @b: Pointer to "struct tomoyo_acl_head". | 193 | * @b: Pointer to "struct tomoyo_acl_head". |
196 | * | 194 | * |
197 | * Returns true if @a == @b, false otherwise. | 195 | * Returns true if @a == @b, false otherwise. |
198 | */ | 196 | */ |
199 | static bool tomoyo_same_transition_control(const struct tomoyo_acl_head *a, | 197 | static bool tomoyo_same_transition_control(const struct tomoyo_acl_head *a, |
200 | const struct tomoyo_acl_head *b) | 198 | const struct tomoyo_acl_head *b) |
201 | { | 199 | { |
202 | const struct tomoyo_transition_control *p1 = container_of(a, | 200 | const struct tomoyo_transition_control *p1 = container_of(a, |
203 | typeof(*p1), | 201 | typeof(*p1), |
204 | head); | 202 | head); |
205 | const struct tomoyo_transition_control *p2 = container_of(b, | 203 | const struct tomoyo_transition_control *p2 = container_of(b, |
206 | typeof(*p2), | 204 | typeof(*p2), |
207 | head); | 205 | head); |
208 | return p1->type == p2->type && p1->is_last_name == p2->is_last_name | 206 | return p1->type == p2->type && p1->is_last_name == p2->is_last_name |
209 | && p1->domainname == p2->domainname | 207 | && p1->domainname == p2->domainname |
210 | && p1->program == p2->program; | 208 | && p1->program == p2->program; |
211 | } | 209 | } |
212 | 210 | ||
213 | /** | 211 | /** |
214 | * tomoyo_write_transition_control - Write "struct tomoyo_transition_control" list. | 212 | * tomoyo_write_transition_control - Write "struct tomoyo_transition_control" list. |
215 | * | 213 | * |
216 | * @param: Pointer to "struct tomoyo_acl_param". | 214 | * @param: Pointer to "struct tomoyo_acl_param". |
217 | * @type: Type of this entry. | 215 | * @type: Type of this entry. |
218 | * | 216 | * |
219 | * Returns 0 on success, negative value otherwise. | 217 | * Returns 0 on success, negative value otherwise. |
220 | */ | 218 | */ |
221 | int tomoyo_write_transition_control(struct tomoyo_acl_param *param, | 219 | int tomoyo_write_transition_control(struct tomoyo_acl_param *param, |
222 | const u8 type) | 220 | const u8 type) |
223 | { | 221 | { |
224 | struct tomoyo_transition_control e = { .type = type }; | 222 | struct tomoyo_transition_control e = { .type = type }; |
225 | int error = param->is_delete ? -ENOENT : -ENOMEM; | 223 | int error = param->is_delete ? -ENOENT : -ENOMEM; |
226 | char *program = param->data; | 224 | char *program = param->data; |
227 | char *domainname = strstr(program, " from "); | 225 | char *domainname = strstr(program, " from "); |
228 | if (domainname) { | 226 | if (domainname) { |
229 | *domainname = '\0'; | 227 | *domainname = '\0'; |
230 | domainname += 6; | 228 | domainname += 6; |
231 | } else if (type == TOMOYO_TRANSITION_CONTROL_NO_KEEP || | 229 | } else if (type == TOMOYO_TRANSITION_CONTROL_NO_KEEP || |
232 | type == TOMOYO_TRANSITION_CONTROL_KEEP) { | 230 | type == TOMOYO_TRANSITION_CONTROL_KEEP) { |
233 | domainname = program; | 231 | domainname = program; |
234 | program = NULL; | 232 | program = NULL; |
235 | } | 233 | } |
236 | if (program && strcmp(program, "any")) { | 234 | if (program && strcmp(program, "any")) { |
237 | if (!tomoyo_correct_path(program)) | 235 | if (!tomoyo_correct_path(program)) |
238 | return -EINVAL; | 236 | return -EINVAL; |
239 | e.program = tomoyo_get_name(program); | 237 | e.program = tomoyo_get_name(program); |
240 | if (!e.program) | 238 | if (!e.program) |
241 | goto out; | 239 | goto out; |
242 | } | 240 | } |
243 | if (domainname && strcmp(domainname, "any")) { | 241 | if (domainname && strcmp(domainname, "any")) { |
244 | if (!tomoyo_correct_domain(domainname)) { | 242 | if (!tomoyo_correct_domain(domainname)) { |
245 | if (!tomoyo_correct_path(domainname)) | 243 | if (!tomoyo_correct_path(domainname)) |
246 | goto out; | 244 | goto out; |
247 | e.is_last_name = true; | 245 | e.is_last_name = true; |
248 | } | 246 | } |
249 | e.domainname = tomoyo_get_name(domainname); | 247 | e.domainname = tomoyo_get_name(domainname); |
250 | if (!e.domainname) | 248 | if (!e.domainname) |
251 | goto out; | 249 | goto out; |
252 | } | 250 | } |
253 | param->list = ¶m->ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL]; | 251 | param->list = ¶m->ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL]; |
254 | error = tomoyo_update_policy(&e.head, sizeof(e), param, | 252 | error = tomoyo_update_policy(&e.head, sizeof(e), param, |
255 | tomoyo_same_transition_control); | 253 | tomoyo_same_transition_control); |
256 | out: | 254 | out: |
257 | tomoyo_put_name(e.domainname); | 255 | tomoyo_put_name(e.domainname); |
258 | tomoyo_put_name(e.program); | 256 | tomoyo_put_name(e.program); |
259 | return error; | 257 | return error; |
260 | } | 258 | } |
261 | 259 | ||
262 | /** | 260 | /** |
263 | * tomoyo_scan_transition - Try to find specific domain transition type. | 261 | * tomoyo_scan_transition - Try to find specific domain transition type. |
264 | * | 262 | * |
265 | * @list: Pointer to "struct list_head". | 263 | * @list: Pointer to "struct list_head". |
266 | * @domainname: The name of current domain. | 264 | * @domainname: The name of current domain. |
267 | * @program: The name of requested program. | 265 | * @program: The name of requested program. |
268 | * @last_name: The last component of @domainname. | 266 | * @last_name: The last component of @domainname. |
269 | * @type: One of values in "enum tomoyo_transition_type". | 267 | * @type: One of values in "enum tomoyo_transition_type". |
270 | * | 268 | * |
271 | * Returns true if found one, false otherwise. | 269 | * Returns true if found one, false otherwise. |
272 | * | 270 | * |
273 | * Caller holds tomoyo_read_lock(). | 271 | * Caller holds tomoyo_read_lock(). |
274 | */ | 272 | */ |
275 | static inline bool tomoyo_scan_transition | 273 | static inline bool tomoyo_scan_transition |
276 | (const struct list_head *list, const struct tomoyo_path_info *domainname, | 274 | (const struct list_head *list, const struct tomoyo_path_info *domainname, |
277 | const struct tomoyo_path_info *program, const char *last_name, | 275 | const struct tomoyo_path_info *program, const char *last_name, |
278 | const enum tomoyo_transition_type type) | 276 | const enum tomoyo_transition_type type) |
279 | { | 277 | { |
280 | const struct tomoyo_transition_control *ptr; | 278 | const struct tomoyo_transition_control *ptr; |
281 | list_for_each_entry_rcu(ptr, list, head.list) { | 279 | list_for_each_entry_rcu(ptr, list, head.list) { |
282 | if (ptr->head.is_deleted || ptr->type != type) | 280 | if (ptr->head.is_deleted || ptr->type != type) |
283 | continue; | 281 | continue; |
284 | if (ptr->domainname) { | 282 | if (ptr->domainname) { |
285 | if (!ptr->is_last_name) { | 283 | if (!ptr->is_last_name) { |
286 | if (ptr->domainname != domainname) | 284 | if (ptr->domainname != domainname) |
287 | continue; | 285 | continue; |
288 | } else { | 286 | } else { |
289 | /* | 287 | /* |
290 | * Use direct strcmp() since this is | 288 | * Use direct strcmp() since this is |
291 | * unlikely used. | 289 | * unlikely used. |
292 | */ | 290 | */ |
293 | if (strcmp(ptr->domainname->name, last_name)) | 291 | if (strcmp(ptr->domainname->name, last_name)) |
294 | continue; | 292 | continue; |
295 | } | 293 | } |
296 | } | 294 | } |
297 | if (ptr->program && tomoyo_pathcmp(ptr->program, program)) | 295 | if (ptr->program && tomoyo_pathcmp(ptr->program, program)) |
298 | continue; | 296 | continue; |
299 | return true; | 297 | return true; |
300 | } | 298 | } |
301 | return false; | 299 | return false; |
302 | } | 300 | } |
303 | 301 | ||
304 | /** | 302 | /** |
305 | * tomoyo_transition_type - Get domain transition type. | 303 | * tomoyo_transition_type - Get domain transition type. |
306 | * | 304 | * |
307 | * @ns: Pointer to "struct tomoyo_policy_namespace". | 305 | * @ns: Pointer to "struct tomoyo_policy_namespace". |
308 | * @domainname: The name of current domain. | 306 | * @domainname: The name of current domain. |
309 | * @program: The name of requested program. | 307 | * @program: The name of requested program. |
310 | * | 308 | * |
311 | * Returns TOMOYO_TRANSITION_CONTROL_TRANSIT if executing @program causes | 309 | * Returns TOMOYO_TRANSITION_CONTROL_TRANSIT if executing @program causes |
312 | * domain transition across namespaces, TOMOYO_TRANSITION_CONTROL_INITIALIZE if | 310 | * domain transition across namespaces, TOMOYO_TRANSITION_CONTROL_INITIALIZE if |
313 | * executing @program reinitializes domain transition within that namespace, | 311 | * executing @program reinitializes domain transition within that namespace, |
314 | * TOMOYO_TRANSITION_CONTROL_KEEP if executing @program stays at @domainname , | 312 | * TOMOYO_TRANSITION_CONTROL_KEEP if executing @program stays at @domainname , |
315 | * others otherwise. | 313 | * others otherwise. |
316 | * | 314 | * |
317 | * Caller holds tomoyo_read_lock(). | 315 | * Caller holds tomoyo_read_lock(). |
318 | */ | 316 | */ |
319 | static enum tomoyo_transition_type tomoyo_transition_type | 317 | static enum tomoyo_transition_type tomoyo_transition_type |
320 | (const struct tomoyo_policy_namespace *ns, | 318 | (const struct tomoyo_policy_namespace *ns, |
321 | const struct tomoyo_path_info *domainname, | 319 | const struct tomoyo_path_info *domainname, |
322 | const struct tomoyo_path_info *program) | 320 | const struct tomoyo_path_info *program) |
323 | { | 321 | { |
324 | const char *last_name = tomoyo_last_word(domainname->name); | 322 | const char *last_name = tomoyo_last_word(domainname->name); |
325 | enum tomoyo_transition_type type = TOMOYO_TRANSITION_CONTROL_NO_RESET; | 323 | enum tomoyo_transition_type type = TOMOYO_TRANSITION_CONTROL_NO_RESET; |
326 | while (type < TOMOYO_MAX_TRANSITION_TYPE) { | 324 | while (type < TOMOYO_MAX_TRANSITION_TYPE) { |
327 | const struct list_head * const list = | 325 | const struct list_head * const list = |
328 | &ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL]; | 326 | &ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL]; |
329 | if (!tomoyo_scan_transition(list, domainname, program, | 327 | if (!tomoyo_scan_transition(list, domainname, program, |
330 | last_name, type)) { | 328 | last_name, type)) { |
331 | type++; | 329 | type++; |
332 | continue; | 330 | continue; |
333 | } | 331 | } |
334 | if (type != TOMOYO_TRANSITION_CONTROL_NO_RESET && | 332 | if (type != TOMOYO_TRANSITION_CONTROL_NO_RESET && |
335 | type != TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE) | 333 | type != TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE) |
336 | break; | 334 | break; |
337 | /* | 335 | /* |
338 | * Do not check for reset_domain if no_reset_domain matched. | 336 | * Do not check for reset_domain if no_reset_domain matched. |
339 | * Do not check for initialize_domain if no_initialize_domain | 337 | * Do not check for initialize_domain if no_initialize_domain |
340 | * matched. | 338 | * matched. |
341 | */ | 339 | */ |
342 | type++; | 340 | type++; |
343 | type++; | 341 | type++; |
344 | } | 342 | } |
345 | return type; | 343 | return type; |
346 | } | 344 | } |
347 | 345 | ||
348 | /** | 346 | /** |
349 | * tomoyo_same_aggregator - Check for duplicated "struct tomoyo_aggregator" entry. | 347 | * tomoyo_same_aggregator - Check for duplicated "struct tomoyo_aggregator" entry. |
350 | * | 348 | * |
351 | * @a: Pointer to "struct tomoyo_acl_head". | 349 | * @a: Pointer to "struct tomoyo_acl_head". |
352 | * @b: Pointer to "struct tomoyo_acl_head". | 350 | * @b: Pointer to "struct tomoyo_acl_head". |
353 | * | 351 | * |
354 | * Returns true if @a == @b, false otherwise. | 352 | * Returns true if @a == @b, false otherwise. |
355 | */ | 353 | */ |
356 | static bool tomoyo_same_aggregator(const struct tomoyo_acl_head *a, | 354 | static bool tomoyo_same_aggregator(const struct tomoyo_acl_head *a, |
357 | const struct tomoyo_acl_head *b) | 355 | const struct tomoyo_acl_head *b) |
358 | { | 356 | { |
359 | const struct tomoyo_aggregator *p1 = container_of(a, typeof(*p1), | 357 | const struct tomoyo_aggregator *p1 = container_of(a, typeof(*p1), |
360 | head); | 358 | head); |
361 | const struct tomoyo_aggregator *p2 = container_of(b, typeof(*p2), | 359 | const struct tomoyo_aggregator *p2 = container_of(b, typeof(*p2), |
362 | head); | 360 | head); |
363 | return p1->original_name == p2->original_name && | 361 | return p1->original_name == p2->original_name && |
364 | p1->aggregated_name == p2->aggregated_name; | 362 | p1->aggregated_name == p2->aggregated_name; |
365 | } | 363 | } |
366 | 364 | ||
367 | /** | 365 | /** |
368 | * tomoyo_write_aggregator - Write "struct tomoyo_aggregator" list. | 366 | * tomoyo_write_aggregator - Write "struct tomoyo_aggregator" list. |
369 | * | 367 | * |
370 | * @param: Pointer to "struct tomoyo_acl_param". | 368 | * @param: Pointer to "struct tomoyo_acl_param". |
371 | * | 369 | * |
372 | * Returns 0 on success, negative value otherwise. | 370 | * Returns 0 on success, negative value otherwise. |
373 | * | 371 | * |
374 | * Caller holds tomoyo_read_lock(). | 372 | * Caller holds tomoyo_read_lock(). |
375 | */ | 373 | */ |
376 | int tomoyo_write_aggregator(struct tomoyo_acl_param *param) | 374 | int tomoyo_write_aggregator(struct tomoyo_acl_param *param) |
377 | { | 375 | { |
378 | struct tomoyo_aggregator e = { }; | 376 | struct tomoyo_aggregator e = { }; |
379 | int error = param->is_delete ? -ENOENT : -ENOMEM; | 377 | int error = param->is_delete ? -ENOENT : -ENOMEM; |
380 | const char *original_name = tomoyo_read_token(param); | 378 | const char *original_name = tomoyo_read_token(param); |
381 | const char *aggregated_name = tomoyo_read_token(param); | 379 | const char *aggregated_name = tomoyo_read_token(param); |
382 | if (!tomoyo_correct_word(original_name) || | 380 | if (!tomoyo_correct_word(original_name) || |
383 | !tomoyo_correct_path(aggregated_name)) | 381 | !tomoyo_correct_path(aggregated_name)) |
384 | return -EINVAL; | 382 | return -EINVAL; |
385 | e.original_name = tomoyo_get_name(original_name); | 383 | e.original_name = tomoyo_get_name(original_name); |
386 | e.aggregated_name = tomoyo_get_name(aggregated_name); | 384 | e.aggregated_name = tomoyo_get_name(aggregated_name); |
387 | if (!e.original_name || !e.aggregated_name || | 385 | if (!e.original_name || !e.aggregated_name || |
388 | e.aggregated_name->is_patterned) /* No patterns allowed. */ | 386 | e.aggregated_name->is_patterned) /* No patterns allowed. */ |
389 | goto out; | 387 | goto out; |
390 | param->list = ¶m->ns->policy_list[TOMOYO_ID_AGGREGATOR]; | 388 | param->list = ¶m->ns->policy_list[TOMOYO_ID_AGGREGATOR]; |
391 | error = tomoyo_update_policy(&e.head, sizeof(e), param, | 389 | error = tomoyo_update_policy(&e.head, sizeof(e), param, |
392 | tomoyo_same_aggregator); | 390 | tomoyo_same_aggregator); |
393 | out: | 391 | out: |
394 | tomoyo_put_name(e.original_name); | 392 | tomoyo_put_name(e.original_name); |
395 | tomoyo_put_name(e.aggregated_name); | 393 | tomoyo_put_name(e.aggregated_name); |
396 | return error; | 394 | return error; |
397 | } | 395 | } |
398 | 396 | ||
399 | /** | 397 | /** |
400 | * tomoyo_find_namespace - Find specified namespace. | 398 | * tomoyo_find_namespace - Find specified namespace. |
401 | * | 399 | * |
402 | * @name: Name of namespace to find. | 400 | * @name: Name of namespace to find. |
403 | * @len: Length of @name. | 401 | * @len: Length of @name. |
404 | * | 402 | * |
405 | * Returns pointer to "struct tomoyo_policy_namespace" if found, | 403 | * Returns pointer to "struct tomoyo_policy_namespace" if found, |
406 | * NULL otherwise. | 404 | * NULL otherwise. |
407 | * | 405 | * |
408 | * Caller holds tomoyo_read_lock(). | 406 | * Caller holds tomoyo_read_lock(). |
409 | */ | 407 | */ |
410 | static struct tomoyo_policy_namespace *tomoyo_find_namespace | 408 | static struct tomoyo_policy_namespace *tomoyo_find_namespace |
411 | (const char *name, const unsigned int len) | 409 | (const char *name, const unsigned int len) |
412 | { | 410 | { |
413 | struct tomoyo_policy_namespace *ns; | 411 | struct tomoyo_policy_namespace *ns; |
414 | list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) { | 412 | list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) { |
415 | if (strncmp(name, ns->name, len) || | 413 | if (strncmp(name, ns->name, len) || |
416 | (name[len] && name[len] != ' ')) | 414 | (name[len] && name[len] != ' ')) |
417 | continue; | 415 | continue; |
418 | return ns; | 416 | return ns; |
419 | } | 417 | } |
420 | return NULL; | 418 | return NULL; |
421 | } | 419 | } |
422 | 420 | ||
423 | /** | 421 | /** |
424 | * tomoyo_assign_namespace - Create a new namespace. | 422 | * tomoyo_assign_namespace - Create a new namespace. |
425 | * | 423 | * |
426 | * @domainname: Name of namespace to create. | 424 | * @domainname: Name of namespace to create. |
427 | * | 425 | * |
428 | * Returns pointer to "struct tomoyo_policy_namespace" on success, | 426 | * Returns pointer to "struct tomoyo_policy_namespace" on success, |
429 | * NULL otherwise. | 427 | * NULL otherwise. |
430 | * | 428 | * |
431 | * Caller holds tomoyo_read_lock(). | 429 | * Caller holds tomoyo_read_lock(). |
432 | */ | 430 | */ |
433 | struct tomoyo_policy_namespace *tomoyo_assign_namespace(const char *domainname) | 431 | struct tomoyo_policy_namespace *tomoyo_assign_namespace(const char *domainname) |
434 | { | 432 | { |
435 | struct tomoyo_policy_namespace *ptr; | 433 | struct tomoyo_policy_namespace *ptr; |
436 | struct tomoyo_policy_namespace *entry; | 434 | struct tomoyo_policy_namespace *entry; |
437 | const char *cp = domainname; | 435 | const char *cp = domainname; |
438 | unsigned int len = 0; | 436 | unsigned int len = 0; |
439 | while (*cp && *cp++ != ' ') | 437 | while (*cp && *cp++ != ' ') |
440 | len++; | 438 | len++; |
441 | ptr = tomoyo_find_namespace(domainname, len); | 439 | ptr = tomoyo_find_namespace(domainname, len); |
442 | if (ptr) | 440 | if (ptr) |
443 | return ptr; | 441 | return ptr; |
444 | if (len >= TOMOYO_EXEC_TMPSIZE - 10 || !tomoyo_domain_def(domainname)) | 442 | if (len >= TOMOYO_EXEC_TMPSIZE - 10 || !tomoyo_domain_def(domainname)) |
445 | return NULL; | 443 | return NULL; |
446 | entry = kzalloc(sizeof(*entry) + len + 1, GFP_NOFS); | 444 | entry = kzalloc(sizeof(*entry) + len + 1, GFP_NOFS); |
447 | if (!entry) | 445 | if (!entry) |
448 | return NULL; | 446 | return NULL; |
449 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 447 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
450 | goto out; | 448 | goto out; |
451 | ptr = tomoyo_find_namespace(domainname, len); | 449 | ptr = tomoyo_find_namespace(domainname, len); |
452 | if (!ptr && tomoyo_memory_ok(entry)) { | 450 | if (!ptr && tomoyo_memory_ok(entry)) { |
453 | char *name = (char *) (entry + 1); | 451 | char *name = (char *) (entry + 1); |
454 | ptr = entry; | 452 | ptr = entry; |
455 | memmove(name, domainname, len); | 453 | memmove(name, domainname, len); |
456 | name[len] = '\0'; | 454 | name[len] = '\0'; |
457 | entry->name = name; | 455 | entry->name = name; |
458 | tomoyo_init_policy_namespace(entry); | 456 | tomoyo_init_policy_namespace(entry); |
459 | entry = NULL; | 457 | entry = NULL; |
460 | } | 458 | } |
461 | mutex_unlock(&tomoyo_policy_lock); | 459 | mutex_unlock(&tomoyo_policy_lock); |
462 | out: | 460 | out: |
463 | kfree(entry); | 461 | kfree(entry); |
464 | return ptr; | 462 | return ptr; |
465 | } | 463 | } |
466 | 464 | ||
467 | /** | 465 | /** |
468 | * tomoyo_namespace_jump - Check for namespace jump. | 466 | * tomoyo_namespace_jump - Check for namespace jump. |
469 | * | 467 | * |
470 | * @domainname: Name of domain. | 468 | * @domainname: Name of domain. |
471 | * | 469 | * |
472 | * Returns true if namespace differs, false otherwise. | 470 | * Returns true if namespace differs, false otherwise. |
473 | */ | 471 | */ |
474 | static bool tomoyo_namespace_jump(const char *domainname) | 472 | static bool tomoyo_namespace_jump(const char *domainname) |
475 | { | 473 | { |
476 | const char *namespace = tomoyo_current_namespace()->name; | 474 | const char *namespace = tomoyo_current_namespace()->name; |
477 | const int len = strlen(namespace); | 475 | const int len = strlen(namespace); |
478 | return strncmp(domainname, namespace, len) || | 476 | return strncmp(domainname, namespace, len) || |
479 | (domainname[len] && domainname[len] != ' '); | 477 | (domainname[len] && domainname[len] != ' '); |
480 | } | 478 | } |
481 | 479 | ||
482 | /** | 480 | /** |
483 | * tomoyo_assign_domain - Create a domain or a namespace. | 481 | * tomoyo_assign_domain - Create a domain or a namespace. |
484 | * | 482 | * |
485 | * @domainname: The name of domain. | 483 | * @domainname: The name of domain. |
486 | * @transit: True if transit to domain found or created. | 484 | * @transit: True if transit to domain found or created. |
487 | * | 485 | * |
488 | * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise. | 486 | * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise. |
489 | * | 487 | * |
490 | * Caller holds tomoyo_read_lock(). | 488 | * Caller holds tomoyo_read_lock(). |
491 | */ | 489 | */ |
492 | struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname, | 490 | struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname, |
493 | const bool transit) | 491 | const bool transit) |
494 | { | 492 | { |
495 | struct tomoyo_domain_info e = { }; | 493 | struct tomoyo_domain_info e = { }; |
496 | struct tomoyo_domain_info *entry = tomoyo_find_domain(domainname); | 494 | struct tomoyo_domain_info *entry = tomoyo_find_domain(domainname); |
497 | bool created = false; | 495 | bool created = false; |
498 | if (entry) { | 496 | if (entry) { |
499 | if (transit) { | 497 | if (transit) { |
500 | /* | 498 | /* |
501 | * Since namespace is created at runtime, profiles may | 499 | * Since namespace is created at runtime, profiles may |
502 | * not be created by the moment the process transits to | 500 | * not be created by the moment the process transits to |
503 | * that domain. Do not perform domain transition if | 501 | * that domain. Do not perform domain transition if |
504 | * profile for that domain is not yet created. | 502 | * profile for that domain is not yet created. |
505 | */ | 503 | */ |
506 | if (!entry->ns->profile_ptr[entry->profile]) | 504 | if (!entry->ns->profile_ptr[entry->profile]) |
507 | return NULL; | 505 | return NULL; |
508 | } | 506 | } |
509 | return entry; | 507 | return entry; |
510 | } | 508 | } |
511 | /* Requested domain does not exist. */ | 509 | /* Requested domain does not exist. */ |
512 | /* Don't create requested domain if domainname is invalid. */ | 510 | /* Don't create requested domain if domainname is invalid. */ |
513 | if (strlen(domainname) >= TOMOYO_EXEC_TMPSIZE - 10 || | 511 | if (strlen(domainname) >= TOMOYO_EXEC_TMPSIZE - 10 || |
514 | !tomoyo_correct_domain(domainname)) | 512 | !tomoyo_correct_domain(domainname)) |
515 | return NULL; | 513 | return NULL; |
516 | /* | 514 | /* |
517 | * Since definition of profiles and acl_groups may differ across | 515 | * Since definition of profiles and acl_groups may differ across |
518 | * namespaces, do not inherit "use_profile" and "use_group" settings | 516 | * namespaces, do not inherit "use_profile" and "use_group" settings |
519 | * by automatically creating requested domain upon domain transition. | 517 | * by automatically creating requested domain upon domain transition. |
520 | */ | 518 | */ |
521 | if (transit && tomoyo_namespace_jump(domainname)) | 519 | if (transit && tomoyo_namespace_jump(domainname)) |
522 | return NULL; | 520 | return NULL; |
523 | e.ns = tomoyo_assign_namespace(domainname); | 521 | e.ns = tomoyo_assign_namespace(domainname); |
524 | if (!e.ns) | 522 | if (!e.ns) |
525 | return NULL; | 523 | return NULL; |
526 | /* | 524 | /* |
527 | * "use_profile" and "use_group" settings for automatically created | 525 | * "use_profile" and "use_group" settings for automatically created |
528 | * domains are inherited from current domain. These are 0 for manually | 526 | * domains are inherited from current domain. These are 0 for manually |
529 | * created domains. | 527 | * created domains. |
530 | */ | 528 | */ |
531 | if (transit) { | 529 | if (transit) { |
532 | const struct tomoyo_domain_info *domain = tomoyo_domain(); | 530 | const struct tomoyo_domain_info *domain = tomoyo_domain(); |
533 | e.profile = domain->profile; | 531 | e.profile = domain->profile; |
534 | e.group = domain->group; | 532 | e.group = domain->group; |
535 | } | 533 | } |
536 | e.domainname = tomoyo_get_name(domainname); | 534 | e.domainname = tomoyo_get_name(domainname); |
537 | if (!e.domainname) | 535 | if (!e.domainname) |
538 | return NULL; | 536 | return NULL; |
539 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 537 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
540 | goto out; | 538 | goto out; |
541 | entry = tomoyo_find_domain(domainname); | 539 | entry = tomoyo_find_domain(domainname); |
542 | if (!entry) { | 540 | if (!entry) { |
543 | entry = tomoyo_commit_ok(&e, sizeof(e)); | 541 | entry = tomoyo_commit_ok(&e, sizeof(e)); |
544 | if (entry) { | 542 | if (entry) { |
545 | INIT_LIST_HEAD(&entry->acl_info_list); | 543 | INIT_LIST_HEAD(&entry->acl_info_list); |
546 | list_add_tail_rcu(&entry->list, &tomoyo_domain_list); | 544 | list_add_tail_rcu(&entry->list, &tomoyo_domain_list); |
547 | created = true; | 545 | created = true; |
548 | } | 546 | } |
549 | } | 547 | } |
550 | mutex_unlock(&tomoyo_policy_lock); | 548 | mutex_unlock(&tomoyo_policy_lock); |
551 | out: | 549 | out: |
552 | tomoyo_put_name(e.domainname); | 550 | tomoyo_put_name(e.domainname); |
553 | if (entry && transit) { | 551 | if (entry && transit) { |
554 | if (created) { | 552 | if (created) { |
555 | struct tomoyo_request_info r; | 553 | struct tomoyo_request_info r; |
556 | tomoyo_init_request_info(&r, entry, | 554 | tomoyo_init_request_info(&r, entry, |
557 | TOMOYO_MAC_FILE_EXECUTE); | 555 | TOMOYO_MAC_FILE_EXECUTE); |
558 | r.granted = false; | 556 | r.granted = false; |
559 | tomoyo_write_log(&r, "use_profile %u\n", | 557 | tomoyo_write_log(&r, "use_profile %u\n", |
560 | entry->profile); | 558 | entry->profile); |
561 | tomoyo_write_log(&r, "use_group %u\n", entry->group); | 559 | tomoyo_write_log(&r, "use_group %u\n", entry->group); |
562 | } | 560 | } |
563 | } | 561 | } |
564 | return entry; | 562 | return entry; |
565 | } | 563 | } |
566 | 564 | ||
567 | /** | 565 | /** |
568 | * tomoyo_find_next_domain - Find a domain. | 566 | * tomoyo_find_next_domain - Find a domain. |
569 | * | 567 | * |
570 | * @bprm: Pointer to "struct linux_binprm". | 568 | * @bprm: Pointer to "struct linux_binprm". |
571 | * | 569 | * |
572 | * Returns 0 on success, negative value otherwise. | 570 | * Returns 0 on success, negative value otherwise. |
573 | * | 571 | * |
574 | * Caller holds tomoyo_read_lock(). | 572 | * Caller holds tomoyo_read_lock(). |
575 | */ | 573 | */ |
576 | int tomoyo_find_next_domain(struct linux_binprm *bprm) | 574 | int tomoyo_find_next_domain(struct linux_binprm *bprm) |
577 | { | 575 | { |
578 | struct tomoyo_domain_info *old_domain = tomoyo_domain(); | 576 | struct tomoyo_domain_info *old_domain = tomoyo_domain(); |
579 | struct tomoyo_domain_info *domain = NULL; | 577 | struct tomoyo_domain_info *domain = NULL; |
580 | const char *original_name = bprm->filename; | 578 | const char *original_name = bprm->filename; |
581 | int retval = -ENOMEM; | 579 | int retval = -ENOMEM; |
582 | bool need_kfree = false; | 580 | bool need_kfree = false; |
583 | bool reject_on_transition_failure = false; | 581 | bool reject_on_transition_failure = false; |
584 | struct tomoyo_path_info rn = { }; /* real name */ | 582 | struct tomoyo_path_info rn = { }; /* real name */ |
585 | struct tomoyo_execve *ee = kzalloc(sizeof(*ee), GFP_NOFS); | 583 | struct tomoyo_execve *ee = kzalloc(sizeof(*ee), GFP_NOFS); |
586 | if (!ee) | 584 | if (!ee) |
587 | return -ENOMEM; | 585 | return -ENOMEM; |
588 | ee->tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS); | 586 | ee->tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS); |
589 | if (!ee->tmp) { | 587 | if (!ee->tmp) { |
590 | kfree(ee); | 588 | kfree(ee); |
591 | return -ENOMEM; | 589 | return -ENOMEM; |
592 | } | 590 | } |
593 | /* ee->dump->data is allocated by tomoyo_dump_page(). */ | 591 | /* ee->dump->data is allocated by tomoyo_dump_page(). */ |
594 | tomoyo_init_request_info(&ee->r, NULL, TOMOYO_MAC_FILE_EXECUTE); | 592 | tomoyo_init_request_info(&ee->r, NULL, TOMOYO_MAC_FILE_EXECUTE); |
595 | ee->r.ee = ee; | 593 | ee->r.ee = ee; |
596 | ee->bprm = bprm; | 594 | ee->bprm = bprm; |
597 | ee->r.obj = &ee->obj; | 595 | ee->r.obj = &ee->obj; |
598 | ee->obj.path1 = bprm->file->f_path; | 596 | ee->obj.path1 = bprm->file->f_path; |
599 | retry: | 597 | retry: |
600 | if (need_kfree) { | 598 | if (need_kfree) { |
601 | kfree(rn.name); | 599 | kfree(rn.name); |
602 | need_kfree = false; | 600 | need_kfree = false; |
603 | } | 601 | } |
604 | /* Get symlink's pathname of program. */ | 602 | /* Get symlink's pathname of program. */ |
605 | retval = -ENOENT; | 603 | retval = -ENOENT; |
606 | rn.name = tomoyo_realpath_nofollow(original_name); | 604 | rn.name = tomoyo_realpath_nofollow(original_name); |
607 | if (!rn.name) | 605 | if (!rn.name) |
608 | goto out; | 606 | goto out; |
609 | tomoyo_fill_path_info(&rn); | 607 | tomoyo_fill_path_info(&rn); |
610 | need_kfree = true; | 608 | need_kfree = true; |
611 | 609 | ||
612 | /* Check 'aggregator' directive. */ | 610 | /* Check 'aggregator' directive. */ |
613 | { | 611 | { |
614 | struct tomoyo_aggregator *ptr; | 612 | struct tomoyo_aggregator *ptr; |
615 | struct list_head *list = | 613 | struct list_head *list = |
616 | &old_domain->ns->policy_list[TOMOYO_ID_AGGREGATOR]; | 614 | &old_domain->ns->policy_list[TOMOYO_ID_AGGREGATOR]; |
617 | /* Check 'aggregator' directive. */ | 615 | /* Check 'aggregator' directive. */ |
618 | list_for_each_entry_rcu(ptr, list, head.list) { | 616 | list_for_each_entry_rcu(ptr, list, head.list) { |
619 | if (ptr->head.is_deleted || | 617 | if (ptr->head.is_deleted || |
620 | !tomoyo_path_matches_pattern(&rn, | 618 | !tomoyo_path_matches_pattern(&rn, |
621 | ptr->original_name)) | 619 | ptr->original_name)) |
622 | continue; | 620 | continue; |
623 | kfree(rn.name); | 621 | kfree(rn.name); |
624 | need_kfree = false; | 622 | need_kfree = false; |
625 | /* This is OK because it is read only. */ | 623 | /* This is OK because it is read only. */ |
626 | rn = *ptr->aggregated_name; | 624 | rn = *ptr->aggregated_name; |
627 | break; | 625 | break; |
628 | } | 626 | } |
629 | } | 627 | } |
630 | 628 | ||
631 | /* Check execute permission. */ | 629 | /* Check execute permission. */ |
632 | retval = tomoyo_path_permission(&ee->r, TOMOYO_TYPE_EXECUTE, &rn); | 630 | retval = tomoyo_path_permission(&ee->r, TOMOYO_TYPE_EXECUTE, &rn); |
633 | if (retval == TOMOYO_RETRY_REQUEST) | 631 | if (retval == TOMOYO_RETRY_REQUEST) |
634 | goto retry; | 632 | goto retry; |
635 | if (retval < 0) | 633 | if (retval < 0) |
636 | goto out; | 634 | goto out; |
637 | /* | 635 | /* |
638 | * To be able to specify domainnames with wildcards, use the | 636 | * To be able to specify domainnames with wildcards, use the |
639 | * pathname specified in the policy (which may contain | 637 | * pathname specified in the policy (which may contain |
640 | * wildcard) rather than the pathname passed to execve() | 638 | * wildcard) rather than the pathname passed to execve() |
641 | * (which never contains wildcard). | 639 | * (which never contains wildcard). |
642 | */ | 640 | */ |
643 | if (ee->r.param.path.matched_path) { | 641 | if (ee->r.param.path.matched_path) { |
644 | if (need_kfree) | 642 | if (need_kfree) |
645 | kfree(rn.name); | 643 | kfree(rn.name); |
646 | need_kfree = false; | 644 | need_kfree = false; |
647 | /* This is OK because it is read only. */ | 645 | /* This is OK because it is read only. */ |
648 | rn = *ee->r.param.path.matched_path; | 646 | rn = *ee->r.param.path.matched_path; |
649 | } | 647 | } |
650 | 648 | ||
651 | /* Calculate domain to transit to. */ | 649 | /* Calculate domain to transit to. */ |
652 | switch (tomoyo_transition_type(old_domain->ns, old_domain->domainname, | 650 | switch (tomoyo_transition_type(old_domain->ns, old_domain->domainname, |
653 | &rn)) { | 651 | &rn)) { |
654 | case TOMOYO_TRANSITION_CONTROL_RESET: | 652 | case TOMOYO_TRANSITION_CONTROL_RESET: |
655 | /* Transit to the root of specified namespace. */ | 653 | /* Transit to the root of specified namespace. */ |
656 | snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>", rn.name); | 654 | snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>", rn.name); |
657 | /* | 655 | /* |
658 | * Make do_execve() fail if domain transition across namespaces | 656 | * Make do_execve() fail if domain transition across namespaces |
659 | * has failed. | 657 | * has failed. |
660 | */ | 658 | */ |
661 | reject_on_transition_failure = true; | 659 | reject_on_transition_failure = true; |
662 | break; | 660 | break; |
663 | case TOMOYO_TRANSITION_CONTROL_INITIALIZE: | 661 | case TOMOYO_TRANSITION_CONTROL_INITIALIZE: |
664 | /* Transit to the child of current namespace's root. */ | 662 | /* Transit to the child of current namespace's root. */ |
665 | snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", | 663 | snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", |
666 | old_domain->ns->name, rn.name); | 664 | old_domain->ns->name, rn.name); |
667 | break; | 665 | break; |
668 | case TOMOYO_TRANSITION_CONTROL_KEEP: | 666 | case TOMOYO_TRANSITION_CONTROL_KEEP: |
669 | /* Keep current domain. */ | 667 | /* Keep current domain. */ |
670 | domain = old_domain; | 668 | domain = old_domain; |
671 | break; | 669 | break; |
672 | default: | 670 | default: |
673 | if (old_domain == &tomoyo_kernel_domain && | 671 | if (old_domain == &tomoyo_kernel_domain && |
674 | !tomoyo_policy_loaded) { | 672 | !tomoyo_policy_loaded) { |
675 | /* | 673 | /* |
676 | * Needn't to transit from kernel domain before | 674 | * Needn't to transit from kernel domain before |
677 | * starting /sbin/init. But transit from kernel domain | 675 | * starting /sbin/init. But transit from kernel domain |
678 | * if executing initializers because they might start | 676 | * if executing initializers because they might start |
679 | * before /sbin/init. | 677 | * before /sbin/init. |
680 | */ | 678 | */ |
681 | domain = old_domain; | 679 | domain = old_domain; |
682 | } else { | 680 | } else { |
683 | /* Normal domain transition. */ | 681 | /* Normal domain transition. */ |
684 | snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", | 682 | snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", |
685 | old_domain->domainname->name, rn.name); | 683 | old_domain->domainname->name, rn.name); |
686 | } | 684 | } |
687 | break; | 685 | break; |
688 | } | 686 | } |
689 | if (!domain) | 687 | if (!domain) |
690 | domain = tomoyo_assign_domain(ee->tmp, true); | 688 | domain = tomoyo_assign_domain(ee->tmp, true); |
691 | if (domain) | 689 | if (domain) |
692 | retval = 0; | 690 | retval = 0; |
693 | else if (reject_on_transition_failure) { | 691 | else if (reject_on_transition_failure) { |
694 | printk(KERN_WARNING "ERROR: Domain '%s' not ready.\n", | 692 | printk(KERN_WARNING "ERROR: Domain '%s' not ready.\n", |
695 | ee->tmp); | 693 | ee->tmp); |
696 | retval = -ENOMEM; | 694 | retval = -ENOMEM; |
697 | } else if (ee->r.mode == TOMOYO_CONFIG_ENFORCING) | 695 | } else if (ee->r.mode == TOMOYO_CONFIG_ENFORCING) |
698 | retval = -ENOMEM; | 696 | retval = -ENOMEM; |
699 | else { | 697 | else { |
700 | retval = 0; | 698 | retval = 0; |
701 | if (!old_domain->flags[TOMOYO_DIF_TRANSITION_FAILED]) { | 699 | if (!old_domain->flags[TOMOYO_DIF_TRANSITION_FAILED]) { |
702 | old_domain->flags[TOMOYO_DIF_TRANSITION_FAILED] = true; | 700 | old_domain->flags[TOMOYO_DIF_TRANSITION_FAILED] = true; |
703 | ee->r.granted = false; | 701 | ee->r.granted = false; |
704 | tomoyo_write_log(&ee->r, "%s", tomoyo_dif | 702 | tomoyo_write_log(&ee->r, "%s", tomoyo_dif |
705 | [TOMOYO_DIF_TRANSITION_FAILED]); | 703 | [TOMOYO_DIF_TRANSITION_FAILED]); |
706 | printk(KERN_WARNING | 704 | printk(KERN_WARNING |
707 | "ERROR: Domain '%s' not defined.\n", ee->tmp); | 705 | "ERROR: Domain '%s' not defined.\n", ee->tmp); |
708 | } | 706 | } |
709 | } | 707 | } |
710 | out: | 708 | out: |
711 | if (!domain) | 709 | if (!domain) |
712 | domain = old_domain; | 710 | domain = old_domain; |
713 | /* Update reference count on "struct tomoyo_domain_info". */ | 711 | /* Update reference count on "struct tomoyo_domain_info". */ |
714 | atomic_inc(&domain->users); | 712 | atomic_inc(&domain->users); |
715 | bprm->cred->security = domain; | 713 | bprm->cred->security = domain; |
716 | if (need_kfree) | 714 | if (need_kfree) |
717 | kfree(rn.name); | 715 | kfree(rn.name); |
718 | kfree(ee->tmp); | 716 | kfree(ee->tmp); |
719 | kfree(ee->dump.data); | 717 | kfree(ee->dump.data); |
720 | kfree(ee); | 718 | kfree(ee); |
721 | return retval; | 719 | return retval; |
722 | } | 720 | } |
723 | 721 | ||
724 | /** | 722 | /** |
725 | * tomoyo_dump_page - Dump a page to buffer. | 723 | * tomoyo_dump_page - Dump a page to buffer. |
726 | * | 724 | * |
727 | * @bprm: Pointer to "struct linux_binprm". | 725 | * @bprm: Pointer to "struct linux_binprm". |
728 | * @pos: Location to dump. | 726 | * @pos: Location to dump. |
729 | * @dump: Poiner to "struct tomoyo_page_dump". | 727 | * @dump: Poiner to "struct tomoyo_page_dump". |
730 | * | 728 | * |
731 | * Returns true on success, false otherwise. | 729 | * Returns true on success, false otherwise. |
732 | */ | 730 | */ |
733 | bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos, | 731 | bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos, |
734 | struct tomoyo_page_dump *dump) | 732 | struct tomoyo_page_dump *dump) |
735 | { | 733 | { |
736 | struct page *page; | 734 | struct page *page; |
737 | /* dump->data is released by tomoyo_finish_execve(). */ | 735 | /* dump->data is released by tomoyo_finish_execve(). */ |
738 | if (!dump->data) { | 736 | if (!dump->data) { |
739 | dump->data = kzalloc(PAGE_SIZE, GFP_NOFS); | 737 | dump->data = kzalloc(PAGE_SIZE, GFP_NOFS); |
740 | if (!dump->data) | 738 | if (!dump->data) |
741 | return false; | 739 | return false; |
742 | } | 740 | } |
743 | /* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */ | 741 | /* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */ |
744 | #ifdef CONFIG_MMU | 742 | #ifdef CONFIG_MMU |
745 | if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0) | 743 | if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0) |
746 | return false; | 744 | return false; |
747 | #else | 745 | #else |
748 | page = bprm->page[pos / PAGE_SIZE]; | 746 | page = bprm->page[pos / PAGE_SIZE]; |
749 | #endif | 747 | #endif |
750 | if (page != dump->page) { | 748 | if (page != dump->page) { |
751 | const unsigned int offset = pos % PAGE_SIZE; | 749 | const unsigned int offset = pos % PAGE_SIZE; |
752 | /* | 750 | /* |
753 | * Maybe kmap()/kunmap() should be used here. | 751 | * Maybe kmap()/kunmap() should be used here. |
754 | * But remove_arg_zero() uses kmap_atomic()/kunmap_atomic(). | 752 | * But remove_arg_zero() uses kmap_atomic()/kunmap_atomic(). |
755 | * So do I. | 753 | * So do I. |
756 | */ | 754 | */ |
757 | char *kaddr = kmap_atomic(page, KM_USER0); | 755 | char *kaddr = kmap_atomic(page, KM_USER0); |
758 | dump->page = page; | 756 | dump->page = page; |
759 | memcpy(dump->data + offset, kaddr + offset, | 757 | memcpy(dump->data + offset, kaddr + offset, |
760 | PAGE_SIZE - offset); | 758 | PAGE_SIZE - offset); |
761 | kunmap_atomic(kaddr, KM_USER0); | 759 | kunmap_atomic(kaddr, KM_USER0); |
762 | } | 760 | } |
763 | /* Same with put_arg_page(page) in fs/exec.c */ | 761 | /* Same with put_arg_page(page) in fs/exec.c */ |
764 | #ifdef CONFIG_MMU | 762 | #ifdef CONFIG_MMU |
765 | put_page(page); | 763 | put_page(page); |
766 | #endif | 764 | #endif |
767 | return true; | 765 | return true; |
768 | } | 766 | } |
769 | 767 |
security/tomoyo/file.c
1 | /* | 1 | /* |
2 | * security/tomoyo/file.c | 2 | * security/tomoyo/file.c |
3 | * | 3 | * |
4 | * Pathname restriction functions. | 4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION |
5 | * | ||
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
7 | */ | 5 | */ |
8 | 6 | ||
9 | #include "common.h" | 7 | #include "common.h" |
10 | #include <linux/slab.h> | 8 | #include <linux/slab.h> |
11 | 9 | ||
12 | /* | 10 | /* |
13 | * Mapping table from "enum tomoyo_path_acl_index" to "enum tomoyo_mac_index". | 11 | * Mapping table from "enum tomoyo_path_acl_index" to "enum tomoyo_mac_index". |
14 | */ | 12 | */ |
15 | static const u8 tomoyo_p2mac[TOMOYO_MAX_PATH_OPERATION] = { | 13 | static const u8 tomoyo_p2mac[TOMOYO_MAX_PATH_OPERATION] = { |
16 | [TOMOYO_TYPE_EXECUTE] = TOMOYO_MAC_FILE_EXECUTE, | 14 | [TOMOYO_TYPE_EXECUTE] = TOMOYO_MAC_FILE_EXECUTE, |
17 | [TOMOYO_TYPE_READ] = TOMOYO_MAC_FILE_OPEN, | 15 | [TOMOYO_TYPE_READ] = TOMOYO_MAC_FILE_OPEN, |
18 | [TOMOYO_TYPE_WRITE] = TOMOYO_MAC_FILE_OPEN, | 16 | [TOMOYO_TYPE_WRITE] = TOMOYO_MAC_FILE_OPEN, |
19 | [TOMOYO_TYPE_APPEND] = TOMOYO_MAC_FILE_OPEN, | 17 | [TOMOYO_TYPE_APPEND] = TOMOYO_MAC_FILE_OPEN, |
20 | [TOMOYO_TYPE_UNLINK] = TOMOYO_MAC_FILE_UNLINK, | 18 | [TOMOYO_TYPE_UNLINK] = TOMOYO_MAC_FILE_UNLINK, |
21 | [TOMOYO_TYPE_GETATTR] = TOMOYO_MAC_FILE_GETATTR, | 19 | [TOMOYO_TYPE_GETATTR] = TOMOYO_MAC_FILE_GETATTR, |
22 | [TOMOYO_TYPE_RMDIR] = TOMOYO_MAC_FILE_RMDIR, | 20 | [TOMOYO_TYPE_RMDIR] = TOMOYO_MAC_FILE_RMDIR, |
23 | [TOMOYO_TYPE_TRUNCATE] = TOMOYO_MAC_FILE_TRUNCATE, | 21 | [TOMOYO_TYPE_TRUNCATE] = TOMOYO_MAC_FILE_TRUNCATE, |
24 | [TOMOYO_TYPE_SYMLINK] = TOMOYO_MAC_FILE_SYMLINK, | 22 | [TOMOYO_TYPE_SYMLINK] = TOMOYO_MAC_FILE_SYMLINK, |
25 | [TOMOYO_TYPE_CHROOT] = TOMOYO_MAC_FILE_CHROOT, | 23 | [TOMOYO_TYPE_CHROOT] = TOMOYO_MAC_FILE_CHROOT, |
26 | [TOMOYO_TYPE_UMOUNT] = TOMOYO_MAC_FILE_UMOUNT, | 24 | [TOMOYO_TYPE_UMOUNT] = TOMOYO_MAC_FILE_UMOUNT, |
27 | }; | 25 | }; |
28 | 26 | ||
29 | /* | 27 | /* |
30 | * Mapping table from "enum tomoyo_mkdev_acl_index" to "enum tomoyo_mac_index". | 28 | * Mapping table from "enum tomoyo_mkdev_acl_index" to "enum tomoyo_mac_index". |
31 | */ | 29 | */ |
32 | const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION] = { | 30 | const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION] = { |
33 | [TOMOYO_TYPE_MKBLOCK] = TOMOYO_MAC_FILE_MKBLOCK, | 31 | [TOMOYO_TYPE_MKBLOCK] = TOMOYO_MAC_FILE_MKBLOCK, |
34 | [TOMOYO_TYPE_MKCHAR] = TOMOYO_MAC_FILE_MKCHAR, | 32 | [TOMOYO_TYPE_MKCHAR] = TOMOYO_MAC_FILE_MKCHAR, |
35 | }; | 33 | }; |
36 | 34 | ||
37 | /* | 35 | /* |
38 | * Mapping table from "enum tomoyo_path2_acl_index" to "enum tomoyo_mac_index". | 36 | * Mapping table from "enum tomoyo_path2_acl_index" to "enum tomoyo_mac_index". |
39 | */ | 37 | */ |
40 | const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION] = { | 38 | const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION] = { |
41 | [TOMOYO_TYPE_LINK] = TOMOYO_MAC_FILE_LINK, | 39 | [TOMOYO_TYPE_LINK] = TOMOYO_MAC_FILE_LINK, |
42 | [TOMOYO_TYPE_RENAME] = TOMOYO_MAC_FILE_RENAME, | 40 | [TOMOYO_TYPE_RENAME] = TOMOYO_MAC_FILE_RENAME, |
43 | [TOMOYO_TYPE_PIVOT_ROOT] = TOMOYO_MAC_FILE_PIVOT_ROOT, | 41 | [TOMOYO_TYPE_PIVOT_ROOT] = TOMOYO_MAC_FILE_PIVOT_ROOT, |
44 | }; | 42 | }; |
45 | 43 | ||
46 | /* | 44 | /* |
47 | * Mapping table from "enum tomoyo_path_number_acl_index" to | 45 | * Mapping table from "enum tomoyo_path_number_acl_index" to |
48 | * "enum tomoyo_mac_index". | 46 | * "enum tomoyo_mac_index". |
49 | */ | 47 | */ |
50 | const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = { | 48 | const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = { |
51 | [TOMOYO_TYPE_CREATE] = TOMOYO_MAC_FILE_CREATE, | 49 | [TOMOYO_TYPE_CREATE] = TOMOYO_MAC_FILE_CREATE, |
52 | [TOMOYO_TYPE_MKDIR] = TOMOYO_MAC_FILE_MKDIR, | 50 | [TOMOYO_TYPE_MKDIR] = TOMOYO_MAC_FILE_MKDIR, |
53 | [TOMOYO_TYPE_MKFIFO] = TOMOYO_MAC_FILE_MKFIFO, | 51 | [TOMOYO_TYPE_MKFIFO] = TOMOYO_MAC_FILE_MKFIFO, |
54 | [TOMOYO_TYPE_MKSOCK] = TOMOYO_MAC_FILE_MKSOCK, | 52 | [TOMOYO_TYPE_MKSOCK] = TOMOYO_MAC_FILE_MKSOCK, |
55 | [TOMOYO_TYPE_IOCTL] = TOMOYO_MAC_FILE_IOCTL, | 53 | [TOMOYO_TYPE_IOCTL] = TOMOYO_MAC_FILE_IOCTL, |
56 | [TOMOYO_TYPE_CHMOD] = TOMOYO_MAC_FILE_CHMOD, | 54 | [TOMOYO_TYPE_CHMOD] = TOMOYO_MAC_FILE_CHMOD, |
57 | [TOMOYO_TYPE_CHOWN] = TOMOYO_MAC_FILE_CHOWN, | 55 | [TOMOYO_TYPE_CHOWN] = TOMOYO_MAC_FILE_CHOWN, |
58 | [TOMOYO_TYPE_CHGRP] = TOMOYO_MAC_FILE_CHGRP, | 56 | [TOMOYO_TYPE_CHGRP] = TOMOYO_MAC_FILE_CHGRP, |
59 | }; | 57 | }; |
60 | 58 | ||
61 | /** | 59 | /** |
62 | * tomoyo_put_name_union - Drop reference on "struct tomoyo_name_union". | 60 | * tomoyo_put_name_union - Drop reference on "struct tomoyo_name_union". |
63 | * | 61 | * |
64 | * @ptr: Pointer to "struct tomoyo_name_union". | 62 | * @ptr: Pointer to "struct tomoyo_name_union". |
65 | * | 63 | * |
66 | * Returns nothing. | 64 | * Returns nothing. |
67 | */ | 65 | */ |
68 | void tomoyo_put_name_union(struct tomoyo_name_union *ptr) | 66 | void tomoyo_put_name_union(struct tomoyo_name_union *ptr) |
69 | { | 67 | { |
70 | tomoyo_put_group(ptr->group); | 68 | tomoyo_put_group(ptr->group); |
71 | tomoyo_put_name(ptr->filename); | 69 | tomoyo_put_name(ptr->filename); |
72 | } | 70 | } |
73 | 71 | ||
74 | /** | 72 | /** |
75 | * tomoyo_compare_name_union - Check whether a name matches "struct tomoyo_name_union" or not. | 73 | * tomoyo_compare_name_union - Check whether a name matches "struct tomoyo_name_union" or not. |
76 | * | 74 | * |
77 | * @name: Pointer to "struct tomoyo_path_info". | 75 | * @name: Pointer to "struct tomoyo_path_info". |
78 | * @ptr: Pointer to "struct tomoyo_name_union". | 76 | * @ptr: Pointer to "struct tomoyo_name_union". |
79 | * | 77 | * |
80 | * Returns "struct tomoyo_path_info" if @name matches @ptr, NULL otherwise. | 78 | * Returns "struct tomoyo_path_info" if @name matches @ptr, NULL otherwise. |
81 | */ | 79 | */ |
82 | const struct tomoyo_path_info * | 80 | const struct tomoyo_path_info * |
83 | tomoyo_compare_name_union(const struct tomoyo_path_info *name, | 81 | tomoyo_compare_name_union(const struct tomoyo_path_info *name, |
84 | const struct tomoyo_name_union *ptr) | 82 | const struct tomoyo_name_union *ptr) |
85 | { | 83 | { |
86 | if (ptr->group) | 84 | if (ptr->group) |
87 | return tomoyo_path_matches_group(name, ptr->group); | 85 | return tomoyo_path_matches_group(name, ptr->group); |
88 | if (tomoyo_path_matches_pattern(name, ptr->filename)) | 86 | if (tomoyo_path_matches_pattern(name, ptr->filename)) |
89 | return ptr->filename; | 87 | return ptr->filename; |
90 | return NULL; | 88 | return NULL; |
91 | } | 89 | } |
92 | 90 | ||
93 | /** | 91 | /** |
94 | * tomoyo_put_number_union - Drop reference on "struct tomoyo_number_union". | 92 | * tomoyo_put_number_union - Drop reference on "struct tomoyo_number_union". |
95 | * | 93 | * |
96 | * @ptr: Pointer to "struct tomoyo_number_union". | 94 | * @ptr: Pointer to "struct tomoyo_number_union". |
97 | * | 95 | * |
98 | * Returns nothing. | 96 | * Returns nothing. |
99 | */ | 97 | */ |
100 | void tomoyo_put_number_union(struct tomoyo_number_union *ptr) | 98 | void tomoyo_put_number_union(struct tomoyo_number_union *ptr) |
101 | { | 99 | { |
102 | tomoyo_put_group(ptr->group); | 100 | tomoyo_put_group(ptr->group); |
103 | } | 101 | } |
104 | 102 | ||
105 | /** | 103 | /** |
106 | * tomoyo_compare_number_union - Check whether a value matches "struct tomoyo_number_union" or not. | 104 | * tomoyo_compare_number_union - Check whether a value matches "struct tomoyo_number_union" or not. |
107 | * | 105 | * |
108 | * @value: Number to check. | 106 | * @value: Number to check. |
109 | * @ptr: Pointer to "struct tomoyo_number_union". | 107 | * @ptr: Pointer to "struct tomoyo_number_union". |
110 | * | 108 | * |
111 | * Returns true if @value matches @ptr, false otherwise. | 109 | * Returns true if @value matches @ptr, false otherwise. |
112 | */ | 110 | */ |
113 | bool tomoyo_compare_number_union(const unsigned long value, | 111 | bool tomoyo_compare_number_union(const unsigned long value, |
114 | const struct tomoyo_number_union *ptr) | 112 | const struct tomoyo_number_union *ptr) |
115 | { | 113 | { |
116 | if (ptr->group) | 114 | if (ptr->group) |
117 | return tomoyo_number_matches_group(value, value, ptr->group); | 115 | return tomoyo_number_matches_group(value, value, ptr->group); |
118 | return value >= ptr->values[0] && value <= ptr->values[1]; | 116 | return value >= ptr->values[0] && value <= ptr->values[1]; |
119 | } | 117 | } |
120 | 118 | ||
121 | /** | 119 | /** |
122 | * tomoyo_add_slash - Add trailing '/' if needed. | 120 | * tomoyo_add_slash - Add trailing '/' if needed. |
123 | * | 121 | * |
124 | * @buf: Pointer to "struct tomoyo_path_info". | 122 | * @buf: Pointer to "struct tomoyo_path_info". |
125 | * | 123 | * |
126 | * Returns nothing. | 124 | * Returns nothing. |
127 | * | 125 | * |
128 | * @buf must be generated by tomoyo_encode() because this function does not | 126 | * @buf must be generated by tomoyo_encode() because this function does not |
129 | * allocate memory for adding '/'. | 127 | * allocate memory for adding '/'. |
130 | */ | 128 | */ |
131 | static void tomoyo_add_slash(struct tomoyo_path_info *buf) | 129 | static void tomoyo_add_slash(struct tomoyo_path_info *buf) |
132 | { | 130 | { |
133 | if (buf->is_dir) | 131 | if (buf->is_dir) |
134 | return; | 132 | return; |
135 | /* | 133 | /* |
136 | * This is OK because tomoyo_encode() reserves space for appending "/". | 134 | * This is OK because tomoyo_encode() reserves space for appending "/". |
137 | */ | 135 | */ |
138 | strcat((char *) buf->name, "/"); | 136 | strcat((char *) buf->name, "/"); |
139 | tomoyo_fill_path_info(buf); | 137 | tomoyo_fill_path_info(buf); |
140 | } | 138 | } |
141 | 139 | ||
142 | /** | 140 | /** |
143 | * tomoyo_get_realpath - Get realpath. | 141 | * tomoyo_get_realpath - Get realpath. |
144 | * | 142 | * |
145 | * @buf: Pointer to "struct tomoyo_path_info". | 143 | * @buf: Pointer to "struct tomoyo_path_info". |
146 | * @path: Pointer to "struct path". | 144 | * @path: Pointer to "struct path". |
147 | * | 145 | * |
148 | * Returns true on success, false otherwise. | 146 | * Returns true on success, false otherwise. |
149 | */ | 147 | */ |
150 | static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path) | 148 | static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path) |
151 | { | 149 | { |
152 | buf->name = tomoyo_realpath_from_path(path); | 150 | buf->name = tomoyo_realpath_from_path(path); |
153 | if (buf->name) { | 151 | if (buf->name) { |
154 | tomoyo_fill_path_info(buf); | 152 | tomoyo_fill_path_info(buf); |
155 | return true; | 153 | return true; |
156 | } | 154 | } |
157 | return false; | 155 | return false; |
158 | } | 156 | } |
159 | 157 | ||
160 | /** | 158 | /** |
161 | * tomoyo_audit_path_log - Audit path request log. | 159 | * tomoyo_audit_path_log - Audit path request log. |
162 | * | 160 | * |
163 | * @r: Pointer to "struct tomoyo_request_info". | 161 | * @r: Pointer to "struct tomoyo_request_info". |
164 | * | 162 | * |
165 | * Returns 0 on success, negative value otherwise. | 163 | * Returns 0 on success, negative value otherwise. |
166 | */ | 164 | */ |
167 | static int tomoyo_audit_path_log(struct tomoyo_request_info *r) | 165 | static int tomoyo_audit_path_log(struct tomoyo_request_info *r) |
168 | { | 166 | { |
169 | return tomoyo_supervisor(r, "file %s %s\n", tomoyo_path_keyword | 167 | return tomoyo_supervisor(r, "file %s %s\n", tomoyo_path_keyword |
170 | [r->param.path.operation], | 168 | [r->param.path.operation], |
171 | r->param.path.filename->name); | 169 | r->param.path.filename->name); |
172 | } | 170 | } |
173 | 171 | ||
174 | /** | 172 | /** |
175 | * tomoyo_audit_path2_log - Audit path/path request log. | 173 | * tomoyo_audit_path2_log - Audit path/path request log. |
176 | * | 174 | * |
177 | * @r: Pointer to "struct tomoyo_request_info". | 175 | * @r: Pointer to "struct tomoyo_request_info". |
178 | * | 176 | * |
179 | * Returns 0 on success, negative value otherwise. | 177 | * Returns 0 on success, negative value otherwise. |
180 | */ | 178 | */ |
181 | static int tomoyo_audit_path2_log(struct tomoyo_request_info *r) | 179 | static int tomoyo_audit_path2_log(struct tomoyo_request_info *r) |
182 | { | 180 | { |
183 | return tomoyo_supervisor(r, "file %s %s %s\n", tomoyo_mac_keywords | 181 | return tomoyo_supervisor(r, "file %s %s %s\n", tomoyo_mac_keywords |
184 | [tomoyo_pp2mac[r->param.path2.operation]], | 182 | [tomoyo_pp2mac[r->param.path2.operation]], |
185 | r->param.path2.filename1->name, | 183 | r->param.path2.filename1->name, |
186 | r->param.path2.filename2->name); | 184 | r->param.path2.filename2->name); |
187 | } | 185 | } |
188 | 186 | ||
189 | /** | 187 | /** |
190 | * tomoyo_audit_mkdev_log - Audit path/number/number/number request log. | 188 | * tomoyo_audit_mkdev_log - Audit path/number/number/number request log. |
191 | * | 189 | * |
192 | * @r: Pointer to "struct tomoyo_request_info". | 190 | * @r: Pointer to "struct tomoyo_request_info". |
193 | * | 191 | * |
194 | * Returns 0 on success, negative value otherwise. | 192 | * Returns 0 on success, negative value otherwise. |
195 | */ | 193 | */ |
196 | static int tomoyo_audit_mkdev_log(struct tomoyo_request_info *r) | 194 | static int tomoyo_audit_mkdev_log(struct tomoyo_request_info *r) |
197 | { | 195 | { |
198 | return tomoyo_supervisor(r, "file %s %s 0%o %u %u\n", | 196 | return tomoyo_supervisor(r, "file %s %s 0%o %u %u\n", |
199 | tomoyo_mac_keywords | 197 | tomoyo_mac_keywords |
200 | [tomoyo_pnnn2mac[r->param.mkdev.operation]], | 198 | [tomoyo_pnnn2mac[r->param.mkdev.operation]], |
201 | r->param.mkdev.filename->name, | 199 | r->param.mkdev.filename->name, |
202 | r->param.mkdev.mode, r->param.mkdev.major, | 200 | r->param.mkdev.mode, r->param.mkdev.major, |
203 | r->param.mkdev.minor); | 201 | r->param.mkdev.minor); |
204 | } | 202 | } |
205 | 203 | ||
206 | /** | 204 | /** |
207 | * tomoyo_audit_path_number_log - Audit path/number request log. | 205 | * tomoyo_audit_path_number_log - Audit path/number request log. |
208 | * | 206 | * |
209 | * @r: Pointer to "struct tomoyo_request_info". | 207 | * @r: Pointer to "struct tomoyo_request_info". |
210 | * | 208 | * |
211 | * Returns 0 on success, negative value otherwise. | 209 | * Returns 0 on success, negative value otherwise. |
212 | */ | 210 | */ |
213 | static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r) | 211 | static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r) |
214 | { | 212 | { |
215 | const u8 type = r->param.path_number.operation; | 213 | const u8 type = r->param.path_number.operation; |
216 | u8 radix; | 214 | u8 radix; |
217 | char buffer[64]; | 215 | char buffer[64]; |
218 | switch (type) { | 216 | switch (type) { |
219 | case TOMOYO_TYPE_CREATE: | 217 | case TOMOYO_TYPE_CREATE: |
220 | case TOMOYO_TYPE_MKDIR: | 218 | case TOMOYO_TYPE_MKDIR: |
221 | case TOMOYO_TYPE_MKFIFO: | 219 | case TOMOYO_TYPE_MKFIFO: |
222 | case TOMOYO_TYPE_MKSOCK: | 220 | case TOMOYO_TYPE_MKSOCK: |
223 | case TOMOYO_TYPE_CHMOD: | 221 | case TOMOYO_TYPE_CHMOD: |
224 | radix = TOMOYO_VALUE_TYPE_OCTAL; | 222 | radix = TOMOYO_VALUE_TYPE_OCTAL; |
225 | break; | 223 | break; |
226 | case TOMOYO_TYPE_IOCTL: | 224 | case TOMOYO_TYPE_IOCTL: |
227 | radix = TOMOYO_VALUE_TYPE_HEXADECIMAL; | 225 | radix = TOMOYO_VALUE_TYPE_HEXADECIMAL; |
228 | break; | 226 | break; |
229 | default: | 227 | default: |
230 | radix = TOMOYO_VALUE_TYPE_DECIMAL; | 228 | radix = TOMOYO_VALUE_TYPE_DECIMAL; |
231 | break; | 229 | break; |
232 | } | 230 | } |
233 | tomoyo_print_ulong(buffer, sizeof(buffer), r->param.path_number.number, | 231 | tomoyo_print_ulong(buffer, sizeof(buffer), r->param.path_number.number, |
234 | radix); | 232 | radix); |
235 | return tomoyo_supervisor(r, "file %s %s %s\n", tomoyo_mac_keywords | 233 | return tomoyo_supervisor(r, "file %s %s %s\n", tomoyo_mac_keywords |
236 | [tomoyo_pn2mac[type]], | 234 | [tomoyo_pn2mac[type]], |
237 | r->param.path_number.filename->name, buffer); | 235 | r->param.path_number.filename->name, buffer); |
238 | } | 236 | } |
239 | 237 | ||
240 | /** | 238 | /** |
241 | * tomoyo_check_path_acl - Check permission for path operation. | 239 | * tomoyo_check_path_acl - Check permission for path operation. |
242 | * | 240 | * |
243 | * @r: Pointer to "struct tomoyo_request_info". | 241 | * @r: Pointer to "struct tomoyo_request_info". |
244 | * @ptr: Pointer to "struct tomoyo_acl_info". | 242 | * @ptr: Pointer to "struct tomoyo_acl_info". |
245 | * | 243 | * |
246 | * Returns true if granted, false otherwise. | 244 | * Returns true if granted, false otherwise. |
247 | * | 245 | * |
248 | * To be able to use wildcard for domain transition, this function sets | 246 | * To be able to use wildcard for domain transition, this function sets |
249 | * matching entry on success. Since the caller holds tomoyo_read_lock(), | 247 | * matching entry on success. Since the caller holds tomoyo_read_lock(), |
250 | * it is safe to set matching entry. | 248 | * it is safe to set matching entry. |
251 | */ | 249 | */ |
252 | static bool tomoyo_check_path_acl(struct tomoyo_request_info *r, | 250 | static bool tomoyo_check_path_acl(struct tomoyo_request_info *r, |
253 | const struct tomoyo_acl_info *ptr) | 251 | const struct tomoyo_acl_info *ptr) |
254 | { | 252 | { |
255 | const struct tomoyo_path_acl *acl = container_of(ptr, typeof(*acl), | 253 | const struct tomoyo_path_acl *acl = container_of(ptr, typeof(*acl), |
256 | head); | 254 | head); |
257 | if (acl->perm & (1 << r->param.path.operation)) { | 255 | if (acl->perm & (1 << r->param.path.operation)) { |
258 | r->param.path.matched_path = | 256 | r->param.path.matched_path = |
259 | tomoyo_compare_name_union(r->param.path.filename, | 257 | tomoyo_compare_name_union(r->param.path.filename, |
260 | &acl->name); | 258 | &acl->name); |
261 | return r->param.path.matched_path != NULL; | 259 | return r->param.path.matched_path != NULL; |
262 | } | 260 | } |
263 | return false; | 261 | return false; |
264 | } | 262 | } |
265 | 263 | ||
266 | /** | 264 | /** |
267 | * tomoyo_check_path_number_acl - Check permission for path number operation. | 265 | * tomoyo_check_path_number_acl - Check permission for path number operation. |
268 | * | 266 | * |
269 | * @r: Pointer to "struct tomoyo_request_info". | 267 | * @r: Pointer to "struct tomoyo_request_info". |
270 | * @ptr: Pointer to "struct tomoyo_acl_info". | 268 | * @ptr: Pointer to "struct tomoyo_acl_info". |
271 | * | 269 | * |
272 | * Returns true if granted, false otherwise. | 270 | * Returns true if granted, false otherwise. |
273 | */ | 271 | */ |
274 | static bool tomoyo_check_path_number_acl(struct tomoyo_request_info *r, | 272 | static bool tomoyo_check_path_number_acl(struct tomoyo_request_info *r, |
275 | const struct tomoyo_acl_info *ptr) | 273 | const struct tomoyo_acl_info *ptr) |
276 | { | 274 | { |
277 | const struct tomoyo_path_number_acl *acl = | 275 | const struct tomoyo_path_number_acl *acl = |
278 | container_of(ptr, typeof(*acl), head); | 276 | container_of(ptr, typeof(*acl), head); |
279 | return (acl->perm & (1 << r->param.path_number.operation)) && | 277 | return (acl->perm & (1 << r->param.path_number.operation)) && |
280 | tomoyo_compare_number_union(r->param.path_number.number, | 278 | tomoyo_compare_number_union(r->param.path_number.number, |
281 | &acl->number) && | 279 | &acl->number) && |
282 | tomoyo_compare_name_union(r->param.path_number.filename, | 280 | tomoyo_compare_name_union(r->param.path_number.filename, |
283 | &acl->name); | 281 | &acl->name); |
284 | } | 282 | } |
285 | 283 | ||
286 | /** | 284 | /** |
287 | * tomoyo_check_path2_acl - Check permission for path path operation. | 285 | * tomoyo_check_path2_acl - Check permission for path path operation. |
288 | * | 286 | * |
289 | * @r: Pointer to "struct tomoyo_request_info". | 287 | * @r: Pointer to "struct tomoyo_request_info". |
290 | * @ptr: Pointer to "struct tomoyo_acl_info". | 288 | * @ptr: Pointer to "struct tomoyo_acl_info". |
291 | * | 289 | * |
292 | * Returns true if granted, false otherwise. | 290 | * Returns true if granted, false otherwise. |
293 | */ | 291 | */ |
294 | static bool tomoyo_check_path2_acl(struct tomoyo_request_info *r, | 292 | static bool tomoyo_check_path2_acl(struct tomoyo_request_info *r, |
295 | const struct tomoyo_acl_info *ptr) | 293 | const struct tomoyo_acl_info *ptr) |
296 | { | 294 | { |
297 | const struct tomoyo_path2_acl *acl = | 295 | const struct tomoyo_path2_acl *acl = |
298 | container_of(ptr, typeof(*acl), head); | 296 | container_of(ptr, typeof(*acl), head); |
299 | return (acl->perm & (1 << r->param.path2.operation)) && | 297 | return (acl->perm & (1 << r->param.path2.operation)) && |
300 | tomoyo_compare_name_union(r->param.path2.filename1, &acl->name1) | 298 | tomoyo_compare_name_union(r->param.path2.filename1, &acl->name1) |
301 | && tomoyo_compare_name_union(r->param.path2.filename2, | 299 | && tomoyo_compare_name_union(r->param.path2.filename2, |
302 | &acl->name2); | 300 | &acl->name2); |
303 | } | 301 | } |
304 | 302 | ||
305 | /** | 303 | /** |
306 | * tomoyo_check_mkdev_acl - Check permission for path number number number operation. | 304 | * tomoyo_check_mkdev_acl - Check permission for path number number number operation. |
307 | * | 305 | * |
308 | * @r: Pointer to "struct tomoyo_request_info". | 306 | * @r: Pointer to "struct tomoyo_request_info". |
309 | * @ptr: Pointer to "struct tomoyo_acl_info". | 307 | * @ptr: Pointer to "struct tomoyo_acl_info". |
310 | * | 308 | * |
311 | * Returns true if granted, false otherwise. | 309 | * Returns true if granted, false otherwise. |
312 | */ | 310 | */ |
313 | static bool tomoyo_check_mkdev_acl(struct tomoyo_request_info *r, | 311 | static bool tomoyo_check_mkdev_acl(struct tomoyo_request_info *r, |
314 | const struct tomoyo_acl_info *ptr) | 312 | const struct tomoyo_acl_info *ptr) |
315 | { | 313 | { |
316 | const struct tomoyo_mkdev_acl *acl = | 314 | const struct tomoyo_mkdev_acl *acl = |
317 | container_of(ptr, typeof(*acl), head); | 315 | container_of(ptr, typeof(*acl), head); |
318 | return (acl->perm & (1 << r->param.mkdev.operation)) && | 316 | return (acl->perm & (1 << r->param.mkdev.operation)) && |
319 | tomoyo_compare_number_union(r->param.mkdev.mode, | 317 | tomoyo_compare_number_union(r->param.mkdev.mode, |
320 | &acl->mode) && | 318 | &acl->mode) && |
321 | tomoyo_compare_number_union(r->param.mkdev.major, | 319 | tomoyo_compare_number_union(r->param.mkdev.major, |
322 | &acl->major) && | 320 | &acl->major) && |
323 | tomoyo_compare_number_union(r->param.mkdev.minor, | 321 | tomoyo_compare_number_union(r->param.mkdev.minor, |
324 | &acl->minor) && | 322 | &acl->minor) && |
325 | tomoyo_compare_name_union(r->param.mkdev.filename, | 323 | tomoyo_compare_name_union(r->param.mkdev.filename, |
326 | &acl->name); | 324 | &acl->name); |
327 | } | 325 | } |
328 | 326 | ||
329 | /** | 327 | /** |
330 | * tomoyo_same_path_acl - Check for duplicated "struct tomoyo_path_acl" entry. | 328 | * tomoyo_same_path_acl - Check for duplicated "struct tomoyo_path_acl" entry. |
331 | * | 329 | * |
332 | * @a: Pointer to "struct tomoyo_acl_info". | 330 | * @a: Pointer to "struct tomoyo_acl_info". |
333 | * @b: Pointer to "struct tomoyo_acl_info". | 331 | * @b: Pointer to "struct tomoyo_acl_info". |
334 | * | 332 | * |
335 | * Returns true if @a == @b except permission bits, false otherwise. | 333 | * Returns true if @a == @b except permission bits, false otherwise. |
336 | */ | 334 | */ |
337 | static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a, | 335 | static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a, |
338 | const struct tomoyo_acl_info *b) | 336 | const struct tomoyo_acl_info *b) |
339 | { | 337 | { |
340 | const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head); | 338 | const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head); |
341 | const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head); | 339 | const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head); |
342 | return tomoyo_same_name_union(&p1->name, &p2->name); | 340 | return tomoyo_same_name_union(&p1->name, &p2->name); |
343 | } | 341 | } |
344 | 342 | ||
345 | /** | 343 | /** |
346 | * tomoyo_merge_path_acl - Merge duplicated "struct tomoyo_path_acl" entry. | 344 | * tomoyo_merge_path_acl - Merge duplicated "struct tomoyo_path_acl" entry. |
347 | * | 345 | * |
348 | * @a: Pointer to "struct tomoyo_acl_info". | 346 | * @a: Pointer to "struct tomoyo_acl_info". |
349 | * @b: Pointer to "struct tomoyo_acl_info". | 347 | * @b: Pointer to "struct tomoyo_acl_info". |
350 | * @is_delete: True for @a &= ~@b, false for @a |= @b. | 348 | * @is_delete: True for @a &= ~@b, false for @a |= @b. |
351 | * | 349 | * |
352 | * Returns true if @a is empty, false otherwise. | 350 | * Returns true if @a is empty, false otherwise. |
353 | */ | 351 | */ |
354 | static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a, | 352 | static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a, |
355 | struct tomoyo_acl_info *b, | 353 | struct tomoyo_acl_info *b, |
356 | const bool is_delete) | 354 | const bool is_delete) |
357 | { | 355 | { |
358 | u16 * const a_perm = &container_of(a, struct tomoyo_path_acl, head) | 356 | u16 * const a_perm = &container_of(a, struct tomoyo_path_acl, head) |
359 | ->perm; | 357 | ->perm; |
360 | u16 perm = *a_perm; | 358 | u16 perm = *a_perm; |
361 | const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm; | 359 | const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm; |
362 | if (is_delete) | 360 | if (is_delete) |
363 | perm &= ~b_perm; | 361 | perm &= ~b_perm; |
364 | else | 362 | else |
365 | perm |= b_perm; | 363 | perm |= b_perm; |
366 | *a_perm = perm; | 364 | *a_perm = perm; |
367 | return !perm; | 365 | return !perm; |
368 | } | 366 | } |
369 | 367 | ||
370 | /** | 368 | /** |
371 | * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list. | 369 | * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list. |
372 | * | 370 | * |
373 | * @perm: Permission. | 371 | * @perm: Permission. |
374 | * @param: Pointer to "struct tomoyo_acl_param". | 372 | * @param: Pointer to "struct tomoyo_acl_param". |
375 | * | 373 | * |
376 | * Returns 0 on success, negative value otherwise. | 374 | * Returns 0 on success, negative value otherwise. |
377 | * | 375 | * |
378 | * Caller holds tomoyo_read_lock(). | 376 | * Caller holds tomoyo_read_lock(). |
379 | */ | 377 | */ |
380 | static int tomoyo_update_path_acl(const u16 perm, | 378 | static int tomoyo_update_path_acl(const u16 perm, |
381 | struct tomoyo_acl_param *param) | 379 | struct tomoyo_acl_param *param) |
382 | { | 380 | { |
383 | struct tomoyo_path_acl e = { | 381 | struct tomoyo_path_acl e = { |
384 | .head.type = TOMOYO_TYPE_PATH_ACL, | 382 | .head.type = TOMOYO_TYPE_PATH_ACL, |
385 | .perm = perm | 383 | .perm = perm |
386 | }; | 384 | }; |
387 | int error; | 385 | int error; |
388 | if (!tomoyo_parse_name_union(param, &e.name)) | 386 | if (!tomoyo_parse_name_union(param, &e.name)) |
389 | error = -EINVAL; | 387 | error = -EINVAL; |
390 | else | 388 | else |
391 | error = tomoyo_update_domain(&e.head, sizeof(e), param, | 389 | error = tomoyo_update_domain(&e.head, sizeof(e), param, |
392 | tomoyo_same_path_acl, | 390 | tomoyo_same_path_acl, |
393 | tomoyo_merge_path_acl); | 391 | tomoyo_merge_path_acl); |
394 | tomoyo_put_name_union(&e.name); | 392 | tomoyo_put_name_union(&e.name); |
395 | return error; | 393 | return error; |
396 | } | 394 | } |
397 | 395 | ||
398 | /** | 396 | /** |
399 | * tomoyo_same_mkdev_acl - Check for duplicated "struct tomoyo_mkdev_acl" entry. | 397 | * tomoyo_same_mkdev_acl - Check for duplicated "struct tomoyo_mkdev_acl" entry. |
400 | * | 398 | * |
401 | * @a: Pointer to "struct tomoyo_acl_info". | 399 | * @a: Pointer to "struct tomoyo_acl_info". |
402 | * @b: Pointer to "struct tomoyo_acl_info". | 400 | * @b: Pointer to "struct tomoyo_acl_info". |
403 | * | 401 | * |
404 | * Returns true if @a == @b except permission bits, false otherwise. | 402 | * Returns true if @a == @b except permission bits, false otherwise. |
405 | */ | 403 | */ |
406 | static bool tomoyo_same_mkdev_acl(const struct tomoyo_acl_info *a, | 404 | static bool tomoyo_same_mkdev_acl(const struct tomoyo_acl_info *a, |
407 | const struct tomoyo_acl_info *b) | 405 | const struct tomoyo_acl_info *b) |
408 | { | 406 | { |
409 | const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1), head); | 407 | const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1), head); |
410 | const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2), head); | 408 | const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2), head); |
411 | return tomoyo_same_name_union(&p1->name, &p2->name) && | 409 | return tomoyo_same_name_union(&p1->name, &p2->name) && |
412 | tomoyo_same_number_union(&p1->mode, &p2->mode) && | 410 | tomoyo_same_number_union(&p1->mode, &p2->mode) && |
413 | tomoyo_same_number_union(&p1->major, &p2->major) && | 411 | tomoyo_same_number_union(&p1->major, &p2->major) && |
414 | tomoyo_same_number_union(&p1->minor, &p2->minor); | 412 | tomoyo_same_number_union(&p1->minor, &p2->minor); |
415 | } | 413 | } |
416 | 414 | ||
417 | /** | 415 | /** |
418 | * tomoyo_merge_mkdev_acl - Merge duplicated "struct tomoyo_mkdev_acl" entry. | 416 | * tomoyo_merge_mkdev_acl - Merge duplicated "struct tomoyo_mkdev_acl" entry. |
419 | * | 417 | * |
420 | * @a: Pointer to "struct tomoyo_acl_info". | 418 | * @a: Pointer to "struct tomoyo_acl_info". |
421 | * @b: Pointer to "struct tomoyo_acl_info". | 419 | * @b: Pointer to "struct tomoyo_acl_info". |
422 | * @is_delete: True for @a &= ~@b, false for @a |= @b. | 420 | * @is_delete: True for @a &= ~@b, false for @a |= @b. |
423 | * | 421 | * |
424 | * Returns true if @a is empty, false otherwise. | 422 | * Returns true if @a is empty, false otherwise. |
425 | */ | 423 | */ |
426 | static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a, | 424 | static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a, |
427 | struct tomoyo_acl_info *b, | 425 | struct tomoyo_acl_info *b, |
428 | const bool is_delete) | 426 | const bool is_delete) |
429 | { | 427 | { |
430 | u8 *const a_perm = &container_of(a, struct tomoyo_mkdev_acl, | 428 | u8 *const a_perm = &container_of(a, struct tomoyo_mkdev_acl, |
431 | head)->perm; | 429 | head)->perm; |
432 | u8 perm = *a_perm; | 430 | u8 perm = *a_perm; |
433 | const u8 b_perm = container_of(b, struct tomoyo_mkdev_acl, head) | 431 | const u8 b_perm = container_of(b, struct tomoyo_mkdev_acl, head) |
434 | ->perm; | 432 | ->perm; |
435 | if (is_delete) | 433 | if (is_delete) |
436 | perm &= ~b_perm; | 434 | perm &= ~b_perm; |
437 | else | 435 | else |
438 | perm |= b_perm; | 436 | perm |= b_perm; |
439 | *a_perm = perm; | 437 | *a_perm = perm; |
440 | return !perm; | 438 | return !perm; |
441 | } | 439 | } |
442 | 440 | ||
443 | /** | 441 | /** |
444 | * tomoyo_update_mkdev_acl - Update "struct tomoyo_mkdev_acl" list. | 442 | * tomoyo_update_mkdev_acl - Update "struct tomoyo_mkdev_acl" list. |
445 | * | 443 | * |
446 | * @perm: Permission. | 444 | * @perm: Permission. |
447 | * @param: Pointer to "struct tomoyo_acl_param". | 445 | * @param: Pointer to "struct tomoyo_acl_param". |
448 | * | 446 | * |
449 | * Returns 0 on success, negative value otherwise. | 447 | * Returns 0 on success, negative value otherwise. |
450 | * | 448 | * |
451 | * Caller holds tomoyo_read_lock(). | 449 | * Caller holds tomoyo_read_lock(). |
452 | */ | 450 | */ |
453 | static int tomoyo_update_mkdev_acl(const u8 perm, | 451 | static int tomoyo_update_mkdev_acl(const u8 perm, |
454 | struct tomoyo_acl_param *param) | 452 | struct tomoyo_acl_param *param) |
455 | { | 453 | { |
456 | struct tomoyo_mkdev_acl e = { | 454 | struct tomoyo_mkdev_acl e = { |
457 | .head.type = TOMOYO_TYPE_MKDEV_ACL, | 455 | .head.type = TOMOYO_TYPE_MKDEV_ACL, |
458 | .perm = perm | 456 | .perm = perm |
459 | }; | 457 | }; |
460 | int error; | 458 | int error; |
461 | if (!tomoyo_parse_name_union(param, &e.name) || | 459 | if (!tomoyo_parse_name_union(param, &e.name) || |
462 | !tomoyo_parse_number_union(param, &e.mode) || | 460 | !tomoyo_parse_number_union(param, &e.mode) || |
463 | !tomoyo_parse_number_union(param, &e.major) || | 461 | !tomoyo_parse_number_union(param, &e.major) || |
464 | !tomoyo_parse_number_union(param, &e.minor)) | 462 | !tomoyo_parse_number_union(param, &e.minor)) |
465 | error = -EINVAL; | 463 | error = -EINVAL; |
466 | else | 464 | else |
467 | error = tomoyo_update_domain(&e.head, sizeof(e), param, | 465 | error = tomoyo_update_domain(&e.head, sizeof(e), param, |
468 | tomoyo_same_mkdev_acl, | 466 | tomoyo_same_mkdev_acl, |
469 | tomoyo_merge_mkdev_acl); | 467 | tomoyo_merge_mkdev_acl); |
470 | tomoyo_put_name_union(&e.name); | 468 | tomoyo_put_name_union(&e.name); |
471 | tomoyo_put_number_union(&e.mode); | 469 | tomoyo_put_number_union(&e.mode); |
472 | tomoyo_put_number_union(&e.major); | 470 | tomoyo_put_number_union(&e.major); |
473 | tomoyo_put_number_union(&e.minor); | 471 | tomoyo_put_number_union(&e.minor); |
474 | return error; | 472 | return error; |
475 | } | 473 | } |
476 | 474 | ||
477 | /** | 475 | /** |
478 | * tomoyo_same_path2_acl - Check for duplicated "struct tomoyo_path2_acl" entry. | 476 | * tomoyo_same_path2_acl - Check for duplicated "struct tomoyo_path2_acl" entry. |
479 | * | 477 | * |
480 | * @a: Pointer to "struct tomoyo_acl_info". | 478 | * @a: Pointer to "struct tomoyo_acl_info". |
481 | * @b: Pointer to "struct tomoyo_acl_info". | 479 | * @b: Pointer to "struct tomoyo_acl_info". |
482 | * | 480 | * |
483 | * Returns true if @a == @b except permission bits, false otherwise. | 481 | * Returns true if @a == @b except permission bits, false otherwise. |
484 | */ | 482 | */ |
485 | static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a, | 483 | static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a, |
486 | const struct tomoyo_acl_info *b) | 484 | const struct tomoyo_acl_info *b) |
487 | { | 485 | { |
488 | const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head); | 486 | const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head); |
489 | const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head); | 487 | const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head); |
490 | return tomoyo_same_name_union(&p1->name1, &p2->name1) && | 488 | return tomoyo_same_name_union(&p1->name1, &p2->name1) && |
491 | tomoyo_same_name_union(&p1->name2, &p2->name2); | 489 | tomoyo_same_name_union(&p1->name2, &p2->name2); |
492 | } | 490 | } |
493 | 491 | ||
494 | /** | 492 | /** |
495 | * tomoyo_merge_path2_acl - Merge duplicated "struct tomoyo_path2_acl" entry. | 493 | * tomoyo_merge_path2_acl - Merge duplicated "struct tomoyo_path2_acl" entry. |
496 | * | 494 | * |
497 | * @a: Pointer to "struct tomoyo_acl_info". | 495 | * @a: Pointer to "struct tomoyo_acl_info". |
498 | * @b: Pointer to "struct tomoyo_acl_info". | 496 | * @b: Pointer to "struct tomoyo_acl_info". |
499 | * @is_delete: True for @a &= ~@b, false for @a |= @b. | 497 | * @is_delete: True for @a &= ~@b, false for @a |= @b. |
500 | * | 498 | * |
501 | * Returns true if @a is empty, false otherwise. | 499 | * Returns true if @a is empty, false otherwise. |
502 | */ | 500 | */ |
503 | static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a, | 501 | static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a, |
504 | struct tomoyo_acl_info *b, | 502 | struct tomoyo_acl_info *b, |
505 | const bool is_delete) | 503 | const bool is_delete) |
506 | { | 504 | { |
507 | u8 * const a_perm = &container_of(a, struct tomoyo_path2_acl, head) | 505 | u8 * const a_perm = &container_of(a, struct tomoyo_path2_acl, head) |
508 | ->perm; | 506 | ->perm; |
509 | u8 perm = *a_perm; | 507 | u8 perm = *a_perm; |
510 | const u8 b_perm = container_of(b, struct tomoyo_path2_acl, head)->perm; | 508 | const u8 b_perm = container_of(b, struct tomoyo_path2_acl, head)->perm; |
511 | if (is_delete) | 509 | if (is_delete) |
512 | perm &= ~b_perm; | 510 | perm &= ~b_perm; |
513 | else | 511 | else |
514 | perm |= b_perm; | 512 | perm |= b_perm; |
515 | *a_perm = perm; | 513 | *a_perm = perm; |
516 | return !perm; | 514 | return !perm; |
517 | } | 515 | } |
518 | 516 | ||
519 | /** | 517 | /** |
520 | * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list. | 518 | * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list. |
521 | * | 519 | * |
522 | * @perm: Permission. | 520 | * @perm: Permission. |
523 | * @param: Pointer to "struct tomoyo_acl_param". | 521 | * @param: Pointer to "struct tomoyo_acl_param". |
524 | * | 522 | * |
525 | * Returns 0 on success, negative value otherwise. | 523 | * Returns 0 on success, negative value otherwise. |
526 | * | 524 | * |
527 | * Caller holds tomoyo_read_lock(). | 525 | * Caller holds tomoyo_read_lock(). |
528 | */ | 526 | */ |
529 | static int tomoyo_update_path2_acl(const u8 perm, | 527 | static int tomoyo_update_path2_acl(const u8 perm, |
530 | struct tomoyo_acl_param *param) | 528 | struct tomoyo_acl_param *param) |
531 | { | 529 | { |
532 | struct tomoyo_path2_acl e = { | 530 | struct tomoyo_path2_acl e = { |
533 | .head.type = TOMOYO_TYPE_PATH2_ACL, | 531 | .head.type = TOMOYO_TYPE_PATH2_ACL, |
534 | .perm = perm | 532 | .perm = perm |
535 | }; | 533 | }; |
536 | int error; | 534 | int error; |
537 | if (!tomoyo_parse_name_union(param, &e.name1) || | 535 | if (!tomoyo_parse_name_union(param, &e.name1) || |
538 | !tomoyo_parse_name_union(param, &e.name2)) | 536 | !tomoyo_parse_name_union(param, &e.name2)) |
539 | error = -EINVAL; | 537 | error = -EINVAL; |
540 | else | 538 | else |
541 | error = tomoyo_update_domain(&e.head, sizeof(e), param, | 539 | error = tomoyo_update_domain(&e.head, sizeof(e), param, |
542 | tomoyo_same_path2_acl, | 540 | tomoyo_same_path2_acl, |
543 | tomoyo_merge_path2_acl); | 541 | tomoyo_merge_path2_acl); |
544 | tomoyo_put_name_union(&e.name1); | 542 | tomoyo_put_name_union(&e.name1); |
545 | tomoyo_put_name_union(&e.name2); | 543 | tomoyo_put_name_union(&e.name2); |
546 | return error; | 544 | return error; |
547 | } | 545 | } |
548 | 546 | ||
549 | /** | 547 | /** |
550 | * tomoyo_path_permission - Check permission for single path operation. | 548 | * tomoyo_path_permission - Check permission for single path operation. |
551 | * | 549 | * |
552 | * @r: Pointer to "struct tomoyo_request_info". | 550 | * @r: Pointer to "struct tomoyo_request_info". |
553 | * @operation: Type of operation. | 551 | * @operation: Type of operation. |
554 | * @filename: Filename to check. | 552 | * @filename: Filename to check. |
555 | * | 553 | * |
556 | * Returns 0 on success, negative value otherwise. | 554 | * Returns 0 on success, negative value otherwise. |
557 | * | 555 | * |
558 | * Caller holds tomoyo_read_lock(). | 556 | * Caller holds tomoyo_read_lock(). |
559 | */ | 557 | */ |
560 | int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, | 558 | int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, |
561 | const struct tomoyo_path_info *filename) | 559 | const struct tomoyo_path_info *filename) |
562 | { | 560 | { |
563 | int error; | 561 | int error; |
564 | 562 | ||
565 | r->type = tomoyo_p2mac[operation]; | 563 | r->type = tomoyo_p2mac[operation]; |
566 | r->mode = tomoyo_get_mode(r->domain->ns, r->profile, r->type); | 564 | r->mode = tomoyo_get_mode(r->domain->ns, r->profile, r->type); |
567 | if (r->mode == TOMOYO_CONFIG_DISABLED) | 565 | if (r->mode == TOMOYO_CONFIG_DISABLED) |
568 | return 0; | 566 | return 0; |
569 | r->param_type = TOMOYO_TYPE_PATH_ACL; | 567 | r->param_type = TOMOYO_TYPE_PATH_ACL; |
570 | r->param.path.filename = filename; | 568 | r->param.path.filename = filename; |
571 | r->param.path.operation = operation; | 569 | r->param.path.operation = operation; |
572 | do { | 570 | do { |
573 | tomoyo_check_acl(r, tomoyo_check_path_acl); | 571 | tomoyo_check_acl(r, tomoyo_check_path_acl); |
574 | error = tomoyo_audit_path_log(r); | 572 | error = tomoyo_audit_path_log(r); |
575 | /* | 573 | /* |
576 | * Do not retry for execute request, for alias may have | 574 | * Do not retry for execute request, for alias may have |
577 | * changed. | 575 | * changed. |
578 | */ | 576 | */ |
579 | } while (error == TOMOYO_RETRY_REQUEST && | 577 | } while (error == TOMOYO_RETRY_REQUEST && |
580 | operation != TOMOYO_TYPE_EXECUTE); | 578 | operation != TOMOYO_TYPE_EXECUTE); |
581 | return error; | 579 | return error; |
582 | } | 580 | } |
583 | 581 | ||
584 | /** | 582 | /** |
585 | * tomoyo_same_path_number_acl - Check for duplicated "struct tomoyo_path_number_acl" entry. | 583 | * tomoyo_same_path_number_acl - Check for duplicated "struct tomoyo_path_number_acl" entry. |
586 | * | 584 | * |
587 | * @a: Pointer to "struct tomoyo_acl_info". | 585 | * @a: Pointer to "struct tomoyo_acl_info". |
588 | * @b: Pointer to "struct tomoyo_acl_info". | 586 | * @b: Pointer to "struct tomoyo_acl_info". |
589 | * | 587 | * |
590 | * Returns true if @a == @b except permission bits, false otherwise. | 588 | * Returns true if @a == @b except permission bits, false otherwise. |
591 | */ | 589 | */ |
592 | static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a, | 590 | static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a, |
593 | const struct tomoyo_acl_info *b) | 591 | const struct tomoyo_acl_info *b) |
594 | { | 592 | { |
595 | const struct tomoyo_path_number_acl *p1 = container_of(a, typeof(*p1), | 593 | const struct tomoyo_path_number_acl *p1 = container_of(a, typeof(*p1), |
596 | head); | 594 | head); |
597 | const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2), | 595 | const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2), |
598 | head); | 596 | head); |
599 | return tomoyo_same_name_union(&p1->name, &p2->name) && | 597 | return tomoyo_same_name_union(&p1->name, &p2->name) && |
600 | tomoyo_same_number_union(&p1->number, &p2->number); | 598 | tomoyo_same_number_union(&p1->number, &p2->number); |
601 | } | 599 | } |
602 | 600 | ||
603 | /** | 601 | /** |
604 | * tomoyo_merge_path_number_acl - Merge duplicated "struct tomoyo_path_number_acl" entry. | 602 | * tomoyo_merge_path_number_acl - Merge duplicated "struct tomoyo_path_number_acl" entry. |
605 | * | 603 | * |
606 | * @a: Pointer to "struct tomoyo_acl_info". | 604 | * @a: Pointer to "struct tomoyo_acl_info". |
607 | * @b: Pointer to "struct tomoyo_acl_info". | 605 | * @b: Pointer to "struct tomoyo_acl_info". |
608 | * @is_delete: True for @a &= ~@b, false for @a |= @b. | 606 | * @is_delete: True for @a &= ~@b, false for @a |= @b. |
609 | * | 607 | * |
610 | * Returns true if @a is empty, false otherwise. | 608 | * Returns true if @a is empty, false otherwise. |
611 | */ | 609 | */ |
612 | static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a, | 610 | static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a, |
613 | struct tomoyo_acl_info *b, | 611 | struct tomoyo_acl_info *b, |
614 | const bool is_delete) | 612 | const bool is_delete) |
615 | { | 613 | { |
616 | u8 * const a_perm = &container_of(a, struct tomoyo_path_number_acl, | 614 | u8 * const a_perm = &container_of(a, struct tomoyo_path_number_acl, |
617 | head)->perm; | 615 | head)->perm; |
618 | u8 perm = *a_perm; | 616 | u8 perm = *a_perm; |
619 | const u8 b_perm = container_of(b, struct tomoyo_path_number_acl, head) | 617 | const u8 b_perm = container_of(b, struct tomoyo_path_number_acl, head) |
620 | ->perm; | 618 | ->perm; |
621 | if (is_delete) | 619 | if (is_delete) |
622 | perm &= ~b_perm; | 620 | perm &= ~b_perm; |
623 | else | 621 | else |
624 | perm |= b_perm; | 622 | perm |= b_perm; |
625 | *a_perm = perm; | 623 | *a_perm = perm; |
626 | return !perm; | 624 | return !perm; |
627 | } | 625 | } |
628 | 626 | ||
629 | /** | 627 | /** |
630 | * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL. | 628 | * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL. |
631 | * | 629 | * |
632 | * @perm: Permission. | 630 | * @perm: Permission. |
633 | * @param: Pointer to "struct tomoyo_acl_param". | 631 | * @param: Pointer to "struct tomoyo_acl_param". |
634 | * | 632 | * |
635 | * Returns 0 on success, negative value otherwise. | 633 | * Returns 0 on success, negative value otherwise. |
636 | */ | 634 | */ |
637 | static int tomoyo_update_path_number_acl(const u8 perm, | 635 | static int tomoyo_update_path_number_acl(const u8 perm, |
638 | struct tomoyo_acl_param *param) | 636 | struct tomoyo_acl_param *param) |
639 | { | 637 | { |
640 | struct tomoyo_path_number_acl e = { | 638 | struct tomoyo_path_number_acl e = { |
641 | .head.type = TOMOYO_TYPE_PATH_NUMBER_ACL, | 639 | .head.type = TOMOYO_TYPE_PATH_NUMBER_ACL, |
642 | .perm = perm | 640 | .perm = perm |
643 | }; | 641 | }; |
644 | int error; | 642 | int error; |
645 | if (!tomoyo_parse_name_union(param, &e.name) || | 643 | if (!tomoyo_parse_name_union(param, &e.name) || |
646 | !tomoyo_parse_number_union(param, &e.number)) | 644 | !tomoyo_parse_number_union(param, &e.number)) |
647 | error = -EINVAL; | 645 | error = -EINVAL; |
648 | else | 646 | else |
649 | error = tomoyo_update_domain(&e.head, sizeof(e), param, | 647 | error = tomoyo_update_domain(&e.head, sizeof(e), param, |
650 | tomoyo_same_path_number_acl, | 648 | tomoyo_same_path_number_acl, |
651 | tomoyo_merge_path_number_acl); | 649 | tomoyo_merge_path_number_acl); |
652 | tomoyo_put_name_union(&e.name); | 650 | tomoyo_put_name_union(&e.name); |
653 | tomoyo_put_number_union(&e.number); | 651 | tomoyo_put_number_union(&e.number); |
654 | return error; | 652 | return error; |
655 | } | 653 | } |
656 | 654 | ||
657 | /** | 655 | /** |
658 | * tomoyo_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp". | 656 | * tomoyo_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp". |
659 | * | 657 | * |
660 | * @type: Type of operation. | 658 | * @type: Type of operation. |
661 | * @path: Pointer to "struct path". | 659 | * @path: Pointer to "struct path". |
662 | * @number: Number. | 660 | * @number: Number. |
663 | * | 661 | * |
664 | * Returns 0 on success, negative value otherwise. | 662 | * Returns 0 on success, negative value otherwise. |
665 | */ | 663 | */ |
666 | int tomoyo_path_number_perm(const u8 type, struct path *path, | 664 | int tomoyo_path_number_perm(const u8 type, struct path *path, |
667 | unsigned long number) | 665 | unsigned long number) |
668 | { | 666 | { |
669 | struct tomoyo_request_info r; | 667 | struct tomoyo_request_info r; |
670 | struct tomoyo_obj_info obj = { | 668 | struct tomoyo_obj_info obj = { |
671 | .path1 = *path, | 669 | .path1 = *path, |
672 | }; | 670 | }; |
673 | int error = -ENOMEM; | 671 | int error = -ENOMEM; |
674 | struct tomoyo_path_info buf; | 672 | struct tomoyo_path_info buf; |
675 | int idx; | 673 | int idx; |
676 | 674 | ||
677 | if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type]) | 675 | if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type]) |
678 | == TOMOYO_CONFIG_DISABLED || !path->dentry) | 676 | == TOMOYO_CONFIG_DISABLED || !path->dentry) |
679 | return 0; | 677 | return 0; |
680 | idx = tomoyo_read_lock(); | 678 | idx = tomoyo_read_lock(); |
681 | if (!tomoyo_get_realpath(&buf, path)) | 679 | if (!tomoyo_get_realpath(&buf, path)) |
682 | goto out; | 680 | goto out; |
683 | r.obj = &obj; | 681 | r.obj = &obj; |
684 | if (type == TOMOYO_TYPE_MKDIR) | 682 | if (type == TOMOYO_TYPE_MKDIR) |
685 | tomoyo_add_slash(&buf); | 683 | tomoyo_add_slash(&buf); |
686 | r.param_type = TOMOYO_TYPE_PATH_NUMBER_ACL; | 684 | r.param_type = TOMOYO_TYPE_PATH_NUMBER_ACL; |
687 | r.param.path_number.operation = type; | 685 | r.param.path_number.operation = type; |
688 | r.param.path_number.filename = &buf; | 686 | r.param.path_number.filename = &buf; |
689 | r.param.path_number.number = number; | 687 | r.param.path_number.number = number; |
690 | do { | 688 | do { |
691 | tomoyo_check_acl(&r, tomoyo_check_path_number_acl); | 689 | tomoyo_check_acl(&r, tomoyo_check_path_number_acl); |
692 | error = tomoyo_audit_path_number_log(&r); | 690 | error = tomoyo_audit_path_number_log(&r); |
693 | } while (error == TOMOYO_RETRY_REQUEST); | 691 | } while (error == TOMOYO_RETRY_REQUEST); |
694 | kfree(buf.name); | 692 | kfree(buf.name); |
695 | out: | 693 | out: |
696 | tomoyo_read_unlock(idx); | 694 | tomoyo_read_unlock(idx); |
697 | if (r.mode != TOMOYO_CONFIG_ENFORCING) | 695 | if (r.mode != TOMOYO_CONFIG_ENFORCING) |
698 | error = 0; | 696 | error = 0; |
699 | return error; | 697 | return error; |
700 | } | 698 | } |
701 | 699 | ||
702 | /** | 700 | /** |
703 | * tomoyo_check_open_permission - Check permission for "read" and "write". | 701 | * tomoyo_check_open_permission - Check permission for "read" and "write". |
704 | * | 702 | * |
705 | * @domain: Pointer to "struct tomoyo_domain_info". | 703 | * @domain: Pointer to "struct tomoyo_domain_info". |
706 | * @path: Pointer to "struct path". | 704 | * @path: Pointer to "struct path". |
707 | * @flag: Flags for open(). | 705 | * @flag: Flags for open(). |
708 | * | 706 | * |
709 | * Returns 0 on success, negative value otherwise. | 707 | * Returns 0 on success, negative value otherwise. |
710 | */ | 708 | */ |
711 | int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | 709 | int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, |
712 | struct path *path, const int flag) | 710 | struct path *path, const int flag) |
713 | { | 711 | { |
714 | const u8 acc_mode = ACC_MODE(flag); | 712 | const u8 acc_mode = ACC_MODE(flag); |
715 | int error = 0; | 713 | int error = 0; |
716 | struct tomoyo_path_info buf; | 714 | struct tomoyo_path_info buf; |
717 | struct tomoyo_request_info r; | 715 | struct tomoyo_request_info r; |
718 | struct tomoyo_obj_info obj = { | 716 | struct tomoyo_obj_info obj = { |
719 | .path1 = *path, | 717 | .path1 = *path, |
720 | }; | 718 | }; |
721 | int idx; | 719 | int idx; |
722 | 720 | ||
723 | buf.name = NULL; | 721 | buf.name = NULL; |
724 | r.mode = TOMOYO_CONFIG_DISABLED; | 722 | r.mode = TOMOYO_CONFIG_DISABLED; |
725 | idx = tomoyo_read_lock(); | 723 | idx = tomoyo_read_lock(); |
726 | if (acc_mode && | 724 | if (acc_mode && |
727 | tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN) | 725 | tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN) |
728 | != TOMOYO_CONFIG_DISABLED) { | 726 | != TOMOYO_CONFIG_DISABLED) { |
729 | if (!tomoyo_get_realpath(&buf, path)) { | 727 | if (!tomoyo_get_realpath(&buf, path)) { |
730 | error = -ENOMEM; | 728 | error = -ENOMEM; |
731 | goto out; | 729 | goto out; |
732 | } | 730 | } |
733 | r.obj = &obj; | 731 | r.obj = &obj; |
734 | if (acc_mode & MAY_READ) | 732 | if (acc_mode & MAY_READ) |
735 | error = tomoyo_path_permission(&r, TOMOYO_TYPE_READ, | 733 | error = tomoyo_path_permission(&r, TOMOYO_TYPE_READ, |
736 | &buf); | 734 | &buf); |
737 | if (!error && (acc_mode & MAY_WRITE)) | 735 | if (!error && (acc_mode & MAY_WRITE)) |
738 | error = tomoyo_path_permission(&r, (flag & O_APPEND) ? | 736 | error = tomoyo_path_permission(&r, (flag & O_APPEND) ? |
739 | TOMOYO_TYPE_APPEND : | 737 | TOMOYO_TYPE_APPEND : |
740 | TOMOYO_TYPE_WRITE, | 738 | TOMOYO_TYPE_WRITE, |
741 | &buf); | 739 | &buf); |
742 | } | 740 | } |
743 | out: | 741 | out: |
744 | kfree(buf.name); | 742 | kfree(buf.name); |
745 | tomoyo_read_unlock(idx); | 743 | tomoyo_read_unlock(idx); |
746 | if (r.mode != TOMOYO_CONFIG_ENFORCING) | 744 | if (r.mode != TOMOYO_CONFIG_ENFORCING) |
747 | error = 0; | 745 | error = 0; |
748 | return error; | 746 | return error; |
749 | } | 747 | } |
750 | 748 | ||
751 | /** | 749 | /** |
752 | * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "append", "chroot" and "unmount". | 750 | * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "append", "chroot" and "unmount". |
753 | * | 751 | * |
754 | * @operation: Type of operation. | 752 | * @operation: Type of operation. |
755 | * @path: Pointer to "struct path". | 753 | * @path: Pointer to "struct path". |
756 | * @target: Symlink's target if @operation is TOMOYO_TYPE_SYMLINK, | 754 | * @target: Symlink's target if @operation is TOMOYO_TYPE_SYMLINK, |
757 | * NULL otherwise. | 755 | * NULL otherwise. |
758 | * | 756 | * |
759 | * Returns 0 on success, negative value otherwise. | 757 | * Returns 0 on success, negative value otherwise. |
760 | */ | 758 | */ |
761 | int tomoyo_path_perm(const u8 operation, struct path *path, const char *target) | 759 | int tomoyo_path_perm(const u8 operation, struct path *path, const char *target) |
762 | { | 760 | { |
763 | struct tomoyo_request_info r; | 761 | struct tomoyo_request_info r; |
764 | struct tomoyo_obj_info obj = { | 762 | struct tomoyo_obj_info obj = { |
765 | .path1 = *path, | 763 | .path1 = *path, |
766 | }; | 764 | }; |
767 | int error; | 765 | int error; |
768 | struct tomoyo_path_info buf; | 766 | struct tomoyo_path_info buf; |
769 | bool is_enforce; | 767 | bool is_enforce; |
770 | struct tomoyo_path_info symlink_target; | 768 | struct tomoyo_path_info symlink_target; |
771 | int idx; | 769 | int idx; |
772 | 770 | ||
773 | if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation]) | 771 | if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation]) |
774 | == TOMOYO_CONFIG_DISABLED) | 772 | == TOMOYO_CONFIG_DISABLED) |
775 | return 0; | 773 | return 0; |
776 | is_enforce = (r.mode == TOMOYO_CONFIG_ENFORCING); | 774 | is_enforce = (r.mode == TOMOYO_CONFIG_ENFORCING); |
777 | error = -ENOMEM; | 775 | error = -ENOMEM; |
778 | buf.name = NULL; | 776 | buf.name = NULL; |
779 | idx = tomoyo_read_lock(); | 777 | idx = tomoyo_read_lock(); |
780 | if (!tomoyo_get_realpath(&buf, path)) | 778 | if (!tomoyo_get_realpath(&buf, path)) |
781 | goto out; | 779 | goto out; |
782 | r.obj = &obj; | 780 | r.obj = &obj; |
783 | switch (operation) { | 781 | switch (operation) { |
784 | case TOMOYO_TYPE_RMDIR: | 782 | case TOMOYO_TYPE_RMDIR: |
785 | case TOMOYO_TYPE_CHROOT: | 783 | case TOMOYO_TYPE_CHROOT: |
786 | tomoyo_add_slash(&buf); | 784 | tomoyo_add_slash(&buf); |
787 | break; | 785 | break; |
788 | case TOMOYO_TYPE_SYMLINK: | 786 | case TOMOYO_TYPE_SYMLINK: |
789 | symlink_target.name = tomoyo_encode(target); | 787 | symlink_target.name = tomoyo_encode(target); |
790 | if (!symlink_target.name) | 788 | if (!symlink_target.name) |
791 | goto out; | 789 | goto out; |
792 | tomoyo_fill_path_info(&symlink_target); | 790 | tomoyo_fill_path_info(&symlink_target); |
793 | obj.symlink_target = &symlink_target; | 791 | obj.symlink_target = &symlink_target; |
794 | break; | 792 | break; |
795 | } | 793 | } |
796 | error = tomoyo_path_permission(&r, operation, &buf); | 794 | error = tomoyo_path_permission(&r, operation, &buf); |
797 | if (operation == TOMOYO_TYPE_SYMLINK) | 795 | if (operation == TOMOYO_TYPE_SYMLINK) |
798 | kfree(symlink_target.name); | 796 | kfree(symlink_target.name); |
799 | out: | 797 | out: |
800 | kfree(buf.name); | 798 | kfree(buf.name); |
801 | tomoyo_read_unlock(idx); | 799 | tomoyo_read_unlock(idx); |
802 | if (!is_enforce) | 800 | if (!is_enforce) |
803 | error = 0; | 801 | error = 0; |
804 | return error; | 802 | return error; |
805 | } | 803 | } |
806 | 804 | ||
807 | /** | 805 | /** |
808 | * tomoyo_mkdev_perm - Check permission for "mkblock" and "mkchar". | 806 | * tomoyo_mkdev_perm - Check permission for "mkblock" and "mkchar". |
809 | * | 807 | * |
810 | * @operation: Type of operation. (TOMOYO_TYPE_MKCHAR or TOMOYO_TYPE_MKBLOCK) | 808 | * @operation: Type of operation. (TOMOYO_TYPE_MKCHAR or TOMOYO_TYPE_MKBLOCK) |
811 | * @path: Pointer to "struct path". | 809 | * @path: Pointer to "struct path". |
812 | * @mode: Create mode. | 810 | * @mode: Create mode. |
813 | * @dev: Device number. | 811 | * @dev: Device number. |
814 | * | 812 | * |
815 | * Returns 0 on success, negative value otherwise. | 813 | * Returns 0 on success, negative value otherwise. |
816 | */ | 814 | */ |
817 | int tomoyo_mkdev_perm(const u8 operation, struct path *path, | 815 | int tomoyo_mkdev_perm(const u8 operation, struct path *path, |
818 | const unsigned int mode, unsigned int dev) | 816 | const unsigned int mode, unsigned int dev) |
819 | { | 817 | { |
820 | struct tomoyo_request_info r; | 818 | struct tomoyo_request_info r; |
821 | struct tomoyo_obj_info obj = { | 819 | struct tomoyo_obj_info obj = { |
822 | .path1 = *path, | 820 | .path1 = *path, |
823 | }; | 821 | }; |
824 | int error = -ENOMEM; | 822 | int error = -ENOMEM; |
825 | struct tomoyo_path_info buf; | 823 | struct tomoyo_path_info buf; |
826 | int idx; | 824 | int idx; |
827 | 825 | ||
828 | if (tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation]) | 826 | if (tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation]) |
829 | == TOMOYO_CONFIG_DISABLED) | 827 | == TOMOYO_CONFIG_DISABLED) |
830 | return 0; | 828 | return 0; |
831 | idx = tomoyo_read_lock(); | 829 | idx = tomoyo_read_lock(); |
832 | error = -ENOMEM; | 830 | error = -ENOMEM; |
833 | if (tomoyo_get_realpath(&buf, path)) { | 831 | if (tomoyo_get_realpath(&buf, path)) { |
834 | r.obj = &obj; | 832 | r.obj = &obj; |
835 | dev = new_decode_dev(dev); | 833 | dev = new_decode_dev(dev); |
836 | r.param_type = TOMOYO_TYPE_MKDEV_ACL; | 834 | r.param_type = TOMOYO_TYPE_MKDEV_ACL; |
837 | r.param.mkdev.filename = &buf; | 835 | r.param.mkdev.filename = &buf; |
838 | r.param.mkdev.operation = operation; | 836 | r.param.mkdev.operation = operation; |
839 | r.param.mkdev.mode = mode; | 837 | r.param.mkdev.mode = mode; |
840 | r.param.mkdev.major = MAJOR(dev); | 838 | r.param.mkdev.major = MAJOR(dev); |
841 | r.param.mkdev.minor = MINOR(dev); | 839 | r.param.mkdev.minor = MINOR(dev); |
842 | tomoyo_check_acl(&r, tomoyo_check_mkdev_acl); | 840 | tomoyo_check_acl(&r, tomoyo_check_mkdev_acl); |
843 | error = tomoyo_audit_mkdev_log(&r); | 841 | error = tomoyo_audit_mkdev_log(&r); |
844 | kfree(buf.name); | 842 | kfree(buf.name); |
845 | } | 843 | } |
846 | tomoyo_read_unlock(idx); | 844 | tomoyo_read_unlock(idx); |
847 | if (r.mode != TOMOYO_CONFIG_ENFORCING) | 845 | if (r.mode != TOMOYO_CONFIG_ENFORCING) |
848 | error = 0; | 846 | error = 0; |
849 | return error; | 847 | return error; |
850 | } | 848 | } |
851 | 849 | ||
852 | /** | 850 | /** |
853 | * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root". | 851 | * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root". |
854 | * | 852 | * |
855 | * @operation: Type of operation. | 853 | * @operation: Type of operation. |
856 | * @path1: Pointer to "struct path". | 854 | * @path1: Pointer to "struct path". |
857 | * @path2: Pointer to "struct path". | 855 | * @path2: Pointer to "struct path". |
858 | * | 856 | * |
859 | * Returns 0 on success, negative value otherwise. | 857 | * Returns 0 on success, negative value otherwise. |
860 | */ | 858 | */ |
861 | int tomoyo_path2_perm(const u8 operation, struct path *path1, | 859 | int tomoyo_path2_perm(const u8 operation, struct path *path1, |
862 | struct path *path2) | 860 | struct path *path2) |
863 | { | 861 | { |
864 | int error = -ENOMEM; | 862 | int error = -ENOMEM; |
865 | struct tomoyo_path_info buf1; | 863 | struct tomoyo_path_info buf1; |
866 | struct tomoyo_path_info buf2; | 864 | struct tomoyo_path_info buf2; |
867 | struct tomoyo_request_info r; | 865 | struct tomoyo_request_info r; |
868 | struct tomoyo_obj_info obj = { | 866 | struct tomoyo_obj_info obj = { |
869 | .path1 = *path1, | 867 | .path1 = *path1, |
870 | .path2 = *path2, | 868 | .path2 = *path2, |
871 | }; | 869 | }; |
872 | int idx; | 870 | int idx; |
873 | 871 | ||
874 | if (tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation]) | 872 | if (tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation]) |
875 | == TOMOYO_CONFIG_DISABLED) | 873 | == TOMOYO_CONFIG_DISABLED) |
876 | return 0; | 874 | return 0; |
877 | buf1.name = NULL; | 875 | buf1.name = NULL; |
878 | buf2.name = NULL; | 876 | buf2.name = NULL; |
879 | idx = tomoyo_read_lock(); | 877 | idx = tomoyo_read_lock(); |
880 | if (!tomoyo_get_realpath(&buf1, path1) || | 878 | if (!tomoyo_get_realpath(&buf1, path1) || |
881 | !tomoyo_get_realpath(&buf2, path2)) | 879 | !tomoyo_get_realpath(&buf2, path2)) |
882 | goto out; | 880 | goto out; |
883 | switch (operation) { | 881 | switch (operation) { |
884 | struct dentry *dentry; | 882 | struct dentry *dentry; |
885 | case TOMOYO_TYPE_RENAME: | 883 | case TOMOYO_TYPE_RENAME: |
886 | case TOMOYO_TYPE_LINK: | 884 | case TOMOYO_TYPE_LINK: |
887 | dentry = path1->dentry; | 885 | dentry = path1->dentry; |
888 | if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode)) | 886 | if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode)) |
889 | break; | 887 | break; |
890 | /* fall through */ | 888 | /* fall through */ |
891 | case TOMOYO_TYPE_PIVOT_ROOT: | 889 | case TOMOYO_TYPE_PIVOT_ROOT: |
892 | tomoyo_add_slash(&buf1); | 890 | tomoyo_add_slash(&buf1); |
893 | tomoyo_add_slash(&buf2); | 891 | tomoyo_add_slash(&buf2); |
894 | break; | 892 | break; |
895 | } | 893 | } |
896 | r.obj = &obj; | 894 | r.obj = &obj; |
897 | r.param_type = TOMOYO_TYPE_PATH2_ACL; | 895 | r.param_type = TOMOYO_TYPE_PATH2_ACL; |
898 | r.param.path2.operation = operation; | 896 | r.param.path2.operation = operation; |
899 | r.param.path2.filename1 = &buf1; | 897 | r.param.path2.filename1 = &buf1; |
900 | r.param.path2.filename2 = &buf2; | 898 | r.param.path2.filename2 = &buf2; |
901 | do { | 899 | do { |
902 | tomoyo_check_acl(&r, tomoyo_check_path2_acl); | 900 | tomoyo_check_acl(&r, tomoyo_check_path2_acl); |
903 | error = tomoyo_audit_path2_log(&r); | 901 | error = tomoyo_audit_path2_log(&r); |
904 | } while (error == TOMOYO_RETRY_REQUEST); | 902 | } while (error == TOMOYO_RETRY_REQUEST); |
905 | out: | 903 | out: |
906 | kfree(buf1.name); | 904 | kfree(buf1.name); |
907 | kfree(buf2.name); | 905 | kfree(buf2.name); |
908 | tomoyo_read_unlock(idx); | 906 | tomoyo_read_unlock(idx); |
909 | if (r.mode != TOMOYO_CONFIG_ENFORCING) | 907 | if (r.mode != TOMOYO_CONFIG_ENFORCING) |
910 | error = 0; | 908 | error = 0; |
911 | return error; | 909 | return error; |
912 | } | 910 | } |
913 | 911 | ||
914 | /** | 912 | /** |
915 | * tomoyo_same_mount_acl - Check for duplicated "struct tomoyo_mount_acl" entry. | 913 | * tomoyo_same_mount_acl - Check for duplicated "struct tomoyo_mount_acl" entry. |
916 | * | 914 | * |
917 | * @a: Pointer to "struct tomoyo_acl_info". | 915 | * @a: Pointer to "struct tomoyo_acl_info". |
918 | * @b: Pointer to "struct tomoyo_acl_info". | 916 | * @b: Pointer to "struct tomoyo_acl_info". |
919 | * | 917 | * |
920 | * Returns true if @a == @b, false otherwise. | 918 | * Returns true if @a == @b, false otherwise. |
921 | */ | 919 | */ |
922 | static bool tomoyo_same_mount_acl(const struct tomoyo_acl_info *a, | 920 | static bool tomoyo_same_mount_acl(const struct tomoyo_acl_info *a, |
923 | const struct tomoyo_acl_info *b) | 921 | const struct tomoyo_acl_info *b) |
924 | { | 922 | { |
925 | const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head); | 923 | const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head); |
926 | const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head); | 924 | const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head); |
927 | return tomoyo_same_name_union(&p1->dev_name, &p2->dev_name) && | 925 | return tomoyo_same_name_union(&p1->dev_name, &p2->dev_name) && |
928 | tomoyo_same_name_union(&p1->dir_name, &p2->dir_name) && | 926 | tomoyo_same_name_union(&p1->dir_name, &p2->dir_name) && |
929 | tomoyo_same_name_union(&p1->fs_type, &p2->fs_type) && | 927 | tomoyo_same_name_union(&p1->fs_type, &p2->fs_type) && |
930 | tomoyo_same_number_union(&p1->flags, &p2->flags); | 928 | tomoyo_same_number_union(&p1->flags, &p2->flags); |
931 | } | 929 | } |
932 | 930 | ||
933 | /** | 931 | /** |
934 | * tomoyo_update_mount_acl - Write "struct tomoyo_mount_acl" list. | 932 | * tomoyo_update_mount_acl - Write "struct tomoyo_mount_acl" list. |
935 | * | 933 | * |
936 | * @param: Pointer to "struct tomoyo_acl_param". | 934 | * @param: Pointer to "struct tomoyo_acl_param". |
937 | * | 935 | * |
938 | * Returns 0 on success, negative value otherwise. | 936 | * Returns 0 on success, negative value otherwise. |
939 | * | 937 | * |
940 | * Caller holds tomoyo_read_lock(). | 938 | * Caller holds tomoyo_read_lock(). |
941 | */ | 939 | */ |
942 | static int tomoyo_update_mount_acl(struct tomoyo_acl_param *param) | 940 | static int tomoyo_update_mount_acl(struct tomoyo_acl_param *param) |
943 | { | 941 | { |
944 | struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL }; | 942 | struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL }; |
945 | int error; | 943 | int error; |
946 | if (!tomoyo_parse_name_union(param, &e.dev_name) || | 944 | if (!tomoyo_parse_name_union(param, &e.dev_name) || |
947 | !tomoyo_parse_name_union(param, &e.dir_name) || | 945 | !tomoyo_parse_name_union(param, &e.dir_name) || |
948 | !tomoyo_parse_name_union(param, &e.fs_type) || | 946 | !tomoyo_parse_name_union(param, &e.fs_type) || |
949 | !tomoyo_parse_number_union(param, &e.flags)) | 947 | !tomoyo_parse_number_union(param, &e.flags)) |
950 | error = -EINVAL; | 948 | error = -EINVAL; |
951 | else | 949 | else |
952 | error = tomoyo_update_domain(&e.head, sizeof(e), param, | 950 | error = tomoyo_update_domain(&e.head, sizeof(e), param, |
953 | tomoyo_same_mount_acl, NULL); | 951 | tomoyo_same_mount_acl, NULL); |
954 | tomoyo_put_name_union(&e.dev_name); | 952 | tomoyo_put_name_union(&e.dev_name); |
955 | tomoyo_put_name_union(&e.dir_name); | 953 | tomoyo_put_name_union(&e.dir_name); |
956 | tomoyo_put_name_union(&e.fs_type); | 954 | tomoyo_put_name_union(&e.fs_type); |
957 | tomoyo_put_number_union(&e.flags); | 955 | tomoyo_put_number_union(&e.flags); |
958 | return error; | 956 | return error; |
959 | } | 957 | } |
960 | 958 | ||
961 | /** | 959 | /** |
962 | * tomoyo_write_file - Update file related list. | 960 | * tomoyo_write_file - Update file related list. |
963 | * | 961 | * |
964 | * @param: Pointer to "struct tomoyo_acl_param". | 962 | * @param: Pointer to "struct tomoyo_acl_param". |
965 | * | 963 | * |
966 | * Returns 0 on success, negative value otherwise. | 964 | * Returns 0 on success, negative value otherwise. |
967 | * | 965 | * |
968 | * Caller holds tomoyo_read_lock(). | 966 | * Caller holds tomoyo_read_lock(). |
969 | */ | 967 | */ |
970 | int tomoyo_write_file(struct tomoyo_acl_param *param) | 968 | int tomoyo_write_file(struct tomoyo_acl_param *param) |
971 | { | 969 | { |
972 | u16 perm = 0; | 970 | u16 perm = 0; |
973 | u8 type; | 971 | u8 type; |
974 | const char *operation = tomoyo_read_token(param); | 972 | const char *operation = tomoyo_read_token(param); |
975 | for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) | 973 | for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) |
976 | if (tomoyo_permstr(operation, tomoyo_path_keyword[type])) | 974 | if (tomoyo_permstr(operation, tomoyo_path_keyword[type])) |
977 | perm |= 1 << type; | 975 | perm |= 1 << type; |
978 | if (perm) | 976 | if (perm) |
979 | return tomoyo_update_path_acl(perm, param); | 977 | return tomoyo_update_path_acl(perm, param); |
980 | for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) | 978 | for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) |
981 | if (tomoyo_permstr(operation, | 979 | if (tomoyo_permstr(operation, |
982 | tomoyo_mac_keywords[tomoyo_pp2mac[type]])) | 980 | tomoyo_mac_keywords[tomoyo_pp2mac[type]])) |
983 | perm |= 1 << type; | 981 | perm |= 1 << type; |
984 | if (perm) | 982 | if (perm) |
985 | return tomoyo_update_path2_acl(perm, param); | 983 | return tomoyo_update_path2_acl(perm, param); |
986 | for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) | 984 | for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) |
987 | if (tomoyo_permstr(operation, | 985 | if (tomoyo_permstr(operation, |
988 | tomoyo_mac_keywords[tomoyo_pn2mac[type]])) | 986 | tomoyo_mac_keywords[tomoyo_pn2mac[type]])) |
989 | perm |= 1 << type; | 987 | perm |= 1 << type; |
990 | if (perm) | 988 | if (perm) |
991 | return tomoyo_update_path_number_acl(perm, param); | 989 | return tomoyo_update_path_number_acl(perm, param); |
992 | for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++) | 990 | for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++) |
993 | if (tomoyo_permstr(operation, | 991 | if (tomoyo_permstr(operation, |
994 | tomoyo_mac_keywords[tomoyo_pnnn2mac[type]])) | 992 | tomoyo_mac_keywords[tomoyo_pnnn2mac[type]])) |
995 | perm |= 1 << type; | 993 | perm |= 1 << type; |
996 | if (perm) | 994 | if (perm) |
997 | return tomoyo_update_mkdev_acl(perm, param); | 995 | return tomoyo_update_mkdev_acl(perm, param); |
998 | if (tomoyo_permstr(operation, | 996 | if (tomoyo_permstr(operation, |
999 | tomoyo_mac_keywords[TOMOYO_MAC_FILE_MOUNT])) | 997 | tomoyo_mac_keywords[TOMOYO_MAC_FILE_MOUNT])) |
1000 | return tomoyo_update_mount_acl(param); | 998 | return tomoyo_update_mount_acl(param); |
1001 | return -EINVAL; | 999 | return -EINVAL; |
1002 | } | 1000 | } |
1003 | 1001 |
security/tomoyo/gc.c
1 | /* | 1 | /* |
2 | * security/tomoyo/gc.c | 2 | * security/tomoyo/gc.c |
3 | * | 3 | * |
4 | * Implementation of the Domain-Based Mandatory Access Control. | 4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION |
5 | * | ||
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
7 | * | ||
8 | */ | 5 | */ |
9 | 6 | ||
10 | #include "common.h" | 7 | #include "common.h" |
11 | #include <linux/kthread.h> | 8 | #include <linux/kthread.h> |
12 | #include <linux/slab.h> | 9 | #include <linux/slab.h> |
13 | 10 | ||
14 | /* The list for "struct tomoyo_io_buffer". */ | 11 | /* The list for "struct tomoyo_io_buffer". */ |
15 | static LIST_HEAD(tomoyo_io_buffer_list); | 12 | static LIST_HEAD(tomoyo_io_buffer_list); |
16 | /* Lock for protecting tomoyo_io_buffer_list. */ | 13 | /* Lock for protecting tomoyo_io_buffer_list. */ |
17 | static DEFINE_SPINLOCK(tomoyo_io_buffer_list_lock); | 14 | static DEFINE_SPINLOCK(tomoyo_io_buffer_list_lock); |
18 | 15 | ||
19 | /* Size of an element. */ | 16 | /* Size of an element. */ |
20 | static const u8 tomoyo_element_size[TOMOYO_MAX_POLICY] = { | 17 | static const u8 tomoyo_element_size[TOMOYO_MAX_POLICY] = { |
21 | [TOMOYO_ID_GROUP] = sizeof(struct tomoyo_group), | 18 | [TOMOYO_ID_GROUP] = sizeof(struct tomoyo_group), |
22 | [TOMOYO_ID_PATH_GROUP] = sizeof(struct tomoyo_path_group), | 19 | [TOMOYO_ID_PATH_GROUP] = sizeof(struct tomoyo_path_group), |
23 | [TOMOYO_ID_NUMBER_GROUP] = sizeof(struct tomoyo_number_group), | 20 | [TOMOYO_ID_NUMBER_GROUP] = sizeof(struct tomoyo_number_group), |
24 | [TOMOYO_ID_AGGREGATOR] = sizeof(struct tomoyo_aggregator), | 21 | [TOMOYO_ID_AGGREGATOR] = sizeof(struct tomoyo_aggregator), |
25 | [TOMOYO_ID_TRANSITION_CONTROL] = | 22 | [TOMOYO_ID_TRANSITION_CONTROL] = |
26 | sizeof(struct tomoyo_transition_control), | 23 | sizeof(struct tomoyo_transition_control), |
27 | [TOMOYO_ID_MANAGER] = sizeof(struct tomoyo_manager), | 24 | [TOMOYO_ID_MANAGER] = sizeof(struct tomoyo_manager), |
28 | /* [TOMOYO_ID_CONDITION] = "struct tomoyo_condition"->size, */ | 25 | /* [TOMOYO_ID_CONDITION] = "struct tomoyo_condition"->size, */ |
29 | /* [TOMOYO_ID_NAME] = "struct tomoyo_name"->size, */ | 26 | /* [TOMOYO_ID_NAME] = "struct tomoyo_name"->size, */ |
30 | /* [TOMOYO_ID_ACL] = | 27 | /* [TOMOYO_ID_ACL] = |
31 | tomoyo_acl_size["struct tomoyo_acl_info"->type], */ | 28 | tomoyo_acl_size["struct tomoyo_acl_info"->type], */ |
32 | [TOMOYO_ID_DOMAIN] = sizeof(struct tomoyo_domain_info), | 29 | [TOMOYO_ID_DOMAIN] = sizeof(struct tomoyo_domain_info), |
33 | }; | 30 | }; |
34 | 31 | ||
35 | /* Size of a domain ACL element. */ | 32 | /* Size of a domain ACL element. */ |
36 | static const u8 tomoyo_acl_size[] = { | 33 | static const u8 tomoyo_acl_size[] = { |
37 | [TOMOYO_TYPE_PATH_ACL] = sizeof(struct tomoyo_path_acl), | 34 | [TOMOYO_TYPE_PATH_ACL] = sizeof(struct tomoyo_path_acl), |
38 | [TOMOYO_TYPE_PATH2_ACL] = sizeof(struct tomoyo_path2_acl), | 35 | [TOMOYO_TYPE_PATH2_ACL] = sizeof(struct tomoyo_path2_acl), |
39 | [TOMOYO_TYPE_PATH_NUMBER_ACL] = sizeof(struct tomoyo_path_number_acl), | 36 | [TOMOYO_TYPE_PATH_NUMBER_ACL] = sizeof(struct tomoyo_path_number_acl), |
40 | [TOMOYO_TYPE_MKDEV_ACL] = sizeof(struct tomoyo_mkdev_acl), | 37 | [TOMOYO_TYPE_MKDEV_ACL] = sizeof(struct tomoyo_mkdev_acl), |
41 | [TOMOYO_TYPE_MOUNT_ACL] = sizeof(struct tomoyo_mount_acl), | 38 | [TOMOYO_TYPE_MOUNT_ACL] = sizeof(struct tomoyo_mount_acl), |
42 | }; | 39 | }; |
43 | 40 | ||
44 | /** | 41 | /** |
45 | * tomoyo_struct_used_by_io_buffer - Check whether the list element is used by /sys/kernel/security/tomoyo/ users or not. | 42 | * tomoyo_struct_used_by_io_buffer - Check whether the list element is used by /sys/kernel/security/tomoyo/ users or not. |
46 | * | 43 | * |
47 | * @element: Pointer to "struct list_head". | 44 | * @element: Pointer to "struct list_head". |
48 | * | 45 | * |
49 | * Returns true if @element is used by /sys/kernel/security/tomoyo/ users, | 46 | * Returns true if @element is used by /sys/kernel/security/tomoyo/ users, |
50 | * false otherwise. | 47 | * false otherwise. |
51 | */ | 48 | */ |
52 | static bool tomoyo_struct_used_by_io_buffer(const struct list_head *element) | 49 | static bool tomoyo_struct_used_by_io_buffer(const struct list_head *element) |
53 | { | 50 | { |
54 | struct tomoyo_io_buffer *head; | 51 | struct tomoyo_io_buffer *head; |
55 | bool in_use = false; | 52 | bool in_use = false; |
56 | 53 | ||
57 | spin_lock(&tomoyo_io_buffer_list_lock); | 54 | spin_lock(&tomoyo_io_buffer_list_lock); |
58 | list_for_each_entry(head, &tomoyo_io_buffer_list, list) { | 55 | list_for_each_entry(head, &tomoyo_io_buffer_list, list) { |
59 | head->users++; | 56 | head->users++; |
60 | spin_unlock(&tomoyo_io_buffer_list_lock); | 57 | spin_unlock(&tomoyo_io_buffer_list_lock); |
61 | if (mutex_lock_interruptible(&head->io_sem)) { | 58 | if (mutex_lock_interruptible(&head->io_sem)) { |
62 | in_use = true; | 59 | in_use = true; |
63 | goto out; | 60 | goto out; |
64 | } | 61 | } |
65 | if (head->r.domain == element || head->r.group == element || | 62 | if (head->r.domain == element || head->r.group == element || |
66 | head->r.acl == element || &head->w.domain->list == element) | 63 | head->r.acl == element || &head->w.domain->list == element) |
67 | in_use = true; | 64 | in_use = true; |
68 | mutex_unlock(&head->io_sem); | 65 | mutex_unlock(&head->io_sem); |
69 | out: | 66 | out: |
70 | spin_lock(&tomoyo_io_buffer_list_lock); | 67 | spin_lock(&tomoyo_io_buffer_list_lock); |
71 | head->users--; | 68 | head->users--; |
72 | if (in_use) | 69 | if (in_use) |
73 | break; | 70 | break; |
74 | } | 71 | } |
75 | spin_unlock(&tomoyo_io_buffer_list_lock); | 72 | spin_unlock(&tomoyo_io_buffer_list_lock); |
76 | return in_use; | 73 | return in_use; |
77 | } | 74 | } |
78 | 75 | ||
79 | /** | 76 | /** |
80 | * tomoyo_name_used_by_io_buffer - Check whether the string is used by /sys/kernel/security/tomoyo/ users or not. | 77 | * tomoyo_name_used_by_io_buffer - Check whether the string is used by /sys/kernel/security/tomoyo/ users or not. |
81 | * | 78 | * |
82 | * @string: String to check. | 79 | * @string: String to check. |
83 | * @size: Memory allocated for @string . | 80 | * @size: Memory allocated for @string . |
84 | * | 81 | * |
85 | * Returns true if @string is used by /sys/kernel/security/tomoyo/ users, | 82 | * Returns true if @string is used by /sys/kernel/security/tomoyo/ users, |
86 | * false otherwise. | 83 | * false otherwise. |
87 | */ | 84 | */ |
88 | static bool tomoyo_name_used_by_io_buffer(const char *string, | 85 | static bool tomoyo_name_used_by_io_buffer(const char *string, |
89 | const size_t size) | 86 | const size_t size) |
90 | { | 87 | { |
91 | struct tomoyo_io_buffer *head; | 88 | struct tomoyo_io_buffer *head; |
92 | bool in_use = false; | 89 | bool in_use = false; |
93 | 90 | ||
94 | spin_lock(&tomoyo_io_buffer_list_lock); | 91 | spin_lock(&tomoyo_io_buffer_list_lock); |
95 | list_for_each_entry(head, &tomoyo_io_buffer_list, list) { | 92 | list_for_each_entry(head, &tomoyo_io_buffer_list, list) { |
96 | int i; | 93 | int i; |
97 | head->users++; | 94 | head->users++; |
98 | spin_unlock(&tomoyo_io_buffer_list_lock); | 95 | spin_unlock(&tomoyo_io_buffer_list_lock); |
99 | if (mutex_lock_interruptible(&head->io_sem)) { | 96 | if (mutex_lock_interruptible(&head->io_sem)) { |
100 | in_use = true; | 97 | in_use = true; |
101 | goto out; | 98 | goto out; |
102 | } | 99 | } |
103 | for (i = 0; i < TOMOYO_MAX_IO_READ_QUEUE; i++) { | 100 | for (i = 0; i < TOMOYO_MAX_IO_READ_QUEUE; i++) { |
104 | const char *w = head->r.w[i]; | 101 | const char *w = head->r.w[i]; |
105 | if (w < string || w > string + size) | 102 | if (w < string || w > string + size) |
106 | continue; | 103 | continue; |
107 | in_use = true; | 104 | in_use = true; |
108 | break; | 105 | break; |
109 | } | 106 | } |
110 | mutex_unlock(&head->io_sem); | 107 | mutex_unlock(&head->io_sem); |
111 | out: | 108 | out: |
112 | spin_lock(&tomoyo_io_buffer_list_lock); | 109 | spin_lock(&tomoyo_io_buffer_list_lock); |
113 | head->users--; | 110 | head->users--; |
114 | if (in_use) | 111 | if (in_use) |
115 | break; | 112 | break; |
116 | } | 113 | } |
117 | spin_unlock(&tomoyo_io_buffer_list_lock); | 114 | spin_unlock(&tomoyo_io_buffer_list_lock); |
118 | return in_use; | 115 | return in_use; |
119 | } | 116 | } |
120 | 117 | ||
121 | /* Structure for garbage collection. */ | 118 | /* Structure for garbage collection. */ |
122 | struct tomoyo_gc { | 119 | struct tomoyo_gc { |
123 | struct list_head list; | 120 | struct list_head list; |
124 | enum tomoyo_policy_id type; | 121 | enum tomoyo_policy_id type; |
125 | size_t size; | 122 | size_t size; |
126 | struct list_head *element; | 123 | struct list_head *element; |
127 | }; | 124 | }; |
128 | /* List of entries to be deleted. */ | 125 | /* List of entries to be deleted. */ |
129 | static LIST_HEAD(tomoyo_gc_list); | 126 | static LIST_HEAD(tomoyo_gc_list); |
130 | /* Length of tomoyo_gc_list. */ | 127 | /* Length of tomoyo_gc_list. */ |
131 | static int tomoyo_gc_list_len; | 128 | static int tomoyo_gc_list_len; |
132 | 129 | ||
133 | /** | 130 | /** |
134 | * tomoyo_add_to_gc - Add an entry to to be deleted list. | 131 | * tomoyo_add_to_gc - Add an entry to to be deleted list. |
135 | * | 132 | * |
136 | * @type: One of values in "enum tomoyo_policy_id". | 133 | * @type: One of values in "enum tomoyo_policy_id". |
137 | * @element: Pointer to "struct list_head". | 134 | * @element: Pointer to "struct list_head". |
138 | * | 135 | * |
139 | * Returns true on success, false otherwise. | 136 | * Returns true on success, false otherwise. |
140 | * | 137 | * |
141 | * Caller holds tomoyo_policy_lock mutex. | 138 | * Caller holds tomoyo_policy_lock mutex. |
142 | * | 139 | * |
143 | * Adding an entry needs kmalloc(). Thus, if we try to add thousands of | 140 | * Adding an entry needs kmalloc(). Thus, if we try to add thousands of |
144 | * entries at once, it will take too long time. Thus, do not add more than 128 | 141 | * entries at once, it will take too long time. Thus, do not add more than 128 |
145 | * entries per a scan. But to be able to handle worst case where all entries | 142 | * entries per a scan. But to be able to handle worst case where all entries |
146 | * are in-use, we accept one more entry per a scan. | 143 | * are in-use, we accept one more entry per a scan. |
147 | * | 144 | * |
148 | * If we use singly linked list using "struct list_head"->prev (which is | 145 | * If we use singly linked list using "struct list_head"->prev (which is |
149 | * LIST_POISON2), we can avoid kmalloc(). | 146 | * LIST_POISON2), we can avoid kmalloc(). |
150 | */ | 147 | */ |
151 | static bool tomoyo_add_to_gc(const int type, struct list_head *element) | 148 | static bool tomoyo_add_to_gc(const int type, struct list_head *element) |
152 | { | 149 | { |
153 | struct tomoyo_gc *entry = kzalloc(sizeof(*entry), GFP_ATOMIC); | 150 | struct tomoyo_gc *entry = kzalloc(sizeof(*entry), GFP_ATOMIC); |
154 | if (!entry) | 151 | if (!entry) |
155 | return false; | 152 | return false; |
156 | entry->type = type; | 153 | entry->type = type; |
157 | if (type == TOMOYO_ID_ACL) | 154 | if (type == TOMOYO_ID_ACL) |
158 | entry->size = tomoyo_acl_size[ | 155 | entry->size = tomoyo_acl_size[ |
159 | container_of(element, | 156 | container_of(element, |
160 | typeof(struct tomoyo_acl_info), | 157 | typeof(struct tomoyo_acl_info), |
161 | list)->type]; | 158 | list)->type]; |
162 | else if (type == TOMOYO_ID_NAME) | 159 | else if (type == TOMOYO_ID_NAME) |
163 | entry->size = strlen(container_of(element, | 160 | entry->size = strlen(container_of(element, |
164 | typeof(struct tomoyo_name), | 161 | typeof(struct tomoyo_name), |
165 | head.list)->entry.name) + 1; | 162 | head.list)->entry.name) + 1; |
166 | else if (type == TOMOYO_ID_CONDITION) | 163 | else if (type == TOMOYO_ID_CONDITION) |
167 | entry->size = | 164 | entry->size = |
168 | container_of(element, typeof(struct tomoyo_condition), | 165 | container_of(element, typeof(struct tomoyo_condition), |
169 | head.list)->size; | 166 | head.list)->size; |
170 | else | 167 | else |
171 | entry->size = tomoyo_element_size[type]; | 168 | entry->size = tomoyo_element_size[type]; |
172 | entry->element = element; | 169 | entry->element = element; |
173 | list_add(&entry->list, &tomoyo_gc_list); | 170 | list_add(&entry->list, &tomoyo_gc_list); |
174 | list_del_rcu(element); | 171 | list_del_rcu(element); |
175 | return tomoyo_gc_list_len++ < 128; | 172 | return tomoyo_gc_list_len++ < 128; |
176 | } | 173 | } |
177 | 174 | ||
178 | /** | 175 | /** |
179 | * tomoyo_element_linked_by_gc - Validate next element of an entry. | 176 | * tomoyo_element_linked_by_gc - Validate next element of an entry. |
180 | * | 177 | * |
181 | * @element: Pointer to an element. | 178 | * @element: Pointer to an element. |
182 | * @size: Size of @element in byte. | 179 | * @size: Size of @element in byte. |
183 | * | 180 | * |
184 | * Returns true if @element is linked by other elements in the garbage | 181 | * Returns true if @element is linked by other elements in the garbage |
185 | * collector's queue, false otherwise. | 182 | * collector's queue, false otherwise. |
186 | */ | 183 | */ |
187 | static bool tomoyo_element_linked_by_gc(const u8 *element, const size_t size) | 184 | static bool tomoyo_element_linked_by_gc(const u8 *element, const size_t size) |
188 | { | 185 | { |
189 | struct tomoyo_gc *p; | 186 | struct tomoyo_gc *p; |
190 | list_for_each_entry(p, &tomoyo_gc_list, list) { | 187 | list_for_each_entry(p, &tomoyo_gc_list, list) { |
191 | const u8 *ptr = (const u8 *) p->element->next; | 188 | const u8 *ptr = (const u8 *) p->element->next; |
192 | if (ptr < element || element + size < ptr) | 189 | if (ptr < element || element + size < ptr) |
193 | continue; | 190 | continue; |
194 | return true; | 191 | return true; |
195 | } | 192 | } |
196 | return false; | 193 | return false; |
197 | } | 194 | } |
198 | 195 | ||
199 | /** | 196 | /** |
200 | * tomoyo_del_transition_control - Delete members in "struct tomoyo_transition_control". | 197 | * tomoyo_del_transition_control - Delete members in "struct tomoyo_transition_control". |
201 | * | 198 | * |
202 | * @element: Pointer to "struct list_head". | 199 | * @element: Pointer to "struct list_head". |
203 | * | 200 | * |
204 | * Returns nothing. | 201 | * Returns nothing. |
205 | */ | 202 | */ |
206 | static void tomoyo_del_transition_control(struct list_head *element) | 203 | static void tomoyo_del_transition_control(struct list_head *element) |
207 | { | 204 | { |
208 | struct tomoyo_transition_control *ptr = | 205 | struct tomoyo_transition_control *ptr = |
209 | container_of(element, typeof(*ptr), head.list); | 206 | container_of(element, typeof(*ptr), head.list); |
210 | tomoyo_put_name(ptr->domainname); | 207 | tomoyo_put_name(ptr->domainname); |
211 | tomoyo_put_name(ptr->program); | 208 | tomoyo_put_name(ptr->program); |
212 | } | 209 | } |
213 | 210 | ||
214 | /** | 211 | /** |
215 | * tomoyo_del_aggregator - Delete members in "struct tomoyo_aggregator". | 212 | * tomoyo_del_aggregator - Delete members in "struct tomoyo_aggregator". |
216 | * | 213 | * |
217 | * @element: Pointer to "struct list_head". | 214 | * @element: Pointer to "struct list_head". |
218 | * | 215 | * |
219 | * Returns nothing. | 216 | * Returns nothing. |
220 | */ | 217 | */ |
221 | static void tomoyo_del_aggregator(struct list_head *element) | 218 | static void tomoyo_del_aggregator(struct list_head *element) |
222 | { | 219 | { |
223 | struct tomoyo_aggregator *ptr = | 220 | struct tomoyo_aggregator *ptr = |
224 | container_of(element, typeof(*ptr), head.list); | 221 | container_of(element, typeof(*ptr), head.list); |
225 | tomoyo_put_name(ptr->original_name); | 222 | tomoyo_put_name(ptr->original_name); |
226 | tomoyo_put_name(ptr->aggregated_name); | 223 | tomoyo_put_name(ptr->aggregated_name); |
227 | } | 224 | } |
228 | 225 | ||
229 | /** | 226 | /** |
230 | * tomoyo_del_manager - Delete members in "struct tomoyo_manager". | 227 | * tomoyo_del_manager - Delete members in "struct tomoyo_manager". |
231 | * | 228 | * |
232 | * @element: Pointer to "struct list_head". | 229 | * @element: Pointer to "struct list_head". |
233 | * | 230 | * |
234 | * Returns nothing. | 231 | * Returns nothing. |
235 | */ | 232 | */ |
236 | static void tomoyo_del_manager(struct list_head *element) | 233 | static void tomoyo_del_manager(struct list_head *element) |
237 | { | 234 | { |
238 | struct tomoyo_manager *ptr = | 235 | struct tomoyo_manager *ptr = |
239 | container_of(element, typeof(*ptr), head.list); | 236 | container_of(element, typeof(*ptr), head.list); |
240 | tomoyo_put_name(ptr->manager); | 237 | tomoyo_put_name(ptr->manager); |
241 | } | 238 | } |
242 | 239 | ||
243 | /** | 240 | /** |
244 | * tomoyo_del_acl - Delete members in "struct tomoyo_acl_info". | 241 | * tomoyo_del_acl - Delete members in "struct tomoyo_acl_info". |
245 | * | 242 | * |
246 | * @element: Pointer to "struct list_head". | 243 | * @element: Pointer to "struct list_head". |
247 | * | 244 | * |
248 | * Returns nothing. | 245 | * Returns nothing. |
249 | */ | 246 | */ |
250 | static void tomoyo_del_acl(struct list_head *element) | 247 | static void tomoyo_del_acl(struct list_head *element) |
251 | { | 248 | { |
252 | struct tomoyo_acl_info *acl = | 249 | struct tomoyo_acl_info *acl = |
253 | container_of(element, typeof(*acl), list); | 250 | container_of(element, typeof(*acl), list); |
254 | tomoyo_put_condition(acl->cond); | 251 | tomoyo_put_condition(acl->cond); |
255 | switch (acl->type) { | 252 | switch (acl->type) { |
256 | case TOMOYO_TYPE_PATH_ACL: | 253 | case TOMOYO_TYPE_PATH_ACL: |
257 | { | 254 | { |
258 | struct tomoyo_path_acl *entry | 255 | struct tomoyo_path_acl *entry |
259 | = container_of(acl, typeof(*entry), head); | 256 | = container_of(acl, typeof(*entry), head); |
260 | tomoyo_put_name_union(&entry->name); | 257 | tomoyo_put_name_union(&entry->name); |
261 | } | 258 | } |
262 | break; | 259 | break; |
263 | case TOMOYO_TYPE_PATH2_ACL: | 260 | case TOMOYO_TYPE_PATH2_ACL: |
264 | { | 261 | { |
265 | struct tomoyo_path2_acl *entry | 262 | struct tomoyo_path2_acl *entry |
266 | = container_of(acl, typeof(*entry), head); | 263 | = container_of(acl, typeof(*entry), head); |
267 | tomoyo_put_name_union(&entry->name1); | 264 | tomoyo_put_name_union(&entry->name1); |
268 | tomoyo_put_name_union(&entry->name2); | 265 | tomoyo_put_name_union(&entry->name2); |
269 | } | 266 | } |
270 | break; | 267 | break; |
271 | case TOMOYO_TYPE_PATH_NUMBER_ACL: | 268 | case TOMOYO_TYPE_PATH_NUMBER_ACL: |
272 | { | 269 | { |
273 | struct tomoyo_path_number_acl *entry | 270 | struct tomoyo_path_number_acl *entry |
274 | = container_of(acl, typeof(*entry), head); | 271 | = container_of(acl, typeof(*entry), head); |
275 | tomoyo_put_name_union(&entry->name); | 272 | tomoyo_put_name_union(&entry->name); |
276 | tomoyo_put_number_union(&entry->number); | 273 | tomoyo_put_number_union(&entry->number); |
277 | } | 274 | } |
278 | break; | 275 | break; |
279 | case TOMOYO_TYPE_MKDEV_ACL: | 276 | case TOMOYO_TYPE_MKDEV_ACL: |
280 | { | 277 | { |
281 | struct tomoyo_mkdev_acl *entry | 278 | struct tomoyo_mkdev_acl *entry |
282 | = container_of(acl, typeof(*entry), head); | 279 | = container_of(acl, typeof(*entry), head); |
283 | tomoyo_put_name_union(&entry->name); | 280 | tomoyo_put_name_union(&entry->name); |
284 | tomoyo_put_number_union(&entry->mode); | 281 | tomoyo_put_number_union(&entry->mode); |
285 | tomoyo_put_number_union(&entry->major); | 282 | tomoyo_put_number_union(&entry->major); |
286 | tomoyo_put_number_union(&entry->minor); | 283 | tomoyo_put_number_union(&entry->minor); |
287 | } | 284 | } |
288 | break; | 285 | break; |
289 | case TOMOYO_TYPE_MOUNT_ACL: | 286 | case TOMOYO_TYPE_MOUNT_ACL: |
290 | { | 287 | { |
291 | struct tomoyo_mount_acl *entry | 288 | struct tomoyo_mount_acl *entry |
292 | = container_of(acl, typeof(*entry), head); | 289 | = container_of(acl, typeof(*entry), head); |
293 | tomoyo_put_name_union(&entry->dev_name); | 290 | tomoyo_put_name_union(&entry->dev_name); |
294 | tomoyo_put_name_union(&entry->dir_name); | 291 | tomoyo_put_name_union(&entry->dir_name); |
295 | tomoyo_put_name_union(&entry->fs_type); | 292 | tomoyo_put_name_union(&entry->fs_type); |
296 | tomoyo_put_number_union(&entry->flags); | 293 | tomoyo_put_number_union(&entry->flags); |
297 | } | 294 | } |
298 | break; | 295 | break; |
299 | } | 296 | } |
300 | } | 297 | } |
301 | 298 | ||
302 | /** | 299 | /** |
303 | * tomoyo_del_domain - Delete members in "struct tomoyo_domain_info". | 300 | * tomoyo_del_domain - Delete members in "struct tomoyo_domain_info". |
304 | * | 301 | * |
305 | * @element: Pointer to "struct list_head". | 302 | * @element: Pointer to "struct list_head". |
306 | * | 303 | * |
307 | * Returns true if deleted, false otherwise. | 304 | * Returns true if deleted, false otherwise. |
308 | */ | 305 | */ |
309 | static bool tomoyo_del_domain(struct list_head *element) | 306 | static bool tomoyo_del_domain(struct list_head *element) |
310 | { | 307 | { |
311 | struct tomoyo_domain_info *domain = | 308 | struct tomoyo_domain_info *domain = |
312 | container_of(element, typeof(*domain), list); | 309 | container_of(element, typeof(*domain), list); |
313 | struct tomoyo_acl_info *acl; | 310 | struct tomoyo_acl_info *acl; |
314 | struct tomoyo_acl_info *tmp; | 311 | struct tomoyo_acl_info *tmp; |
315 | /* | 312 | /* |
316 | * Since we don't protect whole execve() operation using SRCU, | 313 | * Since we don't protect whole execve() operation using SRCU, |
317 | * we need to recheck domain->users at this point. | 314 | * we need to recheck domain->users at this point. |
318 | * | 315 | * |
319 | * (1) Reader starts SRCU section upon execve(). | 316 | * (1) Reader starts SRCU section upon execve(). |
320 | * (2) Reader traverses tomoyo_domain_list and finds this domain. | 317 | * (2) Reader traverses tomoyo_domain_list and finds this domain. |
321 | * (3) Writer marks this domain as deleted. | 318 | * (3) Writer marks this domain as deleted. |
322 | * (4) Garbage collector removes this domain from tomoyo_domain_list | 319 | * (4) Garbage collector removes this domain from tomoyo_domain_list |
323 | * because this domain is marked as deleted and used by nobody. | 320 | * because this domain is marked as deleted and used by nobody. |
324 | * (5) Reader saves reference to this domain into | 321 | * (5) Reader saves reference to this domain into |
325 | * "struct linux_binprm"->cred->security . | 322 | * "struct linux_binprm"->cred->security . |
326 | * (6) Reader finishes SRCU section, although execve() operation has | 323 | * (6) Reader finishes SRCU section, although execve() operation has |
327 | * not finished yet. | 324 | * not finished yet. |
328 | * (7) Garbage collector waits for SRCU synchronization. | 325 | * (7) Garbage collector waits for SRCU synchronization. |
329 | * (8) Garbage collector kfree() this domain because this domain is | 326 | * (8) Garbage collector kfree() this domain because this domain is |
330 | * used by nobody. | 327 | * used by nobody. |
331 | * (9) Reader finishes execve() operation and restores this domain from | 328 | * (9) Reader finishes execve() operation and restores this domain from |
332 | * "struct linux_binprm"->cred->security. | 329 | * "struct linux_binprm"->cred->security. |
333 | * | 330 | * |
334 | * By updating domain->users at (5), we can solve this race problem | 331 | * By updating domain->users at (5), we can solve this race problem |
335 | * by rechecking domain->users at (8). | 332 | * by rechecking domain->users at (8). |
336 | */ | 333 | */ |
337 | if (atomic_read(&domain->users)) | 334 | if (atomic_read(&domain->users)) |
338 | return false; | 335 | return false; |
339 | list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) { | 336 | list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) { |
340 | tomoyo_del_acl(&acl->list); | 337 | tomoyo_del_acl(&acl->list); |
341 | tomoyo_memory_free(acl); | 338 | tomoyo_memory_free(acl); |
342 | } | 339 | } |
343 | tomoyo_put_name(domain->domainname); | 340 | tomoyo_put_name(domain->domainname); |
344 | return true; | 341 | return true; |
345 | } | 342 | } |
346 | 343 | ||
347 | /** | 344 | /** |
348 | * tomoyo_del_condition - Delete members in "struct tomoyo_condition". | 345 | * tomoyo_del_condition - Delete members in "struct tomoyo_condition". |
349 | * | 346 | * |
350 | * @element: Pointer to "struct list_head". | 347 | * @element: Pointer to "struct list_head". |
351 | * | 348 | * |
352 | * Returns nothing. | 349 | * Returns nothing. |
353 | */ | 350 | */ |
354 | void tomoyo_del_condition(struct list_head *element) | 351 | void tomoyo_del_condition(struct list_head *element) |
355 | { | 352 | { |
356 | struct tomoyo_condition *cond = container_of(element, typeof(*cond), | 353 | struct tomoyo_condition *cond = container_of(element, typeof(*cond), |
357 | head.list); | 354 | head.list); |
358 | const u16 condc = cond->condc; | 355 | const u16 condc = cond->condc; |
359 | const u16 numbers_count = cond->numbers_count; | 356 | const u16 numbers_count = cond->numbers_count; |
360 | const u16 names_count = cond->names_count; | 357 | const u16 names_count = cond->names_count; |
361 | const u16 argc = cond->argc; | 358 | const u16 argc = cond->argc; |
362 | const u16 envc = cond->envc; | 359 | const u16 envc = cond->envc; |
363 | unsigned int i; | 360 | unsigned int i; |
364 | const struct tomoyo_condition_element *condp | 361 | const struct tomoyo_condition_element *condp |
365 | = (const struct tomoyo_condition_element *) (cond + 1); | 362 | = (const struct tomoyo_condition_element *) (cond + 1); |
366 | struct tomoyo_number_union *numbers_p | 363 | struct tomoyo_number_union *numbers_p |
367 | = (struct tomoyo_number_union *) (condp + condc); | 364 | = (struct tomoyo_number_union *) (condp + condc); |
368 | struct tomoyo_name_union *names_p | 365 | struct tomoyo_name_union *names_p |
369 | = (struct tomoyo_name_union *) (numbers_p + numbers_count); | 366 | = (struct tomoyo_name_union *) (numbers_p + numbers_count); |
370 | const struct tomoyo_argv *argv | 367 | const struct tomoyo_argv *argv |
371 | = (const struct tomoyo_argv *) (names_p + names_count); | 368 | = (const struct tomoyo_argv *) (names_p + names_count); |
372 | const struct tomoyo_envp *envp | 369 | const struct tomoyo_envp *envp |
373 | = (const struct tomoyo_envp *) (argv + argc); | 370 | = (const struct tomoyo_envp *) (argv + argc); |
374 | for (i = 0; i < numbers_count; i++) | 371 | for (i = 0; i < numbers_count; i++) |
375 | tomoyo_put_number_union(numbers_p++); | 372 | tomoyo_put_number_union(numbers_p++); |
376 | for (i = 0; i < names_count; i++) | 373 | for (i = 0; i < names_count; i++) |
377 | tomoyo_put_name_union(names_p++); | 374 | tomoyo_put_name_union(names_p++); |
378 | for (i = 0; i < argc; argv++, i++) | 375 | for (i = 0; i < argc; argv++, i++) |
379 | tomoyo_put_name(argv->value); | 376 | tomoyo_put_name(argv->value); |
380 | for (i = 0; i < envc; envp++, i++) { | 377 | for (i = 0; i < envc; envp++, i++) { |
381 | tomoyo_put_name(envp->name); | 378 | tomoyo_put_name(envp->name); |
382 | tomoyo_put_name(envp->value); | 379 | tomoyo_put_name(envp->value); |
383 | } | 380 | } |
384 | } | 381 | } |
385 | 382 | ||
386 | /** | 383 | /** |
387 | * tomoyo_del_name - Delete members in "struct tomoyo_name". | 384 | * tomoyo_del_name - Delete members in "struct tomoyo_name". |
388 | * | 385 | * |
389 | * @element: Pointer to "struct list_head". | 386 | * @element: Pointer to "struct list_head". |
390 | * | 387 | * |
391 | * Returns nothing. | 388 | * Returns nothing. |
392 | */ | 389 | */ |
393 | static void tomoyo_del_name(struct list_head *element) | 390 | static void tomoyo_del_name(struct list_head *element) |
394 | { | 391 | { |
395 | const struct tomoyo_name *ptr = | 392 | const struct tomoyo_name *ptr = |
396 | container_of(element, typeof(*ptr), head.list); | 393 | container_of(element, typeof(*ptr), head.list); |
397 | } | 394 | } |
398 | 395 | ||
399 | /** | 396 | /** |
400 | * tomoyo_del_path_group - Delete members in "struct tomoyo_path_group". | 397 | * tomoyo_del_path_group - Delete members in "struct tomoyo_path_group". |
401 | * | 398 | * |
402 | * @element: Pointer to "struct list_head". | 399 | * @element: Pointer to "struct list_head". |
403 | * | 400 | * |
404 | * Returns nothing. | 401 | * Returns nothing. |
405 | */ | 402 | */ |
406 | static void tomoyo_del_path_group(struct list_head *element) | 403 | static void tomoyo_del_path_group(struct list_head *element) |
407 | { | 404 | { |
408 | struct tomoyo_path_group *member = | 405 | struct tomoyo_path_group *member = |
409 | container_of(element, typeof(*member), head.list); | 406 | container_of(element, typeof(*member), head.list); |
410 | tomoyo_put_name(member->member_name); | 407 | tomoyo_put_name(member->member_name); |
411 | } | 408 | } |
412 | 409 | ||
413 | /** | 410 | /** |
414 | * tomoyo_del_group - Delete "struct tomoyo_group". | 411 | * tomoyo_del_group - Delete "struct tomoyo_group". |
415 | * | 412 | * |
416 | * @element: Pointer to "struct list_head". | 413 | * @element: Pointer to "struct list_head". |
417 | * | 414 | * |
418 | * Returns nothing. | 415 | * Returns nothing. |
419 | */ | 416 | */ |
420 | static void tomoyo_del_group(struct list_head *element) | 417 | static void tomoyo_del_group(struct list_head *element) |
421 | { | 418 | { |
422 | struct tomoyo_group *group = | 419 | struct tomoyo_group *group = |
423 | container_of(element, typeof(*group), head.list); | 420 | container_of(element, typeof(*group), head.list); |
424 | tomoyo_put_name(group->group_name); | 421 | tomoyo_put_name(group->group_name); |
425 | } | 422 | } |
426 | 423 | ||
427 | /** | 424 | /** |
428 | * tomoyo_del_number_group - Delete members in "struct tomoyo_number_group". | 425 | * tomoyo_del_number_group - Delete members in "struct tomoyo_number_group". |
429 | * | 426 | * |
430 | * @element: Pointer to "struct list_head". | 427 | * @element: Pointer to "struct list_head". |
431 | * | 428 | * |
432 | * Returns nothing. | 429 | * Returns nothing. |
433 | */ | 430 | */ |
434 | static void tomoyo_del_number_group(struct list_head *element) | 431 | static void tomoyo_del_number_group(struct list_head *element) |
435 | { | 432 | { |
436 | struct tomoyo_number_group *member = | 433 | struct tomoyo_number_group *member = |
437 | container_of(element, typeof(*member), head.list); | 434 | container_of(element, typeof(*member), head.list); |
438 | } | 435 | } |
439 | 436 | ||
440 | /** | 437 | /** |
441 | * tomoyo_collect_member - Delete elements with "struct tomoyo_acl_head". | 438 | * tomoyo_collect_member - Delete elements with "struct tomoyo_acl_head". |
442 | * | 439 | * |
443 | * @id: One of values in "enum tomoyo_policy_id". | 440 | * @id: One of values in "enum tomoyo_policy_id". |
444 | * @member_list: Pointer to "struct list_head". | 441 | * @member_list: Pointer to "struct list_head". |
445 | * | 442 | * |
446 | * Returns true if some elements are deleted, false otherwise. | 443 | * Returns true if some elements are deleted, false otherwise. |
447 | */ | 444 | */ |
448 | static bool tomoyo_collect_member(const enum tomoyo_policy_id id, | 445 | static bool tomoyo_collect_member(const enum tomoyo_policy_id id, |
449 | struct list_head *member_list) | 446 | struct list_head *member_list) |
450 | { | 447 | { |
451 | struct tomoyo_acl_head *member; | 448 | struct tomoyo_acl_head *member; |
452 | list_for_each_entry(member, member_list, list) { | 449 | list_for_each_entry(member, member_list, list) { |
453 | if (!member->is_deleted) | 450 | if (!member->is_deleted) |
454 | continue; | 451 | continue; |
455 | if (!tomoyo_add_to_gc(id, &member->list)) | 452 | if (!tomoyo_add_to_gc(id, &member->list)) |
456 | return false; | 453 | return false; |
457 | } | 454 | } |
458 | return true; | 455 | return true; |
459 | } | 456 | } |
460 | 457 | ||
461 | /** | 458 | /** |
462 | * tomoyo_collect_acl - Delete elements in "struct tomoyo_domain_info". | 459 | * tomoyo_collect_acl - Delete elements in "struct tomoyo_domain_info". |
463 | * | 460 | * |
464 | * @list: Pointer to "struct list_head". | 461 | * @list: Pointer to "struct list_head". |
465 | * | 462 | * |
466 | * Returns true if some elements are deleted, false otherwise. | 463 | * Returns true if some elements are deleted, false otherwise. |
467 | */ | 464 | */ |
468 | static bool tomoyo_collect_acl(struct list_head *list) | 465 | static bool tomoyo_collect_acl(struct list_head *list) |
469 | { | 466 | { |
470 | struct tomoyo_acl_info *acl; | 467 | struct tomoyo_acl_info *acl; |
471 | list_for_each_entry(acl, list, list) { | 468 | list_for_each_entry(acl, list, list) { |
472 | if (!acl->is_deleted) | 469 | if (!acl->is_deleted) |
473 | continue; | 470 | continue; |
474 | if (!tomoyo_add_to_gc(TOMOYO_ID_ACL, &acl->list)) | 471 | if (!tomoyo_add_to_gc(TOMOYO_ID_ACL, &acl->list)) |
475 | return false; | 472 | return false; |
476 | } | 473 | } |
477 | return true; | 474 | return true; |
478 | } | 475 | } |
479 | 476 | ||
480 | /** | 477 | /** |
481 | * tomoyo_collect_entry - Scan lists for deleted elements. | 478 | * tomoyo_collect_entry - Scan lists for deleted elements. |
482 | * | 479 | * |
483 | * Returns nothing. | 480 | * Returns nothing. |
484 | */ | 481 | */ |
485 | static void tomoyo_collect_entry(void) | 482 | static void tomoyo_collect_entry(void) |
486 | { | 483 | { |
487 | int i; | 484 | int i; |
488 | enum tomoyo_policy_id id; | 485 | enum tomoyo_policy_id id; |
489 | struct tomoyo_policy_namespace *ns; | 486 | struct tomoyo_policy_namespace *ns; |
490 | int idx; | 487 | int idx; |
491 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 488 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
492 | return; | 489 | return; |
493 | idx = tomoyo_read_lock(); | 490 | idx = tomoyo_read_lock(); |
494 | { | 491 | { |
495 | struct tomoyo_domain_info *domain; | 492 | struct tomoyo_domain_info *domain; |
496 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { | 493 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { |
497 | if (!tomoyo_collect_acl(&domain->acl_info_list)) | 494 | if (!tomoyo_collect_acl(&domain->acl_info_list)) |
498 | goto unlock; | 495 | goto unlock; |
499 | if (!domain->is_deleted || atomic_read(&domain->users)) | 496 | if (!domain->is_deleted || atomic_read(&domain->users)) |
500 | continue; | 497 | continue; |
501 | /* | 498 | /* |
502 | * Nobody is referring this domain. But somebody may | 499 | * Nobody is referring this domain. But somebody may |
503 | * refer this domain after successful execve(). | 500 | * refer this domain after successful execve(). |
504 | * We recheck domain->users after SRCU synchronization. | 501 | * We recheck domain->users after SRCU synchronization. |
505 | */ | 502 | */ |
506 | if (!tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, &domain->list)) | 503 | if (!tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, &domain->list)) |
507 | goto unlock; | 504 | goto unlock; |
508 | } | 505 | } |
509 | } | 506 | } |
510 | list_for_each_entry_rcu(ns, &tomoyo_namespace_list, namespace_list) { | 507 | list_for_each_entry_rcu(ns, &tomoyo_namespace_list, namespace_list) { |
511 | for (id = 0; id < TOMOYO_MAX_POLICY; id++) | 508 | for (id = 0; id < TOMOYO_MAX_POLICY; id++) |
512 | if (!tomoyo_collect_member(id, &ns->policy_list[id])) | 509 | if (!tomoyo_collect_member(id, &ns->policy_list[id])) |
513 | goto unlock; | 510 | goto unlock; |
514 | for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++) | 511 | for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++) |
515 | if (!tomoyo_collect_acl(&ns->acl_group[i])) | 512 | if (!tomoyo_collect_acl(&ns->acl_group[i])) |
516 | goto unlock; | 513 | goto unlock; |
517 | for (i = 0; i < TOMOYO_MAX_GROUP; i++) { | 514 | for (i = 0; i < TOMOYO_MAX_GROUP; i++) { |
518 | struct list_head *list = &ns->group_list[i]; | 515 | struct list_head *list = &ns->group_list[i]; |
519 | struct tomoyo_group *group; | 516 | struct tomoyo_group *group; |
520 | switch (i) { | 517 | switch (i) { |
521 | case 0: | 518 | case 0: |
522 | id = TOMOYO_ID_PATH_GROUP; | 519 | id = TOMOYO_ID_PATH_GROUP; |
523 | break; | 520 | break; |
524 | default: | 521 | default: |
525 | id = TOMOYO_ID_NUMBER_GROUP; | 522 | id = TOMOYO_ID_NUMBER_GROUP; |
526 | break; | 523 | break; |
527 | } | 524 | } |
528 | list_for_each_entry(group, list, head.list) { | 525 | list_for_each_entry(group, list, head.list) { |
529 | if (!tomoyo_collect_member | 526 | if (!tomoyo_collect_member |
530 | (id, &group->member_list)) | 527 | (id, &group->member_list)) |
531 | goto unlock; | 528 | goto unlock; |
532 | if (!list_empty(&group->member_list) || | 529 | if (!list_empty(&group->member_list) || |
533 | atomic_read(&group->head.users)) | 530 | atomic_read(&group->head.users)) |
534 | continue; | 531 | continue; |
535 | if (!tomoyo_add_to_gc(TOMOYO_ID_GROUP, | 532 | if (!tomoyo_add_to_gc(TOMOYO_ID_GROUP, |
536 | &group->head.list)) | 533 | &group->head.list)) |
537 | goto unlock; | 534 | goto unlock; |
538 | } | 535 | } |
539 | } | 536 | } |
540 | } | 537 | } |
541 | id = TOMOYO_ID_CONDITION; | 538 | id = TOMOYO_ID_CONDITION; |
542 | for (i = 0; i < TOMOYO_MAX_HASH + 1; i++) { | 539 | for (i = 0; i < TOMOYO_MAX_HASH + 1; i++) { |
543 | struct list_head *list = !i ? | 540 | struct list_head *list = !i ? |
544 | &tomoyo_condition_list : &tomoyo_name_list[i - 1]; | 541 | &tomoyo_condition_list : &tomoyo_name_list[i - 1]; |
545 | struct tomoyo_shared_acl_head *ptr; | 542 | struct tomoyo_shared_acl_head *ptr; |
546 | list_for_each_entry(ptr, list, list) { | 543 | list_for_each_entry(ptr, list, list) { |
547 | if (atomic_read(&ptr->users)) | 544 | if (atomic_read(&ptr->users)) |
548 | continue; | 545 | continue; |
549 | if (!tomoyo_add_to_gc(id, &ptr->list)) | 546 | if (!tomoyo_add_to_gc(id, &ptr->list)) |
550 | goto unlock; | 547 | goto unlock; |
551 | } | 548 | } |
552 | id = TOMOYO_ID_NAME; | 549 | id = TOMOYO_ID_NAME; |
553 | } | 550 | } |
554 | unlock: | 551 | unlock: |
555 | tomoyo_read_unlock(idx); | 552 | tomoyo_read_unlock(idx); |
556 | mutex_unlock(&tomoyo_policy_lock); | 553 | mutex_unlock(&tomoyo_policy_lock); |
557 | } | 554 | } |
558 | 555 | ||
559 | /** | 556 | /** |
560 | * tomoyo_kfree_entry - Delete entries in tomoyo_gc_list. | 557 | * tomoyo_kfree_entry - Delete entries in tomoyo_gc_list. |
561 | * | 558 | * |
562 | * Returns true if some entries were kfree()d, false otherwise. | 559 | * Returns true if some entries were kfree()d, false otherwise. |
563 | */ | 560 | */ |
564 | static bool tomoyo_kfree_entry(void) | 561 | static bool tomoyo_kfree_entry(void) |
565 | { | 562 | { |
566 | struct tomoyo_gc *p; | 563 | struct tomoyo_gc *p; |
567 | struct tomoyo_gc *tmp; | 564 | struct tomoyo_gc *tmp; |
568 | bool result = false; | 565 | bool result = false; |
569 | 566 | ||
570 | list_for_each_entry_safe(p, tmp, &tomoyo_gc_list, list) { | 567 | list_for_each_entry_safe(p, tmp, &tomoyo_gc_list, list) { |
571 | struct list_head *element = p->element; | 568 | struct list_head *element = p->element; |
572 | 569 | ||
573 | /* | 570 | /* |
574 | * list_del_rcu() in tomoyo_add_to_gc() guarantees that the | 571 | * list_del_rcu() in tomoyo_add_to_gc() guarantees that the |
575 | * list element became no longer reachable from the list which | 572 | * list element became no longer reachable from the list which |
576 | * the element was originally on (e.g. tomoyo_domain_list). | 573 | * the element was originally on (e.g. tomoyo_domain_list). |
577 | * Also, synchronize_srcu() in tomoyo_gc_thread() guarantees | 574 | * Also, synchronize_srcu() in tomoyo_gc_thread() guarantees |
578 | * that the list element became no longer referenced by syscall | 575 | * that the list element became no longer referenced by syscall |
579 | * users. | 576 | * users. |
580 | * | 577 | * |
581 | * However, there are three users which may still be using the | 578 | * However, there are three users which may still be using the |
582 | * list element. We need to defer until all of these users | 579 | * list element. We need to defer until all of these users |
583 | * forget the list element. | 580 | * forget the list element. |
584 | * | 581 | * |
585 | * Firstly, defer until "struct tomoyo_io_buffer"->r.{domain, | 582 | * Firstly, defer until "struct tomoyo_io_buffer"->r.{domain, |
586 | * group,acl} and "struct tomoyo_io_buffer"->w.domain forget | 583 | * group,acl} and "struct tomoyo_io_buffer"->w.domain forget |
587 | * the list element. | 584 | * the list element. |
588 | */ | 585 | */ |
589 | if (tomoyo_struct_used_by_io_buffer(element)) | 586 | if (tomoyo_struct_used_by_io_buffer(element)) |
590 | continue; | 587 | continue; |
591 | /* | 588 | /* |
592 | * Secondly, defer until all other elements in the | 589 | * Secondly, defer until all other elements in the |
593 | * tomoyo_gc_list list forget the list element. | 590 | * tomoyo_gc_list list forget the list element. |
594 | */ | 591 | */ |
595 | if (tomoyo_element_linked_by_gc((const u8 *) element, p->size)) | 592 | if (tomoyo_element_linked_by_gc((const u8 *) element, p->size)) |
596 | continue; | 593 | continue; |
597 | switch (p->type) { | 594 | switch (p->type) { |
598 | case TOMOYO_ID_TRANSITION_CONTROL: | 595 | case TOMOYO_ID_TRANSITION_CONTROL: |
599 | tomoyo_del_transition_control(element); | 596 | tomoyo_del_transition_control(element); |
600 | break; | 597 | break; |
601 | case TOMOYO_ID_AGGREGATOR: | 598 | case TOMOYO_ID_AGGREGATOR: |
602 | tomoyo_del_aggregator(element); | 599 | tomoyo_del_aggregator(element); |
603 | break; | 600 | break; |
604 | case TOMOYO_ID_MANAGER: | 601 | case TOMOYO_ID_MANAGER: |
605 | tomoyo_del_manager(element); | 602 | tomoyo_del_manager(element); |
606 | break; | 603 | break; |
607 | case TOMOYO_ID_CONDITION: | 604 | case TOMOYO_ID_CONDITION: |
608 | tomoyo_del_condition(element); | 605 | tomoyo_del_condition(element); |
609 | break; | 606 | break; |
610 | case TOMOYO_ID_NAME: | 607 | case TOMOYO_ID_NAME: |
611 | /* | 608 | /* |
612 | * Thirdly, defer until all "struct tomoyo_io_buffer" | 609 | * Thirdly, defer until all "struct tomoyo_io_buffer" |
613 | * ->r.w[] forget the list element. | 610 | * ->r.w[] forget the list element. |
614 | */ | 611 | */ |
615 | if (tomoyo_name_used_by_io_buffer( | 612 | if (tomoyo_name_used_by_io_buffer( |
616 | container_of(element, typeof(struct tomoyo_name), | 613 | container_of(element, typeof(struct tomoyo_name), |
617 | head.list)->entry.name, p->size)) | 614 | head.list)->entry.name, p->size)) |
618 | continue; | 615 | continue; |
619 | tomoyo_del_name(element); | 616 | tomoyo_del_name(element); |
620 | break; | 617 | break; |
621 | case TOMOYO_ID_ACL: | 618 | case TOMOYO_ID_ACL: |
622 | tomoyo_del_acl(element); | 619 | tomoyo_del_acl(element); |
623 | break; | 620 | break; |
624 | case TOMOYO_ID_DOMAIN: | 621 | case TOMOYO_ID_DOMAIN: |
625 | if (!tomoyo_del_domain(element)) | 622 | if (!tomoyo_del_domain(element)) |
626 | continue; | 623 | continue; |
627 | break; | 624 | break; |
628 | case TOMOYO_ID_PATH_GROUP: | 625 | case TOMOYO_ID_PATH_GROUP: |
629 | tomoyo_del_path_group(element); | 626 | tomoyo_del_path_group(element); |
630 | break; | 627 | break; |
631 | case TOMOYO_ID_GROUP: | 628 | case TOMOYO_ID_GROUP: |
632 | tomoyo_del_group(element); | 629 | tomoyo_del_group(element); |
633 | break; | 630 | break; |
634 | case TOMOYO_ID_NUMBER_GROUP: | 631 | case TOMOYO_ID_NUMBER_GROUP: |
635 | tomoyo_del_number_group(element); | 632 | tomoyo_del_number_group(element); |
636 | break; | 633 | break; |
637 | case TOMOYO_MAX_POLICY: | 634 | case TOMOYO_MAX_POLICY: |
638 | break; | 635 | break; |
639 | } | 636 | } |
640 | tomoyo_memory_free(element); | 637 | tomoyo_memory_free(element); |
641 | list_del(&p->list); | 638 | list_del(&p->list); |
642 | kfree(p); | 639 | kfree(p); |
643 | tomoyo_gc_list_len--; | 640 | tomoyo_gc_list_len--; |
644 | result = true; | 641 | result = true; |
645 | } | 642 | } |
646 | return result; | 643 | return result; |
647 | } | 644 | } |
648 | 645 | ||
649 | /** | 646 | /** |
650 | * tomoyo_gc_thread - Garbage collector thread function. | 647 | * tomoyo_gc_thread - Garbage collector thread function. |
651 | * | 648 | * |
652 | * @unused: Unused. | 649 | * @unused: Unused. |
653 | * | 650 | * |
654 | * In case OOM-killer choose this thread for termination, we create this thread | 651 | * In case OOM-killer choose this thread for termination, we create this thread |
655 | * as a short live thread whenever /sys/kernel/security/tomoyo/ interface was | 652 | * as a short live thread whenever /sys/kernel/security/tomoyo/ interface was |
656 | * close()d. | 653 | * close()d. |
657 | * | 654 | * |
658 | * Returns 0. | 655 | * Returns 0. |
659 | */ | 656 | */ |
660 | static int tomoyo_gc_thread(void *unused) | 657 | static int tomoyo_gc_thread(void *unused) |
661 | { | 658 | { |
662 | /* Garbage collector thread is exclusive. */ | 659 | /* Garbage collector thread is exclusive. */ |
663 | static DEFINE_MUTEX(tomoyo_gc_mutex); | 660 | static DEFINE_MUTEX(tomoyo_gc_mutex); |
664 | if (!mutex_trylock(&tomoyo_gc_mutex)) | 661 | if (!mutex_trylock(&tomoyo_gc_mutex)) |
665 | goto out; | 662 | goto out; |
666 | daemonize("GC for TOMOYO"); | 663 | daemonize("GC for TOMOYO"); |
667 | do { | 664 | do { |
668 | tomoyo_collect_entry(); | 665 | tomoyo_collect_entry(); |
669 | if (list_empty(&tomoyo_gc_list)) | 666 | if (list_empty(&tomoyo_gc_list)) |
670 | break; | 667 | break; |
671 | synchronize_srcu(&tomoyo_ss); | 668 | synchronize_srcu(&tomoyo_ss); |
672 | } while (tomoyo_kfree_entry()); | 669 | } while (tomoyo_kfree_entry()); |
673 | { | 670 | { |
674 | struct tomoyo_io_buffer *head; | 671 | struct tomoyo_io_buffer *head; |
675 | struct tomoyo_io_buffer *tmp; | 672 | struct tomoyo_io_buffer *tmp; |
676 | 673 | ||
677 | spin_lock(&tomoyo_io_buffer_list_lock); | 674 | spin_lock(&tomoyo_io_buffer_list_lock); |
678 | list_for_each_entry_safe(head, tmp, &tomoyo_io_buffer_list, | 675 | list_for_each_entry_safe(head, tmp, &tomoyo_io_buffer_list, |
679 | list) { | 676 | list) { |
680 | if (head->users) | 677 | if (head->users) |
681 | continue; | 678 | continue; |
682 | list_del(&head->list); | 679 | list_del(&head->list); |
683 | kfree(head->read_buf); | 680 | kfree(head->read_buf); |
684 | kfree(head->write_buf); | 681 | kfree(head->write_buf); |
685 | kfree(head); | 682 | kfree(head); |
686 | } | 683 | } |
687 | spin_unlock(&tomoyo_io_buffer_list_lock); | 684 | spin_unlock(&tomoyo_io_buffer_list_lock); |
688 | } | 685 | } |
689 | mutex_unlock(&tomoyo_gc_mutex); | 686 | mutex_unlock(&tomoyo_gc_mutex); |
690 | out: | 687 | out: |
691 | /* This acts as do_exit(0). */ | 688 | /* This acts as do_exit(0). */ |
692 | return 0; | 689 | return 0; |
693 | } | 690 | } |
694 | 691 | ||
695 | /** | 692 | /** |
696 | * tomoyo_notify_gc - Register/unregister /sys/kernel/security/tomoyo/ users. | 693 | * tomoyo_notify_gc - Register/unregister /sys/kernel/security/tomoyo/ users. |
697 | * | 694 | * |
698 | * @head: Pointer to "struct tomoyo_io_buffer". | 695 | * @head: Pointer to "struct tomoyo_io_buffer". |
699 | * @is_register: True if register, false if unregister. | 696 | * @is_register: True if register, false if unregister. |
700 | * | 697 | * |
701 | * Returns nothing. | 698 | * Returns nothing. |
702 | */ | 699 | */ |
703 | void tomoyo_notify_gc(struct tomoyo_io_buffer *head, const bool is_register) | 700 | void tomoyo_notify_gc(struct tomoyo_io_buffer *head, const bool is_register) |
704 | { | 701 | { |
705 | bool is_write = false; | 702 | bool is_write = false; |
706 | 703 | ||
707 | spin_lock(&tomoyo_io_buffer_list_lock); | 704 | spin_lock(&tomoyo_io_buffer_list_lock); |
708 | if (is_register) { | 705 | if (is_register) { |
709 | head->users = 1; | 706 | head->users = 1; |
710 | list_add(&head->list, &tomoyo_io_buffer_list); | 707 | list_add(&head->list, &tomoyo_io_buffer_list); |
711 | } else { | 708 | } else { |
712 | is_write = head->write_buf != NULL; | 709 | is_write = head->write_buf != NULL; |
713 | if (!--head->users) { | 710 | if (!--head->users) { |
714 | list_del(&head->list); | 711 | list_del(&head->list); |
715 | kfree(head->read_buf); | 712 | kfree(head->read_buf); |
716 | kfree(head->write_buf); | 713 | kfree(head->write_buf); |
717 | kfree(head); | 714 | kfree(head); |
718 | } | 715 | } |
719 | } | 716 | } |
720 | spin_unlock(&tomoyo_io_buffer_list_lock); | 717 | spin_unlock(&tomoyo_io_buffer_list_lock); |
721 | if (is_write) { | 718 | if (is_write) { |
722 | struct task_struct *task = kthread_create(tomoyo_gc_thread, | 719 | struct task_struct *task = kthread_create(tomoyo_gc_thread, |
723 | NULL, | 720 | NULL, |
724 | "GC for TOMOYO"); | 721 | "GC for TOMOYO"); |
725 | if (!IS_ERR(task)) | 722 | if (!IS_ERR(task)) |
726 | wake_up_process(task); | 723 | wake_up_process(task); |
727 | } | 724 | } |
728 | } | 725 | } |
729 | 726 |
security/tomoyo/group.c
1 | /* | 1 | /* |
2 | * security/tomoyo/group.c | 2 | * security/tomoyo/group.c |
3 | * | 3 | * |
4 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | 4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/slab.h> | 7 | #include <linux/slab.h> |
8 | #include "common.h" | 8 | #include "common.h" |
9 | 9 | ||
10 | /** | ||
11 | * tomoyo_same_path_group - Check for duplicated "struct tomoyo_path_group" entry. | ||
12 | * | ||
13 | * @a: Pointer to "struct tomoyo_acl_head". | ||
14 | * @b: Pointer to "struct tomoyo_acl_head". | ||
15 | * | ||
16 | * Returns true if @a == @b, false otherwise. | ||
17 | */ | ||
10 | static bool tomoyo_same_path_group(const struct tomoyo_acl_head *a, | 18 | static bool tomoyo_same_path_group(const struct tomoyo_acl_head *a, |
11 | const struct tomoyo_acl_head *b) | 19 | const struct tomoyo_acl_head *b) |
12 | { | 20 | { |
13 | return container_of(a, struct tomoyo_path_group, head)->member_name == | 21 | return container_of(a, struct tomoyo_path_group, head)->member_name == |
14 | container_of(b, struct tomoyo_path_group, head)->member_name; | 22 | container_of(b, struct tomoyo_path_group, head)->member_name; |
15 | } | 23 | } |
16 | 24 | ||
25 | /** | ||
26 | * tomoyo_same_number_group - Check for duplicated "struct tomoyo_number_group" entry. | ||
27 | * | ||
28 | * @a: Pointer to "struct tomoyo_acl_head". | ||
29 | * @b: Pointer to "struct tomoyo_acl_head". | ||
30 | * | ||
31 | * Returns true if @a == @b, false otherwise. | ||
32 | */ | ||
17 | static bool tomoyo_same_number_group(const struct tomoyo_acl_head *a, | 33 | static bool tomoyo_same_number_group(const struct tomoyo_acl_head *a, |
18 | const struct tomoyo_acl_head *b) | 34 | const struct tomoyo_acl_head *b) |
19 | { | 35 | { |
20 | return !memcmp(&container_of(a, struct tomoyo_number_group, head) | 36 | return !memcmp(&container_of(a, struct tomoyo_number_group, head) |
21 | ->number, | 37 | ->number, |
22 | &container_of(b, struct tomoyo_number_group, head) | 38 | &container_of(b, struct tomoyo_number_group, head) |
23 | ->number, | 39 | ->number, |
24 | sizeof(container_of(a, struct tomoyo_number_group, head) | 40 | sizeof(container_of(a, struct tomoyo_number_group, head) |
25 | ->number)); | 41 | ->number)); |
26 | } | 42 | } |
27 | 43 | ||
28 | /** | 44 | /** |
29 | * tomoyo_write_group - Write "struct tomoyo_path_group"/"struct tomoyo_number_group" list. | 45 | * tomoyo_write_group - Write "struct tomoyo_path_group"/"struct tomoyo_number_group" list. |
30 | * | 46 | * |
31 | * @param: Pointer to "struct tomoyo_acl_param". | 47 | * @param: Pointer to "struct tomoyo_acl_param". |
32 | * @type: Type of this group. | 48 | * @type: Type of this group. |
33 | * | 49 | * |
34 | * Returns 0 on success, negative value otherwise. | 50 | * Returns 0 on success, negative value otherwise. |
35 | */ | 51 | */ |
36 | int tomoyo_write_group(struct tomoyo_acl_param *param, const u8 type) | 52 | int tomoyo_write_group(struct tomoyo_acl_param *param, const u8 type) |
37 | { | 53 | { |
38 | struct tomoyo_group *group = tomoyo_get_group(param, type); | 54 | struct tomoyo_group *group = tomoyo_get_group(param, type); |
39 | int error = -EINVAL; | 55 | int error = -EINVAL; |
40 | if (!group) | 56 | if (!group) |
41 | return -ENOMEM; | 57 | return -ENOMEM; |
42 | param->list = &group->member_list; | 58 | param->list = &group->member_list; |
43 | if (type == TOMOYO_PATH_GROUP) { | 59 | if (type == TOMOYO_PATH_GROUP) { |
44 | struct tomoyo_path_group e = { }; | 60 | struct tomoyo_path_group e = { }; |
45 | e.member_name = tomoyo_get_name(tomoyo_read_token(param)); | 61 | e.member_name = tomoyo_get_name(tomoyo_read_token(param)); |
46 | if (!e.member_name) { | 62 | if (!e.member_name) { |
47 | error = -ENOMEM; | 63 | error = -ENOMEM; |
48 | goto out; | 64 | goto out; |
49 | } | 65 | } |
50 | error = tomoyo_update_policy(&e.head, sizeof(e), param, | 66 | error = tomoyo_update_policy(&e.head, sizeof(e), param, |
51 | tomoyo_same_path_group); | 67 | tomoyo_same_path_group); |
52 | tomoyo_put_name(e.member_name); | 68 | tomoyo_put_name(e.member_name); |
53 | } else if (type == TOMOYO_NUMBER_GROUP) { | 69 | } else if (type == TOMOYO_NUMBER_GROUP) { |
54 | struct tomoyo_number_group e = { }; | 70 | struct tomoyo_number_group e = { }; |
55 | if (param->data[0] == '@' || | 71 | if (param->data[0] == '@' || |
56 | !tomoyo_parse_number_union(param, &e.number)) | 72 | !tomoyo_parse_number_union(param, &e.number)) |
57 | goto out; | 73 | goto out; |
58 | error = tomoyo_update_policy(&e.head, sizeof(e), param, | 74 | error = tomoyo_update_policy(&e.head, sizeof(e), param, |
59 | tomoyo_same_number_group); | 75 | tomoyo_same_number_group); |
60 | /* | 76 | /* |
61 | * tomoyo_put_number_union() is not needed because | 77 | * tomoyo_put_number_union() is not needed because |
62 | * param->data[0] != '@'. | 78 | * param->data[0] != '@'. |
63 | */ | 79 | */ |
64 | } | 80 | } |
65 | out: | 81 | out: |
66 | tomoyo_put_group(group); | 82 | tomoyo_put_group(group); |
67 | return error; | 83 | return error; |
68 | } | 84 | } |
69 | 85 | ||
70 | /** | 86 | /** |
71 | * tomoyo_path_matches_group - Check whether the given pathname matches members of the given pathname group. | 87 | * tomoyo_path_matches_group - Check whether the given pathname matches members of the given pathname group. |
72 | * | 88 | * |
73 | * @pathname: The name of pathname. | 89 | * @pathname: The name of pathname. |
74 | * @group: Pointer to "struct tomoyo_path_group". | 90 | * @group: Pointer to "struct tomoyo_path_group". |
75 | * | 91 | * |
76 | * Returns matched member's pathname if @pathname matches pathnames in @group, | 92 | * Returns matched member's pathname if @pathname matches pathnames in @group, |
77 | * NULL otherwise. | 93 | * NULL otherwise. |
78 | * | 94 | * |
79 | * Caller holds tomoyo_read_lock(). | 95 | * Caller holds tomoyo_read_lock(). |
80 | */ | 96 | */ |
81 | const struct tomoyo_path_info * | 97 | const struct tomoyo_path_info * |
82 | tomoyo_path_matches_group(const struct tomoyo_path_info *pathname, | 98 | tomoyo_path_matches_group(const struct tomoyo_path_info *pathname, |
83 | const struct tomoyo_group *group) | 99 | const struct tomoyo_group *group) |
84 | { | 100 | { |
85 | struct tomoyo_path_group *member; | 101 | struct tomoyo_path_group *member; |
86 | list_for_each_entry_rcu(member, &group->member_list, head.list) { | 102 | list_for_each_entry_rcu(member, &group->member_list, head.list) { |
87 | if (member->head.is_deleted) | 103 | if (member->head.is_deleted) |
88 | continue; | 104 | continue; |
89 | if (!tomoyo_path_matches_pattern(pathname, member->member_name)) | 105 | if (!tomoyo_path_matches_pattern(pathname, member->member_name)) |
90 | continue; | 106 | continue; |
91 | return member->member_name; | 107 | return member->member_name; |
92 | } | 108 | } |
93 | return NULL; | 109 | return NULL; |
94 | } | 110 | } |
95 | 111 | ||
96 | /** | 112 | /** |
97 | * tomoyo_number_matches_group - Check whether the given number matches members of the given number group. | 113 | * tomoyo_number_matches_group - Check whether the given number matches members of the given number group. |
98 | * | 114 | * |
99 | * @min: Min number. | 115 | * @min: Min number. |
100 | * @max: Max number. | 116 | * @max: Max number. |
101 | * @group: Pointer to "struct tomoyo_number_group". | 117 | * @group: Pointer to "struct tomoyo_number_group". |
102 | * | 118 | * |
103 | * Returns true if @min and @max partially overlaps @group, false otherwise. | 119 | * Returns true if @min and @max partially overlaps @group, false otherwise. |
104 | * | 120 | * |
105 | * Caller holds tomoyo_read_lock(). | 121 | * Caller holds tomoyo_read_lock(). |
106 | */ | 122 | */ |
107 | bool tomoyo_number_matches_group(const unsigned long min, | 123 | bool tomoyo_number_matches_group(const unsigned long min, |
108 | const unsigned long max, | 124 | const unsigned long max, |
109 | const struct tomoyo_group *group) | 125 | const struct tomoyo_group *group) |
110 | { | 126 | { |
111 | struct tomoyo_number_group *member; | 127 | struct tomoyo_number_group *member; |
112 | bool matched = false; | 128 | bool matched = false; |
113 | list_for_each_entry_rcu(member, &group->member_list, head.list) { | 129 | list_for_each_entry_rcu(member, &group->member_list, head.list) { |
114 | if (member->head.is_deleted) | 130 | if (member->head.is_deleted) |
115 | continue; | 131 | continue; |
116 | if (min > member->number.values[1] || | 132 | if (min > member->number.values[1] || |
117 | max < member->number.values[0]) | 133 | max < member->number.values[0]) |
118 | continue; | 134 | continue; |
119 | matched = true; | 135 | matched = true; |
120 | break; | 136 | break; |
121 | } | 137 | } |
122 | return matched; | 138 | return matched; |
123 | } | 139 | } |
124 | 140 |
security/tomoyo/load_policy.c
1 | /* | 1 | /* |
2 | * security/tomoyo/load_policy.c | 2 | * security/tomoyo/load_policy.c |
3 | * | 3 | * |
4 | * Policy loader launcher for TOMOYO. | 4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION |
5 | * | ||
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
7 | */ | 5 | */ |
8 | 6 | ||
9 | #include "common.h" | 7 | #include "common.h" |
10 | 8 | ||
11 | #ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER | 9 | #ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER |
12 | 10 | ||
13 | /* | 11 | /* |
14 | * Path to the policy loader. (default = CONFIG_SECURITY_TOMOYO_POLICY_LOADER) | 12 | * Path to the policy loader. (default = CONFIG_SECURITY_TOMOYO_POLICY_LOADER) |
15 | */ | 13 | */ |
16 | static const char *tomoyo_loader; | 14 | static const char *tomoyo_loader; |
17 | 15 | ||
18 | /** | 16 | /** |
19 | * tomoyo_loader_setup - Set policy loader. | 17 | * tomoyo_loader_setup - Set policy loader. |
20 | * | 18 | * |
21 | * @str: Program to use as a policy loader (e.g. /sbin/tomoyo-init ). | 19 | * @str: Program to use as a policy loader (e.g. /sbin/tomoyo-init ). |
22 | * | 20 | * |
23 | * Returns 0. | 21 | * Returns 0. |
24 | */ | 22 | */ |
25 | static int __init tomoyo_loader_setup(char *str) | 23 | static int __init tomoyo_loader_setup(char *str) |
26 | { | 24 | { |
27 | tomoyo_loader = str; | 25 | tomoyo_loader = str; |
28 | return 0; | 26 | return 0; |
29 | } | 27 | } |
30 | 28 | ||
31 | __setup("TOMOYO_loader=", tomoyo_loader_setup); | 29 | __setup("TOMOYO_loader=", tomoyo_loader_setup); |
32 | 30 | ||
33 | /** | 31 | /** |
34 | * tomoyo_policy_loader_exists - Check whether /sbin/tomoyo-init exists. | 32 | * tomoyo_policy_loader_exists - Check whether /sbin/tomoyo-init exists. |
35 | * | 33 | * |
36 | * Returns true if /sbin/tomoyo-init exists, false otherwise. | 34 | * Returns true if /sbin/tomoyo-init exists, false otherwise. |
37 | */ | 35 | */ |
38 | static bool tomoyo_policy_loader_exists(void) | 36 | static bool tomoyo_policy_loader_exists(void) |
39 | { | 37 | { |
40 | struct path path; | 38 | struct path path; |
41 | if (!tomoyo_loader) | 39 | if (!tomoyo_loader) |
42 | tomoyo_loader = CONFIG_SECURITY_TOMOYO_POLICY_LOADER; | 40 | tomoyo_loader = CONFIG_SECURITY_TOMOYO_POLICY_LOADER; |
43 | if (kern_path(tomoyo_loader, LOOKUP_FOLLOW, &path)) { | 41 | if (kern_path(tomoyo_loader, LOOKUP_FOLLOW, &path)) { |
44 | printk(KERN_INFO "Not activating Mandatory Access Control " | 42 | printk(KERN_INFO "Not activating Mandatory Access Control " |
45 | "as %s does not exist.\n", tomoyo_loader); | 43 | "as %s does not exist.\n", tomoyo_loader); |
46 | return false; | 44 | return false; |
47 | } | 45 | } |
48 | path_put(&path); | 46 | path_put(&path); |
49 | return true; | 47 | return true; |
50 | } | 48 | } |
51 | 49 | ||
52 | /* | 50 | /* |
53 | * Path to the trigger. (default = CONFIG_SECURITY_TOMOYO_ACTIVATION_TRIGGER) | 51 | * Path to the trigger. (default = CONFIG_SECURITY_TOMOYO_ACTIVATION_TRIGGER) |
54 | */ | 52 | */ |
55 | static const char *tomoyo_trigger; | 53 | static const char *tomoyo_trigger; |
56 | 54 | ||
57 | /** | 55 | /** |
58 | * tomoyo_trigger_setup - Set trigger for activation. | 56 | * tomoyo_trigger_setup - Set trigger for activation. |
59 | * | 57 | * |
60 | * @str: Program to use as an activation trigger (e.g. /sbin/init ). | 58 | * @str: Program to use as an activation trigger (e.g. /sbin/init ). |
61 | * | 59 | * |
62 | * Returns 0. | 60 | * Returns 0. |
63 | */ | 61 | */ |
64 | static int __init tomoyo_trigger_setup(char *str) | 62 | static int __init tomoyo_trigger_setup(char *str) |
65 | { | 63 | { |
66 | tomoyo_trigger = str; | 64 | tomoyo_trigger = str; |
67 | return 0; | 65 | return 0; |
68 | } | 66 | } |
69 | 67 | ||
70 | __setup("TOMOYO_trigger=", tomoyo_trigger_setup); | 68 | __setup("TOMOYO_trigger=", tomoyo_trigger_setup); |
71 | 69 | ||
72 | /** | 70 | /** |
73 | * tomoyo_load_policy - Run external policy loader to load policy. | 71 | * tomoyo_load_policy - Run external policy loader to load policy. |
74 | * | 72 | * |
75 | * @filename: The program about to start. | 73 | * @filename: The program about to start. |
76 | * | 74 | * |
77 | * This function checks whether @filename is /sbin/init , and if so | 75 | * This function checks whether @filename is /sbin/init , and if so |
78 | * invoke /sbin/tomoyo-init and wait for the termination of /sbin/tomoyo-init | 76 | * invoke /sbin/tomoyo-init and wait for the termination of /sbin/tomoyo-init |
79 | * and then continues invocation of /sbin/init. | 77 | * and then continues invocation of /sbin/init. |
80 | * /sbin/tomoyo-init reads policy files in /etc/tomoyo/ directory and | 78 | * /sbin/tomoyo-init reads policy files in /etc/tomoyo/ directory and |
81 | * writes to /sys/kernel/security/tomoyo/ interfaces. | 79 | * writes to /sys/kernel/security/tomoyo/ interfaces. |
82 | * | 80 | * |
83 | * Returns nothing. | 81 | * Returns nothing. |
84 | */ | 82 | */ |
85 | void tomoyo_load_policy(const char *filename) | 83 | void tomoyo_load_policy(const char *filename) |
86 | { | 84 | { |
87 | static bool done; | 85 | static bool done; |
88 | char *argv[2]; | 86 | char *argv[2]; |
89 | char *envp[3]; | 87 | char *envp[3]; |
90 | 88 | ||
91 | if (tomoyo_policy_loaded || done) | 89 | if (tomoyo_policy_loaded || done) |
92 | return; | 90 | return; |
93 | if (!tomoyo_trigger) | 91 | if (!tomoyo_trigger) |
94 | tomoyo_trigger = CONFIG_SECURITY_TOMOYO_ACTIVATION_TRIGGER; | 92 | tomoyo_trigger = CONFIG_SECURITY_TOMOYO_ACTIVATION_TRIGGER; |
95 | if (strcmp(filename, tomoyo_trigger)) | 93 | if (strcmp(filename, tomoyo_trigger)) |
96 | return; | 94 | return; |
97 | if (!tomoyo_policy_loader_exists()) | 95 | if (!tomoyo_policy_loader_exists()) |
98 | return; | 96 | return; |
99 | done = true; | 97 | done = true; |
100 | printk(KERN_INFO "Calling %s to load policy. Please wait.\n", | 98 | printk(KERN_INFO "Calling %s to load policy. Please wait.\n", |
101 | tomoyo_loader); | 99 | tomoyo_loader); |
102 | argv[0] = (char *) tomoyo_loader; | 100 | argv[0] = (char *) tomoyo_loader; |
103 | argv[1] = NULL; | 101 | argv[1] = NULL; |
104 | envp[0] = "HOME=/"; | 102 | envp[0] = "HOME=/"; |
105 | envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; | 103 | envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; |
106 | envp[2] = NULL; | 104 | envp[2] = NULL; |
107 | call_usermodehelper(argv[0], argv, envp, 1); | 105 | call_usermodehelper(argv[0], argv, envp, 1); |
108 | tomoyo_check_profile(); | 106 | tomoyo_check_profile(); |
109 | } | 107 | } |
110 | 108 | ||
111 | #endif | 109 | #endif |
112 | 110 |
security/tomoyo/memory.c
1 | /* | 1 | /* |
2 | * security/tomoyo/memory.c | 2 | * security/tomoyo/memory.c |
3 | * | 3 | * |
4 | * Memory management functions for TOMOYO. | 4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION |
5 | * | ||
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
7 | */ | 5 | */ |
8 | 6 | ||
9 | #include <linux/hash.h> | 7 | #include <linux/hash.h> |
10 | #include <linux/slab.h> | 8 | #include <linux/slab.h> |
11 | #include "common.h" | 9 | #include "common.h" |
12 | 10 | ||
13 | /** | 11 | /** |
14 | * tomoyo_warn_oom - Print out of memory warning message. | 12 | * tomoyo_warn_oom - Print out of memory warning message. |
15 | * | 13 | * |
16 | * @function: Function's name. | 14 | * @function: Function's name. |
17 | */ | 15 | */ |
18 | void tomoyo_warn_oom(const char *function) | 16 | void tomoyo_warn_oom(const char *function) |
19 | { | 17 | { |
20 | /* Reduce error messages. */ | 18 | /* Reduce error messages. */ |
21 | static pid_t tomoyo_last_pid; | 19 | static pid_t tomoyo_last_pid; |
22 | const pid_t pid = current->pid; | 20 | const pid_t pid = current->pid; |
23 | if (tomoyo_last_pid != pid) { | 21 | if (tomoyo_last_pid != pid) { |
24 | printk(KERN_WARNING "ERROR: Out of memory at %s.\n", | 22 | printk(KERN_WARNING "ERROR: Out of memory at %s.\n", |
25 | function); | 23 | function); |
26 | tomoyo_last_pid = pid; | 24 | tomoyo_last_pid = pid; |
27 | } | 25 | } |
28 | if (!tomoyo_policy_loaded) | 26 | if (!tomoyo_policy_loaded) |
29 | panic("MAC Initialization failed.\n"); | 27 | panic("MAC Initialization failed.\n"); |
30 | } | 28 | } |
31 | 29 | ||
32 | /* Lock for protecting tomoyo_memory_used. */ | 30 | /* Lock for protecting tomoyo_memory_used. */ |
33 | static DEFINE_SPINLOCK(tomoyo_policy_memory_lock); | 31 | static DEFINE_SPINLOCK(tomoyo_policy_memory_lock); |
34 | /* Memoy currently used by policy/audit log/query. */ | 32 | /* Memoy currently used by policy/audit log/query. */ |
35 | unsigned int tomoyo_memory_used[TOMOYO_MAX_MEMORY_STAT]; | 33 | unsigned int tomoyo_memory_used[TOMOYO_MAX_MEMORY_STAT]; |
36 | /* Memory quota for "policy"/"audit log"/"query". */ | 34 | /* Memory quota for "policy"/"audit log"/"query". */ |
37 | unsigned int tomoyo_memory_quota[TOMOYO_MAX_MEMORY_STAT]; | 35 | unsigned int tomoyo_memory_quota[TOMOYO_MAX_MEMORY_STAT]; |
38 | 36 | ||
39 | /** | 37 | /** |
40 | * tomoyo_memory_ok - Check memory quota. | 38 | * tomoyo_memory_ok - Check memory quota. |
41 | * | 39 | * |
42 | * @ptr: Pointer to allocated memory. | 40 | * @ptr: Pointer to allocated memory. |
43 | * | 41 | * |
44 | * Returns true on success, false otherwise. | 42 | * Returns true on success, false otherwise. |
45 | * | 43 | * |
46 | * Returns true if @ptr is not NULL and quota not exceeded, false otherwise. | 44 | * Returns true if @ptr is not NULL and quota not exceeded, false otherwise. |
47 | */ | 45 | */ |
48 | bool tomoyo_memory_ok(void *ptr) | 46 | bool tomoyo_memory_ok(void *ptr) |
49 | { | 47 | { |
50 | if (ptr) { | 48 | if (ptr) { |
51 | const size_t s = ksize(ptr); | 49 | const size_t s = ksize(ptr); |
52 | bool result; | 50 | bool result; |
53 | spin_lock(&tomoyo_policy_memory_lock); | 51 | spin_lock(&tomoyo_policy_memory_lock); |
54 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] += s; | 52 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] += s; |
55 | result = !tomoyo_memory_quota[TOMOYO_MEMORY_POLICY] || | 53 | result = !tomoyo_memory_quota[TOMOYO_MEMORY_POLICY] || |
56 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] <= | 54 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] <= |
57 | tomoyo_memory_quota[TOMOYO_MEMORY_POLICY]; | 55 | tomoyo_memory_quota[TOMOYO_MEMORY_POLICY]; |
58 | if (!result) | 56 | if (!result) |
59 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -= s; | 57 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -= s; |
60 | spin_unlock(&tomoyo_policy_memory_lock); | 58 | spin_unlock(&tomoyo_policy_memory_lock); |
61 | if (result) | 59 | if (result) |
62 | return true; | 60 | return true; |
63 | } | 61 | } |
64 | tomoyo_warn_oom(__func__); | 62 | tomoyo_warn_oom(__func__); |
65 | return false; | 63 | return false; |
66 | } | 64 | } |
67 | 65 | ||
68 | /** | 66 | /** |
69 | * tomoyo_commit_ok - Check memory quota. | 67 | * tomoyo_commit_ok - Check memory quota. |
70 | * | 68 | * |
71 | * @data: Data to copy from. | 69 | * @data: Data to copy from. |
72 | * @size: Size in byte. | 70 | * @size: Size in byte. |
73 | * | 71 | * |
74 | * Returns pointer to allocated memory on success, NULL otherwise. | 72 | * Returns pointer to allocated memory on success, NULL otherwise. |
75 | * @data is zero-cleared on success. | 73 | * @data is zero-cleared on success. |
76 | */ | 74 | */ |
77 | void *tomoyo_commit_ok(void *data, const unsigned int size) | 75 | void *tomoyo_commit_ok(void *data, const unsigned int size) |
78 | { | 76 | { |
79 | void *ptr = kzalloc(size, GFP_NOFS); | 77 | void *ptr = kzalloc(size, GFP_NOFS); |
80 | if (tomoyo_memory_ok(ptr)) { | 78 | if (tomoyo_memory_ok(ptr)) { |
81 | memmove(ptr, data, size); | 79 | memmove(ptr, data, size); |
82 | memset(data, 0, size); | 80 | memset(data, 0, size); |
83 | return ptr; | 81 | return ptr; |
84 | } | 82 | } |
85 | kfree(ptr); | 83 | kfree(ptr); |
86 | return NULL; | 84 | return NULL; |
87 | } | 85 | } |
88 | 86 | ||
89 | /** | 87 | /** |
90 | * tomoyo_memory_free - Free memory for elements. | 88 | * tomoyo_memory_free - Free memory for elements. |
91 | * | 89 | * |
92 | * @ptr: Pointer to allocated memory. | 90 | * @ptr: Pointer to allocated memory. |
93 | */ | 91 | */ |
94 | void tomoyo_memory_free(void *ptr) | 92 | void tomoyo_memory_free(void *ptr) |
95 | { | 93 | { |
96 | size_t s = ksize(ptr); | 94 | size_t s = ksize(ptr); |
97 | spin_lock(&tomoyo_policy_memory_lock); | 95 | spin_lock(&tomoyo_policy_memory_lock); |
98 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -= s; | 96 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -= s; |
99 | spin_unlock(&tomoyo_policy_memory_lock); | 97 | spin_unlock(&tomoyo_policy_memory_lock); |
100 | kfree(ptr); | 98 | kfree(ptr); |
101 | } | 99 | } |
102 | 100 | ||
103 | /** | 101 | /** |
104 | * tomoyo_get_group - Allocate memory for "struct tomoyo_path_group"/"struct tomoyo_number_group". | 102 | * tomoyo_get_group - Allocate memory for "struct tomoyo_path_group"/"struct tomoyo_number_group". |
105 | * | 103 | * |
106 | * @param: Pointer to "struct tomoyo_acl_param". | 104 | * @param: Pointer to "struct tomoyo_acl_param". |
107 | * @idx: Index number. | 105 | * @idx: Index number. |
108 | * | 106 | * |
109 | * Returns pointer to "struct tomoyo_group" on success, NULL otherwise. | 107 | * Returns pointer to "struct tomoyo_group" on success, NULL otherwise. |
110 | */ | 108 | */ |
111 | struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param, | 109 | struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param, |
112 | const u8 idx) | 110 | const u8 idx) |
113 | { | 111 | { |
114 | struct tomoyo_group e = { }; | 112 | struct tomoyo_group e = { }; |
115 | struct tomoyo_group *group = NULL; | 113 | struct tomoyo_group *group = NULL; |
116 | struct list_head *list; | 114 | struct list_head *list; |
117 | const char *group_name = tomoyo_read_token(param); | 115 | const char *group_name = tomoyo_read_token(param); |
118 | bool found = false; | 116 | bool found = false; |
119 | if (!tomoyo_correct_word(group_name) || idx >= TOMOYO_MAX_GROUP) | 117 | if (!tomoyo_correct_word(group_name) || idx >= TOMOYO_MAX_GROUP) |
120 | return NULL; | 118 | return NULL; |
121 | e.group_name = tomoyo_get_name(group_name); | 119 | e.group_name = tomoyo_get_name(group_name); |
122 | if (!e.group_name) | 120 | if (!e.group_name) |
123 | return NULL; | 121 | return NULL; |
124 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 122 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
125 | goto out; | 123 | goto out; |
126 | list = ¶m->ns->group_list[idx]; | 124 | list = ¶m->ns->group_list[idx]; |
127 | list_for_each_entry(group, list, head.list) { | 125 | list_for_each_entry(group, list, head.list) { |
128 | if (e.group_name != group->group_name) | 126 | if (e.group_name != group->group_name) |
129 | continue; | 127 | continue; |
130 | atomic_inc(&group->head.users); | 128 | atomic_inc(&group->head.users); |
131 | found = true; | 129 | found = true; |
132 | break; | 130 | break; |
133 | } | 131 | } |
134 | if (!found) { | 132 | if (!found) { |
135 | struct tomoyo_group *entry = tomoyo_commit_ok(&e, sizeof(e)); | 133 | struct tomoyo_group *entry = tomoyo_commit_ok(&e, sizeof(e)); |
136 | if (entry) { | 134 | if (entry) { |
137 | INIT_LIST_HEAD(&entry->member_list); | 135 | INIT_LIST_HEAD(&entry->member_list); |
138 | atomic_set(&entry->head.users, 1); | 136 | atomic_set(&entry->head.users, 1); |
139 | list_add_tail_rcu(&entry->head.list, list); | 137 | list_add_tail_rcu(&entry->head.list, list); |
140 | group = entry; | 138 | group = entry; |
141 | found = true; | 139 | found = true; |
142 | } | 140 | } |
143 | } | 141 | } |
144 | mutex_unlock(&tomoyo_policy_lock); | 142 | mutex_unlock(&tomoyo_policy_lock); |
145 | out: | 143 | out: |
146 | tomoyo_put_name(e.group_name); | 144 | tomoyo_put_name(e.group_name); |
147 | return found ? group : NULL; | 145 | return found ? group : NULL; |
148 | } | 146 | } |
149 | 147 | ||
150 | /* | 148 | /* |
151 | * tomoyo_name_list is used for holding string data used by TOMOYO. | 149 | * tomoyo_name_list is used for holding string data used by TOMOYO. |
152 | * Since same string data is likely used for multiple times (e.g. | 150 | * Since same string data is likely used for multiple times (e.g. |
153 | * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of | 151 | * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of |
154 | * "const struct tomoyo_path_info *". | 152 | * "const struct tomoyo_path_info *". |
155 | */ | 153 | */ |
156 | struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; | 154 | struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; |
157 | 155 | ||
158 | /** | 156 | /** |
159 | * tomoyo_get_name - Allocate permanent memory for string data. | 157 | * tomoyo_get_name - Allocate permanent memory for string data. |
160 | * | 158 | * |
161 | * @name: The string to store into the permernent memory. | 159 | * @name: The string to store into the permernent memory. |
162 | * | 160 | * |
163 | * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. | 161 | * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. |
164 | */ | 162 | */ |
165 | const struct tomoyo_path_info *tomoyo_get_name(const char *name) | 163 | const struct tomoyo_path_info *tomoyo_get_name(const char *name) |
166 | { | 164 | { |
167 | struct tomoyo_name *ptr; | 165 | struct tomoyo_name *ptr; |
168 | unsigned int hash; | 166 | unsigned int hash; |
169 | int len; | 167 | int len; |
170 | struct list_head *head; | 168 | struct list_head *head; |
171 | 169 | ||
172 | if (!name) | 170 | if (!name) |
173 | return NULL; | 171 | return NULL; |
174 | len = strlen(name) + 1; | 172 | len = strlen(name) + 1; |
175 | hash = full_name_hash((const unsigned char *) name, len - 1); | 173 | hash = full_name_hash((const unsigned char *) name, len - 1); |
176 | head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)]; | 174 | head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)]; |
177 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 175 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
178 | return NULL; | 176 | return NULL; |
179 | list_for_each_entry(ptr, head, head.list) { | 177 | list_for_each_entry(ptr, head, head.list) { |
180 | if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name)) | 178 | if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name)) |
181 | continue; | 179 | continue; |
182 | atomic_inc(&ptr->head.users); | 180 | atomic_inc(&ptr->head.users); |
183 | goto out; | 181 | goto out; |
184 | } | 182 | } |
185 | ptr = kzalloc(sizeof(*ptr) + len, GFP_NOFS); | 183 | ptr = kzalloc(sizeof(*ptr) + len, GFP_NOFS); |
186 | if (tomoyo_memory_ok(ptr)) { | 184 | if (tomoyo_memory_ok(ptr)) { |
187 | ptr->entry.name = ((char *) ptr) + sizeof(*ptr); | 185 | ptr->entry.name = ((char *) ptr) + sizeof(*ptr); |
188 | memmove((char *) ptr->entry.name, name, len); | 186 | memmove((char *) ptr->entry.name, name, len); |
189 | atomic_set(&ptr->head.users, 1); | 187 | atomic_set(&ptr->head.users, 1); |
190 | tomoyo_fill_path_info(&ptr->entry); | 188 | tomoyo_fill_path_info(&ptr->entry); |
191 | list_add_tail(&ptr->head.list, head); | 189 | list_add_tail(&ptr->head.list, head); |
192 | } else { | 190 | } else { |
193 | kfree(ptr); | 191 | kfree(ptr); |
194 | ptr = NULL; | 192 | ptr = NULL; |
195 | } | 193 | } |
196 | out: | 194 | out: |
197 | mutex_unlock(&tomoyo_policy_lock); | 195 | mutex_unlock(&tomoyo_policy_lock); |
198 | return ptr ? &ptr->entry : NULL; | 196 | return ptr ? &ptr->entry : NULL; |
199 | } | 197 | } |
200 | 198 | ||
201 | /* Initial namespace.*/ | 199 | /* Initial namespace.*/ |
202 | struct tomoyo_policy_namespace tomoyo_kernel_namespace; | 200 | struct tomoyo_policy_namespace tomoyo_kernel_namespace; |
203 | 201 | ||
204 | /** | 202 | /** |
205 | * tomoyo_mm_init - Initialize mm related code. | 203 | * tomoyo_mm_init - Initialize mm related code. |
206 | */ | 204 | */ |
207 | void __init tomoyo_mm_init(void) | 205 | void __init tomoyo_mm_init(void) |
208 | { | 206 | { |
209 | int idx; | 207 | int idx; |
210 | for (idx = 0; idx < TOMOYO_MAX_HASH; idx++) | 208 | for (idx = 0; idx < TOMOYO_MAX_HASH; idx++) |
211 | INIT_LIST_HEAD(&tomoyo_name_list[idx]); | 209 | INIT_LIST_HEAD(&tomoyo_name_list[idx]); |
212 | tomoyo_kernel_namespace.name = "<kernel>"; | 210 | tomoyo_kernel_namespace.name = "<kernel>"; |
213 | tomoyo_init_policy_namespace(&tomoyo_kernel_namespace); | 211 | tomoyo_init_policy_namespace(&tomoyo_kernel_namespace); |
214 | tomoyo_kernel_domain.ns = &tomoyo_kernel_namespace; | 212 | tomoyo_kernel_domain.ns = &tomoyo_kernel_namespace; |
215 | INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list); | 213 | INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list); |
216 | tomoyo_kernel_domain.domainname = tomoyo_get_name("<kernel>"); | 214 | tomoyo_kernel_domain.domainname = tomoyo_get_name("<kernel>"); |
217 | list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list); | 215 | list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list); |
218 | } | 216 | } |
219 | 217 |
security/tomoyo/mount.c
1 | /* | 1 | /* |
2 | * security/tomoyo/mount.c | 2 | * security/tomoyo/mount.c |
3 | * | 3 | * |
4 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | 4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/slab.h> | 7 | #include <linux/slab.h> |
8 | #include "common.h" | 8 | #include "common.h" |
9 | 9 | ||
10 | /* String table for special mount operations. */ | 10 | /* String table for special mount operations. */ |
11 | static const char * const tomoyo_mounts[TOMOYO_MAX_SPECIAL_MOUNT] = { | 11 | static const char * const tomoyo_mounts[TOMOYO_MAX_SPECIAL_MOUNT] = { |
12 | [TOMOYO_MOUNT_BIND] = "--bind", | 12 | [TOMOYO_MOUNT_BIND] = "--bind", |
13 | [TOMOYO_MOUNT_MOVE] = "--move", | 13 | [TOMOYO_MOUNT_MOVE] = "--move", |
14 | [TOMOYO_MOUNT_REMOUNT] = "--remount", | 14 | [TOMOYO_MOUNT_REMOUNT] = "--remount", |
15 | [TOMOYO_MOUNT_MAKE_UNBINDABLE] = "--make-unbindable", | 15 | [TOMOYO_MOUNT_MAKE_UNBINDABLE] = "--make-unbindable", |
16 | [TOMOYO_MOUNT_MAKE_PRIVATE] = "--make-private", | 16 | [TOMOYO_MOUNT_MAKE_PRIVATE] = "--make-private", |
17 | [TOMOYO_MOUNT_MAKE_SLAVE] = "--make-slave", | 17 | [TOMOYO_MOUNT_MAKE_SLAVE] = "--make-slave", |
18 | [TOMOYO_MOUNT_MAKE_SHARED] = "--make-shared", | 18 | [TOMOYO_MOUNT_MAKE_SHARED] = "--make-shared", |
19 | }; | 19 | }; |
20 | 20 | ||
21 | /** | 21 | /** |
22 | * tomoyo_audit_mount_log - Audit mount log. | 22 | * tomoyo_audit_mount_log - Audit mount log. |
23 | * | 23 | * |
24 | * @r: Pointer to "struct tomoyo_request_info". | 24 | * @r: Pointer to "struct tomoyo_request_info". |
25 | * | 25 | * |
26 | * Returns 0 on success, negative value otherwise. | 26 | * Returns 0 on success, negative value otherwise. |
27 | */ | 27 | */ |
28 | static int tomoyo_audit_mount_log(struct tomoyo_request_info *r) | 28 | static int tomoyo_audit_mount_log(struct tomoyo_request_info *r) |
29 | { | 29 | { |
30 | return tomoyo_supervisor(r, "file mount %s %s %s 0x%lX\n", | 30 | return tomoyo_supervisor(r, "file mount %s %s %s 0x%lX\n", |
31 | r->param.mount.dev->name, | 31 | r->param.mount.dev->name, |
32 | r->param.mount.dir->name, | 32 | r->param.mount.dir->name, |
33 | r->param.mount.type->name, | 33 | r->param.mount.type->name, |
34 | r->param.mount.flags); | 34 | r->param.mount.flags); |
35 | } | 35 | } |
36 | 36 | ||
37 | /** | 37 | /** |
38 | * tomoyo_check_mount_acl - Check permission for path path path number operation. | 38 | * tomoyo_check_mount_acl - Check permission for path path path number operation. |
39 | * | 39 | * |
40 | * @r: Pointer to "struct tomoyo_request_info". | 40 | * @r: Pointer to "struct tomoyo_request_info". |
41 | * @ptr: Pointer to "struct tomoyo_acl_info". | 41 | * @ptr: Pointer to "struct tomoyo_acl_info". |
42 | * | 42 | * |
43 | * Returns true if granted, false otherwise. | 43 | * Returns true if granted, false otherwise. |
44 | */ | 44 | */ |
45 | static bool tomoyo_check_mount_acl(struct tomoyo_request_info *r, | 45 | static bool tomoyo_check_mount_acl(struct tomoyo_request_info *r, |
46 | const struct tomoyo_acl_info *ptr) | 46 | const struct tomoyo_acl_info *ptr) |
47 | { | 47 | { |
48 | const struct tomoyo_mount_acl *acl = | 48 | const struct tomoyo_mount_acl *acl = |
49 | container_of(ptr, typeof(*acl), head); | 49 | container_of(ptr, typeof(*acl), head); |
50 | return tomoyo_compare_number_union(r->param.mount.flags, | 50 | return tomoyo_compare_number_union(r->param.mount.flags, |
51 | &acl->flags) && | 51 | &acl->flags) && |
52 | tomoyo_compare_name_union(r->param.mount.type, | 52 | tomoyo_compare_name_union(r->param.mount.type, |
53 | &acl->fs_type) && | 53 | &acl->fs_type) && |
54 | tomoyo_compare_name_union(r->param.mount.dir, | 54 | tomoyo_compare_name_union(r->param.mount.dir, |
55 | &acl->dir_name) && | 55 | &acl->dir_name) && |
56 | (!r->param.mount.need_dev || | 56 | (!r->param.mount.need_dev || |
57 | tomoyo_compare_name_union(r->param.mount.dev, | 57 | tomoyo_compare_name_union(r->param.mount.dev, |
58 | &acl->dev_name)); | 58 | &acl->dev_name)); |
59 | } | 59 | } |
60 | 60 | ||
61 | /** | 61 | /** |
62 | * tomoyo_mount_acl - Check permission for mount() operation. | 62 | * tomoyo_mount_acl - Check permission for mount() operation. |
63 | * | 63 | * |
64 | * @r: Pointer to "struct tomoyo_request_info". | 64 | * @r: Pointer to "struct tomoyo_request_info". |
65 | * @dev_name: Name of device file. | 65 | * @dev_name: Name of device file. Maybe NULL. |
66 | * @dir: Pointer to "struct path". | 66 | * @dir: Pointer to "struct path". |
67 | * @type: Name of filesystem type. | 67 | * @type: Name of filesystem type. |
68 | * @flags: Mount options. | 68 | * @flags: Mount options. |
69 | * | 69 | * |
70 | * Returns 0 on success, negative value otherwise. | 70 | * Returns 0 on success, negative value otherwise. |
71 | * | 71 | * |
72 | * Caller holds tomoyo_read_lock(). | 72 | * Caller holds tomoyo_read_lock(). |
73 | */ | 73 | */ |
74 | static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name, | 74 | static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name, |
75 | struct path *dir, const char *type, | 75 | struct path *dir, const char *type, |
76 | unsigned long flags) | 76 | unsigned long flags) |
77 | { | 77 | { |
78 | struct tomoyo_obj_info obj = { }; | 78 | struct tomoyo_obj_info obj = { }; |
79 | struct path path; | 79 | struct path path; |
80 | struct file_system_type *fstype = NULL; | 80 | struct file_system_type *fstype = NULL; |
81 | const char *requested_type = NULL; | 81 | const char *requested_type = NULL; |
82 | const char *requested_dir_name = NULL; | 82 | const char *requested_dir_name = NULL; |
83 | const char *requested_dev_name = NULL; | 83 | const char *requested_dev_name = NULL; |
84 | struct tomoyo_path_info rtype; | 84 | struct tomoyo_path_info rtype; |
85 | struct tomoyo_path_info rdev; | 85 | struct tomoyo_path_info rdev; |
86 | struct tomoyo_path_info rdir; | 86 | struct tomoyo_path_info rdir; |
87 | int need_dev = 0; | 87 | int need_dev = 0; |
88 | int error = -ENOMEM; | 88 | int error = -ENOMEM; |
89 | r->obj = &obj; | 89 | r->obj = &obj; |
90 | 90 | ||
91 | /* Get fstype. */ | 91 | /* Get fstype. */ |
92 | requested_type = tomoyo_encode(type); | 92 | requested_type = tomoyo_encode(type); |
93 | if (!requested_type) | 93 | if (!requested_type) |
94 | goto out; | 94 | goto out; |
95 | rtype.name = requested_type; | 95 | rtype.name = requested_type; |
96 | tomoyo_fill_path_info(&rtype); | 96 | tomoyo_fill_path_info(&rtype); |
97 | 97 | ||
98 | /* Get mount point. */ | 98 | /* Get mount point. */ |
99 | obj.path2 = *dir; | 99 | obj.path2 = *dir; |
100 | requested_dir_name = tomoyo_realpath_from_path(dir); | 100 | requested_dir_name = tomoyo_realpath_from_path(dir); |
101 | if (!requested_dir_name) { | 101 | if (!requested_dir_name) { |
102 | error = -ENOMEM; | 102 | error = -ENOMEM; |
103 | goto out; | 103 | goto out; |
104 | } | 104 | } |
105 | rdir.name = requested_dir_name; | 105 | rdir.name = requested_dir_name; |
106 | tomoyo_fill_path_info(&rdir); | 106 | tomoyo_fill_path_info(&rdir); |
107 | 107 | ||
108 | /* Compare fs name. */ | 108 | /* Compare fs name. */ |
109 | if (type == tomoyo_mounts[TOMOYO_MOUNT_REMOUNT]) { | 109 | if (type == tomoyo_mounts[TOMOYO_MOUNT_REMOUNT]) { |
110 | /* dev_name is ignored. */ | 110 | /* dev_name is ignored. */ |
111 | } else if (type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_UNBINDABLE] || | 111 | } else if (type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_UNBINDABLE] || |
112 | type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_PRIVATE] || | 112 | type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_PRIVATE] || |
113 | type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_SLAVE] || | 113 | type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_SLAVE] || |
114 | type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_SHARED]) { | 114 | type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_SHARED]) { |
115 | /* dev_name is ignored. */ | 115 | /* dev_name is ignored. */ |
116 | } else if (type == tomoyo_mounts[TOMOYO_MOUNT_BIND] || | 116 | } else if (type == tomoyo_mounts[TOMOYO_MOUNT_BIND] || |
117 | type == tomoyo_mounts[TOMOYO_MOUNT_MOVE]) { | 117 | type == tomoyo_mounts[TOMOYO_MOUNT_MOVE]) { |
118 | need_dev = -1; /* dev_name is a directory */ | 118 | need_dev = -1; /* dev_name is a directory */ |
119 | } else { | 119 | } else { |
120 | fstype = get_fs_type(type); | 120 | fstype = get_fs_type(type); |
121 | if (!fstype) { | 121 | if (!fstype) { |
122 | error = -ENODEV; | 122 | error = -ENODEV; |
123 | goto out; | 123 | goto out; |
124 | } | 124 | } |
125 | if (fstype->fs_flags & FS_REQUIRES_DEV) | 125 | if (fstype->fs_flags & FS_REQUIRES_DEV) |
126 | /* dev_name is a block device file. */ | 126 | /* dev_name is a block device file. */ |
127 | need_dev = 1; | 127 | need_dev = 1; |
128 | } | 128 | } |
129 | if (need_dev) { | 129 | if (need_dev) { |
130 | /* Get mount point or device file. */ | 130 | /* Get mount point or device file. */ |
131 | if (!dev_name || kern_path(dev_name, LOOKUP_FOLLOW, &path)) { | 131 | if (!dev_name || kern_path(dev_name, LOOKUP_FOLLOW, &path)) { |
132 | error = -ENOENT; | 132 | error = -ENOENT; |
133 | goto out; | 133 | goto out; |
134 | } | 134 | } |
135 | obj.path1 = path; | 135 | obj.path1 = path; |
136 | requested_dev_name = tomoyo_realpath_from_path(&path); | 136 | requested_dev_name = tomoyo_realpath_from_path(&path); |
137 | if (!requested_dev_name) { | 137 | if (!requested_dev_name) { |
138 | error = -ENOENT; | 138 | error = -ENOENT; |
139 | goto out; | 139 | goto out; |
140 | } | 140 | } |
141 | } else { | 141 | } else { |
142 | /* Map dev_name to "<NULL>" if no dev_name given. */ | 142 | /* Map dev_name to "<NULL>" if no dev_name given. */ |
143 | if (!dev_name) | 143 | if (!dev_name) |
144 | dev_name = "<NULL>"; | 144 | dev_name = "<NULL>"; |
145 | requested_dev_name = tomoyo_encode(dev_name); | 145 | requested_dev_name = tomoyo_encode(dev_name); |
146 | if (!requested_dev_name) { | 146 | if (!requested_dev_name) { |
147 | error = -ENOMEM; | 147 | error = -ENOMEM; |
148 | goto out; | 148 | goto out; |
149 | } | 149 | } |
150 | } | 150 | } |
151 | rdev.name = requested_dev_name; | 151 | rdev.name = requested_dev_name; |
152 | tomoyo_fill_path_info(&rdev); | 152 | tomoyo_fill_path_info(&rdev); |
153 | r->param_type = TOMOYO_TYPE_MOUNT_ACL; | 153 | r->param_type = TOMOYO_TYPE_MOUNT_ACL; |
154 | r->param.mount.need_dev = need_dev; | 154 | r->param.mount.need_dev = need_dev; |
155 | r->param.mount.dev = &rdev; | 155 | r->param.mount.dev = &rdev; |
156 | r->param.mount.dir = &rdir; | 156 | r->param.mount.dir = &rdir; |
157 | r->param.mount.type = &rtype; | 157 | r->param.mount.type = &rtype; |
158 | r->param.mount.flags = flags; | 158 | r->param.mount.flags = flags; |
159 | do { | 159 | do { |
160 | tomoyo_check_acl(r, tomoyo_check_mount_acl); | 160 | tomoyo_check_acl(r, tomoyo_check_mount_acl); |
161 | error = tomoyo_audit_mount_log(r); | 161 | error = tomoyo_audit_mount_log(r); |
162 | } while (error == TOMOYO_RETRY_REQUEST); | 162 | } while (error == TOMOYO_RETRY_REQUEST); |
163 | out: | 163 | out: |
164 | kfree(requested_dev_name); | 164 | kfree(requested_dev_name); |
165 | kfree(requested_dir_name); | 165 | kfree(requested_dir_name); |
166 | if (fstype) | 166 | if (fstype) |
167 | put_filesystem(fstype); | 167 | put_filesystem(fstype); |
168 | kfree(requested_type); | 168 | kfree(requested_type); |
169 | /* Drop refcount obtained by kern_path(). */ | 169 | /* Drop refcount obtained by kern_path(). */ |
170 | if (obj.path1.dentry) | 170 | if (obj.path1.dentry) |
171 | path_put(&obj.path1); | 171 | path_put(&obj.path1); |
172 | return error; | 172 | return error; |
173 | } | 173 | } |
174 | 174 | ||
175 | /** | 175 | /** |
176 | * tomoyo_mount_permission - Check permission for mount() operation. | 176 | * tomoyo_mount_permission - Check permission for mount() operation. |
177 | * | 177 | * |
178 | * @dev_name: Name of device file. | 178 | * @dev_name: Name of device file. Maybe NULL. |
179 | * @path: Pointer to "struct path". | 179 | * @path: Pointer to "struct path". |
180 | * @type: Name of filesystem type. May be NULL. | 180 | * @type: Name of filesystem type. Maybe NULL. |
181 | * @flags: Mount options. | 181 | * @flags: Mount options. |
182 | * @data_page: Optional data. May be NULL. | 182 | * @data_page: Optional data. Maybe NULL. |
183 | * | 183 | * |
184 | * Returns 0 on success, negative value otherwise. | 184 | * Returns 0 on success, negative value otherwise. |
185 | */ | 185 | */ |
186 | int tomoyo_mount_permission(char *dev_name, struct path *path, | 186 | int tomoyo_mount_permission(char *dev_name, struct path *path, |
187 | const char *type, unsigned long flags, | 187 | const char *type, unsigned long flags, |
188 | void *data_page) | 188 | void *data_page) |
189 | { | 189 | { |
190 | struct tomoyo_request_info r; | 190 | struct tomoyo_request_info r; |
191 | int error; | 191 | int error; |
192 | int idx; | 192 | int idx; |
193 | 193 | ||
194 | if (tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_MOUNT) | 194 | if (tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_MOUNT) |
195 | == TOMOYO_CONFIG_DISABLED) | 195 | == TOMOYO_CONFIG_DISABLED) |
196 | return 0; | 196 | return 0; |
197 | if ((flags & MS_MGC_MSK) == MS_MGC_VAL) | 197 | if ((flags & MS_MGC_MSK) == MS_MGC_VAL) |
198 | flags &= ~MS_MGC_MSK; | 198 | flags &= ~MS_MGC_MSK; |
199 | if (flags & MS_REMOUNT) { | 199 | if (flags & MS_REMOUNT) { |
200 | type = tomoyo_mounts[TOMOYO_MOUNT_REMOUNT]; | 200 | type = tomoyo_mounts[TOMOYO_MOUNT_REMOUNT]; |
201 | flags &= ~MS_REMOUNT; | 201 | flags &= ~MS_REMOUNT; |
202 | } | 202 | } |
203 | if (flags & MS_MOVE) { | 203 | if (flags & MS_MOVE) { |
204 | type = tomoyo_mounts[TOMOYO_MOUNT_MOVE]; | 204 | type = tomoyo_mounts[TOMOYO_MOUNT_MOVE]; |
205 | flags &= ~MS_MOVE; | 205 | flags &= ~MS_MOVE; |
206 | } | 206 | } |
207 | if (flags & MS_BIND) { | 207 | if (flags & MS_BIND) { |
208 | type = tomoyo_mounts[TOMOYO_MOUNT_BIND]; | 208 | type = tomoyo_mounts[TOMOYO_MOUNT_BIND]; |
209 | flags &= ~MS_BIND; | 209 | flags &= ~MS_BIND; |
210 | } | 210 | } |
211 | if (flags & MS_UNBINDABLE) { | 211 | if (flags & MS_UNBINDABLE) { |
212 | type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_UNBINDABLE]; | 212 | type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_UNBINDABLE]; |
213 | flags &= ~MS_UNBINDABLE; | 213 | flags &= ~MS_UNBINDABLE; |
214 | } | 214 | } |
215 | if (flags & MS_PRIVATE) { | 215 | if (flags & MS_PRIVATE) { |
216 | type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_PRIVATE]; | 216 | type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_PRIVATE]; |
217 | flags &= ~MS_PRIVATE; | 217 | flags &= ~MS_PRIVATE; |
218 | } | 218 | } |
219 | if (flags & MS_SLAVE) { | 219 | if (flags & MS_SLAVE) { |
220 | type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_SLAVE]; | 220 | type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_SLAVE]; |
221 | flags &= ~MS_SLAVE; | 221 | flags &= ~MS_SLAVE; |
222 | } | 222 | } |
223 | if (flags & MS_SHARED) { | 223 | if (flags & MS_SHARED) { |
224 | type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_SHARED]; | 224 | type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_SHARED]; |
225 | flags &= ~MS_SHARED; | 225 | flags &= ~MS_SHARED; |
226 | } | 226 | } |
227 | if (!type) | 227 | if (!type) |
228 | type = "<NULL>"; | 228 | type = "<NULL>"; |
229 | idx = tomoyo_read_lock(); | 229 | idx = tomoyo_read_lock(); |
230 | error = tomoyo_mount_acl(&r, dev_name, path, type, flags); | 230 | error = tomoyo_mount_acl(&r, dev_name, path, type, flags); |
231 | tomoyo_read_unlock(idx); | 231 | tomoyo_read_unlock(idx); |
232 | return error; | 232 | return error; |
233 | } | 233 | } |
234 | 234 |
security/tomoyo/realpath.c
1 | /* | 1 | /* |
2 | * security/tomoyo/realpath.c | 2 | * security/tomoyo/realpath.c |
3 | * | 3 | * |
4 | * Pathname calculation functions for TOMOYO. | 4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION |
5 | * | ||
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
7 | */ | 5 | */ |
8 | 6 | ||
9 | #include <linux/types.h> | 7 | #include <linux/types.h> |
10 | #include <linux/mount.h> | 8 | #include <linux/mount.h> |
11 | #include <linux/mnt_namespace.h> | 9 | #include <linux/mnt_namespace.h> |
12 | #include <linux/fs_struct.h> | 10 | #include <linux/fs_struct.h> |
13 | #include <linux/magic.h> | 11 | #include <linux/magic.h> |
14 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
15 | #include <net/sock.h> | 13 | #include <net/sock.h> |
16 | #include "common.h" | 14 | #include "common.h" |
17 | #include "../../fs/internal.h" | 15 | #include "../../fs/internal.h" |
18 | 16 | ||
19 | /** | 17 | /** |
20 | * tomoyo_encode: Convert binary string to ascii string. | 18 | * tomoyo_encode: Convert binary string to ascii string. |
21 | * | 19 | * |
22 | * @str: String in binary format. | 20 | * @str: String in binary format. |
23 | * | 21 | * |
24 | * Returns pointer to @str in ascii format on success, NULL otherwise. | 22 | * Returns pointer to @str in ascii format on success, NULL otherwise. |
25 | * | 23 | * |
26 | * This function uses kzalloc(), so caller must kfree() if this function | 24 | * This function uses kzalloc(), so caller must kfree() if this function |
27 | * didn't return NULL. | 25 | * didn't return NULL. |
28 | */ | 26 | */ |
29 | char *tomoyo_encode(const char *str) | 27 | char *tomoyo_encode(const char *str) |
30 | { | 28 | { |
31 | int len = 0; | 29 | int len = 0; |
32 | const char *p = str; | 30 | const char *p = str; |
33 | char *cp; | 31 | char *cp; |
34 | char *cp0; | 32 | char *cp0; |
35 | 33 | ||
36 | if (!p) | 34 | if (!p) |
37 | return NULL; | 35 | return NULL; |
38 | while (*p) { | 36 | while (*p) { |
39 | const unsigned char c = *p++; | 37 | const unsigned char c = *p++; |
40 | if (c == '\\') | 38 | if (c == '\\') |
41 | len += 2; | 39 | len += 2; |
42 | else if (c > ' ' && c < 127) | 40 | else if (c > ' ' && c < 127) |
43 | len++; | 41 | len++; |
44 | else | 42 | else |
45 | len += 4; | 43 | len += 4; |
46 | } | 44 | } |
47 | len++; | 45 | len++; |
48 | /* Reserve space for appending "/". */ | 46 | /* Reserve space for appending "/". */ |
49 | cp = kzalloc(len + 10, GFP_NOFS); | 47 | cp = kzalloc(len + 10, GFP_NOFS); |
50 | if (!cp) | 48 | if (!cp) |
51 | return NULL; | 49 | return NULL; |
52 | cp0 = cp; | 50 | cp0 = cp; |
53 | p = str; | 51 | p = str; |
54 | while (*p) { | 52 | while (*p) { |
55 | const unsigned char c = *p++; | 53 | const unsigned char c = *p++; |
56 | 54 | ||
57 | if (c == '\\') { | 55 | if (c == '\\') { |
58 | *cp++ = '\\'; | 56 | *cp++ = '\\'; |
59 | *cp++ = '\\'; | 57 | *cp++ = '\\'; |
60 | } else if (c > ' ' && c < 127) { | 58 | } else if (c > ' ' && c < 127) { |
61 | *cp++ = c; | 59 | *cp++ = c; |
62 | } else { | 60 | } else { |
63 | *cp++ = '\\'; | 61 | *cp++ = '\\'; |
64 | *cp++ = (c >> 6) + '0'; | 62 | *cp++ = (c >> 6) + '0'; |
65 | *cp++ = ((c >> 3) & 7) + '0'; | 63 | *cp++ = ((c >> 3) & 7) + '0'; |
66 | *cp++ = (c & 7) + '0'; | 64 | *cp++ = (c & 7) + '0'; |
67 | } | 65 | } |
68 | } | 66 | } |
69 | return cp0; | 67 | return cp0; |
70 | } | 68 | } |
71 | 69 | ||
72 | /** | 70 | /** |
73 | * tomoyo_get_absolute_path - Get the path of a dentry but ignores chroot'ed root. | 71 | * tomoyo_get_absolute_path - Get the path of a dentry but ignores chroot'ed root. |
74 | * | 72 | * |
75 | * @path: Pointer to "struct path". | 73 | * @path: Pointer to "struct path". |
76 | * @buffer: Pointer to buffer to return value in. | 74 | * @buffer: Pointer to buffer to return value in. |
77 | * @buflen: Sizeof @buffer. | 75 | * @buflen: Sizeof @buffer. |
78 | * | 76 | * |
79 | * Returns the buffer on success, an error code otherwise. | 77 | * Returns the buffer on success, an error code otherwise. |
80 | * | 78 | * |
81 | * If dentry is a directory, trailing '/' is appended. | 79 | * If dentry is a directory, trailing '/' is appended. |
82 | */ | 80 | */ |
83 | static char *tomoyo_get_absolute_path(struct path *path, char * const buffer, | 81 | static char *tomoyo_get_absolute_path(struct path *path, char * const buffer, |
84 | const int buflen) | 82 | const int buflen) |
85 | { | 83 | { |
86 | char *pos = ERR_PTR(-ENOMEM); | 84 | char *pos = ERR_PTR(-ENOMEM); |
87 | if (buflen >= 256) { | 85 | if (buflen >= 256) { |
88 | struct path ns_root = { }; | 86 | struct path ns_root = { }; |
89 | /* go to whatever namespace root we are under */ | 87 | /* go to whatever namespace root we are under */ |
90 | pos = __d_path(path, &ns_root, buffer, buflen - 1); | 88 | pos = __d_path(path, &ns_root, buffer, buflen - 1); |
91 | if (!IS_ERR(pos) && *pos == '/' && pos[1]) { | 89 | if (!IS_ERR(pos) && *pos == '/' && pos[1]) { |
92 | struct inode *inode = path->dentry->d_inode; | 90 | struct inode *inode = path->dentry->d_inode; |
93 | if (inode && S_ISDIR(inode->i_mode)) { | 91 | if (inode && S_ISDIR(inode->i_mode)) { |
94 | buffer[buflen - 2] = '/'; | 92 | buffer[buflen - 2] = '/'; |
95 | buffer[buflen - 1] = '\0'; | 93 | buffer[buflen - 1] = '\0'; |
96 | } | 94 | } |
97 | } | 95 | } |
98 | } | 96 | } |
99 | return pos; | 97 | return pos; |
100 | } | 98 | } |
101 | 99 | ||
102 | /** | 100 | /** |
103 | * tomoyo_get_dentry_path - Get the path of a dentry. | 101 | * tomoyo_get_dentry_path - Get the path of a dentry. |
104 | * | 102 | * |
105 | * @dentry: Pointer to "struct dentry". | 103 | * @dentry: Pointer to "struct dentry". |
106 | * @buffer: Pointer to buffer to return value in. | 104 | * @buffer: Pointer to buffer to return value in. |
107 | * @buflen: Sizeof @buffer. | 105 | * @buflen: Sizeof @buffer. |
108 | * | 106 | * |
109 | * Returns the buffer on success, an error code otherwise. | 107 | * Returns the buffer on success, an error code otherwise. |
110 | * | 108 | * |
111 | * If dentry is a directory, trailing '/' is appended. | 109 | * If dentry is a directory, trailing '/' is appended. |
112 | */ | 110 | */ |
113 | static char *tomoyo_get_dentry_path(struct dentry *dentry, char * const buffer, | 111 | static char *tomoyo_get_dentry_path(struct dentry *dentry, char * const buffer, |
114 | const int buflen) | 112 | const int buflen) |
115 | { | 113 | { |
116 | char *pos = ERR_PTR(-ENOMEM); | 114 | char *pos = ERR_PTR(-ENOMEM); |
117 | if (buflen >= 256) { | 115 | if (buflen >= 256) { |
118 | pos = dentry_path_raw(dentry, buffer, buflen - 1); | 116 | pos = dentry_path_raw(dentry, buffer, buflen - 1); |
119 | if (!IS_ERR(pos) && *pos == '/' && pos[1]) { | 117 | if (!IS_ERR(pos) && *pos == '/' && pos[1]) { |
120 | struct inode *inode = dentry->d_inode; | 118 | struct inode *inode = dentry->d_inode; |
121 | if (inode && S_ISDIR(inode->i_mode)) { | 119 | if (inode && S_ISDIR(inode->i_mode)) { |
122 | buffer[buflen - 2] = '/'; | 120 | buffer[buflen - 2] = '/'; |
123 | buffer[buflen - 1] = '\0'; | 121 | buffer[buflen - 1] = '\0'; |
124 | } | 122 | } |
125 | } | 123 | } |
126 | } | 124 | } |
127 | return pos; | 125 | return pos; |
128 | } | 126 | } |
129 | 127 | ||
130 | /** | 128 | /** |
131 | * tomoyo_get_local_path - Get the path of a dentry. | 129 | * tomoyo_get_local_path - Get the path of a dentry. |
132 | * | 130 | * |
133 | * @dentry: Pointer to "struct dentry". | 131 | * @dentry: Pointer to "struct dentry". |
134 | * @buffer: Pointer to buffer to return value in. | 132 | * @buffer: Pointer to buffer to return value in. |
135 | * @buflen: Sizeof @buffer. | 133 | * @buflen: Sizeof @buffer. |
136 | * | 134 | * |
137 | * Returns the buffer on success, an error code otherwise. | 135 | * Returns the buffer on success, an error code otherwise. |
138 | */ | 136 | */ |
139 | static char *tomoyo_get_local_path(struct dentry *dentry, char * const buffer, | 137 | static char *tomoyo_get_local_path(struct dentry *dentry, char * const buffer, |
140 | const int buflen) | 138 | const int buflen) |
141 | { | 139 | { |
142 | struct super_block *sb = dentry->d_sb; | 140 | struct super_block *sb = dentry->d_sb; |
143 | char *pos = tomoyo_get_dentry_path(dentry, buffer, buflen); | 141 | char *pos = tomoyo_get_dentry_path(dentry, buffer, buflen); |
144 | if (IS_ERR(pos)) | 142 | if (IS_ERR(pos)) |
145 | return pos; | 143 | return pos; |
146 | /* Convert from $PID to self if $PID is current thread. */ | 144 | /* Convert from $PID to self if $PID is current thread. */ |
147 | if (sb->s_magic == PROC_SUPER_MAGIC && *pos == '/') { | 145 | if (sb->s_magic == PROC_SUPER_MAGIC && *pos == '/') { |
148 | char *ep; | 146 | char *ep; |
149 | const pid_t pid = (pid_t) simple_strtoul(pos + 1, &ep, 10); | 147 | const pid_t pid = (pid_t) simple_strtoul(pos + 1, &ep, 10); |
150 | if (*ep == '/' && pid && pid == | 148 | if (*ep == '/' && pid && pid == |
151 | task_tgid_nr_ns(current, sb->s_fs_info)) { | 149 | task_tgid_nr_ns(current, sb->s_fs_info)) { |
152 | pos = ep - 5; | 150 | pos = ep - 5; |
153 | if (pos < buffer) | 151 | if (pos < buffer) |
154 | goto out; | 152 | goto out; |
155 | memmove(pos, "/self", 5); | 153 | memmove(pos, "/self", 5); |
156 | } | 154 | } |
157 | goto prepend_filesystem_name; | 155 | goto prepend_filesystem_name; |
158 | } | 156 | } |
159 | /* Use filesystem name for unnamed devices. */ | 157 | /* Use filesystem name for unnamed devices. */ |
160 | if (!MAJOR(sb->s_dev)) | 158 | if (!MAJOR(sb->s_dev)) |
161 | goto prepend_filesystem_name; | 159 | goto prepend_filesystem_name; |
162 | { | 160 | { |
163 | struct inode *inode = sb->s_root->d_inode; | 161 | struct inode *inode = sb->s_root->d_inode; |
164 | /* | 162 | /* |
165 | * Use filesystem name if filesystem does not support rename() | 163 | * Use filesystem name if filesystem does not support rename() |
166 | * operation. | 164 | * operation. |
167 | */ | 165 | */ |
168 | if (inode->i_op && !inode->i_op->rename) | 166 | if (inode->i_op && !inode->i_op->rename) |
169 | goto prepend_filesystem_name; | 167 | goto prepend_filesystem_name; |
170 | } | 168 | } |
171 | /* Prepend device name. */ | 169 | /* Prepend device name. */ |
172 | { | 170 | { |
173 | char name[64]; | 171 | char name[64]; |
174 | int name_len; | 172 | int name_len; |
175 | const dev_t dev = sb->s_dev; | 173 | const dev_t dev = sb->s_dev; |
176 | name[sizeof(name) - 1] = '\0'; | 174 | name[sizeof(name) - 1] = '\0'; |
177 | snprintf(name, sizeof(name) - 1, "dev(%u,%u):", MAJOR(dev), | 175 | snprintf(name, sizeof(name) - 1, "dev(%u,%u):", MAJOR(dev), |
178 | MINOR(dev)); | 176 | MINOR(dev)); |
179 | name_len = strlen(name); | 177 | name_len = strlen(name); |
180 | pos -= name_len; | 178 | pos -= name_len; |
181 | if (pos < buffer) | 179 | if (pos < buffer) |
182 | goto out; | 180 | goto out; |
183 | memmove(pos, name, name_len); | 181 | memmove(pos, name, name_len); |
184 | return pos; | 182 | return pos; |
185 | } | 183 | } |
186 | /* Prepend filesystem name. */ | 184 | /* Prepend filesystem name. */ |
187 | prepend_filesystem_name: | 185 | prepend_filesystem_name: |
188 | { | 186 | { |
189 | const char *name = sb->s_type->name; | 187 | const char *name = sb->s_type->name; |
190 | const int name_len = strlen(name); | 188 | const int name_len = strlen(name); |
191 | pos -= name_len + 1; | 189 | pos -= name_len + 1; |
192 | if (pos < buffer) | 190 | if (pos < buffer) |
193 | goto out; | 191 | goto out; |
194 | memmove(pos, name, name_len); | 192 | memmove(pos, name, name_len); |
195 | pos[name_len] = ':'; | 193 | pos[name_len] = ':'; |
196 | } | 194 | } |
197 | return pos; | 195 | return pos; |
198 | out: | 196 | out: |
199 | return ERR_PTR(-ENOMEM); | 197 | return ERR_PTR(-ENOMEM); |
200 | } | 198 | } |
201 | 199 | ||
202 | /** | 200 | /** |
203 | * tomoyo_get_socket_name - Get the name of a socket. | 201 | * tomoyo_get_socket_name - Get the name of a socket. |
204 | * | 202 | * |
205 | * @path: Pointer to "struct path". | 203 | * @path: Pointer to "struct path". |
206 | * @buffer: Pointer to buffer to return value in. | 204 | * @buffer: Pointer to buffer to return value in. |
207 | * @buflen: Sizeof @buffer. | 205 | * @buflen: Sizeof @buffer. |
208 | * | 206 | * |
209 | * Returns the buffer. | 207 | * Returns the buffer. |
210 | */ | 208 | */ |
211 | static char *tomoyo_get_socket_name(struct path *path, char * const buffer, | 209 | static char *tomoyo_get_socket_name(struct path *path, char * const buffer, |
212 | const int buflen) | 210 | const int buflen) |
213 | { | 211 | { |
214 | struct inode *inode = path->dentry->d_inode; | 212 | struct inode *inode = path->dentry->d_inode; |
215 | struct socket *sock = inode ? SOCKET_I(inode) : NULL; | 213 | struct socket *sock = inode ? SOCKET_I(inode) : NULL; |
216 | struct sock *sk = sock ? sock->sk : NULL; | 214 | struct sock *sk = sock ? sock->sk : NULL; |
217 | if (sk) { | 215 | if (sk) { |
218 | snprintf(buffer, buflen, "socket:[family=%u:type=%u:" | 216 | snprintf(buffer, buflen, "socket:[family=%u:type=%u:" |
219 | "protocol=%u]", sk->sk_family, sk->sk_type, | 217 | "protocol=%u]", sk->sk_family, sk->sk_type, |
220 | sk->sk_protocol); | 218 | sk->sk_protocol); |
221 | } else { | 219 | } else { |
222 | snprintf(buffer, buflen, "socket:[unknown]"); | 220 | snprintf(buffer, buflen, "socket:[unknown]"); |
223 | } | 221 | } |
224 | return buffer; | 222 | return buffer; |
225 | } | 223 | } |
226 | 224 | ||
227 | /** | 225 | /** |
228 | * tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root. | 226 | * tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root. |
229 | * | 227 | * |
230 | * @path: Pointer to "struct path". | 228 | * @path: Pointer to "struct path". |
231 | * | 229 | * |
232 | * Returns the realpath of the given @path on success, NULL otherwise. | 230 | * Returns the realpath of the given @path on success, NULL otherwise. |
233 | * | 231 | * |
234 | * If dentry is a directory, trailing '/' is appended. | 232 | * If dentry is a directory, trailing '/' is appended. |
235 | * Characters out of 0x20 < c < 0x7F range are converted to | 233 | * Characters out of 0x20 < c < 0x7F range are converted to |
236 | * \ooo style octal string. | 234 | * \ooo style octal string. |
237 | * Character \ is converted to \\ string. | 235 | * Character \ is converted to \\ string. |
238 | * | 236 | * |
239 | * These functions use kzalloc(), so the caller must call kfree() | 237 | * These functions use kzalloc(), so the caller must call kfree() |
240 | * if these functions didn't return NULL. | 238 | * if these functions didn't return NULL. |
241 | */ | 239 | */ |
242 | char *tomoyo_realpath_from_path(struct path *path) | 240 | char *tomoyo_realpath_from_path(struct path *path) |
243 | { | 241 | { |
244 | char *buf = NULL; | 242 | char *buf = NULL; |
245 | char *name = NULL; | 243 | char *name = NULL; |
246 | unsigned int buf_len = PAGE_SIZE / 2; | 244 | unsigned int buf_len = PAGE_SIZE / 2; |
247 | struct dentry *dentry = path->dentry; | 245 | struct dentry *dentry = path->dentry; |
248 | struct super_block *sb; | 246 | struct super_block *sb; |
249 | if (!dentry) | 247 | if (!dentry) |
250 | return NULL; | 248 | return NULL; |
251 | sb = dentry->d_sb; | 249 | sb = dentry->d_sb; |
252 | while (1) { | 250 | while (1) { |
253 | char *pos; | 251 | char *pos; |
254 | struct inode *inode; | 252 | struct inode *inode; |
255 | buf_len <<= 1; | 253 | buf_len <<= 1; |
256 | kfree(buf); | 254 | kfree(buf); |
257 | buf = kmalloc(buf_len, GFP_NOFS); | 255 | buf = kmalloc(buf_len, GFP_NOFS); |
258 | if (!buf) | 256 | if (!buf) |
259 | break; | 257 | break; |
260 | /* To make sure that pos is '\0' terminated. */ | 258 | /* To make sure that pos is '\0' terminated. */ |
261 | buf[buf_len - 1] = '\0'; | 259 | buf[buf_len - 1] = '\0'; |
262 | /* Get better name for socket. */ | 260 | /* Get better name for socket. */ |
263 | if (sb->s_magic == SOCKFS_MAGIC) { | 261 | if (sb->s_magic == SOCKFS_MAGIC) { |
264 | pos = tomoyo_get_socket_name(path, buf, buf_len - 1); | 262 | pos = tomoyo_get_socket_name(path, buf, buf_len - 1); |
265 | goto encode; | 263 | goto encode; |
266 | } | 264 | } |
267 | /* For "pipe:[\$]". */ | 265 | /* For "pipe:[\$]". */ |
268 | if (dentry->d_op && dentry->d_op->d_dname) { | 266 | if (dentry->d_op && dentry->d_op->d_dname) { |
269 | pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1); | 267 | pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1); |
270 | goto encode; | 268 | goto encode; |
271 | } | 269 | } |
272 | inode = sb->s_root->d_inode; | 270 | inode = sb->s_root->d_inode; |
273 | /* | 271 | /* |
274 | * Get local name for filesystems without rename() operation | 272 | * Get local name for filesystems without rename() operation |
275 | * or dentry without vfsmount. | 273 | * or dentry without vfsmount. |
276 | */ | 274 | */ |
277 | if (!path->mnt || (inode->i_op && !inode->i_op->rename)) | 275 | if (!path->mnt || (inode->i_op && !inode->i_op->rename)) |
278 | pos = tomoyo_get_local_path(path->dentry, buf, | 276 | pos = tomoyo_get_local_path(path->dentry, buf, |
279 | buf_len - 1); | 277 | buf_len - 1); |
280 | /* Get absolute name for the rest. */ | 278 | /* Get absolute name for the rest. */ |
281 | else | 279 | else |
282 | pos = tomoyo_get_absolute_path(path, buf, buf_len - 1); | 280 | pos = tomoyo_get_absolute_path(path, buf, buf_len - 1); |
283 | encode: | 281 | encode: |
284 | if (IS_ERR(pos)) | 282 | if (IS_ERR(pos)) |
285 | continue; | 283 | continue; |
286 | name = tomoyo_encode(pos); | 284 | name = tomoyo_encode(pos); |
287 | break; | 285 | break; |
288 | } | 286 | } |
289 | kfree(buf); | 287 | kfree(buf); |
290 | if (!name) | 288 | if (!name) |
291 | tomoyo_warn_oom(__func__); | 289 | tomoyo_warn_oom(__func__); |
292 | return name; | 290 | return name; |
293 | } | 291 | } |
294 | 292 | ||
295 | /** | 293 | /** |
296 | * tomoyo_realpath_nofollow - Get realpath of a pathname. | 294 | * tomoyo_realpath_nofollow - Get realpath of a pathname. |
297 | * | 295 | * |
298 | * @pathname: The pathname to solve. | 296 | * @pathname: The pathname to solve. |
299 | * | 297 | * |
300 | * Returns the realpath of @pathname on success, NULL otherwise. | 298 | * Returns the realpath of @pathname on success, NULL otherwise. |
301 | */ | 299 | */ |
302 | char *tomoyo_realpath_nofollow(const char *pathname) | 300 | char *tomoyo_realpath_nofollow(const char *pathname) |
303 | { | 301 | { |
304 | struct path path; | 302 | struct path path; |
305 | 303 | ||
306 | if (pathname && kern_path(pathname, 0, &path) == 0) { | 304 | if (pathname && kern_path(pathname, 0, &path) == 0) { |
307 | char *buf = tomoyo_realpath_from_path(&path); | 305 | char *buf = tomoyo_realpath_from_path(&path); |
308 | path_put(&path); | 306 | path_put(&path); |
309 | return buf; | 307 | return buf; |
310 | } | 308 | } |
311 | return NULL; | 309 | return NULL; |
312 | } | 310 | } |
313 | 311 |
security/tomoyo/securityfs_if.c
1 | /* | 1 | /* |
2 | * security/tomoyo/common.c | 2 | * security/tomoyo/securityfs_if.c |
3 | * | 3 | * |
4 | * Securityfs interface for TOMOYO. | 4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION |
5 | * | ||
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
7 | */ | 5 | */ |
8 | 6 | ||
9 | #include <linux/security.h> | 7 | #include <linux/security.h> |
10 | #include "common.h" | 8 | #include "common.h" |
11 | 9 | ||
12 | /** | 10 | /** |
13 | * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface. | 11 | * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface. |
14 | * | 12 | * |
15 | * @inode: Pointer to "struct inode". | 13 | * @inode: Pointer to "struct inode". |
16 | * @file: Pointer to "struct file". | 14 | * @file: Pointer to "struct file". |
17 | * | 15 | * |
18 | * Returns 0 on success, negative value otherwise. | 16 | * Returns 0 on success, negative value otherwise. |
19 | */ | 17 | */ |
20 | static int tomoyo_open(struct inode *inode, struct file *file) | 18 | static int tomoyo_open(struct inode *inode, struct file *file) |
21 | { | 19 | { |
22 | const int key = ((u8 *) file->f_path.dentry->d_inode->i_private) | 20 | const int key = ((u8 *) file->f_path.dentry->d_inode->i_private) |
23 | - ((u8 *) NULL); | 21 | - ((u8 *) NULL); |
24 | return tomoyo_open_control(key, file); | 22 | return tomoyo_open_control(key, file); |
25 | } | 23 | } |
26 | 24 | ||
27 | /** | 25 | /** |
28 | * tomoyo_release - close() for /sys/kernel/security/tomoyo/ interface. | 26 | * tomoyo_release - close() for /sys/kernel/security/tomoyo/ interface. |
29 | * | 27 | * |
30 | * @inode: Pointer to "struct inode". | 28 | * @inode: Pointer to "struct inode". |
31 | * @file: Pointer to "struct file". | 29 | * @file: Pointer to "struct file". |
32 | * | 30 | * |
33 | * Returns 0 on success, negative value otherwise. | 31 | * Returns 0 on success, negative value otherwise. |
34 | */ | 32 | */ |
35 | static int tomoyo_release(struct inode *inode, struct file *file) | 33 | static int tomoyo_release(struct inode *inode, struct file *file) |
36 | { | 34 | { |
37 | return tomoyo_close_control(file->private_data); | 35 | return tomoyo_close_control(file->private_data); |
38 | } | 36 | } |
39 | 37 | ||
40 | /** | 38 | /** |
41 | * tomoyo_poll - poll() for /sys/kernel/security/tomoyo/ interface. | 39 | * tomoyo_poll - poll() for /sys/kernel/security/tomoyo/ interface. |
42 | * | 40 | * |
43 | * @file: Pointer to "struct file". | 41 | * @file: Pointer to "struct file". |
44 | * @wait: Pointer to "poll_table". | 42 | * @wait: Pointer to "poll_table". |
45 | * | 43 | * |
46 | * Returns 0 on success, negative value otherwise. | 44 | * Returns 0 on success, negative value otherwise. |
47 | */ | 45 | */ |
48 | static unsigned int tomoyo_poll(struct file *file, poll_table *wait) | 46 | static unsigned int tomoyo_poll(struct file *file, poll_table *wait) |
49 | { | 47 | { |
50 | return tomoyo_poll_control(file, wait); | 48 | return tomoyo_poll_control(file, wait); |
51 | } | 49 | } |
52 | 50 | ||
53 | /** | 51 | /** |
54 | * tomoyo_read - read() for /sys/kernel/security/tomoyo/ interface. | 52 | * tomoyo_read - read() for /sys/kernel/security/tomoyo/ interface. |
55 | * | 53 | * |
56 | * @file: Pointer to "struct file". | 54 | * @file: Pointer to "struct file". |
57 | * @buf: Pointer to buffer. | 55 | * @buf: Pointer to buffer. |
58 | * @count: Size of @buf. | 56 | * @count: Size of @buf. |
59 | * @ppos: Unused. | 57 | * @ppos: Unused. |
60 | * | 58 | * |
61 | * Returns bytes read on success, negative value otherwise. | 59 | * Returns bytes read on success, negative value otherwise. |
62 | */ | 60 | */ |
63 | static ssize_t tomoyo_read(struct file *file, char __user *buf, size_t count, | 61 | static ssize_t tomoyo_read(struct file *file, char __user *buf, size_t count, |
64 | loff_t *ppos) | 62 | loff_t *ppos) |
65 | { | 63 | { |
66 | return tomoyo_read_control(file->private_data, buf, count); | 64 | return tomoyo_read_control(file->private_data, buf, count); |
67 | } | 65 | } |
68 | 66 | ||
69 | /** | 67 | /** |
70 | * tomoyo_write - write() for /sys/kernel/security/tomoyo/ interface. | 68 | * tomoyo_write - write() for /sys/kernel/security/tomoyo/ interface. |
71 | * | 69 | * |
72 | * @file: Pointer to "struct file". | 70 | * @file: Pointer to "struct file". |
73 | * @buf: Pointer to buffer. | 71 | * @buf: Pointer to buffer. |
74 | * @count: Size of @buf. | 72 | * @count: Size of @buf. |
75 | * @ppos: Unused. | 73 | * @ppos: Unused. |
76 | * | 74 | * |
77 | * Returns @count on success, negative value otherwise. | 75 | * Returns @count on success, negative value otherwise. |
78 | */ | 76 | */ |
79 | static ssize_t tomoyo_write(struct file *file, const char __user *buf, | 77 | static ssize_t tomoyo_write(struct file *file, const char __user *buf, |
80 | size_t count, loff_t *ppos) | 78 | size_t count, loff_t *ppos) |
81 | { | 79 | { |
82 | return tomoyo_write_control(file->private_data, buf, count); | 80 | return tomoyo_write_control(file->private_data, buf, count); |
83 | } | 81 | } |
84 | 82 | ||
85 | /* | 83 | /* |
86 | * tomoyo_operations is a "struct file_operations" which is used for handling | 84 | * tomoyo_operations is a "struct file_operations" which is used for handling |
87 | * /sys/kernel/security/tomoyo/ interface. | 85 | * /sys/kernel/security/tomoyo/ interface. |
88 | * | 86 | * |
89 | * Some files under /sys/kernel/security/tomoyo/ directory accept open(O_RDWR). | 87 | * Some files under /sys/kernel/security/tomoyo/ directory accept open(O_RDWR). |
90 | * See tomoyo_io_buffer for internals. | 88 | * See tomoyo_io_buffer for internals. |
91 | */ | 89 | */ |
92 | static const struct file_operations tomoyo_operations = { | 90 | static const struct file_operations tomoyo_operations = { |
93 | .open = tomoyo_open, | 91 | .open = tomoyo_open, |
94 | .release = tomoyo_release, | 92 | .release = tomoyo_release, |
95 | .poll = tomoyo_poll, | 93 | .poll = tomoyo_poll, |
96 | .read = tomoyo_read, | 94 | .read = tomoyo_read, |
97 | .write = tomoyo_write, | 95 | .write = tomoyo_write, |
98 | .llseek = noop_llseek, | 96 | .llseek = noop_llseek, |
99 | }; | 97 | }; |
100 | 98 | ||
101 | /** | 99 | /** |
102 | * tomoyo_create_entry - Create interface files under /sys/kernel/security/tomoyo/ directory. | 100 | * tomoyo_create_entry - Create interface files under /sys/kernel/security/tomoyo/ directory. |
103 | * | 101 | * |
104 | * @name: The name of the interface file. | 102 | * @name: The name of the interface file. |
105 | * @mode: The permission of the interface file. | 103 | * @mode: The permission of the interface file. |
106 | * @parent: The parent directory. | 104 | * @parent: The parent directory. |
107 | * @key: Type of interface. | 105 | * @key: Type of interface. |
108 | * | 106 | * |
109 | * Returns nothing. | 107 | * Returns nothing. |
110 | */ | 108 | */ |
111 | static void __init tomoyo_create_entry(const char *name, const mode_t mode, | 109 | static void __init tomoyo_create_entry(const char *name, const mode_t mode, |
112 | struct dentry *parent, const u8 key) | 110 | struct dentry *parent, const u8 key) |
113 | { | 111 | { |
114 | securityfs_create_file(name, mode, parent, ((u8 *) NULL) + key, | 112 | securityfs_create_file(name, mode, parent, ((u8 *) NULL) + key, |
115 | &tomoyo_operations); | 113 | &tomoyo_operations); |
116 | } | 114 | } |
117 | 115 | ||
118 | /** | 116 | /** |
119 | * tomoyo_initerface_init - Initialize /sys/kernel/security/tomoyo/ interface. | 117 | * tomoyo_initerface_init - Initialize /sys/kernel/security/tomoyo/ interface. |
120 | * | 118 | * |
121 | * Returns 0. | 119 | * Returns 0. |
122 | */ | 120 | */ |
123 | static int __init tomoyo_initerface_init(void) | 121 | static int __init tomoyo_initerface_init(void) |
124 | { | 122 | { |
125 | struct dentry *tomoyo_dir; | 123 | struct dentry *tomoyo_dir; |
126 | 124 | ||
127 | /* Don't create securityfs entries unless registered. */ | 125 | /* Don't create securityfs entries unless registered. */ |
128 | if (current_cred()->security != &tomoyo_kernel_domain) | 126 | if (current_cred()->security != &tomoyo_kernel_domain) |
129 | return 0; | 127 | return 0; |
130 | 128 | ||
131 | tomoyo_dir = securityfs_create_dir("tomoyo", NULL); | 129 | tomoyo_dir = securityfs_create_dir("tomoyo", NULL); |
132 | tomoyo_create_entry("query", 0600, tomoyo_dir, | 130 | tomoyo_create_entry("query", 0600, tomoyo_dir, |
133 | TOMOYO_QUERY); | 131 | TOMOYO_QUERY); |
134 | tomoyo_create_entry("domain_policy", 0600, tomoyo_dir, | 132 | tomoyo_create_entry("domain_policy", 0600, tomoyo_dir, |
135 | TOMOYO_DOMAINPOLICY); | 133 | TOMOYO_DOMAINPOLICY); |
136 | tomoyo_create_entry("exception_policy", 0600, tomoyo_dir, | 134 | tomoyo_create_entry("exception_policy", 0600, tomoyo_dir, |
137 | TOMOYO_EXCEPTIONPOLICY); | 135 | TOMOYO_EXCEPTIONPOLICY); |
138 | tomoyo_create_entry("audit", 0400, tomoyo_dir, | 136 | tomoyo_create_entry("audit", 0400, tomoyo_dir, |
139 | TOMOYO_AUDIT); | 137 | TOMOYO_AUDIT); |
140 | tomoyo_create_entry("self_domain", 0400, tomoyo_dir, | 138 | tomoyo_create_entry("self_domain", 0400, tomoyo_dir, |
141 | TOMOYO_SELFDOMAIN); | 139 | TOMOYO_SELFDOMAIN); |
142 | tomoyo_create_entry(".process_status", 0600, tomoyo_dir, | 140 | tomoyo_create_entry(".process_status", 0600, tomoyo_dir, |
143 | TOMOYO_PROCESS_STATUS); | 141 | TOMOYO_PROCESS_STATUS); |
144 | tomoyo_create_entry("stat", 0644, tomoyo_dir, | 142 | tomoyo_create_entry("stat", 0644, tomoyo_dir, |
145 | TOMOYO_STAT); | 143 | TOMOYO_STAT); |
146 | tomoyo_create_entry("profile", 0600, tomoyo_dir, | 144 | tomoyo_create_entry("profile", 0600, tomoyo_dir, |
147 | TOMOYO_PROFILE); | 145 | TOMOYO_PROFILE); |
148 | tomoyo_create_entry("manager", 0600, tomoyo_dir, | 146 | tomoyo_create_entry("manager", 0600, tomoyo_dir, |
149 | TOMOYO_MANAGER); | 147 | TOMOYO_MANAGER); |
150 | tomoyo_create_entry("version", 0400, tomoyo_dir, | 148 | tomoyo_create_entry("version", 0400, tomoyo_dir, |
151 | TOMOYO_VERSION); | 149 | TOMOYO_VERSION); |
152 | return 0; | 150 | return 0; |
153 | } | 151 | } |
154 | 152 | ||
155 | fs_initcall(tomoyo_initerface_init); | 153 | fs_initcall(tomoyo_initerface_init); |
156 | 154 |
security/tomoyo/tomoyo.c
1 | /* | 1 | /* |
2 | * security/tomoyo/tomoyo.c | 2 | * security/tomoyo/tomoyo.c |
3 | * | 3 | * |
4 | * LSM hooks for TOMOYO Linux. | 4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION |
5 | * | ||
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
7 | */ | 5 | */ |
8 | 6 | ||
9 | #include <linux/security.h> | 7 | #include <linux/security.h> |
10 | #include "common.h" | 8 | #include "common.h" |
11 | 9 | ||
10 | /** | ||
11 | * tomoyo_cred_alloc_blank - Target for security_cred_alloc_blank(). | ||
12 | * | ||
13 | * @new: Pointer to "struct cred". | ||
14 | * @gfp: Memory allocation flags. | ||
15 | * | ||
16 | * Returns 0. | ||
17 | */ | ||
12 | static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp) | 18 | static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp) |
13 | { | 19 | { |
14 | new->security = NULL; | 20 | new->security = NULL; |
15 | return 0; | 21 | return 0; |
16 | } | 22 | } |
17 | 23 | ||
24 | /** | ||
25 | * tomoyo_cred_prepare - Target for security_prepare_creds(). | ||
26 | * | ||
27 | * @new: Pointer to "struct cred". | ||
28 | * @old: Pointer to "struct cred". | ||
29 | * @gfp: Memory allocation flags. | ||
30 | * | ||
31 | * Returns 0. | ||
32 | */ | ||
18 | static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, | 33 | static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, |
19 | gfp_t gfp) | 34 | gfp_t gfp) |
20 | { | 35 | { |
21 | struct tomoyo_domain_info *domain = old->security; | 36 | struct tomoyo_domain_info *domain = old->security; |
22 | new->security = domain; | 37 | new->security = domain; |
23 | if (domain) | 38 | if (domain) |
24 | atomic_inc(&domain->users); | 39 | atomic_inc(&domain->users); |
25 | return 0; | 40 | return 0; |
26 | } | 41 | } |
27 | 42 | ||
43 | /** | ||
44 | * tomoyo_cred_transfer - Target for security_transfer_creds(). | ||
45 | * | ||
46 | * @new: Pointer to "struct cred". | ||
47 | * @old: Pointer to "struct cred". | ||
48 | */ | ||
28 | static void tomoyo_cred_transfer(struct cred *new, const struct cred *old) | 49 | static void tomoyo_cred_transfer(struct cred *new, const struct cred *old) |
29 | { | 50 | { |
30 | tomoyo_cred_prepare(new, old, 0); | 51 | tomoyo_cred_prepare(new, old, 0); |
31 | } | 52 | } |
32 | 53 | ||
54 | /** | ||
55 | * tomoyo_cred_free - Target for security_cred_free(). | ||
56 | * | ||
57 | * @cred: Pointer to "struct cred". | ||
58 | */ | ||
33 | static void tomoyo_cred_free(struct cred *cred) | 59 | static void tomoyo_cred_free(struct cred *cred) |
34 | { | 60 | { |
35 | struct tomoyo_domain_info *domain = cred->security; | 61 | struct tomoyo_domain_info *domain = cred->security; |
36 | if (domain) | 62 | if (domain) |
37 | atomic_dec(&domain->users); | 63 | atomic_dec(&domain->users); |
38 | } | 64 | } |
39 | 65 | ||
66 | /** | ||
67 | * tomoyo_bprm_set_creds - Target for security_bprm_set_creds(). | ||
68 | * | ||
69 | * @bprm: Pointer to "struct linux_binprm". | ||
70 | * | ||
71 | * Returns 0 on success, negative value otherwise. | ||
72 | */ | ||
40 | static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) | 73 | static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) |
41 | { | 74 | { |
42 | int rc; | 75 | int rc; |
43 | 76 | ||
44 | rc = cap_bprm_set_creds(bprm); | 77 | rc = cap_bprm_set_creds(bprm); |
45 | if (rc) | 78 | if (rc) |
46 | return rc; | 79 | return rc; |
47 | 80 | ||
48 | /* | 81 | /* |
49 | * Do only if this function is called for the first time of an execve | 82 | * Do only if this function is called for the first time of an execve |
50 | * operation. | 83 | * operation. |
51 | */ | 84 | */ |
52 | if (bprm->cred_prepared) | 85 | if (bprm->cred_prepared) |
53 | return 0; | 86 | return 0; |
54 | #ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER | 87 | #ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER |
55 | /* | 88 | /* |
56 | * Load policy if /sbin/tomoyo-init exists and /sbin/init is requested | 89 | * Load policy if /sbin/tomoyo-init exists and /sbin/init is requested |
57 | * for the first time. | 90 | * for the first time. |
58 | */ | 91 | */ |
59 | if (!tomoyo_policy_loaded) | 92 | if (!tomoyo_policy_loaded) |
60 | tomoyo_load_policy(bprm->filename); | 93 | tomoyo_load_policy(bprm->filename); |
61 | #endif | 94 | #endif |
62 | /* | 95 | /* |
63 | * Release reference to "struct tomoyo_domain_info" stored inside | 96 | * Release reference to "struct tomoyo_domain_info" stored inside |
64 | * "bprm->cred->security". New reference to "struct tomoyo_domain_info" | 97 | * "bprm->cred->security". New reference to "struct tomoyo_domain_info" |
65 | * stored inside "bprm->cred->security" will be acquired later inside | 98 | * stored inside "bprm->cred->security" will be acquired later inside |
66 | * tomoyo_find_next_domain(). | 99 | * tomoyo_find_next_domain(). |
67 | */ | 100 | */ |
68 | atomic_dec(&((struct tomoyo_domain_info *) | 101 | atomic_dec(&((struct tomoyo_domain_info *) |
69 | bprm->cred->security)->users); | 102 | bprm->cred->security)->users); |
70 | /* | 103 | /* |
71 | * Tell tomoyo_bprm_check_security() is called for the first time of an | 104 | * Tell tomoyo_bprm_check_security() is called for the first time of an |
72 | * execve operation. | 105 | * execve operation. |
73 | */ | 106 | */ |
74 | bprm->cred->security = NULL; | 107 | bprm->cred->security = NULL; |
75 | return 0; | 108 | return 0; |
76 | } | 109 | } |
77 | 110 | ||
111 | /** | ||
112 | * tomoyo_bprm_check_security - Target for security_bprm_check(). | ||
113 | * | ||
114 | * @bprm: Pointer to "struct linux_binprm". | ||
115 | * | ||
116 | * Returns 0 on success, negative value otherwise. | ||
117 | */ | ||
78 | static int tomoyo_bprm_check_security(struct linux_binprm *bprm) | 118 | static int tomoyo_bprm_check_security(struct linux_binprm *bprm) |
79 | { | 119 | { |
80 | struct tomoyo_domain_info *domain = bprm->cred->security; | 120 | struct tomoyo_domain_info *domain = bprm->cred->security; |
81 | 121 | ||
82 | /* | 122 | /* |
83 | * Execute permission is checked against pathname passed to do_execve() | 123 | * Execute permission is checked against pathname passed to do_execve() |
84 | * using current domain. | 124 | * using current domain. |
85 | */ | 125 | */ |
86 | if (!domain) { | 126 | if (!domain) { |
87 | const int idx = tomoyo_read_lock(); | 127 | const int idx = tomoyo_read_lock(); |
88 | const int err = tomoyo_find_next_domain(bprm); | 128 | const int err = tomoyo_find_next_domain(bprm); |
89 | tomoyo_read_unlock(idx); | 129 | tomoyo_read_unlock(idx); |
90 | return err; | 130 | return err; |
91 | } | 131 | } |
92 | /* | 132 | /* |
93 | * Read permission is checked against interpreters using next domain. | 133 | * Read permission is checked against interpreters using next domain. |
94 | */ | 134 | */ |
95 | return tomoyo_check_open_permission(domain, &bprm->file->f_path, O_RDONLY); | 135 | return tomoyo_check_open_permission(domain, &bprm->file->f_path, |
136 | O_RDONLY); | ||
96 | } | 137 | } |
97 | 138 | ||
139 | /** | ||
140 | * tomoyo_inode_getattr - Target for security_inode_getattr(). | ||
141 | * | ||
142 | * @mnt: Pointer to "struct vfsmount". | ||
143 | * @dentry: Pointer to "struct dentry". | ||
144 | * | ||
145 | * Returns 0 on success, negative value otherwise. | ||
146 | */ | ||
98 | static int tomoyo_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) | 147 | static int tomoyo_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) |
99 | { | 148 | { |
100 | struct path path = { mnt, dentry }; | 149 | struct path path = { mnt, dentry }; |
101 | return tomoyo_path_perm(TOMOYO_TYPE_GETATTR, &path, NULL); | 150 | return tomoyo_path_perm(TOMOYO_TYPE_GETATTR, &path, NULL); |
102 | } | 151 | } |
103 | 152 | ||
153 | /** | ||
154 | * tomoyo_path_truncate - Target for security_path_truncate(). | ||
155 | * | ||
156 | * @path: Pointer to "struct path". | ||
157 | * | ||
158 | * Returns 0 on success, negative value otherwise. | ||
159 | */ | ||
104 | static int tomoyo_path_truncate(struct path *path) | 160 | static int tomoyo_path_truncate(struct path *path) |
105 | { | 161 | { |
106 | return tomoyo_path_perm(TOMOYO_TYPE_TRUNCATE, path, NULL); | 162 | return tomoyo_path_perm(TOMOYO_TYPE_TRUNCATE, path, NULL); |
107 | } | 163 | } |
108 | 164 | ||
165 | /** | ||
166 | * tomoyo_path_unlink - Target for security_path_unlink(). | ||
167 | * | ||
168 | * @parent: Pointer to "struct path". | ||
169 | * @dentry: Pointer to "struct dentry". | ||
170 | * | ||
171 | * Returns 0 on success, negative value otherwise. | ||
172 | */ | ||
109 | static int tomoyo_path_unlink(struct path *parent, struct dentry *dentry) | 173 | static int tomoyo_path_unlink(struct path *parent, struct dentry *dentry) |
110 | { | 174 | { |
111 | struct path path = { parent->mnt, dentry }; | 175 | struct path path = { parent->mnt, dentry }; |
112 | return tomoyo_path_perm(TOMOYO_TYPE_UNLINK, &path, NULL); | 176 | return tomoyo_path_perm(TOMOYO_TYPE_UNLINK, &path, NULL); |
113 | } | 177 | } |
114 | 178 | ||
179 | /** | ||
180 | * tomoyo_path_mkdir - Target for security_path_mkdir(). | ||
181 | * | ||
182 | * @parent: Pointer to "struct path". | ||
183 | * @dentry: Pointer to "struct dentry". | ||
184 | * @mode: DAC permission mode. | ||
185 | * | ||
186 | * Returns 0 on success, negative value otherwise. | ||
187 | */ | ||
115 | static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry, | 188 | static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry, |
116 | int mode) | 189 | int mode) |
117 | { | 190 | { |
118 | struct path path = { parent->mnt, dentry }; | 191 | struct path path = { parent->mnt, dentry }; |
119 | return tomoyo_path_number_perm(TOMOYO_TYPE_MKDIR, &path, | 192 | return tomoyo_path_number_perm(TOMOYO_TYPE_MKDIR, &path, |
120 | mode & S_IALLUGO); | 193 | mode & S_IALLUGO); |
121 | } | 194 | } |
122 | 195 | ||
196 | /** | ||
197 | * tomoyo_path_rmdir - Target for security_path_rmdir(). | ||
198 | * | ||
199 | * @parent: Pointer to "struct path". | ||
200 | * @dentry: Pointer to "struct dentry". | ||
201 | * | ||
202 | * Returns 0 on success, negative value otherwise. | ||
203 | */ | ||
123 | static int tomoyo_path_rmdir(struct path *parent, struct dentry *dentry) | 204 | static int tomoyo_path_rmdir(struct path *parent, struct dentry *dentry) |
124 | { | 205 | { |
125 | struct path path = { parent->mnt, dentry }; | 206 | struct path path = { parent->mnt, dentry }; |
126 | return tomoyo_path_perm(TOMOYO_TYPE_RMDIR, &path, NULL); | 207 | return tomoyo_path_perm(TOMOYO_TYPE_RMDIR, &path, NULL); |
127 | } | 208 | } |
128 | 209 | ||
210 | /** | ||
211 | * tomoyo_path_symlink - Target for security_path_symlink(). | ||
212 | * | ||
213 | * @parent: Pointer to "struct path". | ||
214 | * @dentry: Pointer to "struct dentry". | ||
215 | * @old_name: Symlink's content. | ||
216 | * | ||
217 | * Returns 0 on success, negative value otherwise. | ||
218 | */ | ||
129 | static int tomoyo_path_symlink(struct path *parent, struct dentry *dentry, | 219 | static int tomoyo_path_symlink(struct path *parent, struct dentry *dentry, |
130 | const char *old_name) | 220 | const char *old_name) |
131 | { | 221 | { |
132 | struct path path = { parent->mnt, dentry }; | 222 | struct path path = { parent->mnt, dentry }; |
133 | return tomoyo_path_perm(TOMOYO_TYPE_SYMLINK, &path, old_name); | 223 | return tomoyo_path_perm(TOMOYO_TYPE_SYMLINK, &path, old_name); |
134 | } | 224 | } |
135 | 225 | ||
226 | /** | ||
227 | * tomoyo_path_mknod - Target for security_path_mknod(). | ||
228 | * | ||
229 | * @parent: Pointer to "struct path". | ||
230 | * @dentry: Pointer to "struct dentry". | ||
231 | * @mode: DAC permission mode. | ||
232 | * @dev: Device attributes. | ||
233 | * | ||
234 | * Returns 0 on success, negative value otherwise. | ||
235 | */ | ||
136 | static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry, | 236 | static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry, |
137 | int mode, unsigned int dev) | 237 | int mode, unsigned int dev) |
138 | { | 238 | { |
139 | struct path path = { parent->mnt, dentry }; | 239 | struct path path = { parent->mnt, dentry }; |
140 | int type = TOMOYO_TYPE_CREATE; | 240 | int type = TOMOYO_TYPE_CREATE; |
141 | const unsigned int perm = mode & S_IALLUGO; | 241 | const unsigned int perm = mode & S_IALLUGO; |
142 | 242 | ||
143 | switch (mode & S_IFMT) { | 243 | switch (mode & S_IFMT) { |
144 | case S_IFCHR: | 244 | case S_IFCHR: |
145 | type = TOMOYO_TYPE_MKCHAR; | 245 | type = TOMOYO_TYPE_MKCHAR; |
146 | break; | 246 | break; |
147 | case S_IFBLK: | 247 | case S_IFBLK: |
148 | type = TOMOYO_TYPE_MKBLOCK; | 248 | type = TOMOYO_TYPE_MKBLOCK; |
149 | break; | 249 | break; |
150 | default: | 250 | default: |
151 | goto no_dev; | 251 | goto no_dev; |
152 | } | 252 | } |
153 | return tomoyo_mkdev_perm(type, &path, perm, dev); | 253 | return tomoyo_mkdev_perm(type, &path, perm, dev); |
154 | no_dev: | 254 | no_dev: |
155 | switch (mode & S_IFMT) { | 255 | switch (mode & S_IFMT) { |
156 | case S_IFIFO: | 256 | case S_IFIFO: |
157 | type = TOMOYO_TYPE_MKFIFO; | 257 | type = TOMOYO_TYPE_MKFIFO; |
158 | break; | 258 | break; |
159 | case S_IFSOCK: | 259 | case S_IFSOCK: |
160 | type = TOMOYO_TYPE_MKSOCK; | 260 | type = TOMOYO_TYPE_MKSOCK; |
161 | break; | 261 | break; |
162 | } | 262 | } |
163 | return tomoyo_path_number_perm(type, &path, perm); | 263 | return tomoyo_path_number_perm(type, &path, perm); |
164 | } | 264 | } |
165 | 265 | ||
266 | /** | ||
267 | * tomoyo_path_link - Target for security_path_link(). | ||
268 | * | ||
269 | * @old_dentry: Pointer to "struct dentry". | ||
270 | * @new_dir: Pointer to "struct path". | ||
271 | * @new_dentry: Pointer to "struct dentry". | ||
272 | * | ||
273 | * Returns 0 on success, negative value otherwise. | ||
274 | */ | ||
166 | static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir, | 275 | static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir, |
167 | struct dentry *new_dentry) | 276 | struct dentry *new_dentry) |
168 | { | 277 | { |
169 | struct path path1 = { new_dir->mnt, old_dentry }; | 278 | struct path path1 = { new_dir->mnt, old_dentry }; |
170 | struct path path2 = { new_dir->mnt, new_dentry }; | 279 | struct path path2 = { new_dir->mnt, new_dentry }; |
171 | return tomoyo_path2_perm(TOMOYO_TYPE_LINK, &path1, &path2); | 280 | return tomoyo_path2_perm(TOMOYO_TYPE_LINK, &path1, &path2); |
172 | } | 281 | } |
173 | 282 | ||
283 | /** | ||
284 | * tomoyo_path_rename - Target for security_path_rename(). | ||
285 | * | ||
286 | * @old_parent: Pointer to "struct path". | ||
287 | * @old_dentry: Pointer to "struct dentry". | ||
288 | * @new_parent: Pointer to "struct path". | ||
289 | * @new_dentry: Pointer to "struct dentry". | ||
290 | * | ||
291 | * Returns 0 on success, negative value otherwise. | ||
292 | */ | ||
174 | static int tomoyo_path_rename(struct path *old_parent, | 293 | static int tomoyo_path_rename(struct path *old_parent, |
175 | struct dentry *old_dentry, | 294 | struct dentry *old_dentry, |
176 | struct path *new_parent, | 295 | struct path *new_parent, |
177 | struct dentry *new_dentry) | 296 | struct dentry *new_dentry) |
178 | { | 297 | { |
179 | struct path path1 = { old_parent->mnt, old_dentry }; | 298 | struct path path1 = { old_parent->mnt, old_dentry }; |
180 | struct path path2 = { new_parent->mnt, new_dentry }; | 299 | struct path path2 = { new_parent->mnt, new_dentry }; |
181 | return tomoyo_path2_perm(TOMOYO_TYPE_RENAME, &path1, &path2); | 300 | return tomoyo_path2_perm(TOMOYO_TYPE_RENAME, &path1, &path2); |
182 | } | 301 | } |
183 | 302 | ||
303 | /** | ||
304 | * tomoyo_file_fcntl - Target for security_file_fcntl(). | ||
305 | * | ||
306 | * @file: Pointer to "struct file". | ||
307 | * @cmd: Command for fcntl(). | ||
308 | * @arg: Argument for @cmd. | ||
309 | * | ||
310 | * Returns 0 on success, negative value otherwise. | ||
311 | */ | ||
184 | static int tomoyo_file_fcntl(struct file *file, unsigned int cmd, | 312 | static int tomoyo_file_fcntl(struct file *file, unsigned int cmd, |
185 | unsigned long arg) | 313 | unsigned long arg) |
186 | { | 314 | { |
187 | if (!(cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND))) | 315 | if (!(cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND))) |
188 | return 0; | 316 | return 0; |
189 | return tomoyo_check_open_permission(tomoyo_domain(), &file->f_path, | 317 | return tomoyo_check_open_permission(tomoyo_domain(), &file->f_path, |
190 | O_WRONLY | (arg & O_APPEND)); | 318 | O_WRONLY | (arg & O_APPEND)); |
191 | } | 319 | } |
192 | 320 | ||
321 | /** | ||
322 | * tomoyo_dentry_open - Target for security_dentry_open(). | ||
323 | * | ||
324 | * @f: Pointer to "struct file". | ||
325 | * @cred: Pointer to "struct cred". | ||
326 | * | ||
327 | * Returns 0 on success, negative value otherwise. | ||
328 | */ | ||
193 | static int tomoyo_dentry_open(struct file *f, const struct cred *cred) | 329 | static int tomoyo_dentry_open(struct file *f, const struct cred *cred) |
194 | { | 330 | { |
195 | int flags = f->f_flags; | 331 | int flags = f->f_flags; |
196 | /* Don't check read permission here if called from do_execve(). */ | 332 | /* Don't check read permission here if called from do_execve(). */ |
197 | if (current->in_execve) | 333 | if (current->in_execve) |
198 | return 0; | 334 | return 0; |
199 | return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, flags); | 335 | return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, flags); |
200 | } | 336 | } |
201 | 337 | ||
338 | /** | ||
339 | * tomoyo_file_ioctl - Target for security_file_ioctl(). | ||
340 | * | ||
341 | * @file: Pointer to "struct file". | ||
342 | * @cmd: Command for ioctl(). | ||
343 | * @arg: Argument for @cmd. | ||
344 | * | ||
345 | * Returns 0 on success, negative value otherwise. | ||
346 | */ | ||
202 | static int tomoyo_file_ioctl(struct file *file, unsigned int cmd, | 347 | static int tomoyo_file_ioctl(struct file *file, unsigned int cmd, |
203 | unsigned long arg) | 348 | unsigned long arg) |
204 | { | 349 | { |
205 | return tomoyo_path_number_perm(TOMOYO_TYPE_IOCTL, &file->f_path, cmd); | 350 | return tomoyo_path_number_perm(TOMOYO_TYPE_IOCTL, &file->f_path, cmd); |
206 | } | 351 | } |
207 | 352 | ||
353 | /** | ||
354 | * tomoyo_path_chmod - Target for security_path_chmod(). | ||
355 | * | ||
356 | * @dentry: Pointer to "struct dentry". | ||
357 | * @mnt: Pointer to "struct vfsmount". | ||
358 | * @mode: DAC permission mode. | ||
359 | * | ||
360 | * Returns 0 on success, negative value otherwise. | ||
361 | */ | ||
208 | static int tomoyo_path_chmod(struct dentry *dentry, struct vfsmount *mnt, | 362 | static int tomoyo_path_chmod(struct dentry *dentry, struct vfsmount *mnt, |
209 | mode_t mode) | 363 | mode_t mode) |
210 | { | 364 | { |
211 | struct path path = { mnt, dentry }; | 365 | struct path path = { mnt, dentry }; |
212 | return tomoyo_path_number_perm(TOMOYO_TYPE_CHMOD, &path, | 366 | return tomoyo_path_number_perm(TOMOYO_TYPE_CHMOD, &path, |
213 | mode & S_IALLUGO); | 367 | mode & S_IALLUGO); |
214 | } | 368 | } |
215 | 369 | ||
370 | /** | ||
371 | * tomoyo_path_chown - Target for security_path_chown(). | ||
372 | * | ||
373 | * @path: Pointer to "struct path". | ||
374 | * @uid: Owner ID. | ||
375 | * @gid: Group ID. | ||
376 | * | ||
377 | * Returns 0 on success, negative value otherwise. | ||
378 | */ | ||
216 | static int tomoyo_path_chown(struct path *path, uid_t uid, gid_t gid) | 379 | static int tomoyo_path_chown(struct path *path, uid_t uid, gid_t gid) |
217 | { | 380 | { |
218 | int error = 0; | 381 | int error = 0; |
219 | if (uid != (uid_t) -1) | 382 | if (uid != (uid_t) -1) |
220 | error = tomoyo_path_number_perm(TOMOYO_TYPE_CHOWN, path, uid); | 383 | error = tomoyo_path_number_perm(TOMOYO_TYPE_CHOWN, path, uid); |
221 | if (!error && gid != (gid_t) -1) | 384 | if (!error && gid != (gid_t) -1) |
222 | error = tomoyo_path_number_perm(TOMOYO_TYPE_CHGRP, path, gid); | 385 | error = tomoyo_path_number_perm(TOMOYO_TYPE_CHGRP, path, gid); |
223 | return error; | 386 | return error; |
224 | } | 387 | } |
225 | 388 | ||
389 | /** | ||
390 | * tomoyo_path_chroot - Target for security_path_chroot(). | ||
391 | * | ||
392 | * @path: Pointer to "struct path". | ||
393 | * | ||
394 | * Returns 0 on success, negative value otherwise. | ||
395 | */ | ||
226 | static int tomoyo_path_chroot(struct path *path) | 396 | static int tomoyo_path_chroot(struct path *path) |
227 | { | 397 | { |
228 | return tomoyo_path_perm(TOMOYO_TYPE_CHROOT, path, NULL); | 398 | return tomoyo_path_perm(TOMOYO_TYPE_CHROOT, path, NULL); |
229 | } | 399 | } |
230 | 400 | ||
401 | /** | ||
402 | * tomoyo_sb_mount - Target for security_sb_mount(). | ||
403 | * | ||
404 | * @dev_name: Name of device file. Maybe NULL. | ||
405 | * @path: Pointer to "struct path". | ||
406 | * @type: Name of filesystem type. Maybe NULL. | ||
407 | * @flags: Mount options. | ||
408 | * @data: Optional data. Maybe NULL. | ||
409 | * | ||
410 | * Returns 0 on success, negative value otherwise. | ||
411 | */ | ||
231 | static int tomoyo_sb_mount(char *dev_name, struct path *path, | 412 | static int tomoyo_sb_mount(char *dev_name, struct path *path, |
232 | char *type, unsigned long flags, void *data) | 413 | char *type, unsigned long flags, void *data) |
233 | { | 414 | { |
234 | return tomoyo_mount_permission(dev_name, path, type, flags, data); | 415 | return tomoyo_mount_permission(dev_name, path, type, flags, data); |
235 | } | 416 | } |
236 | 417 | ||
418 | /** | ||
419 | * tomoyo_sb_umount - Target for security_sb_umount(). | ||
420 | * | ||
421 | * @mnt: Pointer to "struct vfsmount". | ||
422 | * @flags: Unmount options. | ||
423 | * | ||
424 | * Returns 0 on success, negative value otherwise. | ||
425 | */ | ||
237 | static int tomoyo_sb_umount(struct vfsmount *mnt, int flags) | 426 | static int tomoyo_sb_umount(struct vfsmount *mnt, int flags) |
238 | { | 427 | { |
239 | struct path path = { mnt, mnt->mnt_root }; | 428 | struct path path = { mnt, mnt->mnt_root }; |
240 | return tomoyo_path_perm(TOMOYO_TYPE_UMOUNT, &path, NULL); | 429 | return tomoyo_path_perm(TOMOYO_TYPE_UMOUNT, &path, NULL); |
241 | } | 430 | } |
242 | 431 | ||
432 | /** | ||
433 | * tomoyo_sb_pivotroot - Target for security_sb_pivotroot(). | ||
434 | * | ||
435 | * @old_path: Pointer to "struct path". | ||
436 | * @new_path: Pointer to "struct path". | ||
437 | * | ||
438 | * Returns 0 on success, negative value otherwise. | ||
439 | */ | ||
243 | static int tomoyo_sb_pivotroot(struct path *old_path, struct path *new_path) | 440 | static int tomoyo_sb_pivotroot(struct path *old_path, struct path *new_path) |
244 | { | 441 | { |
245 | return tomoyo_path2_perm(TOMOYO_TYPE_PIVOT_ROOT, new_path, old_path); | 442 | return tomoyo_path2_perm(TOMOYO_TYPE_PIVOT_ROOT, new_path, old_path); |
246 | } | 443 | } |
247 | 444 | ||
248 | /* | 445 | /* |
249 | * tomoyo_security_ops is a "struct security_operations" which is used for | 446 | * tomoyo_security_ops is a "struct security_operations" which is used for |
250 | * registering TOMOYO. | 447 | * registering TOMOYO. |
251 | */ | 448 | */ |
252 | static struct security_operations tomoyo_security_ops = { | 449 | static struct security_operations tomoyo_security_ops = { |
253 | .name = "tomoyo", | 450 | .name = "tomoyo", |
254 | .cred_alloc_blank = tomoyo_cred_alloc_blank, | 451 | .cred_alloc_blank = tomoyo_cred_alloc_blank, |
255 | .cred_prepare = tomoyo_cred_prepare, | 452 | .cred_prepare = tomoyo_cred_prepare, |
256 | .cred_transfer = tomoyo_cred_transfer, | 453 | .cred_transfer = tomoyo_cred_transfer, |
257 | .cred_free = tomoyo_cred_free, | 454 | .cred_free = tomoyo_cred_free, |
258 | .bprm_set_creds = tomoyo_bprm_set_creds, | 455 | .bprm_set_creds = tomoyo_bprm_set_creds, |
259 | .bprm_check_security = tomoyo_bprm_check_security, | 456 | .bprm_check_security = tomoyo_bprm_check_security, |
260 | .file_fcntl = tomoyo_file_fcntl, | 457 | .file_fcntl = tomoyo_file_fcntl, |
261 | .dentry_open = tomoyo_dentry_open, | 458 | .dentry_open = tomoyo_dentry_open, |
262 | .path_truncate = tomoyo_path_truncate, | 459 | .path_truncate = tomoyo_path_truncate, |
263 | .path_unlink = tomoyo_path_unlink, | 460 | .path_unlink = tomoyo_path_unlink, |
264 | .path_mkdir = tomoyo_path_mkdir, | 461 | .path_mkdir = tomoyo_path_mkdir, |
265 | .path_rmdir = tomoyo_path_rmdir, | 462 | .path_rmdir = tomoyo_path_rmdir, |
266 | .path_symlink = tomoyo_path_symlink, | 463 | .path_symlink = tomoyo_path_symlink, |
267 | .path_mknod = tomoyo_path_mknod, | 464 | .path_mknod = tomoyo_path_mknod, |
268 | .path_link = tomoyo_path_link, | 465 | .path_link = tomoyo_path_link, |
269 | .path_rename = tomoyo_path_rename, | 466 | .path_rename = tomoyo_path_rename, |
270 | .inode_getattr = tomoyo_inode_getattr, | 467 | .inode_getattr = tomoyo_inode_getattr, |
271 | .file_ioctl = tomoyo_file_ioctl, | 468 | .file_ioctl = tomoyo_file_ioctl, |
272 | .path_chmod = tomoyo_path_chmod, | 469 | .path_chmod = tomoyo_path_chmod, |
273 | .path_chown = tomoyo_path_chown, | 470 | .path_chown = tomoyo_path_chown, |
274 | .path_chroot = tomoyo_path_chroot, | 471 | .path_chroot = tomoyo_path_chroot, |
275 | .sb_mount = tomoyo_sb_mount, | 472 | .sb_mount = tomoyo_sb_mount, |
276 | .sb_umount = tomoyo_sb_umount, | 473 | .sb_umount = tomoyo_sb_umount, |
277 | .sb_pivotroot = tomoyo_sb_pivotroot, | 474 | .sb_pivotroot = tomoyo_sb_pivotroot, |
278 | }; | 475 | }; |
279 | 476 | ||
280 | /* Lock for GC. */ | 477 | /* Lock for GC. */ |
281 | struct srcu_struct tomoyo_ss; | 478 | struct srcu_struct tomoyo_ss; |
282 | 479 | ||
480 | /** | ||
481 | * tomoyo_init - Register TOMOYO Linux as a LSM module. | ||
482 | * | ||
483 | * Returns 0. | ||
484 | */ | ||
283 | static int __init tomoyo_init(void) | 485 | static int __init tomoyo_init(void) |
284 | { | 486 | { |
285 | struct cred *cred = (struct cred *) current_cred(); | 487 | struct cred *cred = (struct cred *) current_cred(); |
286 | 488 | ||
287 | if (!security_module_enable(&tomoyo_security_ops)) | 489 | if (!security_module_enable(&tomoyo_security_ops)) |
288 | return 0; | 490 | return 0; |
289 | /* register ourselves with the security framework */ | 491 | /* register ourselves with the security framework */ |
290 | if (register_security(&tomoyo_security_ops) || | 492 | if (register_security(&tomoyo_security_ops) || |
291 | init_srcu_struct(&tomoyo_ss)) | 493 | init_srcu_struct(&tomoyo_ss)) |
292 | panic("Failure registering TOMOYO Linux"); | 494 | panic("Failure registering TOMOYO Linux"); |
293 | printk(KERN_INFO "TOMOYO Linux initialized\n"); | 495 | printk(KERN_INFO "TOMOYO Linux initialized\n"); |
294 | cred->security = &tomoyo_kernel_domain; | 496 | cred->security = &tomoyo_kernel_domain; |
295 | tomoyo_mm_init(); | 497 | tomoyo_mm_init(); |
296 | return 0; | 498 | return 0; |
297 | } | 499 | } |
298 | 500 |
security/tomoyo/util.c
1 | /* | 1 | /* |
2 | * security/tomoyo/util.c | 2 | * security/tomoyo/util.c |
3 | * | 3 | * |
4 | * Utility functions for TOMOYO. | 4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION |
5 | * | ||
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
7 | */ | 5 | */ |
8 | 6 | ||
9 | #include <linux/slab.h> | 7 | #include <linux/slab.h> |
10 | #include "common.h" | 8 | #include "common.h" |
11 | 9 | ||
12 | /* Lock for protecting policy. */ | 10 | /* Lock for protecting policy. */ |
13 | DEFINE_MUTEX(tomoyo_policy_lock); | 11 | DEFINE_MUTEX(tomoyo_policy_lock); |
14 | 12 | ||
15 | /* Has /sbin/init started? */ | 13 | /* Has /sbin/init started? */ |
16 | bool tomoyo_policy_loaded; | 14 | bool tomoyo_policy_loaded; |
17 | 15 | ||
18 | /* | 16 | /* |
19 | * Mapping table from "enum tomoyo_mac_index" to | 17 | * Mapping table from "enum tomoyo_mac_index" to |
20 | * "enum tomoyo_mac_category_index". | 18 | * "enum tomoyo_mac_category_index". |
21 | */ | 19 | */ |
22 | const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX] = { | 20 | const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX] = { |
23 | /* CONFIG::file group */ | 21 | /* CONFIG::file group */ |
24 | [TOMOYO_MAC_FILE_EXECUTE] = TOMOYO_MAC_CATEGORY_FILE, | 22 | [TOMOYO_MAC_FILE_EXECUTE] = TOMOYO_MAC_CATEGORY_FILE, |
25 | [TOMOYO_MAC_FILE_OPEN] = TOMOYO_MAC_CATEGORY_FILE, | 23 | [TOMOYO_MAC_FILE_OPEN] = TOMOYO_MAC_CATEGORY_FILE, |
26 | [TOMOYO_MAC_FILE_CREATE] = TOMOYO_MAC_CATEGORY_FILE, | 24 | [TOMOYO_MAC_FILE_CREATE] = TOMOYO_MAC_CATEGORY_FILE, |
27 | [TOMOYO_MAC_FILE_UNLINK] = TOMOYO_MAC_CATEGORY_FILE, | 25 | [TOMOYO_MAC_FILE_UNLINK] = TOMOYO_MAC_CATEGORY_FILE, |
28 | [TOMOYO_MAC_FILE_GETATTR] = TOMOYO_MAC_CATEGORY_FILE, | 26 | [TOMOYO_MAC_FILE_GETATTR] = TOMOYO_MAC_CATEGORY_FILE, |
29 | [TOMOYO_MAC_FILE_MKDIR] = TOMOYO_MAC_CATEGORY_FILE, | 27 | [TOMOYO_MAC_FILE_MKDIR] = TOMOYO_MAC_CATEGORY_FILE, |
30 | [TOMOYO_MAC_FILE_RMDIR] = TOMOYO_MAC_CATEGORY_FILE, | 28 | [TOMOYO_MAC_FILE_RMDIR] = TOMOYO_MAC_CATEGORY_FILE, |
31 | [TOMOYO_MAC_FILE_MKFIFO] = TOMOYO_MAC_CATEGORY_FILE, | 29 | [TOMOYO_MAC_FILE_MKFIFO] = TOMOYO_MAC_CATEGORY_FILE, |
32 | [TOMOYO_MAC_FILE_MKSOCK] = TOMOYO_MAC_CATEGORY_FILE, | 30 | [TOMOYO_MAC_FILE_MKSOCK] = TOMOYO_MAC_CATEGORY_FILE, |
33 | [TOMOYO_MAC_FILE_TRUNCATE] = TOMOYO_MAC_CATEGORY_FILE, | 31 | [TOMOYO_MAC_FILE_TRUNCATE] = TOMOYO_MAC_CATEGORY_FILE, |
34 | [TOMOYO_MAC_FILE_SYMLINK] = TOMOYO_MAC_CATEGORY_FILE, | 32 | [TOMOYO_MAC_FILE_SYMLINK] = TOMOYO_MAC_CATEGORY_FILE, |
35 | [TOMOYO_MAC_FILE_MKBLOCK] = TOMOYO_MAC_CATEGORY_FILE, | 33 | [TOMOYO_MAC_FILE_MKBLOCK] = TOMOYO_MAC_CATEGORY_FILE, |
36 | [TOMOYO_MAC_FILE_MKCHAR] = TOMOYO_MAC_CATEGORY_FILE, | 34 | [TOMOYO_MAC_FILE_MKCHAR] = TOMOYO_MAC_CATEGORY_FILE, |
37 | [TOMOYO_MAC_FILE_LINK] = TOMOYO_MAC_CATEGORY_FILE, | 35 | [TOMOYO_MAC_FILE_LINK] = TOMOYO_MAC_CATEGORY_FILE, |
38 | [TOMOYO_MAC_FILE_RENAME] = TOMOYO_MAC_CATEGORY_FILE, | 36 | [TOMOYO_MAC_FILE_RENAME] = TOMOYO_MAC_CATEGORY_FILE, |
39 | [TOMOYO_MAC_FILE_CHMOD] = TOMOYO_MAC_CATEGORY_FILE, | 37 | [TOMOYO_MAC_FILE_CHMOD] = TOMOYO_MAC_CATEGORY_FILE, |
40 | [TOMOYO_MAC_FILE_CHOWN] = TOMOYO_MAC_CATEGORY_FILE, | 38 | [TOMOYO_MAC_FILE_CHOWN] = TOMOYO_MAC_CATEGORY_FILE, |
41 | [TOMOYO_MAC_FILE_CHGRP] = TOMOYO_MAC_CATEGORY_FILE, | 39 | [TOMOYO_MAC_FILE_CHGRP] = TOMOYO_MAC_CATEGORY_FILE, |
42 | [TOMOYO_MAC_FILE_IOCTL] = TOMOYO_MAC_CATEGORY_FILE, | 40 | [TOMOYO_MAC_FILE_IOCTL] = TOMOYO_MAC_CATEGORY_FILE, |
43 | [TOMOYO_MAC_FILE_CHROOT] = TOMOYO_MAC_CATEGORY_FILE, | 41 | [TOMOYO_MAC_FILE_CHROOT] = TOMOYO_MAC_CATEGORY_FILE, |
44 | [TOMOYO_MAC_FILE_MOUNT] = TOMOYO_MAC_CATEGORY_FILE, | 42 | [TOMOYO_MAC_FILE_MOUNT] = TOMOYO_MAC_CATEGORY_FILE, |
45 | [TOMOYO_MAC_FILE_UMOUNT] = TOMOYO_MAC_CATEGORY_FILE, | 43 | [TOMOYO_MAC_FILE_UMOUNT] = TOMOYO_MAC_CATEGORY_FILE, |
46 | [TOMOYO_MAC_FILE_PIVOT_ROOT] = TOMOYO_MAC_CATEGORY_FILE, | 44 | [TOMOYO_MAC_FILE_PIVOT_ROOT] = TOMOYO_MAC_CATEGORY_FILE, |
47 | }; | 45 | }; |
48 | 46 | ||
49 | /** | 47 | /** |
50 | * tomoyo_convert_time - Convert time_t to YYYY/MM/DD hh/mm/ss. | 48 | * tomoyo_convert_time - Convert time_t to YYYY/MM/DD hh/mm/ss. |
51 | * | 49 | * |
52 | * @time: Seconds since 1970/01/01 00:00:00. | 50 | * @time: Seconds since 1970/01/01 00:00:00. |
53 | * @stamp: Pointer to "struct tomoyo_time". | 51 | * @stamp: Pointer to "struct tomoyo_time". |
54 | * | 52 | * |
55 | * Returns nothing. | 53 | * Returns nothing. |
56 | * | 54 | * |
57 | * This function does not handle Y2038 problem. | 55 | * This function does not handle Y2038 problem. |
58 | */ | 56 | */ |
59 | void tomoyo_convert_time(time_t time, struct tomoyo_time *stamp) | 57 | void tomoyo_convert_time(time_t time, struct tomoyo_time *stamp) |
60 | { | 58 | { |
61 | static const u16 tomoyo_eom[2][12] = { | 59 | static const u16 tomoyo_eom[2][12] = { |
62 | { 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, | 60 | { 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, |
63 | { 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } | 61 | { 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } |
64 | }; | 62 | }; |
65 | u16 y; | 63 | u16 y; |
66 | u8 m; | 64 | u8 m; |
67 | bool r; | 65 | bool r; |
68 | stamp->sec = time % 60; | 66 | stamp->sec = time % 60; |
69 | time /= 60; | 67 | time /= 60; |
70 | stamp->min = time % 60; | 68 | stamp->min = time % 60; |
71 | time /= 60; | 69 | time /= 60; |
72 | stamp->hour = time % 24; | 70 | stamp->hour = time % 24; |
73 | time /= 24; | 71 | time /= 24; |
74 | for (y = 1970; ; y++) { | 72 | for (y = 1970; ; y++) { |
75 | const unsigned short days = (y & 3) ? 365 : 366; | 73 | const unsigned short days = (y & 3) ? 365 : 366; |
76 | if (time < days) | 74 | if (time < days) |
77 | break; | 75 | break; |
78 | time -= days; | 76 | time -= days; |
79 | } | 77 | } |
80 | r = (y & 3) == 0; | 78 | r = (y & 3) == 0; |
81 | for (m = 0; m < 11 && time >= tomoyo_eom[r][m]; m++) | 79 | for (m = 0; m < 11 && time >= tomoyo_eom[r][m]; m++) |
82 | ; | 80 | ; |
83 | if (m) | 81 | if (m) |
84 | time -= tomoyo_eom[r][m - 1]; | 82 | time -= tomoyo_eom[r][m - 1]; |
85 | stamp->year = y; | 83 | stamp->year = y; |
86 | stamp->month = ++m; | 84 | stamp->month = ++m; |
87 | stamp->day = ++time; | 85 | stamp->day = ++time; |
88 | } | 86 | } |
89 | 87 | ||
90 | /** | 88 | /** |
91 | * tomoyo_permstr - Find permission keywords. | 89 | * tomoyo_permstr - Find permission keywords. |
92 | * | 90 | * |
93 | * @string: String representation for permissions in foo/bar/buz format. | 91 | * @string: String representation for permissions in foo/bar/buz format. |
94 | * @keyword: Keyword to find from @string/ | 92 | * @keyword: Keyword to find from @string/ |
95 | * | 93 | * |
96 | * Returns ture if @keyword was found in @string, false otherwise. | 94 | * Returns ture if @keyword was found in @string, false otherwise. |
97 | * | 95 | * |
98 | * This function assumes that strncmp(w1, w2, strlen(w1)) != 0 if w1 != w2. | 96 | * This function assumes that strncmp(w1, w2, strlen(w1)) != 0 if w1 != w2. |
99 | */ | 97 | */ |
100 | bool tomoyo_permstr(const char *string, const char *keyword) | 98 | bool tomoyo_permstr(const char *string, const char *keyword) |
101 | { | 99 | { |
102 | const char *cp = strstr(string, keyword); | 100 | const char *cp = strstr(string, keyword); |
103 | if (cp) | 101 | if (cp) |
104 | return cp == string || *(cp - 1) == '/'; | 102 | return cp == string || *(cp - 1) == '/'; |
105 | return false; | 103 | return false; |
106 | } | 104 | } |
107 | 105 | ||
108 | /** | 106 | /** |
109 | * tomoyo_read_token - Read a word from a line. | 107 | * tomoyo_read_token - Read a word from a line. |
110 | * | 108 | * |
111 | * @param: Pointer to "struct tomoyo_acl_param". | 109 | * @param: Pointer to "struct tomoyo_acl_param". |
112 | * | 110 | * |
113 | * Returns a word on success, "" otherwise. | 111 | * Returns a word on success, "" otherwise. |
114 | * | 112 | * |
115 | * To allow the caller to skip NULL check, this function returns "" rather than | 113 | * To allow the caller to skip NULL check, this function returns "" rather than |
116 | * NULL if there is no more words to read. | 114 | * NULL if there is no more words to read. |
117 | */ | 115 | */ |
118 | char *tomoyo_read_token(struct tomoyo_acl_param *param) | 116 | char *tomoyo_read_token(struct tomoyo_acl_param *param) |
119 | { | 117 | { |
120 | char *pos = param->data; | 118 | char *pos = param->data; |
121 | char *del = strchr(pos, ' '); | 119 | char *del = strchr(pos, ' '); |
122 | if (del) | 120 | if (del) |
123 | *del++ = '\0'; | 121 | *del++ = '\0'; |
124 | else | 122 | else |
125 | del = pos + strlen(pos); | 123 | del = pos + strlen(pos); |
126 | param->data = del; | 124 | param->data = del; |
127 | return pos; | 125 | return pos; |
128 | } | 126 | } |
129 | 127 | ||
130 | /** | 128 | /** |
131 | * tomoyo_parse_ulong - Parse an "unsigned long" value. | 129 | * tomoyo_parse_ulong - Parse an "unsigned long" value. |
132 | * | 130 | * |
133 | * @result: Pointer to "unsigned long". | 131 | * @result: Pointer to "unsigned long". |
134 | * @str: Pointer to string to parse. | 132 | * @str: Pointer to string to parse. |
135 | * | 133 | * |
136 | * Returns one of values in "enum tomoyo_value_type". | 134 | * Returns one of values in "enum tomoyo_value_type". |
137 | * | 135 | * |
138 | * The @src is updated to point the first character after the value | 136 | * The @src is updated to point the first character after the value |
139 | * on success. | 137 | * on success. |
140 | */ | 138 | */ |
141 | u8 tomoyo_parse_ulong(unsigned long *result, char **str) | 139 | u8 tomoyo_parse_ulong(unsigned long *result, char **str) |
142 | { | 140 | { |
143 | const char *cp = *str; | 141 | const char *cp = *str; |
144 | char *ep; | 142 | char *ep; |
145 | int base = 10; | 143 | int base = 10; |
146 | if (*cp == '0') { | 144 | if (*cp == '0') { |
147 | char c = *(cp + 1); | 145 | char c = *(cp + 1); |
148 | if (c == 'x' || c == 'X') { | 146 | if (c == 'x' || c == 'X') { |
149 | base = 16; | 147 | base = 16; |
150 | cp += 2; | 148 | cp += 2; |
151 | } else if (c >= '0' && c <= '7') { | 149 | } else if (c >= '0' && c <= '7') { |
152 | base = 8; | 150 | base = 8; |
153 | cp++; | 151 | cp++; |
154 | } | 152 | } |
155 | } | 153 | } |
156 | *result = simple_strtoul(cp, &ep, base); | 154 | *result = simple_strtoul(cp, &ep, base); |
157 | if (cp == ep) | 155 | if (cp == ep) |
158 | return TOMOYO_VALUE_TYPE_INVALID; | 156 | return TOMOYO_VALUE_TYPE_INVALID; |
159 | *str = ep; | 157 | *str = ep; |
160 | switch (base) { | 158 | switch (base) { |
161 | case 16: | 159 | case 16: |
162 | return TOMOYO_VALUE_TYPE_HEXADECIMAL; | 160 | return TOMOYO_VALUE_TYPE_HEXADECIMAL; |
163 | case 8: | 161 | case 8: |
164 | return TOMOYO_VALUE_TYPE_OCTAL; | 162 | return TOMOYO_VALUE_TYPE_OCTAL; |
165 | default: | 163 | default: |
166 | return TOMOYO_VALUE_TYPE_DECIMAL; | 164 | return TOMOYO_VALUE_TYPE_DECIMAL; |
167 | } | 165 | } |
168 | } | 166 | } |
169 | 167 | ||
170 | /** | 168 | /** |
171 | * tomoyo_print_ulong - Print an "unsigned long" value. | 169 | * tomoyo_print_ulong - Print an "unsigned long" value. |
172 | * | 170 | * |
173 | * @buffer: Pointer to buffer. | 171 | * @buffer: Pointer to buffer. |
174 | * @buffer_len: Size of @buffer. | 172 | * @buffer_len: Size of @buffer. |
175 | * @value: An "unsigned long" value. | 173 | * @value: An "unsigned long" value. |
176 | * @type: Type of @value. | 174 | * @type: Type of @value. |
177 | * | 175 | * |
178 | * Returns nothing. | 176 | * Returns nothing. |
179 | */ | 177 | */ |
180 | void tomoyo_print_ulong(char *buffer, const int buffer_len, | 178 | void tomoyo_print_ulong(char *buffer, const int buffer_len, |
181 | const unsigned long value, const u8 type) | 179 | const unsigned long value, const u8 type) |
182 | { | 180 | { |
183 | if (type == TOMOYO_VALUE_TYPE_DECIMAL) | 181 | if (type == TOMOYO_VALUE_TYPE_DECIMAL) |
184 | snprintf(buffer, buffer_len, "%lu", value); | 182 | snprintf(buffer, buffer_len, "%lu", value); |
185 | else if (type == TOMOYO_VALUE_TYPE_OCTAL) | 183 | else if (type == TOMOYO_VALUE_TYPE_OCTAL) |
186 | snprintf(buffer, buffer_len, "0%lo", value); | 184 | snprintf(buffer, buffer_len, "0%lo", value); |
187 | else if (type == TOMOYO_VALUE_TYPE_HEXADECIMAL) | 185 | else if (type == TOMOYO_VALUE_TYPE_HEXADECIMAL) |
188 | snprintf(buffer, buffer_len, "0x%lX", value); | 186 | snprintf(buffer, buffer_len, "0x%lX", value); |
189 | else | 187 | else |
190 | snprintf(buffer, buffer_len, "type(%u)", type); | 188 | snprintf(buffer, buffer_len, "type(%u)", type); |
191 | } | 189 | } |
192 | 190 | ||
193 | /** | 191 | /** |
194 | * tomoyo_parse_name_union - Parse a tomoyo_name_union. | 192 | * tomoyo_parse_name_union - Parse a tomoyo_name_union. |
195 | * | 193 | * |
196 | * @param: Pointer to "struct tomoyo_acl_param". | 194 | * @param: Pointer to "struct tomoyo_acl_param". |
197 | * @ptr: Pointer to "struct tomoyo_name_union". | 195 | * @ptr: Pointer to "struct tomoyo_name_union". |
198 | * | 196 | * |
199 | * Returns true on success, false otherwise. | 197 | * Returns true on success, false otherwise. |
200 | */ | 198 | */ |
201 | bool tomoyo_parse_name_union(struct tomoyo_acl_param *param, | 199 | bool tomoyo_parse_name_union(struct tomoyo_acl_param *param, |
202 | struct tomoyo_name_union *ptr) | 200 | struct tomoyo_name_union *ptr) |
203 | { | 201 | { |
204 | char *filename; | 202 | char *filename; |
205 | if (param->data[0] == '@') { | 203 | if (param->data[0] == '@') { |
206 | param->data++; | 204 | param->data++; |
207 | ptr->group = tomoyo_get_group(param, TOMOYO_PATH_GROUP); | 205 | ptr->group = tomoyo_get_group(param, TOMOYO_PATH_GROUP); |
208 | return ptr->group != NULL; | 206 | return ptr->group != NULL; |
209 | } | 207 | } |
210 | filename = tomoyo_read_token(param); | 208 | filename = tomoyo_read_token(param); |
211 | if (!tomoyo_correct_word(filename)) | 209 | if (!tomoyo_correct_word(filename)) |
212 | return false; | 210 | return false; |
213 | ptr->filename = tomoyo_get_name(filename); | 211 | ptr->filename = tomoyo_get_name(filename); |
214 | return ptr->filename != NULL; | 212 | return ptr->filename != NULL; |
215 | } | 213 | } |
216 | 214 | ||
217 | /** | 215 | /** |
218 | * tomoyo_parse_number_union - Parse a tomoyo_number_union. | 216 | * tomoyo_parse_number_union - Parse a tomoyo_number_union. |
219 | * | 217 | * |
220 | * @param: Pointer to "struct tomoyo_acl_param". | 218 | * @param: Pointer to "struct tomoyo_acl_param". |
221 | * @ptr: Pointer to "struct tomoyo_number_union". | 219 | * @ptr: Pointer to "struct tomoyo_number_union". |
222 | * | 220 | * |
223 | * Returns true on success, false otherwise. | 221 | * Returns true on success, false otherwise. |
224 | */ | 222 | */ |
225 | bool tomoyo_parse_number_union(struct tomoyo_acl_param *param, | 223 | bool tomoyo_parse_number_union(struct tomoyo_acl_param *param, |
226 | struct tomoyo_number_union *ptr) | 224 | struct tomoyo_number_union *ptr) |
227 | { | 225 | { |
228 | char *data; | 226 | char *data; |
229 | u8 type; | 227 | u8 type; |
230 | unsigned long v; | 228 | unsigned long v; |
231 | memset(ptr, 0, sizeof(*ptr)); | 229 | memset(ptr, 0, sizeof(*ptr)); |
232 | if (param->data[0] == '@') { | 230 | if (param->data[0] == '@') { |
233 | param->data++; | 231 | param->data++; |
234 | ptr->group = tomoyo_get_group(param, TOMOYO_NUMBER_GROUP); | 232 | ptr->group = tomoyo_get_group(param, TOMOYO_NUMBER_GROUP); |
235 | return ptr->group != NULL; | 233 | return ptr->group != NULL; |
236 | } | 234 | } |
237 | data = tomoyo_read_token(param); | 235 | data = tomoyo_read_token(param); |
238 | type = tomoyo_parse_ulong(&v, &data); | 236 | type = tomoyo_parse_ulong(&v, &data); |
239 | if (type == TOMOYO_VALUE_TYPE_INVALID) | 237 | if (type == TOMOYO_VALUE_TYPE_INVALID) |
240 | return false; | 238 | return false; |
241 | ptr->values[0] = v; | 239 | ptr->values[0] = v; |
242 | ptr->value_type[0] = type; | 240 | ptr->value_type[0] = type; |
243 | if (!*data) { | 241 | if (!*data) { |
244 | ptr->values[1] = v; | 242 | ptr->values[1] = v; |
245 | ptr->value_type[1] = type; | 243 | ptr->value_type[1] = type; |
246 | return true; | 244 | return true; |
247 | } | 245 | } |
248 | if (*data++ != '-') | 246 | if (*data++ != '-') |
249 | return false; | 247 | return false; |
250 | type = tomoyo_parse_ulong(&v, &data); | 248 | type = tomoyo_parse_ulong(&v, &data); |
251 | if (type == TOMOYO_VALUE_TYPE_INVALID || *data || ptr->values[0] > v) | 249 | if (type == TOMOYO_VALUE_TYPE_INVALID || *data || ptr->values[0] > v) |
252 | return false; | 250 | return false; |
253 | ptr->values[1] = v; | 251 | ptr->values[1] = v; |
254 | ptr->value_type[1] = type; | 252 | ptr->value_type[1] = type; |
255 | return true; | 253 | return true; |
256 | } | 254 | } |
257 | 255 | ||
258 | /** | 256 | /** |
259 | * tomoyo_byte_range - Check whether the string is a \ooo style octal value. | 257 | * tomoyo_byte_range - Check whether the string is a \ooo style octal value. |
260 | * | 258 | * |
261 | * @str: Pointer to the string. | 259 | * @str: Pointer to the string. |
262 | * | 260 | * |
263 | * Returns true if @str is a \ooo style octal value, false otherwise. | 261 | * Returns true if @str is a \ooo style octal value, false otherwise. |
264 | * | 262 | * |
265 | * TOMOYO uses \ooo style representation for 0x01 - 0x20 and 0x7F - 0xFF. | 263 | * TOMOYO uses \ooo style representation for 0x01 - 0x20 and 0x7F - 0xFF. |
266 | * This function verifies that \ooo is in valid range. | 264 | * This function verifies that \ooo is in valid range. |
267 | */ | 265 | */ |
268 | static inline bool tomoyo_byte_range(const char *str) | 266 | static inline bool tomoyo_byte_range(const char *str) |
269 | { | 267 | { |
270 | return *str >= '0' && *str++ <= '3' && | 268 | return *str >= '0' && *str++ <= '3' && |
271 | *str >= '0' && *str++ <= '7' && | 269 | *str >= '0' && *str++ <= '7' && |
272 | *str >= '0' && *str <= '7'; | 270 | *str >= '0' && *str <= '7'; |
273 | } | 271 | } |
274 | 272 | ||
275 | /** | 273 | /** |
276 | * tomoyo_alphabet_char - Check whether the character is an alphabet. | 274 | * tomoyo_alphabet_char - Check whether the character is an alphabet. |
277 | * | 275 | * |
278 | * @c: The character to check. | 276 | * @c: The character to check. |
279 | * | 277 | * |
280 | * Returns true if @c is an alphabet character, false otherwise. | 278 | * Returns true if @c is an alphabet character, false otherwise. |
281 | */ | 279 | */ |
282 | static inline bool tomoyo_alphabet_char(const char c) | 280 | static inline bool tomoyo_alphabet_char(const char c) |
283 | { | 281 | { |
284 | return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); | 282 | return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); |
285 | } | 283 | } |
286 | 284 | ||
287 | /** | 285 | /** |
288 | * tomoyo_make_byte - Make byte value from three octal characters. | 286 | * tomoyo_make_byte - Make byte value from three octal characters. |
289 | * | 287 | * |
290 | * @c1: The first character. | 288 | * @c1: The first character. |
291 | * @c2: The second character. | 289 | * @c2: The second character. |
292 | * @c3: The third character. | 290 | * @c3: The third character. |
293 | * | 291 | * |
294 | * Returns byte value. | 292 | * Returns byte value. |
295 | */ | 293 | */ |
296 | static inline u8 tomoyo_make_byte(const u8 c1, const u8 c2, const u8 c3) | 294 | static inline u8 tomoyo_make_byte(const u8 c1, const u8 c2, const u8 c3) |
297 | { | 295 | { |
298 | return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0'); | 296 | return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0'); |
299 | } | 297 | } |
300 | 298 | ||
301 | /** | 299 | /** |
302 | * tomoyo_valid - Check whether the character is a valid char. | 300 | * tomoyo_valid - Check whether the character is a valid char. |
303 | * | 301 | * |
304 | * @c: The character to check. | 302 | * @c: The character to check. |
305 | * | 303 | * |
306 | * Returns true if @c is a valid character, false otherwise. | 304 | * Returns true if @c is a valid character, false otherwise. |
307 | */ | 305 | */ |
308 | static inline bool tomoyo_valid(const unsigned char c) | 306 | static inline bool tomoyo_valid(const unsigned char c) |
309 | { | 307 | { |
310 | return c > ' ' && c < 127; | 308 | return c > ' ' && c < 127; |
311 | } | 309 | } |
312 | 310 | ||
313 | /** | 311 | /** |
314 | * tomoyo_invalid - Check whether the character is an invalid char. | 312 | * tomoyo_invalid - Check whether the character is an invalid char. |
315 | * | 313 | * |
316 | * @c: The character to check. | 314 | * @c: The character to check. |
317 | * | 315 | * |
318 | * Returns true if @c is an invalid character, false otherwise. | 316 | * Returns true if @c is an invalid character, false otherwise. |
319 | */ | 317 | */ |
320 | static inline bool tomoyo_invalid(const unsigned char c) | 318 | static inline bool tomoyo_invalid(const unsigned char c) |
321 | { | 319 | { |
322 | return c && (c <= ' ' || c >= 127); | 320 | return c && (c <= ' ' || c >= 127); |
323 | } | 321 | } |
324 | 322 | ||
325 | /** | 323 | /** |
326 | * tomoyo_str_starts - Check whether the given string starts with the given keyword. | 324 | * tomoyo_str_starts - Check whether the given string starts with the given keyword. |
327 | * | 325 | * |
328 | * @src: Pointer to pointer to the string. | 326 | * @src: Pointer to pointer to the string. |
329 | * @find: Pointer to the keyword. | 327 | * @find: Pointer to the keyword. |
330 | * | 328 | * |
331 | * Returns true if @src starts with @find, false otherwise. | 329 | * Returns true if @src starts with @find, false otherwise. |
332 | * | 330 | * |
333 | * The @src is updated to point the first character after the @find | 331 | * The @src is updated to point the first character after the @find |
334 | * if @src starts with @find. | 332 | * if @src starts with @find. |
335 | */ | 333 | */ |
336 | bool tomoyo_str_starts(char **src, const char *find) | 334 | bool tomoyo_str_starts(char **src, const char *find) |
337 | { | 335 | { |
338 | const int len = strlen(find); | 336 | const int len = strlen(find); |
339 | char *tmp = *src; | 337 | char *tmp = *src; |
340 | 338 | ||
341 | if (strncmp(tmp, find, len)) | 339 | if (strncmp(tmp, find, len)) |
342 | return false; | 340 | return false; |
343 | tmp += len; | 341 | tmp += len; |
344 | *src = tmp; | 342 | *src = tmp; |
345 | return true; | 343 | return true; |
346 | } | 344 | } |
347 | 345 | ||
348 | /** | 346 | /** |
349 | * tomoyo_normalize_line - Format string. | 347 | * tomoyo_normalize_line - Format string. |
350 | * | 348 | * |
351 | * @buffer: The line to normalize. | 349 | * @buffer: The line to normalize. |
352 | * | 350 | * |
353 | * Leading and trailing whitespaces are removed. | 351 | * Leading and trailing whitespaces are removed. |
354 | * Multiple whitespaces are packed into single space. | 352 | * Multiple whitespaces are packed into single space. |
355 | * | 353 | * |
356 | * Returns nothing. | 354 | * Returns nothing. |
357 | */ | 355 | */ |
358 | void tomoyo_normalize_line(unsigned char *buffer) | 356 | void tomoyo_normalize_line(unsigned char *buffer) |
359 | { | 357 | { |
360 | unsigned char *sp = buffer; | 358 | unsigned char *sp = buffer; |
361 | unsigned char *dp = buffer; | 359 | unsigned char *dp = buffer; |
362 | bool first = true; | 360 | bool first = true; |
363 | 361 | ||
364 | while (tomoyo_invalid(*sp)) | 362 | while (tomoyo_invalid(*sp)) |
365 | sp++; | 363 | sp++; |
366 | while (*sp) { | 364 | while (*sp) { |
367 | if (!first) | 365 | if (!first) |
368 | *dp++ = ' '; | 366 | *dp++ = ' '; |
369 | first = false; | 367 | first = false; |
370 | while (tomoyo_valid(*sp)) | 368 | while (tomoyo_valid(*sp)) |
371 | *dp++ = *sp++; | 369 | *dp++ = *sp++; |
372 | while (tomoyo_invalid(*sp)) | 370 | while (tomoyo_invalid(*sp)) |
373 | sp++; | 371 | sp++; |
374 | } | 372 | } |
375 | *dp = '\0'; | 373 | *dp = '\0'; |
376 | } | 374 | } |
377 | 375 | ||
378 | /** | 376 | /** |
379 | * tomoyo_correct_word2 - Validate a string. | 377 | * tomoyo_correct_word2 - Validate a string. |
380 | * | 378 | * |
381 | * @string: The string to check. May be non-'\0'-terminated. | 379 | * @string: The string to check. Maybe non-'\0'-terminated. |
382 | * @len: Length of @string. | 380 | * @len: Length of @string. |
383 | * | 381 | * |
384 | * Check whether the given string follows the naming rules. | 382 | * Check whether the given string follows the naming rules. |
385 | * Returns true if @string follows the naming rules, false otherwise. | 383 | * Returns true if @string follows the naming rules, false otherwise. |
386 | */ | 384 | */ |
387 | static bool tomoyo_correct_word2(const char *string, size_t len) | 385 | static bool tomoyo_correct_word2(const char *string, size_t len) |
388 | { | 386 | { |
389 | const char *const start = string; | 387 | const char *const start = string; |
390 | bool in_repetition = false; | 388 | bool in_repetition = false; |
391 | unsigned char c; | 389 | unsigned char c; |
392 | unsigned char d; | 390 | unsigned char d; |
393 | unsigned char e; | 391 | unsigned char e; |
394 | if (!len) | 392 | if (!len) |
395 | goto out; | 393 | goto out; |
396 | while (len--) { | 394 | while (len--) { |
397 | c = *string++; | 395 | c = *string++; |
398 | if (c == '\\') { | 396 | if (c == '\\') { |
399 | if (!len--) | 397 | if (!len--) |
400 | goto out; | 398 | goto out; |
401 | c = *string++; | 399 | c = *string++; |
402 | switch (c) { | 400 | switch (c) { |
403 | case '\\': /* "\\" */ | 401 | case '\\': /* "\\" */ |
404 | continue; | 402 | continue; |
405 | case '$': /* "\$" */ | 403 | case '$': /* "\$" */ |
406 | case '+': /* "\+" */ | 404 | case '+': /* "\+" */ |
407 | case '?': /* "\?" */ | 405 | case '?': /* "\?" */ |
408 | case '*': /* "\*" */ | 406 | case '*': /* "\*" */ |
409 | case '@': /* "\@" */ | 407 | case '@': /* "\@" */ |
410 | case 'x': /* "\x" */ | 408 | case 'x': /* "\x" */ |
411 | case 'X': /* "\X" */ | 409 | case 'X': /* "\X" */ |
412 | case 'a': /* "\a" */ | 410 | case 'a': /* "\a" */ |
413 | case 'A': /* "\A" */ | 411 | case 'A': /* "\A" */ |
414 | case '-': /* "\-" */ | 412 | case '-': /* "\-" */ |
415 | continue; | 413 | continue; |
416 | case '{': /* "/\{" */ | 414 | case '{': /* "/\{" */ |
417 | if (string - 3 < start || *(string - 3) != '/') | 415 | if (string - 3 < start || *(string - 3) != '/') |
418 | break; | 416 | break; |
419 | in_repetition = true; | 417 | in_repetition = true; |
420 | continue; | 418 | continue; |
421 | case '}': /* "\}/" */ | 419 | case '}': /* "\}/" */ |
422 | if (*string != '/') | 420 | if (*string != '/') |
423 | break; | 421 | break; |
424 | if (!in_repetition) | 422 | if (!in_repetition) |
425 | break; | 423 | break; |
426 | in_repetition = false; | 424 | in_repetition = false; |
427 | continue; | 425 | continue; |
428 | case '0': /* "\ooo" */ | 426 | case '0': /* "\ooo" */ |
429 | case '1': | 427 | case '1': |
430 | case '2': | 428 | case '2': |
431 | case '3': | 429 | case '3': |
432 | if (!len-- || !len--) | 430 | if (!len-- || !len--) |
433 | break; | 431 | break; |
434 | d = *string++; | 432 | d = *string++; |
435 | e = *string++; | 433 | e = *string++; |
436 | if (d < '0' || d > '7' || e < '0' || e > '7') | 434 | if (d < '0' || d > '7' || e < '0' || e > '7') |
437 | break; | 435 | break; |
438 | c = tomoyo_make_byte(c, d, e); | 436 | c = tomoyo_make_byte(c, d, e); |
439 | if (tomoyo_invalid(c)) | 437 | if (tomoyo_invalid(c)) |
440 | continue; /* pattern is not \000 */ | 438 | continue; /* pattern is not \000 */ |
441 | } | 439 | } |
442 | goto out; | 440 | goto out; |
443 | } else if (in_repetition && c == '/') { | 441 | } else if (in_repetition && c == '/') { |
444 | goto out; | 442 | goto out; |
445 | } else if (tomoyo_invalid(c)) { | 443 | } else if (tomoyo_invalid(c)) { |
446 | goto out; | 444 | goto out; |
447 | } | 445 | } |
448 | } | 446 | } |
449 | if (in_repetition) | 447 | if (in_repetition) |
450 | goto out; | 448 | goto out; |
451 | return true; | 449 | return true; |
452 | out: | 450 | out: |
453 | return false; | 451 | return false; |
454 | } | 452 | } |
455 | 453 | ||
456 | /** | 454 | /** |
457 | * tomoyo_correct_word - Validate a string. | 455 | * tomoyo_correct_word - Validate a string. |
458 | * | 456 | * |
459 | * @string: The string to check. | 457 | * @string: The string to check. |
460 | * | 458 | * |
461 | * Check whether the given string follows the naming rules. | 459 | * Check whether the given string follows the naming rules. |
462 | * Returns true if @string follows the naming rules, false otherwise. | 460 | * Returns true if @string follows the naming rules, false otherwise. |
463 | */ | 461 | */ |
464 | bool tomoyo_correct_word(const char *string) | 462 | bool tomoyo_correct_word(const char *string) |
465 | { | 463 | { |
466 | return tomoyo_correct_word2(string, strlen(string)); | 464 | return tomoyo_correct_word2(string, strlen(string)); |
467 | } | 465 | } |
468 | 466 | ||
469 | /** | 467 | /** |
470 | * tomoyo_correct_path - Validate a pathname. | 468 | * tomoyo_correct_path - Validate a pathname. |
471 | * | 469 | * |
472 | * @filename: The pathname to check. | 470 | * @filename: The pathname to check. |
473 | * | 471 | * |
474 | * Check whether the given pathname follows the naming rules. | 472 | * Check whether the given pathname follows the naming rules. |
475 | * Returns true if @filename follows the naming rules, false otherwise. | 473 | * Returns true if @filename follows the naming rules, false otherwise. |
476 | */ | 474 | */ |
477 | bool tomoyo_correct_path(const char *filename) | 475 | bool tomoyo_correct_path(const char *filename) |
478 | { | 476 | { |
479 | return *filename == '/' && tomoyo_correct_word(filename); | 477 | return *filename == '/' && tomoyo_correct_word(filename); |
480 | } | 478 | } |
481 | 479 | ||
482 | /** | 480 | /** |
483 | * tomoyo_correct_domain - Check whether the given domainname follows the naming rules. | 481 | * tomoyo_correct_domain - Check whether the given domainname follows the naming rules. |
484 | * | 482 | * |
485 | * @domainname: The domainname to check. | 483 | * @domainname: The domainname to check. |
486 | * | 484 | * |
487 | * Returns true if @domainname follows the naming rules, false otherwise. | 485 | * Returns true if @domainname follows the naming rules, false otherwise. |
488 | */ | 486 | */ |
489 | bool tomoyo_correct_domain(const unsigned char *domainname) | 487 | bool tomoyo_correct_domain(const unsigned char *domainname) |
490 | { | 488 | { |
491 | if (!domainname || !tomoyo_domain_def(domainname)) | 489 | if (!domainname || !tomoyo_domain_def(domainname)) |
492 | return false; | 490 | return false; |
493 | domainname = strchr(domainname, ' '); | 491 | domainname = strchr(domainname, ' '); |
494 | if (!domainname++) | 492 | if (!domainname++) |
495 | return true; | 493 | return true; |
496 | while (1) { | 494 | while (1) { |
497 | const unsigned char *cp = strchr(domainname, ' '); | 495 | const unsigned char *cp = strchr(domainname, ' '); |
498 | if (!cp) | 496 | if (!cp) |
499 | break; | 497 | break; |
500 | if (*domainname != '/' || | 498 | if (*domainname != '/' || |
501 | !tomoyo_correct_word2(domainname, cp - domainname)) | 499 | !tomoyo_correct_word2(domainname, cp - domainname)) |
502 | return false; | 500 | return false; |
503 | domainname = cp + 1; | 501 | domainname = cp + 1; |
504 | } | 502 | } |
505 | return tomoyo_correct_path(domainname); | 503 | return tomoyo_correct_path(domainname); |
506 | } | 504 | } |
507 | 505 | ||
508 | /** | 506 | /** |
509 | * tomoyo_domain_def - Check whether the given token can be a domainname. | 507 | * tomoyo_domain_def - Check whether the given token can be a domainname. |
510 | * | 508 | * |
511 | * @buffer: The token to check. | 509 | * @buffer: The token to check. |
512 | * | 510 | * |
513 | * Returns true if @buffer possibly be a domainname, false otherwise. | 511 | * Returns true if @buffer possibly be a domainname, false otherwise. |
514 | */ | 512 | */ |
515 | bool tomoyo_domain_def(const unsigned char *buffer) | 513 | bool tomoyo_domain_def(const unsigned char *buffer) |
516 | { | 514 | { |
517 | const unsigned char *cp; | 515 | const unsigned char *cp; |
518 | int len; | 516 | int len; |
519 | if (*buffer != '<') | 517 | if (*buffer != '<') |
520 | return false; | 518 | return false; |
521 | cp = strchr(buffer, ' '); | 519 | cp = strchr(buffer, ' '); |
522 | if (!cp) | 520 | if (!cp) |
523 | len = strlen(buffer); | 521 | len = strlen(buffer); |
524 | else | 522 | else |
525 | len = cp - buffer; | 523 | len = cp - buffer; |
526 | if (buffer[len - 1] != '>' || | 524 | if (buffer[len - 1] != '>' || |
527 | !tomoyo_correct_word2(buffer + 1, len - 2)) | 525 | !tomoyo_correct_word2(buffer + 1, len - 2)) |
528 | return false; | 526 | return false; |
529 | return true; | 527 | return true; |
530 | } | 528 | } |
531 | 529 | ||
532 | /** | 530 | /** |
533 | * tomoyo_find_domain - Find a domain by the given name. | 531 | * tomoyo_find_domain - Find a domain by the given name. |
534 | * | 532 | * |
535 | * @domainname: The domainname to find. | 533 | * @domainname: The domainname to find. |
536 | * | 534 | * |
537 | * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise. | 535 | * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise. |
538 | * | 536 | * |
539 | * Caller holds tomoyo_read_lock(). | 537 | * Caller holds tomoyo_read_lock(). |
540 | */ | 538 | */ |
541 | struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname) | 539 | struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname) |
542 | { | 540 | { |
543 | struct tomoyo_domain_info *domain; | 541 | struct tomoyo_domain_info *domain; |
544 | struct tomoyo_path_info name; | 542 | struct tomoyo_path_info name; |
545 | 543 | ||
546 | name.name = domainname; | 544 | name.name = domainname; |
547 | tomoyo_fill_path_info(&name); | 545 | tomoyo_fill_path_info(&name); |
548 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { | 546 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { |
549 | if (!domain->is_deleted && | 547 | if (!domain->is_deleted && |
550 | !tomoyo_pathcmp(&name, domain->domainname)) | 548 | !tomoyo_pathcmp(&name, domain->domainname)) |
551 | return domain; | 549 | return domain; |
552 | } | 550 | } |
553 | return NULL; | 551 | return NULL; |
554 | } | 552 | } |
555 | 553 | ||
556 | /** | 554 | /** |
557 | * tomoyo_const_part_length - Evaluate the initial length without a pattern in a token. | 555 | * tomoyo_const_part_length - Evaluate the initial length without a pattern in a token. |
558 | * | 556 | * |
559 | * @filename: The string to evaluate. | 557 | * @filename: The string to evaluate. |
560 | * | 558 | * |
561 | * Returns the initial length without a pattern in @filename. | 559 | * Returns the initial length without a pattern in @filename. |
562 | */ | 560 | */ |
563 | static int tomoyo_const_part_length(const char *filename) | 561 | static int tomoyo_const_part_length(const char *filename) |
564 | { | 562 | { |
565 | char c; | 563 | char c; |
566 | int len = 0; | 564 | int len = 0; |
567 | 565 | ||
568 | if (!filename) | 566 | if (!filename) |
569 | return 0; | 567 | return 0; |
570 | while ((c = *filename++) != '\0') { | 568 | while ((c = *filename++) != '\0') { |
571 | if (c != '\\') { | 569 | if (c != '\\') { |
572 | len++; | 570 | len++; |
573 | continue; | 571 | continue; |
574 | } | 572 | } |
575 | c = *filename++; | 573 | c = *filename++; |
576 | switch (c) { | 574 | switch (c) { |
577 | case '\\': /* "\\" */ | 575 | case '\\': /* "\\" */ |
578 | len += 2; | 576 | len += 2; |
579 | continue; | 577 | continue; |
580 | case '0': /* "\ooo" */ | 578 | case '0': /* "\ooo" */ |
581 | case '1': | 579 | case '1': |
582 | case '2': | 580 | case '2': |
583 | case '3': | 581 | case '3': |
584 | c = *filename++; | 582 | c = *filename++; |
585 | if (c < '0' || c > '7') | 583 | if (c < '0' || c > '7') |
586 | break; | 584 | break; |
587 | c = *filename++; | 585 | c = *filename++; |
588 | if (c < '0' || c > '7') | 586 | if (c < '0' || c > '7') |
589 | break; | 587 | break; |
590 | len += 4; | 588 | len += 4; |
591 | continue; | 589 | continue; |
592 | } | 590 | } |
593 | break; | 591 | break; |
594 | } | 592 | } |
595 | return len; | 593 | return len; |
596 | } | 594 | } |
597 | 595 | ||
598 | /** | 596 | /** |
599 | * tomoyo_fill_path_info - Fill in "struct tomoyo_path_info" members. | 597 | * tomoyo_fill_path_info - Fill in "struct tomoyo_path_info" members. |
600 | * | 598 | * |
601 | * @ptr: Pointer to "struct tomoyo_path_info" to fill in. | 599 | * @ptr: Pointer to "struct tomoyo_path_info" to fill in. |
602 | * | 600 | * |
603 | * The caller sets "struct tomoyo_path_info"->name. | 601 | * The caller sets "struct tomoyo_path_info"->name. |
604 | */ | 602 | */ |
605 | void tomoyo_fill_path_info(struct tomoyo_path_info *ptr) | 603 | void tomoyo_fill_path_info(struct tomoyo_path_info *ptr) |
606 | { | 604 | { |
607 | const char *name = ptr->name; | 605 | const char *name = ptr->name; |
608 | const int len = strlen(name); | 606 | const int len = strlen(name); |
609 | 607 | ||
610 | ptr->const_len = tomoyo_const_part_length(name); | 608 | ptr->const_len = tomoyo_const_part_length(name); |
611 | ptr->is_dir = len && (name[len - 1] == '/'); | 609 | ptr->is_dir = len && (name[len - 1] == '/'); |
612 | ptr->is_patterned = (ptr->const_len < len); | 610 | ptr->is_patterned = (ptr->const_len < len); |
613 | ptr->hash = full_name_hash(name, len); | 611 | ptr->hash = full_name_hash(name, len); |
614 | } | 612 | } |
615 | 613 | ||
616 | /** | 614 | /** |
617 | * tomoyo_file_matches_pattern2 - Pattern matching without '/' character and "\-" pattern. | 615 | * tomoyo_file_matches_pattern2 - Pattern matching without '/' character and "\-" pattern. |
618 | * | 616 | * |
619 | * @filename: The start of string to check. | 617 | * @filename: The start of string to check. |
620 | * @filename_end: The end of string to check. | 618 | * @filename_end: The end of string to check. |
621 | * @pattern: The start of pattern to compare. | 619 | * @pattern: The start of pattern to compare. |
622 | * @pattern_end: The end of pattern to compare. | 620 | * @pattern_end: The end of pattern to compare. |
623 | * | 621 | * |
624 | * Returns true if @filename matches @pattern, false otherwise. | 622 | * Returns true if @filename matches @pattern, false otherwise. |
625 | */ | 623 | */ |
626 | static bool tomoyo_file_matches_pattern2(const char *filename, | 624 | static bool tomoyo_file_matches_pattern2(const char *filename, |
627 | const char *filename_end, | 625 | const char *filename_end, |
628 | const char *pattern, | 626 | const char *pattern, |
629 | const char *pattern_end) | 627 | const char *pattern_end) |
630 | { | 628 | { |
631 | while (filename < filename_end && pattern < pattern_end) { | 629 | while (filename < filename_end && pattern < pattern_end) { |
632 | char c; | 630 | char c; |
633 | if (*pattern != '\\') { | 631 | if (*pattern != '\\') { |
634 | if (*filename++ != *pattern++) | 632 | if (*filename++ != *pattern++) |
635 | return false; | 633 | return false; |
636 | continue; | 634 | continue; |
637 | } | 635 | } |
638 | c = *filename; | 636 | c = *filename; |
639 | pattern++; | 637 | pattern++; |
640 | switch (*pattern) { | 638 | switch (*pattern) { |
641 | int i; | 639 | int i; |
642 | int j; | 640 | int j; |
643 | case '?': | 641 | case '?': |
644 | if (c == '/') { | 642 | if (c == '/') { |
645 | return false; | 643 | return false; |
646 | } else if (c == '\\') { | 644 | } else if (c == '\\') { |
647 | if (filename[1] == '\\') | 645 | if (filename[1] == '\\') |
648 | filename++; | 646 | filename++; |
649 | else if (tomoyo_byte_range(filename + 1)) | 647 | else if (tomoyo_byte_range(filename + 1)) |
650 | filename += 3; | 648 | filename += 3; |
651 | else | 649 | else |
652 | return false; | 650 | return false; |
653 | } | 651 | } |
654 | break; | 652 | break; |
655 | case '\\': | 653 | case '\\': |
656 | if (c != '\\') | 654 | if (c != '\\') |
657 | return false; | 655 | return false; |
658 | if (*++filename != '\\') | 656 | if (*++filename != '\\') |
659 | return false; | 657 | return false; |
660 | break; | 658 | break; |
661 | case '+': | 659 | case '+': |
662 | if (!isdigit(c)) | 660 | if (!isdigit(c)) |
663 | return false; | 661 | return false; |
664 | break; | 662 | break; |
665 | case 'x': | 663 | case 'x': |
666 | if (!isxdigit(c)) | 664 | if (!isxdigit(c)) |
667 | return false; | 665 | return false; |
668 | break; | 666 | break; |
669 | case 'a': | 667 | case 'a': |
670 | if (!tomoyo_alphabet_char(c)) | 668 | if (!tomoyo_alphabet_char(c)) |
671 | return false; | 669 | return false; |
672 | break; | 670 | break; |
673 | case '0': | 671 | case '0': |
674 | case '1': | 672 | case '1': |
675 | case '2': | 673 | case '2': |
676 | case '3': | 674 | case '3': |
677 | if (c == '\\' && tomoyo_byte_range(filename + 1) | 675 | if (c == '\\' && tomoyo_byte_range(filename + 1) |
678 | && strncmp(filename + 1, pattern, 3) == 0) { | 676 | && strncmp(filename + 1, pattern, 3) == 0) { |
679 | filename += 3; | 677 | filename += 3; |
680 | pattern += 2; | 678 | pattern += 2; |
681 | break; | 679 | break; |
682 | } | 680 | } |
683 | return false; /* Not matched. */ | 681 | return false; /* Not matched. */ |
684 | case '*': | 682 | case '*': |
685 | case '@': | 683 | case '@': |
686 | for (i = 0; i <= filename_end - filename; i++) { | 684 | for (i = 0; i <= filename_end - filename; i++) { |
687 | if (tomoyo_file_matches_pattern2( | 685 | if (tomoyo_file_matches_pattern2( |
688 | filename + i, filename_end, | 686 | filename + i, filename_end, |
689 | pattern + 1, pattern_end)) | 687 | pattern + 1, pattern_end)) |
690 | return true; | 688 | return true; |
691 | c = filename[i]; | 689 | c = filename[i]; |
692 | if (c == '.' && *pattern == '@') | 690 | if (c == '.' && *pattern == '@') |
693 | break; | 691 | break; |
694 | if (c != '\\') | 692 | if (c != '\\') |
695 | continue; | 693 | continue; |
696 | if (filename[i + 1] == '\\') | 694 | if (filename[i + 1] == '\\') |
697 | i++; | 695 | i++; |
698 | else if (tomoyo_byte_range(filename + i + 1)) | 696 | else if (tomoyo_byte_range(filename + i + 1)) |
699 | i += 3; | 697 | i += 3; |
700 | else | 698 | else |
701 | break; /* Bad pattern. */ | 699 | break; /* Bad pattern. */ |
702 | } | 700 | } |
703 | return false; /* Not matched. */ | 701 | return false; /* Not matched. */ |
704 | default: | 702 | default: |
705 | j = 0; | 703 | j = 0; |
706 | c = *pattern; | 704 | c = *pattern; |
707 | if (c == '$') { | 705 | if (c == '$') { |
708 | while (isdigit(filename[j])) | 706 | while (isdigit(filename[j])) |
709 | j++; | 707 | j++; |
710 | } else if (c == 'X') { | 708 | } else if (c == 'X') { |
711 | while (isxdigit(filename[j])) | 709 | while (isxdigit(filename[j])) |
712 | j++; | 710 | j++; |
713 | } else if (c == 'A') { | 711 | } else if (c == 'A') { |
714 | while (tomoyo_alphabet_char(filename[j])) | 712 | while (tomoyo_alphabet_char(filename[j])) |
715 | j++; | 713 | j++; |
716 | } | 714 | } |
717 | for (i = 1; i <= j; i++) { | 715 | for (i = 1; i <= j; i++) { |
718 | if (tomoyo_file_matches_pattern2( | 716 | if (tomoyo_file_matches_pattern2( |
719 | filename + i, filename_end, | 717 | filename + i, filename_end, |
720 | pattern + 1, pattern_end)) | 718 | pattern + 1, pattern_end)) |
721 | return true; | 719 | return true; |
722 | } | 720 | } |
723 | return false; /* Not matched or bad pattern. */ | 721 | return false; /* Not matched or bad pattern. */ |
724 | } | 722 | } |
725 | filename++; | 723 | filename++; |
726 | pattern++; | 724 | pattern++; |
727 | } | 725 | } |
728 | while (*pattern == '\\' && | 726 | while (*pattern == '\\' && |
729 | (*(pattern + 1) == '*' || *(pattern + 1) == '@')) | 727 | (*(pattern + 1) == '*' || *(pattern + 1) == '@')) |
730 | pattern += 2; | 728 | pattern += 2; |
731 | return filename == filename_end && pattern == pattern_end; | 729 | return filename == filename_end && pattern == pattern_end; |
732 | } | 730 | } |
733 | 731 | ||
734 | /** | 732 | /** |
735 | * tomoyo_file_matches_pattern - Pattern matching without '/' character. | 733 | * tomoyo_file_matches_pattern - Pattern matching without '/' character. |
736 | * | 734 | * |
737 | * @filename: The start of string to check. | 735 | * @filename: The start of string to check. |
738 | * @filename_end: The end of string to check. | 736 | * @filename_end: The end of string to check. |
739 | * @pattern: The start of pattern to compare. | 737 | * @pattern: The start of pattern to compare. |
740 | * @pattern_end: The end of pattern to compare. | 738 | * @pattern_end: The end of pattern to compare. |
741 | * | 739 | * |
742 | * Returns true if @filename matches @pattern, false otherwise. | 740 | * Returns true if @filename matches @pattern, false otherwise. |
743 | */ | 741 | */ |
744 | static bool tomoyo_file_matches_pattern(const char *filename, | 742 | static bool tomoyo_file_matches_pattern(const char *filename, |
745 | const char *filename_end, | 743 | const char *filename_end, |
746 | const char *pattern, | 744 | const char *pattern, |
747 | const char *pattern_end) | 745 | const char *pattern_end) |
748 | { | 746 | { |
749 | const char *pattern_start = pattern; | 747 | const char *pattern_start = pattern; |
750 | bool first = true; | 748 | bool first = true; |
751 | bool result; | 749 | bool result; |
752 | 750 | ||
753 | while (pattern < pattern_end - 1) { | 751 | while (pattern < pattern_end - 1) { |
754 | /* Split at "\-" pattern. */ | 752 | /* Split at "\-" pattern. */ |
755 | if (*pattern++ != '\\' || *pattern++ != '-') | 753 | if (*pattern++ != '\\' || *pattern++ != '-') |
756 | continue; | 754 | continue; |
757 | result = tomoyo_file_matches_pattern2(filename, | 755 | result = tomoyo_file_matches_pattern2(filename, |
758 | filename_end, | 756 | filename_end, |
759 | pattern_start, | 757 | pattern_start, |
760 | pattern - 2); | 758 | pattern - 2); |
761 | if (first) | 759 | if (first) |
762 | result = !result; | 760 | result = !result; |
763 | if (result) | 761 | if (result) |
764 | return false; | 762 | return false; |
765 | first = false; | 763 | first = false; |
766 | pattern_start = pattern; | 764 | pattern_start = pattern; |
767 | } | 765 | } |
768 | result = tomoyo_file_matches_pattern2(filename, filename_end, | 766 | result = tomoyo_file_matches_pattern2(filename, filename_end, |
769 | pattern_start, pattern_end); | 767 | pattern_start, pattern_end); |
770 | return first ? result : !result; | 768 | return first ? result : !result; |
771 | } | 769 | } |
772 | 770 | ||
773 | /** | 771 | /** |
774 | * tomoyo_path_matches_pattern2 - Do pathname pattern matching. | 772 | * tomoyo_path_matches_pattern2 - Do pathname pattern matching. |
775 | * | 773 | * |
776 | * @f: The start of string to check. | 774 | * @f: The start of string to check. |
777 | * @p: The start of pattern to compare. | 775 | * @p: The start of pattern to compare. |
778 | * | 776 | * |
779 | * Returns true if @f matches @p, false otherwise. | 777 | * Returns true if @f matches @p, false otherwise. |
780 | */ | 778 | */ |
781 | static bool tomoyo_path_matches_pattern2(const char *f, const char *p) | 779 | static bool tomoyo_path_matches_pattern2(const char *f, const char *p) |
782 | { | 780 | { |
783 | const char *f_delimiter; | 781 | const char *f_delimiter; |
784 | const char *p_delimiter; | 782 | const char *p_delimiter; |
785 | 783 | ||
786 | while (*f && *p) { | 784 | while (*f && *p) { |
787 | f_delimiter = strchr(f, '/'); | 785 | f_delimiter = strchr(f, '/'); |
788 | if (!f_delimiter) | 786 | if (!f_delimiter) |
789 | f_delimiter = f + strlen(f); | 787 | f_delimiter = f + strlen(f); |
790 | p_delimiter = strchr(p, '/'); | 788 | p_delimiter = strchr(p, '/'); |
791 | if (!p_delimiter) | 789 | if (!p_delimiter) |
792 | p_delimiter = p + strlen(p); | 790 | p_delimiter = p + strlen(p); |
793 | if (*p == '\\' && *(p + 1) == '{') | 791 | if (*p == '\\' && *(p + 1) == '{') |
794 | goto recursive; | 792 | goto recursive; |
795 | if (!tomoyo_file_matches_pattern(f, f_delimiter, p, | 793 | if (!tomoyo_file_matches_pattern(f, f_delimiter, p, |
796 | p_delimiter)) | 794 | p_delimiter)) |
797 | return false; | 795 | return false; |
798 | f = f_delimiter; | 796 | f = f_delimiter; |
799 | if (*f) | 797 | if (*f) |
800 | f++; | 798 | f++; |
801 | p = p_delimiter; | 799 | p = p_delimiter; |
802 | if (*p) | 800 | if (*p) |
803 | p++; | 801 | p++; |
804 | } | 802 | } |
805 | /* Ignore trailing "\*" and "\@" in @pattern. */ | 803 | /* Ignore trailing "\*" and "\@" in @pattern. */ |
806 | while (*p == '\\' && | 804 | while (*p == '\\' && |
807 | (*(p + 1) == '*' || *(p + 1) == '@')) | 805 | (*(p + 1) == '*' || *(p + 1) == '@')) |
808 | p += 2; | 806 | p += 2; |
809 | return !*f && !*p; | 807 | return !*f && !*p; |
810 | recursive: | 808 | recursive: |
811 | /* | 809 | /* |
812 | * The "\{" pattern is permitted only after '/' character. | 810 | * The "\{" pattern is permitted only after '/' character. |
813 | * This guarantees that below "*(p - 1)" is safe. | 811 | * This guarantees that below "*(p - 1)" is safe. |
814 | * Also, the "\}" pattern is permitted only before '/' character | 812 | * Also, the "\}" pattern is permitted only before '/' character |
815 | * so that "\{" + "\}" pair will not break the "\-" operator. | 813 | * so that "\{" + "\}" pair will not break the "\-" operator. |
816 | */ | 814 | */ |
817 | if (*(p - 1) != '/' || p_delimiter <= p + 3 || *p_delimiter != '/' || | 815 | if (*(p - 1) != '/' || p_delimiter <= p + 3 || *p_delimiter != '/' || |
818 | *(p_delimiter - 1) != '}' || *(p_delimiter - 2) != '\\') | 816 | *(p_delimiter - 1) != '}' || *(p_delimiter - 2) != '\\') |
819 | return false; /* Bad pattern. */ | 817 | return false; /* Bad pattern. */ |
820 | do { | 818 | do { |
821 | /* Compare current component with pattern. */ | 819 | /* Compare current component with pattern. */ |
822 | if (!tomoyo_file_matches_pattern(f, f_delimiter, p + 2, | 820 | if (!tomoyo_file_matches_pattern(f, f_delimiter, p + 2, |
823 | p_delimiter - 2)) | 821 | p_delimiter - 2)) |
824 | break; | 822 | break; |
825 | /* Proceed to next component. */ | 823 | /* Proceed to next component. */ |
826 | f = f_delimiter; | 824 | f = f_delimiter; |
827 | if (!*f) | 825 | if (!*f) |
828 | break; | 826 | break; |
829 | f++; | 827 | f++; |
830 | /* Continue comparison. */ | 828 | /* Continue comparison. */ |
831 | if (tomoyo_path_matches_pattern2(f, p_delimiter + 1)) | 829 | if (tomoyo_path_matches_pattern2(f, p_delimiter + 1)) |
832 | return true; | 830 | return true; |
833 | f_delimiter = strchr(f, '/'); | 831 | f_delimiter = strchr(f, '/'); |
834 | } while (f_delimiter); | 832 | } while (f_delimiter); |
835 | return false; /* Not matched. */ | 833 | return false; /* Not matched. */ |
836 | } | 834 | } |
837 | 835 | ||
838 | /** | 836 | /** |
839 | * tomoyo_path_matches_pattern - Check whether the given filename matches the given pattern. | 837 | * tomoyo_path_matches_pattern - Check whether the given filename matches the given pattern. |
840 | * | 838 | * |
841 | * @filename: The filename to check. | 839 | * @filename: The filename to check. |
842 | * @pattern: The pattern to compare. | 840 | * @pattern: The pattern to compare. |
843 | * | 841 | * |
844 | * Returns true if matches, false otherwise. | 842 | * Returns true if matches, false otherwise. |
845 | * | 843 | * |
846 | * The following patterns are available. | 844 | * The following patterns are available. |
847 | * \\ \ itself. | 845 | * \\ \ itself. |
848 | * \ooo Octal representation of a byte. | 846 | * \ooo Octal representation of a byte. |
849 | * \* Zero or more repetitions of characters other than '/'. | 847 | * \* Zero or more repetitions of characters other than '/'. |
850 | * \@ Zero or more repetitions of characters other than '/' or '.'. | 848 | * \@ Zero or more repetitions of characters other than '/' or '.'. |
851 | * \? 1 byte character other than '/'. | 849 | * \? 1 byte character other than '/'. |
852 | * \$ One or more repetitions of decimal digits. | 850 | * \$ One or more repetitions of decimal digits. |
853 | * \+ 1 decimal digit. | 851 | * \+ 1 decimal digit. |
854 | * \X One or more repetitions of hexadecimal digits. | 852 | * \X One or more repetitions of hexadecimal digits. |
855 | * \x 1 hexadecimal digit. | 853 | * \x 1 hexadecimal digit. |
856 | * \A One or more repetitions of alphabet characters. | 854 | * \A One or more repetitions of alphabet characters. |
857 | * \a 1 alphabet character. | 855 | * \a 1 alphabet character. |
858 | * | 856 | * |
859 | * \- Subtraction operator. | 857 | * \- Subtraction operator. |
860 | * | 858 | * |
861 | * /\{dir\}/ '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/ | 859 | * /\{dir\}/ '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/ |
862 | * /dir/dir/dir/ ). | 860 | * /dir/dir/dir/ ). |
863 | */ | 861 | */ |
864 | bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename, | 862 | bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename, |
865 | const struct tomoyo_path_info *pattern) | 863 | const struct tomoyo_path_info *pattern) |
866 | { | 864 | { |
867 | const char *f = filename->name; | 865 | const char *f = filename->name; |
868 | const char *p = pattern->name; | 866 | const char *p = pattern->name; |
869 | const int len = pattern->const_len; | 867 | const int len = pattern->const_len; |
870 | 868 | ||
871 | /* If @pattern doesn't contain pattern, I can use strcmp(). */ | 869 | /* If @pattern doesn't contain pattern, I can use strcmp(). */ |
872 | if (!pattern->is_patterned) | 870 | if (!pattern->is_patterned) |
873 | return !tomoyo_pathcmp(filename, pattern); | 871 | return !tomoyo_pathcmp(filename, pattern); |
874 | /* Don't compare directory and non-directory. */ | 872 | /* Don't compare directory and non-directory. */ |
875 | if (filename->is_dir != pattern->is_dir) | 873 | if (filename->is_dir != pattern->is_dir) |
876 | return false; | 874 | return false; |
877 | /* Compare the initial length without patterns. */ | 875 | /* Compare the initial length without patterns. */ |
878 | if (strncmp(f, p, len)) | 876 | if (strncmp(f, p, len)) |
879 | return false; | 877 | return false; |
880 | f += len; | 878 | f += len; |
881 | p += len; | 879 | p += len; |
882 | return tomoyo_path_matches_pattern2(f, p); | 880 | return tomoyo_path_matches_pattern2(f, p); |
883 | } | 881 | } |
884 | 882 | ||
885 | /** | 883 | /** |
886 | * tomoyo_get_exe - Get tomoyo_realpath() of current process. | 884 | * tomoyo_get_exe - Get tomoyo_realpath() of current process. |
887 | * | 885 | * |
888 | * Returns the tomoyo_realpath() of current process on success, NULL otherwise. | 886 | * Returns the tomoyo_realpath() of current process on success, NULL otherwise. |
889 | * | 887 | * |
890 | * This function uses kzalloc(), so the caller must call kfree() | 888 | * This function uses kzalloc(), so the caller must call kfree() |
891 | * if this function didn't return NULL. | 889 | * if this function didn't return NULL. |
892 | */ | 890 | */ |
893 | const char *tomoyo_get_exe(void) | 891 | const char *tomoyo_get_exe(void) |
894 | { | 892 | { |
895 | struct mm_struct *mm = current->mm; | 893 | struct mm_struct *mm = current->mm; |
896 | struct vm_area_struct *vma; | 894 | struct vm_area_struct *vma; |
897 | const char *cp = NULL; | 895 | const char *cp = NULL; |
898 | 896 | ||
899 | if (!mm) | 897 | if (!mm) |
900 | return NULL; | 898 | return NULL; |
901 | down_read(&mm->mmap_sem); | 899 | down_read(&mm->mmap_sem); |
902 | for (vma = mm->mmap; vma; vma = vma->vm_next) { | 900 | for (vma = mm->mmap; vma; vma = vma->vm_next) { |
903 | if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) { | 901 | if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) { |
904 | cp = tomoyo_realpath_from_path(&vma->vm_file->f_path); | 902 | cp = tomoyo_realpath_from_path(&vma->vm_file->f_path); |
905 | break; | 903 | break; |
906 | } | 904 | } |
907 | } | 905 | } |
908 | up_read(&mm->mmap_sem); | 906 | up_read(&mm->mmap_sem); |
909 | return cp; | 907 | return cp; |
910 | } | 908 | } |
911 | 909 | ||
912 | /** | 910 | /** |
913 | * tomoyo_get_mode - Get MAC mode. | 911 | * tomoyo_get_mode - Get MAC mode. |
914 | * | 912 | * |
915 | * @ns: Pointer to "struct tomoyo_policy_namespace". | 913 | * @ns: Pointer to "struct tomoyo_policy_namespace". |
916 | * @profile: Profile number. | 914 | * @profile: Profile number. |
917 | * @index: Index number of functionality. | 915 | * @index: Index number of functionality. |
918 | * | 916 | * |
919 | * Returns mode. | 917 | * Returns mode. |
920 | */ | 918 | */ |
921 | int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile, | 919 | int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile, |
922 | const u8 index) | 920 | const u8 index) |
923 | { | 921 | { |
924 | u8 mode; | 922 | u8 mode; |
925 | const u8 category = TOMOYO_MAC_CATEGORY_FILE; | 923 | const u8 category = TOMOYO_MAC_CATEGORY_FILE; |
926 | if (!tomoyo_policy_loaded) | 924 | if (!tomoyo_policy_loaded) |
927 | return TOMOYO_CONFIG_DISABLED; | 925 | return TOMOYO_CONFIG_DISABLED; |
928 | mode = tomoyo_profile(ns, profile)->config[index]; | 926 | mode = tomoyo_profile(ns, profile)->config[index]; |
929 | if (mode == TOMOYO_CONFIG_USE_DEFAULT) | 927 | if (mode == TOMOYO_CONFIG_USE_DEFAULT) |
930 | mode = tomoyo_profile(ns, profile)->config[category]; | 928 | mode = tomoyo_profile(ns, profile)->config[category]; |
931 | if (mode == TOMOYO_CONFIG_USE_DEFAULT) | 929 | if (mode == TOMOYO_CONFIG_USE_DEFAULT) |
932 | mode = tomoyo_profile(ns, profile)->default_config; | 930 | mode = tomoyo_profile(ns, profile)->default_config; |
933 | return mode & 3; | 931 | return mode & 3; |
934 | } | 932 | } |
935 | 933 | ||
936 | /** | 934 | /** |
937 | * tomoyo_init_request_info - Initialize "struct tomoyo_request_info" members. | 935 | * tomoyo_init_request_info - Initialize "struct tomoyo_request_info" members. |
938 | * | 936 | * |
939 | * @r: Pointer to "struct tomoyo_request_info" to initialize. | 937 | * @r: Pointer to "struct tomoyo_request_info" to initialize. |
940 | * @domain: Pointer to "struct tomoyo_domain_info". NULL for tomoyo_domain(). | 938 | * @domain: Pointer to "struct tomoyo_domain_info". NULL for tomoyo_domain(). |
941 | * @index: Index number of functionality. | 939 | * @index: Index number of functionality. |
942 | * | 940 | * |
943 | * Returns mode. | 941 | * Returns mode. |
944 | */ | 942 | */ |
945 | int tomoyo_init_request_info(struct tomoyo_request_info *r, | 943 | int tomoyo_init_request_info(struct tomoyo_request_info *r, |
946 | struct tomoyo_domain_info *domain, const u8 index) | 944 | struct tomoyo_domain_info *domain, const u8 index) |
947 | { | 945 | { |
948 | u8 profile; | 946 | u8 profile; |
949 | memset(r, 0, sizeof(*r)); | 947 | memset(r, 0, sizeof(*r)); |
950 | if (!domain) | 948 | if (!domain) |
951 | domain = tomoyo_domain(); | 949 | domain = tomoyo_domain(); |
952 | r->domain = domain; | 950 | r->domain = domain; |
953 | profile = domain->profile; | 951 | profile = domain->profile; |
954 | r->profile = profile; | 952 | r->profile = profile; |
955 | r->type = index; | 953 | r->type = index; |
956 | r->mode = tomoyo_get_mode(domain->ns, profile, index); | 954 | r->mode = tomoyo_get_mode(domain->ns, profile, index); |
957 | return r->mode; | 955 | return r->mode; |
958 | } | 956 | } |
959 | 957 | ||
960 | /** | 958 | /** |
961 | * tomoyo_domain_quota_is_ok - Check for domain's quota. | 959 | * tomoyo_domain_quota_is_ok - Check for domain's quota. |
962 | * | 960 | * |
963 | * @r: Pointer to "struct tomoyo_request_info". | 961 | * @r: Pointer to "struct tomoyo_request_info". |
964 | * | 962 | * |
965 | * Returns true if the domain is not exceeded quota, false otherwise. | 963 | * Returns true if the domain is not exceeded quota, false otherwise. |
966 | * | 964 | * |
967 | * Caller holds tomoyo_read_lock(). | 965 | * Caller holds tomoyo_read_lock(). |
968 | */ | 966 | */ |
969 | bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r) | 967 | bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r) |
970 | { | 968 | { |
971 | unsigned int count = 0; | 969 | unsigned int count = 0; |
972 | struct tomoyo_domain_info *domain = r->domain; | 970 | struct tomoyo_domain_info *domain = r->domain; |
973 | struct tomoyo_acl_info *ptr; | 971 | struct tomoyo_acl_info *ptr; |
974 | 972 | ||
975 | if (r->mode != TOMOYO_CONFIG_LEARNING) | 973 | if (r->mode != TOMOYO_CONFIG_LEARNING) |
976 | return false; | 974 | return false; |
977 | if (!domain) | 975 | if (!domain) |
978 | return true; | 976 | return true; |
979 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { | 977 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { |
980 | u16 perm; | 978 | u16 perm; |
981 | u8 i; | 979 | u8 i; |
982 | if (ptr->is_deleted) | 980 | if (ptr->is_deleted) |
983 | continue; | 981 | continue; |
984 | switch (ptr->type) { | 982 | switch (ptr->type) { |
985 | case TOMOYO_TYPE_PATH_ACL: | 983 | case TOMOYO_TYPE_PATH_ACL: |
986 | perm = container_of(ptr, struct tomoyo_path_acl, head) | 984 | perm = container_of(ptr, struct tomoyo_path_acl, head) |
987 | ->perm; | 985 | ->perm; |
988 | break; | 986 | break; |
989 | case TOMOYO_TYPE_PATH2_ACL: | 987 | case TOMOYO_TYPE_PATH2_ACL: |
990 | perm = container_of(ptr, struct tomoyo_path2_acl, head) | 988 | perm = container_of(ptr, struct tomoyo_path2_acl, head) |
991 | ->perm; | 989 | ->perm; |
992 | break; | 990 | break; |
993 | case TOMOYO_TYPE_PATH_NUMBER_ACL: | 991 | case TOMOYO_TYPE_PATH_NUMBER_ACL: |
994 | perm = container_of(ptr, struct tomoyo_path_number_acl, | 992 | perm = container_of(ptr, struct tomoyo_path_number_acl, |
995 | head)->perm; | 993 | head)->perm; |
996 | break; | 994 | break; |
997 | case TOMOYO_TYPE_MKDEV_ACL: | 995 | case TOMOYO_TYPE_MKDEV_ACL: |
998 | perm = container_of(ptr, struct tomoyo_mkdev_acl, | 996 | perm = container_of(ptr, struct tomoyo_mkdev_acl, |
999 | head)->perm; | 997 | head)->perm; |
1000 | break; | 998 | break; |
1001 | default: | 999 | default: |
1002 | perm = 1; | 1000 | perm = 1; |
1003 | } | 1001 | } |
1004 | for (i = 0; i < 16; i++) | 1002 | for (i = 0; i < 16; i++) |
1005 | if (perm & (1 << i)) | 1003 | if (perm & (1 << i)) |
1006 | count++; | 1004 | count++; |
1007 | } | 1005 | } |
1008 | if (count < tomoyo_profile(domain->ns, domain->profile)-> | 1006 | if (count < tomoyo_profile(domain->ns, domain->profile)-> |
1009 | pref[TOMOYO_PREF_MAX_LEARNING_ENTRY]) | 1007 | pref[TOMOYO_PREF_MAX_LEARNING_ENTRY]) |
1010 | return true; | 1008 | return true; |
1011 | if (!domain->flags[TOMOYO_DIF_QUOTA_WARNED]) { | 1009 | if (!domain->flags[TOMOYO_DIF_QUOTA_WARNED]) { |
1012 | domain->flags[TOMOYO_DIF_QUOTA_WARNED] = true; | 1010 | domain->flags[TOMOYO_DIF_QUOTA_WARNED] = true; |
1013 | /* r->granted = false; */ | 1011 | /* r->granted = false; */ |
1014 | tomoyo_write_log(r, "%s", tomoyo_dif[TOMOYO_DIF_QUOTA_WARNED]); | 1012 | tomoyo_write_log(r, "%s", tomoyo_dif[TOMOYO_DIF_QUOTA_WARNED]); |
1015 | printk(KERN_WARNING "WARNING: " | 1013 | printk(KERN_WARNING "WARNING: " |
1016 | "Domain '%s' has too many ACLs to hold. " | 1014 | "Domain '%s' has too many ACLs to hold. " |
1017 | "Stopped learning mode.\n", domain->domainname->name); | 1015 | "Stopped learning mode.\n", domain->domainname->name); |
1018 | } | 1016 | } |
1019 | return false; | 1017 | return false; |
1020 | } | 1018 | } |
1021 | 1019 |