diff options
author | Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> | 2010-06-24 01:57:16 -0400 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2010-08-02 01:34:45 -0400 |
commit | f23571e866309a2048030ef6a5f0725cf139d4c9 (patch) | |
tree | 0116bcef462f367307b2db927b249b7ce21039c2 /security/tomoyo/common.c | |
parent | 5db5a39b6462c8360c9178b28f4b07c320dfca1c (diff) |
TOMOYO: Copy directly to userspace buffer.
When userspace program reads policy from /sys/kernel/security/tomoyo/
interface, TOMOYO uses line buffered mode. A line has at least one word.
Commit 006dacc "TOMOYO: Support longer pathname." changed a word's max length
from 4000 bytes to max kmalloc()able bytes. By that commit, a line's max length
changed from 8192 bytes to more than max kmalloc()able bytes.
Max number of words in a line remains finite. This patch changes the way of
buffering so that all words in a line are firstly directly copied to userspace
buffer as much as possible and are secondly queued for next read request.
Words queued are guaranteed to be valid until /sys/kernel/security/tomoyo/
interface is close()d.
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/tomoyo/common.c')
-rw-r--r-- | security/tomoyo/common.c | 891 |
1 files changed, 475 insertions, 416 deletions
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index a3c3b5de3b75..7cb6c0459d96 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
@@ -28,7 +28,7 @@ static unsigned int tomoyo_profile_version; | |||
28 | static struct tomoyo_profile *tomoyo_profile_ptr[TOMOYO_MAX_PROFILES]; | 28 | static struct tomoyo_profile *tomoyo_profile_ptr[TOMOYO_MAX_PROFILES]; |
29 | 29 | ||
30 | /* String table for functionality that takes 4 modes. */ | 30 | /* String table for functionality that takes 4 modes. */ |
31 | static const char *tomoyo_mode_4[4] = { | 31 | static const char *tomoyo_mode[4] = { |
32 | "disabled", "learning", "permissive", "enforcing" | 32 | "disabled", "learning", "permissive", "enforcing" |
33 | }; | 33 | }; |
34 | 34 | ||
@@ -76,102 +76,175 @@ static const char *tomoyo_yesno(const unsigned int value) | |||
76 | return value ? "yes" : "no"; | 76 | return value ? "yes" : "no"; |
77 | } | 77 | } |
78 | 78 | ||
79 | static void tomoyo_addprintf(char *buffer, int len, const char *fmt, ...) | ||
80 | { | ||
81 | va_list args; | ||
82 | const int pos = strlen(buffer); | ||
83 | va_start(args, fmt); | ||
84 | vsnprintf(buffer + pos, len - pos - 1, fmt, args); | ||
85 | va_end(args); | ||
86 | } | ||
87 | |||
79 | /** | 88 | /** |
80 | * tomoyo_print_name_union - Print a tomoyo_name_union. | 89 | * tomoyo_flush - Flush queued string to userspace's buffer. |
81 | * | 90 | * |
82 | * @head: Pointer to "struct tomoyo_io_buffer". | 91 | * @head: Pointer to "struct tomoyo_io_buffer". |
83 | * @ptr: Pointer to "struct tomoyo_name_union". | ||
84 | * | 92 | * |
85 | * Returns true on success, false otherwise. | 93 | * Returns true if all data was flushed, false otherwise. |
86 | */ | 94 | */ |
87 | static bool tomoyo_print_name_union(struct tomoyo_io_buffer *head, | 95 | static bool tomoyo_flush(struct tomoyo_io_buffer *head) |
88 | const struct tomoyo_name_union *ptr) | ||
89 | { | 96 | { |
90 | int pos = head->read_avail; | 97 | while (head->r.w_pos) { |
91 | if (pos && head->read_buf[pos - 1] == ' ') | 98 | const char *w = head->r.w[0]; |
92 | head->read_avail--; | 99 | int len = strlen(w); |
93 | if (ptr->is_group) | 100 | if (len) { |
94 | return tomoyo_io_printf(head, " @%s", | 101 | if (len > head->read_user_buf_avail) |
95 | ptr->group->group_name->name); | 102 | len = head->read_user_buf_avail; |
96 | return tomoyo_io_printf(head, " %s", ptr->filename->name); | 103 | if (!len) |
104 | return false; | ||
105 | if (copy_to_user(head->read_user_buf, w, len)) | ||
106 | return false; | ||
107 | head->read_user_buf_avail -= len; | ||
108 | head->read_user_buf += len; | ||
109 | w += len; | ||
110 | } | ||
111 | if (*w) { | ||
112 | head->r.w[0] = w; | ||
113 | return false; | ||
114 | } | ||
115 | /* Add '\0' for query. */ | ||
116 | if (head->poll) { | ||
117 | if (!head->read_user_buf_avail || | ||
118 | copy_to_user(head->read_user_buf, "", 1)) | ||
119 | return false; | ||
120 | head->read_user_buf_avail--; | ||
121 | head->read_user_buf++; | ||
122 | } | ||
123 | head->r.w_pos--; | ||
124 | for (len = 0; len < head->r.w_pos; len++) | ||
125 | head->r.w[len] = head->r.w[len + 1]; | ||
126 | } | ||
127 | head->r.avail = 0; | ||
128 | return true; | ||
97 | } | 129 | } |
98 | 130 | ||
99 | /** | 131 | /** |
100 | * tomoyo_print_number_union - Print a tomoyo_number_union. | 132 | * tomoyo_set_string - Queue string to "struct tomoyo_io_buffer" structure. |
101 | * | 133 | * |
102 | * @head: Pointer to "struct tomoyo_io_buffer". | 134 | * @head: Pointer to "struct tomoyo_io_buffer". |
103 | * @ptr: Pointer to "struct tomoyo_number_union". | 135 | * @string: String to print. |
104 | * | 136 | * |
105 | * Returns true on success, false otherwise. | 137 | * Note that @string has to be kept valid until @head is kfree()d. |
138 | * This means that char[] allocated on stack memory cannot be passed to | ||
139 | * this function. Use tomoyo_io_printf() for char[] allocated on stack memory. | ||
106 | */ | 140 | */ |
107 | bool tomoyo_print_number_union(struct tomoyo_io_buffer *head, | 141 | static void tomoyo_set_string(struct tomoyo_io_buffer *head, const char *string) |
108 | const struct tomoyo_number_union *ptr) | ||
109 | { | 142 | { |
110 | unsigned long min; | 143 | if (head->r.w_pos < TOMOYO_MAX_IO_READ_QUEUE) { |
111 | unsigned long max; | 144 | head->r.w[head->r.w_pos++] = string; |
112 | u8 min_type; | 145 | tomoyo_flush(head); |
113 | u8 max_type; | 146 | } else |
114 | if (!tomoyo_io_printf(head, " ")) | 147 | WARN_ON(1); |
115 | return false; | ||
116 | if (ptr->is_group) | ||
117 | return tomoyo_io_printf(head, "@%s", | ||
118 | ptr->group->group_name->name); | ||
119 | min_type = ptr->min_type; | ||
120 | max_type = ptr->max_type; | ||
121 | min = ptr->values[0]; | ||
122 | max = ptr->values[1]; | ||
123 | switch (min_type) { | ||
124 | case TOMOYO_VALUE_TYPE_HEXADECIMAL: | ||
125 | if (!tomoyo_io_printf(head, "0x%lX", min)) | ||
126 | return false; | ||
127 | break; | ||
128 | case TOMOYO_VALUE_TYPE_OCTAL: | ||
129 | if (!tomoyo_io_printf(head, "0%lo", min)) | ||
130 | return false; | ||
131 | break; | ||
132 | default: | ||
133 | if (!tomoyo_io_printf(head, "%lu", min)) | ||
134 | return false; | ||
135 | break; | ||
136 | } | ||
137 | if (min == max && min_type == max_type) | ||
138 | return true; | ||
139 | switch (max_type) { | ||
140 | case TOMOYO_VALUE_TYPE_HEXADECIMAL: | ||
141 | return tomoyo_io_printf(head, "-0x%lX", max); | ||
142 | case TOMOYO_VALUE_TYPE_OCTAL: | ||
143 | return tomoyo_io_printf(head, "-0%lo", max); | ||
144 | default: | ||
145 | return tomoyo_io_printf(head, "-%lu", max); | ||
146 | } | ||
147 | } | 148 | } |
148 | 149 | ||
149 | /** | 150 | /** |
150 | * tomoyo_io_printf - Transactional printf() to "struct tomoyo_io_buffer" structure. | 151 | * tomoyo_io_printf - printf() to "struct tomoyo_io_buffer" structure. |
151 | * | 152 | * |
152 | * @head: Pointer to "struct tomoyo_io_buffer". | 153 | * @head: Pointer to "struct tomoyo_io_buffer". |
153 | * @fmt: The printf()'s format string, followed by parameters. | 154 | * @fmt: The printf()'s format string, followed by parameters. |
154 | * | ||
155 | * Returns true if output was written, false otherwise. | ||
156 | * | ||
157 | * The snprintf() will truncate, but tomoyo_io_printf() won't. | ||
158 | */ | 155 | */ |
159 | bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) | 156 | void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) |
160 | { | 157 | { |
161 | va_list args; | 158 | va_list args; |
162 | int len; | 159 | int len; |
163 | int pos = head->read_avail; | 160 | int pos = head->r.avail; |
164 | int size = head->readbuf_size - pos; | 161 | int size = head->readbuf_size - pos; |
165 | |||
166 | if (size <= 0) | 162 | if (size <= 0) |
167 | return false; | 163 | return; |
168 | va_start(args, fmt); | 164 | va_start(args, fmt); |
169 | len = vsnprintf(head->read_buf + pos, size, fmt, args); | 165 | len = vsnprintf(head->read_buf + pos, size, fmt, args) + 1; |
170 | va_end(args); | 166 | va_end(args); |
171 | if (pos + len >= head->readbuf_size) | 167 | if (pos + len >= head->readbuf_size) { |
172 | return false; | 168 | WARN_ON(1); |
173 | head->read_avail += len; | 169 | return; |
174 | return true; | 170 | } |
171 | head->r.avail += len; | ||
172 | tomoyo_set_string(head, head->read_buf + pos); | ||
173 | } | ||
174 | |||
175 | static void tomoyo_set_space(struct tomoyo_io_buffer *head) | ||
176 | { | ||
177 | tomoyo_set_string(head, " "); | ||
178 | } | ||
179 | |||
180 | static bool tomoyo_set_lf(struct tomoyo_io_buffer *head) | ||
181 | { | ||
182 | tomoyo_set_string(head, "\n"); | ||
183 | return !head->r.w_pos; | ||
184 | } | ||
185 | |||
186 | /** | ||
187 | * tomoyo_print_name_union - Print a tomoyo_name_union. | ||
188 | * | ||
189 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
190 | * @ptr: Pointer to "struct tomoyo_name_union". | ||
191 | */ | ||
192 | static void tomoyo_print_name_union(struct tomoyo_io_buffer *head, | ||
193 | const struct tomoyo_name_union *ptr) | ||
194 | { | ||
195 | tomoyo_set_space(head); | ||
196 | if (ptr->is_group) { | ||
197 | tomoyo_set_string(head, "@"); | ||
198 | tomoyo_set_string(head, ptr->group->group_name->name); | ||
199 | } else { | ||
200 | tomoyo_set_string(head, ptr->filename->name); | ||
201 | } | ||
202 | } | ||
203 | |||
204 | /** | ||
205 | * tomoyo_print_number_union - Print a tomoyo_number_union. | ||
206 | * | ||
207 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
208 | * @ptr: Pointer to "struct tomoyo_number_union". | ||
209 | */ | ||
210 | static void tomoyo_print_number_union(struct tomoyo_io_buffer *head, | ||
211 | const struct tomoyo_number_union *ptr) | ||
212 | { | ||
213 | tomoyo_set_space(head); | ||
214 | if (ptr->is_group) { | ||
215 | tomoyo_set_string(head, "@"); | ||
216 | tomoyo_set_string(head, ptr->group->group_name->name); | ||
217 | } else { | ||
218 | int i; | ||
219 | unsigned long min = ptr->values[0]; | ||
220 | const unsigned long max = ptr->values[1]; | ||
221 | u8 min_type = ptr->min_type; | ||
222 | const u8 max_type = ptr->max_type; | ||
223 | char buffer[128]; | ||
224 | buffer[0] = '\0'; | ||
225 | for (i = 0; i < 2; i++) { | ||
226 | switch (min_type) { | ||
227 | case TOMOYO_VALUE_TYPE_HEXADECIMAL: | ||
228 | tomoyo_addprintf(buffer, sizeof(buffer), | ||
229 | "0x%lX", min); | ||
230 | break; | ||
231 | case TOMOYO_VALUE_TYPE_OCTAL: | ||
232 | tomoyo_addprintf(buffer, sizeof(buffer), | ||
233 | "0%lo", min); | ||
234 | break; | ||
235 | default: | ||
236 | tomoyo_addprintf(buffer, sizeof(buffer), | ||
237 | "%lu", min); | ||
238 | break; | ||
239 | } | ||
240 | if (min == max && min_type == max_type) | ||
241 | break; | ||
242 | tomoyo_addprintf(buffer, sizeof(buffer), "-"); | ||
243 | min_type = max_type; | ||
244 | min = max; | ||
245 | } | ||
246 | tomoyo_io_printf(head, "%s", buffer); | ||
247 | } | ||
175 | } | 248 | } |
176 | 249 | ||
177 | /** | 250 | /** |
@@ -334,7 +407,7 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head) | |||
334 | config = TOMOYO_CONFIG_USE_DEFAULT; | 407 | config = TOMOYO_CONFIG_USE_DEFAULT; |
335 | } else { | 408 | } else { |
336 | for (mode = 3; mode >= 0; mode--) | 409 | for (mode = 3; mode >= 0; mode--) |
337 | if (strstr(cp, tomoyo_mode_4[mode])) | 410 | if (strstr(cp, tomoyo_mode[mode])) |
338 | /* | 411 | /* |
339 | * Update lower 3 bits in order to distinguish | 412 | * Update lower 3 bits in order to distinguish |
340 | * 'config' from 'TOMOYO_CONFIG_USE_DEAFULT'. | 413 | * 'config' from 'TOMOYO_CONFIG_USE_DEAFULT'. |
@@ -348,6 +421,52 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head) | |||
348 | return 0; | 421 | return 0; |
349 | } | 422 | } |
350 | 423 | ||
424 | static void tomoyo_print_preference(struct tomoyo_io_buffer *head, | ||
425 | const int idx) | ||
426 | { | ||
427 | struct tomoyo_preference *pref = &tomoyo_default_profile.preference; | ||
428 | const struct tomoyo_profile *profile = idx >= 0 ? | ||
429 | tomoyo_profile_ptr[idx] : NULL; | ||
430 | char buffer[16] = ""; | ||
431 | if (profile) { | ||
432 | buffer[sizeof(buffer) - 1] = '\0'; | ||
433 | snprintf(buffer, sizeof(buffer) - 1, "%u-", idx); | ||
434 | } | ||
435 | if (profile) { | ||
436 | pref = profile->learning; | ||
437 | if (pref == &tomoyo_default_profile.preference) | ||
438 | goto skip1; | ||
439 | } | ||
440 | tomoyo_io_printf(head, "%sPREFERENCE::%s={ " | ||
441 | "verbose=%s max_entry=%u }\n", | ||
442 | buffer, "learning", | ||
443 | tomoyo_yesno(pref->learning_verbose), | ||
444 | pref->learning_max_entry); | ||
445 | skip1: | ||
446 | if (profile) { | ||
447 | pref = profile->permissive; | ||
448 | if (pref == &tomoyo_default_profile.preference) | ||
449 | goto skip2; | ||
450 | } | ||
451 | tomoyo_io_printf(head, "%sPREFERENCE::%s={ verbose=%s }\n", | ||
452 | buffer, "permissive", | ||
453 | tomoyo_yesno(pref->permissive_verbose)); | ||
454 | skip2: | ||
455 | if (profile) { | ||
456 | pref = profile->enforcing; | ||
457 | if (pref == &tomoyo_default_profile.preference) | ||
458 | return; | ||
459 | } | ||
460 | tomoyo_io_printf(head, "%sPREFERENCE::%s={ verbose=%s }\n", | ||
461 | buffer, "enforcing", | ||
462 | tomoyo_yesno(pref->enforcing_verbose)); | ||
463 | } | ||
464 | |||
465 | static void tomoyo_print_config(struct tomoyo_io_buffer *head, const u8 config) | ||
466 | { | ||
467 | tomoyo_io_printf(head, "={ mode=%s }\n", tomoyo_mode[config & 3]); | ||
468 | } | ||
469 | |||
351 | /** | 470 | /** |
352 | * tomoyo_read_profile - Read profile table. | 471 | * tomoyo_read_profile - Read profile table. |
353 | * | 472 | * |
@@ -355,83 +474,67 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head) | |||
355 | */ | 474 | */ |
356 | static void tomoyo_read_profile(struct tomoyo_io_buffer *head) | 475 | static void tomoyo_read_profile(struct tomoyo_io_buffer *head) |
357 | { | 476 | { |
358 | int index; | 477 | u8 index; |
359 | if (head->read_eof) | 478 | const struct tomoyo_profile *profile; |
360 | return; | 479 | next: |
361 | if (head->read_bit) | 480 | index = head->r.index; |
362 | goto body; | 481 | profile = tomoyo_profile_ptr[index]; |
363 | tomoyo_io_printf(head, "PROFILE_VERSION=%s\n", "20090903"); | 482 | switch (head->r.step) { |
364 | tomoyo_io_printf(head, "PREFERENCE::learning={ verbose=%s " | 483 | case 0: |
365 | "max_entry=%u }\n", | 484 | tomoyo_io_printf(head, "PROFILE_VERSION=%s\n", "20090903"); |
366 | tomoyo_yesno(tomoyo_default_profile.preference. | 485 | tomoyo_print_preference(head, -1); |
367 | learning_verbose), | 486 | head->r.step++; |
368 | tomoyo_default_profile.preference.learning_max_entry); | 487 | break; |
369 | tomoyo_io_printf(head, "PREFERENCE::permissive={ verbose=%s }\n", | 488 | case 1: |
370 | tomoyo_yesno(tomoyo_default_profile.preference. | 489 | for ( ; head->r.index < TOMOYO_MAX_PROFILES; |
371 | permissive_verbose)); | 490 | head->r.index++) |
372 | tomoyo_io_printf(head, "PREFERENCE::enforcing={ verbose=%s }\n", | 491 | if (tomoyo_profile_ptr[head->r.index]) |
373 | tomoyo_yesno(tomoyo_default_profile.preference. | 492 | break; |
374 | enforcing_verbose)); | 493 | if (head->r.index == TOMOYO_MAX_PROFILES) |
375 | head->read_bit = 1; | 494 | return; |
376 | body: | 495 | head->r.step++; |
377 | for (index = head->read_step; index < TOMOYO_MAX_PROFILES; index++) { | 496 | break; |
378 | bool done; | 497 | case 2: |
379 | u8 config; | 498 | { |
380 | int i; | 499 | const struct tomoyo_path_info *comment = |
381 | int pos; | 500 | profile->comment; |
382 | const struct tomoyo_profile *profile | 501 | tomoyo_io_printf(head, "%u-COMMENT=", index); |
383 | = tomoyo_profile_ptr[index]; | 502 | tomoyo_set_string(head, comment ? comment->name : ""); |
384 | const struct tomoyo_path_info *comment; | 503 | tomoyo_set_lf(head); |
385 | head->read_step = index; | 504 | head->r.step++; |
386 | if (!profile) | 505 | } |
387 | continue; | 506 | break; |
388 | pos = head->read_avail; | 507 | case 3: |
389 | comment = profile->comment; | 508 | { |
390 | done = tomoyo_io_printf(head, "%u-COMMENT=%s\n", index, | 509 | tomoyo_io_printf(head, "%u-%s", index, "CONFIG"); |
391 | comment ? comment->name : ""); | 510 | tomoyo_print_config(head, profile->default_config); |
392 | if (!done) | 511 | head->r.bit = 0; |
393 | goto out; | 512 | head->r.step++; |
394 | config = profile->default_config; | 513 | } |
395 | if (!tomoyo_io_printf(head, "%u-CONFIG={ mode=%s }\n", index, | 514 | break; |
396 | tomoyo_mode_4[config & 3])) | 515 | case 4: |
397 | goto out; | 516 | for ( ; head->r.bit < TOMOYO_MAX_MAC_INDEX |
398 | for (i = 0; i < TOMOYO_MAX_MAC_INDEX + | 517 | + TOMOYO_MAX_MAC_CATEGORY_INDEX; head->r.bit++) { |
399 | TOMOYO_MAX_MAC_CATEGORY_INDEX; i++) { | 518 | const u8 i = head->r.bit; |
400 | config = profile->config[i]; | 519 | const u8 config = profile->config[i]; |
401 | if (config == TOMOYO_CONFIG_USE_DEFAULT) | 520 | if (config == TOMOYO_CONFIG_USE_DEFAULT) |
402 | continue; | 521 | continue; |
403 | if (!tomoyo_io_printf(head, | 522 | tomoyo_io_printf(head, "%u-%s%s", index, "CONFIG::", |
404 | "%u-CONFIG::%s={ mode=%s }\n", | 523 | tomoyo_mac_keywords[i]); |
405 | index, tomoyo_mac_keywords[i], | 524 | tomoyo_print_config(head, config); |
406 | tomoyo_mode_4[config & 3])) | 525 | head->r.bit++; |
407 | goto out; | 526 | break; |
527 | } | ||
528 | if (head->r.bit == TOMOYO_MAX_MAC_INDEX | ||
529 | + TOMOYO_MAX_MAC_CATEGORY_INDEX) { | ||
530 | tomoyo_print_preference(head, index); | ||
531 | head->r.index++; | ||
532 | head->r.step = 1; | ||
408 | } | 533 | } |
409 | if (profile->learning != &tomoyo_default_profile.preference && | ||
410 | !tomoyo_io_printf(head, "%u-PREFERENCE::learning={ " | ||
411 | "verbose=%s max_entry=%u }\n", index, | ||
412 | tomoyo_yesno(profile->preference. | ||
413 | learning_verbose), | ||
414 | profile->preference.learning_max_entry)) | ||
415 | goto out; | ||
416 | if (profile->permissive != &tomoyo_default_profile.preference | ||
417 | && !tomoyo_io_printf(head, "%u-PREFERENCE::permissive={ " | ||
418 | "verbose=%s }\n", index, | ||
419 | tomoyo_yesno(profile->preference. | ||
420 | permissive_verbose))) | ||
421 | goto out; | ||
422 | if (profile->enforcing != &tomoyo_default_profile.preference && | ||
423 | !tomoyo_io_printf(head, "%u-PREFERENCE::enforcing={ " | ||
424 | "verbose=%s }\n", index, | ||
425 | tomoyo_yesno(profile->preference. | ||
426 | enforcing_verbose))) | ||
427 | goto out; | ||
428 | continue; | ||
429 | out: | ||
430 | head->read_avail = pos; | ||
431 | break; | 534 | break; |
432 | } | 535 | } |
433 | if (index == TOMOYO_MAX_PROFILES) | 536 | if (tomoyo_flush(head)) |
434 | head->read_eof = true; | 537 | goto next; |
435 | } | 538 | } |
436 | 539 | ||
437 | static bool tomoyo_same_manager_entry(const struct tomoyo_acl_head *a, | 540 | static bool tomoyo_same_manager_entry(const struct tomoyo_acl_head *a, |
@@ -507,21 +610,20 @@ static int tomoyo_write_manager_policy(struct tomoyo_io_buffer *head) | |||
507 | */ | 610 | */ |
508 | static void tomoyo_read_manager_policy(struct tomoyo_io_buffer *head) | 611 | static void tomoyo_read_manager_policy(struct tomoyo_io_buffer *head) |
509 | { | 612 | { |
510 | bool done = true; | 613 | if (head->r.eof) |
511 | |||
512 | if (head->read_eof) | ||
513 | return; | 614 | return; |
514 | list_for_each_cookie(head->read_var2, | 615 | list_for_each_cookie(head->r.acl, |
515 | &tomoyo_policy_list[TOMOYO_ID_MANAGER]) { | 616 | &tomoyo_policy_list[TOMOYO_ID_MANAGER]) { |
516 | struct tomoyo_policy_manager_entry *ptr = | 617 | struct tomoyo_policy_manager_entry *ptr = |
517 | list_entry(head->read_var2, typeof(*ptr), head.list); | 618 | list_entry(head->r.acl, typeof(*ptr), head.list); |
518 | if (ptr->head.is_deleted) | 619 | if (ptr->head.is_deleted) |
519 | continue; | 620 | continue; |
520 | done = tomoyo_io_printf(head, "%s\n", ptr->manager->name); | 621 | if (!tomoyo_flush(head)) |
521 | if (!done) | 622 | return; |
522 | break; | 623 | tomoyo_set_string(head, ptr->manager->name); |
624 | tomoyo_set_lf(head); | ||
523 | } | 625 | } |
524 | head->read_eof = done; | 626 | head->r.eof = true; |
525 | } | 627 | } |
526 | 628 | ||
527 | /** | 629 | /** |
@@ -595,7 +697,7 @@ static bool tomoyo_select_one(struct tomoyo_io_buffer *head, const char *data) | |||
595 | bool global_pid = false; | 697 | bool global_pid = false; |
596 | 698 | ||
597 | if (!strcmp(data, "allow_execute")) { | 699 | if (!strcmp(data, "allow_execute")) { |
598 | head->print_execute_only = true; | 700 | head->r.print_execute_only = true; |
599 | return true; | 701 | return true; |
600 | } | 702 | } |
601 | if (sscanf(data, "pid=%u", &pid) == 1 || | 703 | if (sscanf(data, "pid=%u", &pid) == 1 || |
@@ -620,14 +722,11 @@ static bool tomoyo_select_one(struct tomoyo_io_buffer *head, const char *data) | |||
620 | /* Accessing read_buf is safe because head->io_sem is held. */ | 722 | /* Accessing read_buf is safe because head->io_sem is held. */ |
621 | if (!head->read_buf) | 723 | if (!head->read_buf) |
622 | return true; /* Do nothing if open(O_WRONLY). */ | 724 | return true; /* Do nothing if open(O_WRONLY). */ |
623 | head->read_avail = 0; | 725 | memset(&head->r, 0, sizeof(head->r)); |
726 | head->r.print_this_domain_only = true; | ||
727 | head->r.eof = !domain; | ||
728 | head->r.domain = &domain->list; | ||
624 | tomoyo_io_printf(head, "# select %s\n", data); | 729 | tomoyo_io_printf(head, "# select %s\n", data); |
625 | head->read_single_domain = true; | ||
626 | head->read_eof = !domain; | ||
627 | head->read_var1 = &domain->list; | ||
628 | head->read_var2 = NULL; | ||
629 | head->read_bit = 0; | ||
630 | head->read_step = 0; | ||
631 | if (domain && domain->is_deleted) | 730 | if (domain && domain->is_deleted) |
632 | tomoyo_io_printf(head, "# This is a deleted domain.\n"); | 731 | tomoyo_io_printf(head, "# This is a deleted domain.\n"); |
633 | return true; | 732 | return true; |
@@ -773,20 +872,22 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, | |||
773 | struct tomoyo_acl_info *acl) | 872 | struct tomoyo_acl_info *acl) |
774 | { | 873 | { |
775 | const u8 acl_type = acl->type; | 874 | const u8 acl_type = acl->type; |
776 | u8 bit = head->read_bit; | 875 | u8 bit; |
777 | int pos = head->read_avail; | ||
778 | 876 | ||
779 | if (acl->is_deleted) | 877 | if (acl->is_deleted) |
780 | return true; | 878 | return true; |
781 | next: | 879 | next: |
782 | if (acl_type == TOMOYO_TYPE_PATH_ACL) { | 880 | bit = head->r.bit; |
881 | if (!tomoyo_flush(head)) | ||
882 | return false; | ||
883 | else if (acl_type == TOMOYO_TYPE_PATH_ACL) { | ||
783 | struct tomoyo_path_acl *ptr = | 884 | struct tomoyo_path_acl *ptr = |
784 | container_of(acl, typeof(*ptr), head); | 885 | container_of(acl, typeof(*ptr), head); |
785 | const u16 perm = ptr->perm; | 886 | const u16 perm = ptr->perm; |
786 | for ( ; bit < TOMOYO_MAX_PATH_OPERATION; bit++) { | 887 | for ( ; bit < TOMOYO_MAX_PATH_OPERATION; bit++) { |
787 | if (!(perm & (1 << bit))) | 888 | if (!(perm & (1 << bit))) |
788 | continue; | 889 | continue; |
789 | if (head->print_execute_only && | 890 | if (head->r.print_execute_only && |
790 | bit != TOMOYO_TYPE_EXECUTE) | 891 | bit != TOMOYO_TYPE_EXECUTE) |
791 | continue; | 892 | continue; |
792 | /* Print "read/write" instead of "read" and "write". */ | 893 | /* Print "read/write" instead of "read" and "write". */ |
@@ -798,11 +899,9 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, | |||
798 | } | 899 | } |
799 | if (bit >= TOMOYO_MAX_PATH_OPERATION) | 900 | if (bit >= TOMOYO_MAX_PATH_OPERATION) |
800 | goto done; | 901 | goto done; |
801 | if (!tomoyo_io_printf(head, "allow_%s ", | 902 | tomoyo_io_printf(head, "allow_%s", tomoyo_path_keyword[bit]); |
802 | tomoyo_path_keyword[bit]) || | 903 | tomoyo_print_name_union(head, &ptr->name); |
803 | !tomoyo_print_name_union(head, &ptr->name)) | 904 | } else if (head->r.print_execute_only) { |
804 | goto out; | ||
805 | } else if (head->print_execute_only) { | ||
806 | return true; | 905 | return true; |
807 | } else if (acl_type == TOMOYO_TYPE_PATH2_ACL) { | 906 | } else if (acl_type == TOMOYO_TYPE_PATH2_ACL) { |
808 | struct tomoyo_path2_acl *ptr = | 907 | struct tomoyo_path2_acl *ptr = |
@@ -810,58 +909,69 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, | |||
810 | bit = tomoyo_fns(ptr->perm, bit); | 909 | bit = tomoyo_fns(ptr->perm, bit); |
811 | if (bit >= TOMOYO_MAX_PATH2_OPERATION) | 910 | if (bit >= TOMOYO_MAX_PATH2_OPERATION) |
812 | goto done; | 911 | goto done; |
813 | if (!tomoyo_io_printf(head, "allow_%s ", | 912 | tomoyo_io_printf(head, "allow_%s", tomoyo_path2_keyword[bit]); |
814 | tomoyo_path2_keyword[bit]) || | 913 | tomoyo_print_name_union(head, &ptr->name1); |
815 | !tomoyo_print_name_union(head, &ptr->name1) || | 914 | tomoyo_print_name_union(head, &ptr->name2); |
816 | !tomoyo_print_name_union(head, &ptr->name2)) | ||
817 | goto out; | ||
818 | } else if (acl_type == TOMOYO_TYPE_PATH_NUMBER_ACL) { | 915 | } else if (acl_type == TOMOYO_TYPE_PATH_NUMBER_ACL) { |
819 | struct tomoyo_path_number_acl *ptr = | 916 | struct tomoyo_path_number_acl *ptr = |
820 | container_of(acl, typeof(*ptr), head); | 917 | container_of(acl, typeof(*ptr), head); |
821 | bit = tomoyo_fns(ptr->perm, bit); | 918 | bit = tomoyo_fns(ptr->perm, bit); |
822 | if (bit >= TOMOYO_MAX_PATH_NUMBER_OPERATION) | 919 | if (bit >= TOMOYO_MAX_PATH_NUMBER_OPERATION) |
823 | goto done; | 920 | goto done; |
824 | if (!tomoyo_io_printf(head, "allow_%s", | 921 | tomoyo_io_printf(head, "allow_%s", |
825 | tomoyo_path_number_keyword[bit]) || | 922 | tomoyo_path_number_keyword[bit]); |
826 | !tomoyo_print_name_union(head, &ptr->name) || | 923 | tomoyo_print_name_union(head, &ptr->name); |
827 | !tomoyo_print_number_union(head, &ptr->number)) | 924 | tomoyo_print_number_union(head, &ptr->number); |
828 | goto out; | ||
829 | } else if (acl_type == TOMOYO_TYPE_MKDEV_ACL) { | 925 | } else if (acl_type == TOMOYO_TYPE_MKDEV_ACL) { |
830 | struct tomoyo_mkdev_acl *ptr = | 926 | struct tomoyo_mkdev_acl *ptr = |
831 | container_of(acl, typeof(*ptr), head); | 927 | container_of(acl, typeof(*ptr), head); |
832 | bit = tomoyo_fns(ptr->perm, bit); | 928 | bit = tomoyo_fns(ptr->perm, bit); |
833 | if (bit >= TOMOYO_MAX_MKDEV_OPERATION) | 929 | if (bit >= TOMOYO_MAX_MKDEV_OPERATION) |
834 | goto done; | 930 | goto done; |
835 | if (!tomoyo_io_printf(head, "allow_%s", | 931 | tomoyo_io_printf(head, "allow_%s", tomoyo_mkdev_keyword[bit]); |
836 | tomoyo_mkdev_keyword[bit]) || | 932 | tomoyo_print_name_union(head, &ptr->name); |
837 | !tomoyo_print_name_union(head, &ptr->name) || | 933 | tomoyo_print_number_union(head, &ptr->mode); |
838 | !tomoyo_print_number_union(head, &ptr->mode) || | 934 | tomoyo_print_number_union(head, &ptr->major); |
839 | !tomoyo_print_number_union(head, &ptr->major) || | 935 | tomoyo_print_number_union(head, &ptr->minor); |
840 | !tomoyo_print_number_union(head, &ptr->minor)) | ||
841 | goto out; | ||
842 | } else if (acl_type == TOMOYO_TYPE_MOUNT_ACL) { | 936 | } else if (acl_type == TOMOYO_TYPE_MOUNT_ACL) { |
843 | struct tomoyo_mount_acl *ptr = | 937 | struct tomoyo_mount_acl *ptr = |
844 | container_of(acl, typeof(*ptr), head); | 938 | container_of(acl, typeof(*ptr), head); |
845 | if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_MOUNT) || | 939 | tomoyo_io_printf(head, "allow_mount"); |
846 | !tomoyo_print_name_union(head, &ptr->dev_name) || | 940 | tomoyo_print_name_union(head, &ptr->dev_name); |
847 | !tomoyo_print_name_union(head, &ptr->dir_name) || | 941 | tomoyo_print_name_union(head, &ptr->dir_name); |
848 | !tomoyo_print_name_union(head, &ptr->fs_type) || | 942 | tomoyo_print_name_union(head, &ptr->fs_type); |
849 | !tomoyo_print_number_union(head, &ptr->flags)) | 943 | tomoyo_print_number_union(head, &ptr->flags); |
850 | goto out; | ||
851 | } | 944 | } |
852 | if (!tomoyo_io_printf(head, "\n")) | 945 | head->r.bit = bit + 1; |
853 | goto out; | 946 | tomoyo_io_printf(head, "\n"); |
854 | head->read_bit = bit; | 947 | if (acl_type != TOMOYO_TYPE_MOUNT_ACL) |
855 | if (acl_type != TOMOYO_TYPE_MOUNT_ACL) { | ||
856 | bit++; | ||
857 | goto next; | 948 | goto next; |
858 | } | ||
859 | done: | 949 | done: |
860 | head->read_bit = 0; | 950 | head->r.bit = 0; |
951 | return true; | ||
952 | } | ||
953 | |||
954 | /** | ||
955 | * tomoyo_read_domain2 - Read domain policy. | ||
956 | * | ||
957 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
958 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
959 | * | ||
960 | * Caller holds tomoyo_read_lock(). | ||
961 | * | ||
962 | * Returns true on success, false otherwise. | ||
963 | */ | ||
964 | static bool tomoyo_read_domain2(struct tomoyo_io_buffer *head, | ||
965 | struct tomoyo_domain_info *domain) | ||
966 | { | ||
967 | list_for_each_cookie(head->r.acl, &domain->acl_info_list) { | ||
968 | struct tomoyo_acl_info *ptr = | ||
969 | list_entry(head->r.acl, typeof(*ptr), list); | ||
970 | if (!tomoyo_print_entry(head, ptr)) | ||
971 | return false; | ||
972 | } | ||
973 | head->r.acl = NULL; | ||
861 | return true; | 974 | return true; |
862 | out: | ||
863 | head->read_avail = pos; | ||
864 | return false; | ||
865 | } | 975 | } |
866 | 976 | ||
867 | /** | 977 | /** |
@@ -873,64 +983,48 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, | |||
873 | */ | 983 | */ |
874 | static void tomoyo_read_domain_policy(struct tomoyo_io_buffer *head) | 984 | static void tomoyo_read_domain_policy(struct tomoyo_io_buffer *head) |
875 | { | 985 | { |
876 | bool done = true; | 986 | if (head->r.eof) |
877 | |||
878 | if (head->read_eof) | ||
879 | return; | 987 | return; |
880 | if (head->read_step == 0) | 988 | list_for_each_cookie(head->r.domain, &tomoyo_domain_list) { |
881 | head->read_step = 1; | ||
882 | list_for_each_cookie(head->read_var1, &tomoyo_domain_list) { | ||
883 | struct tomoyo_domain_info *domain = | 989 | struct tomoyo_domain_info *domain = |
884 | list_entry(head->read_var1, typeof(*domain), list); | 990 | list_entry(head->r.domain, typeof(*domain), list); |
885 | const char *quota_exceeded = ""; | 991 | switch (head->r.step) { |
886 | const char *transition_failed = ""; | 992 | case 0: |
887 | const char *ignore_global_allow_read = ""; | 993 | if (domain->is_deleted && |
888 | if (head->read_step != 1) | 994 | !head->r.print_this_domain_only) |
889 | goto acl_loop; | 995 | continue; |
890 | if (domain->is_deleted && !head->read_single_domain) | 996 | /* Print domainname and flags. */ |
891 | continue; | 997 | tomoyo_set_string(head, domain->domainname->name); |
892 | /* Print domainname and flags. */ | 998 | tomoyo_set_lf(head); |
893 | if (domain->quota_warned) | 999 | tomoyo_io_printf(head, |
894 | quota_exceeded = "quota_exceeded\n"; | 1000 | TOMOYO_KEYWORD_USE_PROFILE "%u\n", |
895 | if (domain->transition_failed) | 1001 | domain->profile); |
896 | transition_failed = "transition_failed\n"; | 1002 | if (domain->quota_warned) |
897 | if (domain->ignore_global_allow_read) | 1003 | tomoyo_set_string(head, "quota_exceeded\n"); |
898 | ignore_global_allow_read | 1004 | if (domain->transition_failed) |
899 | = TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "\n"; | 1005 | tomoyo_set_string(head, "transition_failed\n"); |
900 | done = tomoyo_io_printf(head, "%s\n" TOMOYO_KEYWORD_USE_PROFILE | 1006 | if (domain->ignore_global_allow_read) |
901 | "%u\n%s%s%s\n", | 1007 | tomoyo_set_string(head, |
902 | domain->domainname->name, | 1008 | TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ |
903 | domain->profile, quota_exceeded, | 1009 | "\n"); |
904 | transition_failed, | 1010 | head->r.step++; |
905 | ignore_global_allow_read); | 1011 | tomoyo_set_lf(head); |
906 | if (!done) | 1012 | /* fall through */ |
907 | break; | 1013 | case 1: |
908 | head->read_step = 2; | 1014 | if (!tomoyo_read_domain2(head, domain)) |
909 | acl_loop: | 1015 | return; |
910 | if (head->read_step == 3) | 1016 | head->r.step++; |
911 | goto tail_mark; | 1017 | if (!tomoyo_set_lf(head)) |
912 | /* Print ACL entries in the domain. */ | 1018 | return; |
913 | list_for_each_cookie(head->read_var2, | 1019 | /* fall through */ |
914 | &domain->acl_info_list) { | 1020 | case 2: |
915 | struct tomoyo_acl_info *ptr = | 1021 | head->r.step = 0; |
916 | list_entry(head->read_var2, typeof(*ptr), list); | 1022 | if (head->r.print_this_domain_only) |
917 | done = tomoyo_print_entry(head, ptr); | 1023 | goto done; |
918 | if (!done) | ||
919 | break; | ||
920 | } | 1024 | } |
921 | if (!done) | ||
922 | break; | ||
923 | head->read_var2 = NULL; | ||
924 | head->read_step = 3; | ||
925 | tail_mark: | ||
926 | done = tomoyo_io_printf(head, "\n"); | ||
927 | if (!done) | ||
928 | break; | ||
929 | head->read_step = 1; | ||
930 | if (head->read_single_domain) | ||
931 | break; | ||
932 | } | 1025 | } |
933 | head->read_eof = done; | 1026 | done: |
1027 | head->r.eof = true; | ||
934 | } | 1028 | } |
935 | 1029 | ||
936 | /** | 1030 | /** |
@@ -984,21 +1078,20 @@ static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head) | |||
984 | */ | 1078 | */ |
985 | static void tomoyo_read_domain_profile(struct tomoyo_io_buffer *head) | 1079 | static void tomoyo_read_domain_profile(struct tomoyo_io_buffer *head) |
986 | { | 1080 | { |
987 | bool done = true; | 1081 | if (head->r.eof) |
988 | |||
989 | if (head->read_eof) | ||
990 | return; | 1082 | return; |
991 | list_for_each_cookie(head->read_var1, &tomoyo_domain_list) { | 1083 | list_for_each_cookie(head->r.domain, &tomoyo_domain_list) { |
992 | struct tomoyo_domain_info *domain = | 1084 | struct tomoyo_domain_info *domain = |
993 | list_entry(head->read_var1, typeof(*domain), list); | 1085 | list_entry(head->r.domain, typeof(*domain), list); |
994 | if (domain->is_deleted) | 1086 | if (domain->is_deleted) |
995 | continue; | 1087 | continue; |
996 | done = tomoyo_io_printf(head, "%u %s\n", domain->profile, | 1088 | if (!tomoyo_flush(head)) |
997 | domain->domainname->name); | 1089 | return; |
998 | if (!done) | 1090 | tomoyo_io_printf(head, "%u ", domain->profile); |
999 | break; | 1091 | tomoyo_set_string(head, domain->domainname->name); |
1092 | tomoyo_set_lf(head); | ||
1000 | } | 1093 | } |
1001 | head->read_eof = done; | 1094 | head->r.eof = true; |
1002 | } | 1095 | } |
1003 | 1096 | ||
1004 | /** | 1097 | /** |
@@ -1010,11 +1103,7 @@ static void tomoyo_read_domain_profile(struct tomoyo_io_buffer *head) | |||
1010 | */ | 1103 | */ |
1011 | static int tomoyo_write_pid(struct tomoyo_io_buffer *head) | 1104 | static int tomoyo_write_pid(struct tomoyo_io_buffer *head) |
1012 | { | 1105 | { |
1013 | unsigned long pid; | 1106 | head->r.eof = false; |
1014 | /* No error check. */ | ||
1015 | strict_strtoul(head->write_buf, 10, &pid); | ||
1016 | head->read_step = (int) pid; | ||
1017 | head->read_eof = false; | ||
1018 | return 0; | 1107 | return 0; |
1019 | } | 1108 | } |
1020 | 1109 | ||
@@ -1030,22 +1119,37 @@ static int tomoyo_write_pid(struct tomoyo_io_buffer *head) | |||
1030 | */ | 1119 | */ |
1031 | static void tomoyo_read_pid(struct tomoyo_io_buffer *head) | 1120 | static void tomoyo_read_pid(struct tomoyo_io_buffer *head) |
1032 | { | 1121 | { |
1033 | if (head->read_avail == 0 && !head->read_eof) { | 1122 | char *buf = head->write_buf; |
1034 | const int pid = head->read_step; | 1123 | bool global_pid = false; |
1035 | struct task_struct *p; | 1124 | unsigned int pid; |
1036 | struct tomoyo_domain_info *domain = NULL; | 1125 | struct task_struct *p; |
1037 | rcu_read_lock(); | 1126 | struct tomoyo_domain_info *domain = NULL; |
1038 | read_lock(&tasklist_lock); | 1127 | |
1039 | p = find_task_by_vpid(pid); | 1128 | /* Accessing write_buf is safe because head->io_sem is held. */ |
1040 | if (p) | 1129 | if (!buf) { |
1041 | domain = tomoyo_real_domain(p); | 1130 | head->r.eof = true; |
1042 | read_unlock(&tasklist_lock); | 1131 | return; /* Do nothing if open(O_RDONLY). */ |
1043 | rcu_read_unlock(); | ||
1044 | if (domain) | ||
1045 | tomoyo_io_printf(head, "%d %u %s", pid, domain->profile, | ||
1046 | domain->domainname->name); | ||
1047 | head->read_eof = true; | ||
1048 | } | 1132 | } |
1133 | if (head->r.w_pos || head->r.eof) | ||
1134 | return; | ||
1135 | head->r.eof = true; | ||
1136 | if (tomoyo_str_starts(&buf, "global-pid ")) | ||
1137 | global_pid = true; | ||
1138 | pid = (unsigned int) simple_strtoul(buf, NULL, 10); | ||
1139 | rcu_read_lock(); | ||
1140 | read_lock(&tasklist_lock); | ||
1141 | if (global_pid) | ||
1142 | p = find_task_by_pid_ns(pid, &init_pid_ns); | ||
1143 | else | ||
1144 | p = find_task_by_vpid(pid); | ||
1145 | if (p) | ||
1146 | domain = tomoyo_real_domain(p); | ||
1147 | read_unlock(&tasklist_lock); | ||
1148 | rcu_read_unlock(); | ||
1149 | if (!domain) | ||
1150 | return; | ||
1151 | tomoyo_io_printf(head, "%u %u ", pid, domain->profile); | ||
1152 | tomoyo_set_string(head, domain->domainname->name); | ||
1049 | } | 1153 | } |
1050 | 1154 | ||
1051 | static const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = { | 1155 | static const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = { |
@@ -1092,40 +1196,6 @@ static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head) | |||
1092 | return -EINVAL; | 1196 | return -EINVAL; |
1093 | } | 1197 | } |
1094 | 1198 | ||
1095 | static void tomoyo_print_number(char *buffer, int buffer_len, | ||
1096 | const struct tomoyo_number_union *ptr) | ||
1097 | { | ||
1098 | int i; | ||
1099 | unsigned long min = ptr->values[0]; | ||
1100 | const unsigned long max = ptr->values[1]; | ||
1101 | u8 min_type = ptr->min_type; | ||
1102 | const u8 max_type = ptr->max_type; | ||
1103 | memset(buffer, 0, buffer_len); | ||
1104 | buffer_len -= 2; | ||
1105 | for (i = 0; i < 2; i++) { | ||
1106 | int len; | ||
1107 | switch (min_type) { | ||
1108 | case TOMOYO_VALUE_TYPE_HEXADECIMAL: | ||
1109 | snprintf(buffer, buffer_len, "0x%lX", min); | ||
1110 | break; | ||
1111 | case TOMOYO_VALUE_TYPE_OCTAL: | ||
1112 | snprintf(buffer, buffer_len, "0%lo", min); | ||
1113 | break; | ||
1114 | default: | ||
1115 | snprintf(buffer, buffer_len, "%lu", min); | ||
1116 | break; | ||
1117 | } | ||
1118 | if (min == max && min_type == max_type) | ||
1119 | break; | ||
1120 | len = strlen(buffer); | ||
1121 | buffer[len++] = '-'; | ||
1122 | buffer += len; | ||
1123 | buffer_len -= len; | ||
1124 | min_type = max_type; | ||
1125 | min = max; | ||
1126 | } | ||
1127 | } | ||
1128 | |||
1129 | static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = { | 1199 | static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = { |
1130 | [TOMOYO_PATH_GROUP] = TOMOYO_KEYWORD_PATH_GROUP, | 1200 | [TOMOYO_PATH_GROUP] = TOMOYO_KEYWORD_PATH_GROUP, |
1131 | [TOMOYO_NUMBER_GROUP] = TOMOYO_KEYWORD_NUMBER_GROUP | 1201 | [TOMOYO_NUMBER_GROUP] = TOMOYO_KEYWORD_NUMBER_GROUP |
@@ -1143,37 +1213,34 @@ static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = { | |||
1143 | */ | 1213 | */ |
1144 | static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx) | 1214 | static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx) |
1145 | { | 1215 | { |
1146 | const char *w[3] = { "", "", "" }; | 1216 | list_for_each_cookie(head->r.group, &tomoyo_group_list[idx]) { |
1147 | w[0] = tomoyo_group_name[idx]; | ||
1148 | list_for_each_cookie(head->read_var1, &tomoyo_group_list[idx]) { | ||
1149 | struct tomoyo_group *group = | 1217 | struct tomoyo_group *group = |
1150 | list_entry(head->read_var1, typeof(*group), list); | 1218 | list_entry(head->r.group, typeof(*group), list); |
1151 | w[1] = group->group_name->name; | 1219 | list_for_each_cookie(head->r.acl, &group->member_list) { |
1152 | list_for_each_cookie(head->read_var2, &group->member_list) { | ||
1153 | char buffer[128]; | ||
1154 | struct tomoyo_acl_head *ptr = | 1220 | struct tomoyo_acl_head *ptr = |
1155 | list_entry(head->read_var2, typeof(*ptr), list); | 1221 | list_entry(head->r.acl, typeof(*ptr), list); |
1156 | if (ptr->is_deleted) | 1222 | if (ptr->is_deleted) |
1157 | continue; | 1223 | continue; |
1224 | if (!tomoyo_flush(head)) | ||
1225 | return false; | ||
1226 | tomoyo_set_string(head, tomoyo_group_name[idx]); | ||
1227 | tomoyo_set_string(head, group->group_name->name); | ||
1158 | if (idx == TOMOYO_PATH_GROUP) { | 1228 | if (idx == TOMOYO_PATH_GROUP) { |
1159 | w[2] = container_of(ptr, | 1229 | tomoyo_set_space(head); |
1160 | struct tomoyo_path_group, | 1230 | tomoyo_set_string(head, container_of |
1161 | head)->member_name->name; | 1231 | (ptr, struct tomoyo_path_group, |
1232 | head)->member_name->name); | ||
1162 | } else if (idx == TOMOYO_NUMBER_GROUP) { | 1233 | } else if (idx == TOMOYO_NUMBER_GROUP) { |
1163 | tomoyo_print_number(buffer, sizeof(buffer), | 1234 | tomoyo_print_number_union(head, &container_of |
1164 | &container_of | 1235 | (ptr, |
1165 | (ptr, struct | 1236 | struct tomoyo_number_group, |
1166 | tomoyo_number_group, | 1237 | head)->number); |
1167 | head)->number); | ||
1168 | w[2] = buffer; | ||
1169 | } | 1238 | } |
1170 | if (!tomoyo_io_printf(head, "%s%s %s\n", w[0], w[1], | 1239 | tomoyo_set_lf(head); |
1171 | w[2])) | ||
1172 | return false; | ||
1173 | } | 1240 | } |
1174 | head->read_var2 = NULL; | 1241 | head->r.acl = NULL; |
1175 | } | 1242 | } |
1176 | head->read_var1 = NULL; | 1243 | head->r.group = NULL; |
1177 | return true; | 1244 | return true; |
1178 | } | 1245 | } |
1179 | 1246 | ||
@@ -1189,68 +1256,78 @@ static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx) | |||
1189 | */ | 1256 | */ |
1190 | static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx) | 1257 | static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx) |
1191 | { | 1258 | { |
1192 | list_for_each_cookie(head->read_var2, &tomoyo_policy_list[idx]) { | 1259 | list_for_each_cookie(head->r.acl, &tomoyo_policy_list[idx]) { |
1193 | const char *w[4] = { "", "", "", "" }; | ||
1194 | struct tomoyo_acl_head *acl = | 1260 | struct tomoyo_acl_head *acl = |
1195 | container_of(head->read_var2, typeof(*acl), list); | 1261 | container_of(head->r.acl, typeof(*acl), list); |
1196 | if (acl->is_deleted) | 1262 | if (acl->is_deleted) |
1197 | continue; | 1263 | continue; |
1264 | if (!tomoyo_flush(head)) | ||
1265 | return false; | ||
1198 | switch (idx) { | 1266 | switch (idx) { |
1199 | case TOMOYO_ID_TRANSITION_CONTROL: | 1267 | case TOMOYO_ID_TRANSITION_CONTROL: |
1200 | { | 1268 | { |
1201 | struct tomoyo_transition_control *ptr = | 1269 | struct tomoyo_transition_control *ptr = |
1202 | container_of(acl, typeof(*ptr), head); | 1270 | container_of(acl, typeof(*ptr), head); |
1203 | w[0] = tomoyo_transition_type[ptr->type]; | 1271 | tomoyo_set_string(head, |
1272 | tomoyo_transition_type | ||
1273 | [ptr->type]); | ||
1204 | if (ptr->program) | 1274 | if (ptr->program) |
1205 | w[1] = ptr->program->name; | 1275 | tomoyo_set_string(head, |
1276 | ptr->program->name); | ||
1277 | if (ptr->program && ptr->domainname) | ||
1278 | tomoyo_set_string(head, " from "); | ||
1206 | if (ptr->domainname) | 1279 | if (ptr->domainname) |
1207 | w[3] = ptr->domainname->name; | 1280 | tomoyo_set_string(head, |
1208 | if (w[1][0] && w[3][0]) | 1281 | ptr->domainname-> |
1209 | w[2] = " from "; | 1282 | name); |
1210 | } | 1283 | } |
1211 | break; | 1284 | break; |
1212 | case TOMOYO_ID_GLOBALLY_READABLE: | 1285 | case TOMOYO_ID_GLOBALLY_READABLE: |
1213 | { | 1286 | { |
1214 | struct tomoyo_globally_readable_file_entry *ptr | 1287 | struct tomoyo_globally_readable_file_entry *ptr |
1215 | = container_of(acl, typeof(*ptr), head); | 1288 | = container_of(acl, typeof(*ptr), head); |
1216 | w[0] = TOMOYO_KEYWORD_ALLOW_READ; | 1289 | tomoyo_set_string(head, |
1217 | w[1] = ptr->filename->name; | 1290 | TOMOYO_KEYWORD_ALLOW_READ); |
1291 | tomoyo_set_string(head, ptr->filename->name); | ||
1218 | } | 1292 | } |
1219 | break; | 1293 | break; |
1220 | case TOMOYO_ID_AGGREGATOR: | 1294 | case TOMOYO_ID_AGGREGATOR: |
1221 | { | 1295 | { |
1222 | struct tomoyo_aggregator_entry *ptr = | 1296 | struct tomoyo_aggregator_entry *ptr = |
1223 | container_of(acl, typeof(*ptr), head); | 1297 | container_of(acl, typeof(*ptr), head); |
1224 | w[0] = TOMOYO_KEYWORD_AGGREGATOR; | 1298 | tomoyo_set_string(head, |
1225 | w[1] = ptr->original_name->name; | 1299 | TOMOYO_KEYWORD_AGGREGATOR); |
1226 | w[2] = " "; | 1300 | tomoyo_set_string(head, |
1227 | w[3] = ptr->aggregated_name->name; | 1301 | ptr->original_name->name); |
1302 | tomoyo_set_space(head); | ||
1303 | tomoyo_set_string(head, | ||
1304 | ptr->aggregated_name->name); | ||
1228 | } | 1305 | } |
1229 | break; | 1306 | break; |
1230 | case TOMOYO_ID_PATTERN: | 1307 | case TOMOYO_ID_PATTERN: |
1231 | { | 1308 | { |
1232 | struct tomoyo_pattern_entry *ptr = | 1309 | struct tomoyo_pattern_entry *ptr = |
1233 | container_of(acl, typeof(*ptr), head); | 1310 | container_of(acl, typeof(*ptr), head); |
1234 | w[0] = TOMOYO_KEYWORD_FILE_PATTERN; | 1311 | tomoyo_set_string(head, |
1235 | w[1] = ptr->pattern->name; | 1312 | TOMOYO_KEYWORD_FILE_PATTERN); |
1313 | tomoyo_set_string(head, ptr->pattern->name); | ||
1236 | } | 1314 | } |
1237 | break; | 1315 | break; |
1238 | case TOMOYO_ID_NO_REWRITE: | 1316 | case TOMOYO_ID_NO_REWRITE: |
1239 | { | 1317 | { |
1240 | struct tomoyo_no_rewrite_entry *ptr = | 1318 | struct tomoyo_no_rewrite_entry *ptr = |
1241 | container_of(acl, typeof(*ptr), head); | 1319 | container_of(acl, typeof(*ptr), head); |
1242 | w[0] = TOMOYO_KEYWORD_DENY_REWRITE; | 1320 | tomoyo_set_string(head, |
1243 | w[1] = ptr->pattern->name; | 1321 | TOMOYO_KEYWORD_DENY_REWRITE); |
1322 | tomoyo_set_string(head, ptr->pattern->name); | ||
1244 | } | 1323 | } |
1245 | break; | 1324 | break; |
1246 | default: | 1325 | default: |
1247 | continue; | 1326 | continue; |
1248 | } | 1327 | } |
1249 | if (!tomoyo_io_printf(head, "%s%s%s%s\n", w[0], w[1], w[2], | 1328 | tomoyo_set_lf(head); |
1250 | w[3])) | ||
1251 | return false; | ||
1252 | } | 1329 | } |
1253 | head->read_var2 = NULL; | 1330 | head->r.acl = NULL; |
1254 | return true; | 1331 | return true; |
1255 | } | 1332 | } |
1256 | 1333 | ||
@@ -1263,19 +1340,19 @@ static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx) | |||
1263 | */ | 1340 | */ |
1264 | static void tomoyo_read_exception_policy(struct tomoyo_io_buffer *head) | 1341 | static void tomoyo_read_exception_policy(struct tomoyo_io_buffer *head) |
1265 | { | 1342 | { |
1266 | if (head->read_eof) | 1343 | if (head->r.eof) |
1267 | return; | 1344 | return; |
1268 | while (head->read_step < TOMOYO_MAX_POLICY && | 1345 | while (head->r.step < TOMOYO_MAX_POLICY && |
1269 | tomoyo_read_policy(head, head->read_step)) | 1346 | tomoyo_read_policy(head, head->r.step)) |
1270 | head->read_step++; | 1347 | head->r.step++; |
1271 | if (head->read_step < TOMOYO_MAX_POLICY) | 1348 | if (head->r.step < TOMOYO_MAX_POLICY) |
1272 | return; | 1349 | return; |
1273 | while (head->read_step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP && | 1350 | while (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP && |
1274 | tomoyo_read_group(head, head->read_step - TOMOYO_MAX_POLICY)) | 1351 | tomoyo_read_group(head, head->r.step - TOMOYO_MAX_POLICY)) |
1275 | head->read_step++; | 1352 | head->r.step++; |
1276 | if (head->read_step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP) | 1353 | if (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP) |
1277 | return; | 1354 | return; |
1278 | head->read_eof = true; | 1355 | head->r.eof = true; |
1279 | } | 1356 | } |
1280 | 1357 | ||
1281 | /** | 1358 | /** |
@@ -1290,9 +1367,6 @@ static void tomoyo_read_exception_policy(struct tomoyo_io_buffer *head) | |||
1290 | */ | 1367 | */ |
1291 | static char *tomoyo_print_header(struct tomoyo_request_info *r) | 1368 | static char *tomoyo_print_header(struct tomoyo_request_info *r) |
1292 | { | 1369 | { |
1293 | static const char *tomoyo_mode_4[4] = { | ||
1294 | "disabled", "learning", "permissive", "enforcing" | ||
1295 | }; | ||
1296 | struct timeval tv; | 1370 | struct timeval tv; |
1297 | const pid_t gpid = task_pid_nr(current); | 1371 | const pid_t gpid = task_pid_nr(current); |
1298 | static const int tomoyo_buffer_len = 4096; | 1372 | static const int tomoyo_buffer_len = 4096; |
@@ -1304,7 +1378,7 @@ static char *tomoyo_print_header(struct tomoyo_request_info *r) | |||
1304 | "#timestamp=%lu profile=%u mode=%s (global-pid=%u)" | 1378 | "#timestamp=%lu profile=%u mode=%s (global-pid=%u)" |
1305 | " task={ pid=%u ppid=%u uid=%u gid=%u euid=%u" | 1379 | " task={ pid=%u ppid=%u uid=%u gid=%u euid=%u" |
1306 | " egid=%u suid=%u sgid=%u fsuid=%u fsgid=%u }", | 1380 | " egid=%u suid=%u sgid=%u fsuid=%u fsgid=%u }", |
1307 | tv.tv_sec, r->profile, tomoyo_mode_4[r->mode], gpid, | 1381 | tv.tv_sec, r->profile, tomoyo_mode[r->mode], gpid, |
1308 | (pid_t) sys_getpid(), (pid_t) sys_getppid(), | 1382 | (pid_t) sys_getpid(), (pid_t) sys_getppid(), |
1309 | current_uid(), current_gid(), current_euid(), | 1383 | current_uid(), current_gid(), current_euid(), |
1310 | current_egid(), current_suid(), current_sgid(), | 1384 | current_egid(), current_suid(), current_sgid(), |
@@ -1536,27 +1610,26 @@ static void tomoyo_read_query(struct tomoyo_io_buffer *head) | |||
1536 | int pos = 0; | 1610 | int pos = 0; |
1537 | int len = 0; | 1611 | int len = 0; |
1538 | char *buf; | 1612 | char *buf; |
1539 | if (head->read_avail) | 1613 | if (head->r.w_pos) |
1540 | return; | 1614 | return; |
1541 | if (head->read_buf) { | 1615 | if (head->read_buf) { |
1542 | kfree(head->read_buf); | 1616 | kfree(head->read_buf); |
1543 | head->read_buf = NULL; | 1617 | head->read_buf = NULL; |
1544 | head->readbuf_size = 0; | ||
1545 | } | 1618 | } |
1546 | spin_lock(&tomoyo_query_list_lock); | 1619 | spin_lock(&tomoyo_query_list_lock); |
1547 | list_for_each(tmp, &tomoyo_query_list) { | 1620 | list_for_each(tmp, &tomoyo_query_list) { |
1548 | struct tomoyo_query_entry *ptr | 1621 | struct tomoyo_query_entry *ptr = |
1549 | = list_entry(tmp, struct tomoyo_query_entry, list); | 1622 | list_entry(tmp, typeof(*ptr), list); |
1550 | if (ptr->answer) | 1623 | if (ptr->answer) |
1551 | continue; | 1624 | continue; |
1552 | if (pos++ != head->read_step) | 1625 | if (pos++ != head->r.query_index) |
1553 | continue; | 1626 | continue; |
1554 | len = ptr->query_len; | 1627 | len = ptr->query_len; |
1555 | break; | 1628 | break; |
1556 | } | 1629 | } |
1557 | spin_unlock(&tomoyo_query_list_lock); | 1630 | spin_unlock(&tomoyo_query_list_lock); |
1558 | if (!len) { | 1631 | if (!len) { |
1559 | head->read_step = 0; | 1632 | head->r.query_index = 0; |
1560 | return; | 1633 | return; |
1561 | } | 1634 | } |
1562 | buf = kzalloc(len, GFP_NOFS); | 1635 | buf = kzalloc(len, GFP_NOFS); |
@@ -1565,11 +1638,11 @@ static void tomoyo_read_query(struct tomoyo_io_buffer *head) | |||
1565 | pos = 0; | 1638 | pos = 0; |
1566 | spin_lock(&tomoyo_query_list_lock); | 1639 | spin_lock(&tomoyo_query_list_lock); |
1567 | list_for_each(tmp, &tomoyo_query_list) { | 1640 | list_for_each(tmp, &tomoyo_query_list) { |
1568 | struct tomoyo_query_entry *ptr | 1641 | struct tomoyo_query_entry *ptr = |
1569 | = list_entry(tmp, struct tomoyo_query_entry, list); | 1642 | list_entry(tmp, typeof(*ptr), list); |
1570 | if (ptr->answer) | 1643 | if (ptr->answer) |
1571 | continue; | 1644 | continue; |
1572 | if (pos++ != head->read_step) | 1645 | if (pos++ != head->r.query_index) |
1573 | continue; | 1646 | continue; |
1574 | /* | 1647 | /* |
1575 | * Some query can be skipped because tomoyo_query_list | 1648 | * Some query can be skipped because tomoyo_query_list |
@@ -1581,10 +1654,9 @@ static void tomoyo_read_query(struct tomoyo_io_buffer *head) | |||
1581 | } | 1654 | } |
1582 | spin_unlock(&tomoyo_query_list_lock); | 1655 | spin_unlock(&tomoyo_query_list_lock); |
1583 | if (buf[0]) { | 1656 | if (buf[0]) { |
1584 | head->read_avail = len; | ||
1585 | head->readbuf_size = head->read_avail; | ||
1586 | head->read_buf = buf; | 1657 | head->read_buf = buf; |
1587 | head->read_step++; | 1658 | head->r.w[head->r.w_pos++] = buf; |
1659 | head->r.query_index++; | ||
1588 | } else { | 1660 | } else { |
1589 | kfree(buf); | 1661 | kfree(buf); |
1590 | } | 1662 | } |
@@ -1635,9 +1707,9 @@ static int tomoyo_write_answer(struct tomoyo_io_buffer *head) | |||
1635 | */ | 1707 | */ |
1636 | static void tomoyo_read_version(struct tomoyo_io_buffer *head) | 1708 | static void tomoyo_read_version(struct tomoyo_io_buffer *head) |
1637 | { | 1709 | { |
1638 | if (!head->read_eof) { | 1710 | if (!head->r.eof) { |
1639 | tomoyo_io_printf(head, "2.3.0-pre"); | 1711 | tomoyo_io_printf(head, "2.3.0-pre"); |
1640 | head->read_eof = true; | 1712 | head->r.eof = true; |
1641 | } | 1713 | } |
1642 | } | 1714 | } |
1643 | 1715 | ||
@@ -1650,14 +1722,14 @@ static void tomoyo_read_version(struct tomoyo_io_buffer *head) | |||
1650 | */ | 1722 | */ |
1651 | static void tomoyo_read_self_domain(struct tomoyo_io_buffer *head) | 1723 | static void tomoyo_read_self_domain(struct tomoyo_io_buffer *head) |
1652 | { | 1724 | { |
1653 | if (!head->read_eof) { | 1725 | if (!head->r.eof) { |
1654 | /* | 1726 | /* |
1655 | * tomoyo_domain()->domainname != NULL | 1727 | * tomoyo_domain()->domainname != NULL |
1656 | * because every process belongs to a domain and | 1728 | * because every process belongs to a domain and |
1657 | * the domain's name cannot be NULL. | 1729 | * the domain's name cannot be NULL. |
1658 | */ | 1730 | */ |
1659 | tomoyo_io_printf(head, "%s", tomoyo_domain()->domainname->name); | 1731 | tomoyo_io_printf(head, "%s", tomoyo_domain()->domainname->name); |
1660 | head->read_eof = true; | 1732 | head->r.eof = true; |
1661 | } | 1733 | } |
1662 | } | 1734 | } |
1663 | 1735 | ||
@@ -1817,33 +1889,20 @@ int tomoyo_poll_control(struct file *file, poll_table *wait) | |||
1817 | int tomoyo_read_control(struct file *file, char __user *buffer, | 1889 | int tomoyo_read_control(struct file *file, char __user *buffer, |
1818 | const int buffer_len) | 1890 | const int buffer_len) |
1819 | { | 1891 | { |
1820 | int len = 0; | 1892 | int len; |
1821 | struct tomoyo_io_buffer *head = file->private_data; | 1893 | struct tomoyo_io_buffer *head = file->private_data; |
1822 | char *cp; | ||
1823 | 1894 | ||
1824 | if (!head->read) | 1895 | if (!head->read) |
1825 | return -ENOSYS; | 1896 | return -ENOSYS; |
1826 | if (mutex_lock_interruptible(&head->io_sem)) | 1897 | if (mutex_lock_interruptible(&head->io_sem)) |
1827 | return -EINTR; | 1898 | return -EINTR; |
1828 | /* Call the policy handler. */ | 1899 | head->read_user_buf = buffer; |
1829 | head->read(head); | 1900 | head->read_user_buf_avail = buffer_len; |
1830 | if (len < 0) | 1901 | if (tomoyo_flush(head)) |
1831 | goto out; | 1902 | /* Call the policy handler. */ |
1832 | /* Write to buffer. */ | 1903 | head->read(head); |
1833 | len = head->read_avail; | 1904 | tomoyo_flush(head); |
1834 | if (len > buffer_len) | 1905 | len = head->read_user_buf - buffer; |
1835 | len = buffer_len; | ||
1836 | if (!len) | ||
1837 | goto out; | ||
1838 | /* head->read_buf changes by some functions. */ | ||
1839 | cp = head->read_buf; | ||
1840 | if (copy_to_user(buffer, cp, len)) { | ||
1841 | len = -EFAULT; | ||
1842 | goto out; | ||
1843 | } | ||
1844 | head->read_avail -= len; | ||
1845 | memmove(cp, cp + len, head->read_avail); | ||
1846 | out: | ||
1847 | mutex_unlock(&head->io_sem); | 1906 | mutex_unlock(&head->io_sem); |
1848 | return len; | 1907 | return len; |
1849 | } | 1908 | } |