diff options
Diffstat (limited to 'security')
-rw-r--r-- | security/tomoyo/common.h | 48 | ||||
-rw-r--r-- | security/tomoyo/domain.c | 72 | ||||
-rw-r--r-- | security/tomoyo/file.c | 136 | ||||
-rw-r--r-- | security/tomoyo/memory.c | 1 | ||||
-rw-r--r-- | security/tomoyo/mount.c | 55 | ||||
-rw-r--r-- | security/tomoyo/realpath.c | 214 |
6 files changed, 208 insertions, 318 deletions
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 6270a530c4d8..f4a8aa244af5 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h | |||
@@ -33,14 +33,7 @@ struct linux_binprm; | |||
33 | #define TOMOYO_HASH_BITS 8 | 33 | #define TOMOYO_HASH_BITS 8 |
34 | #define TOMOYO_MAX_HASH (1u<<TOMOYO_HASH_BITS) | 34 | #define TOMOYO_MAX_HASH (1u<<TOMOYO_HASH_BITS) |
35 | 35 | ||
36 | /* | 36 | #define TOMOYO_EXEC_TMPSIZE 4096 |
37 | * This is the max length of a token. | ||
38 | * | ||
39 | * A token consists of only ASCII printable characters. | ||
40 | * Non printable characters in a token is represented in \ooo style | ||
41 | * octal string. Thus, \ itself is represented as \\. | ||
42 | */ | ||
43 | #define TOMOYO_MAX_PATHNAME_LEN 4000 | ||
44 | 37 | ||
45 | /* Profile number is an integer between 0 and 255. */ | 38 | /* Profile number is an integer between 0 and 255. */ |
46 | #define TOMOYO_MAX_PROFILES 256 | 39 | #define TOMOYO_MAX_PROFILES 256 |
@@ -168,17 +161,6 @@ enum tomoyo_securityfs_interface_index { | |||
168 | /********** Structure definitions. **********/ | 161 | /********** Structure definitions. **********/ |
169 | 162 | ||
170 | /* | 163 | /* |
171 | * tomoyo_page_buffer is a structure which is used for holding a pathname | ||
172 | * obtained from "struct dentry" and "struct vfsmount" pair. | ||
173 | * As of now, it is 4096 bytes. If users complain that 4096 bytes is too small | ||
174 | * (because TOMOYO escapes non ASCII printable characters using \ooo format), | ||
175 | * we will make the buffer larger. | ||
176 | */ | ||
177 | struct tomoyo_page_buffer { | ||
178 | char buffer[4096]; | ||
179 | }; | ||
180 | |||
181 | /* | ||
182 | * tomoyo_request_info is a structure which is used for holding | 164 | * tomoyo_request_info is a structure which is used for holding |
183 | * | 165 | * |
184 | * (1) Domain information of current process. | 166 | * (1) Domain information of current process. |
@@ -231,28 +213,6 @@ struct tomoyo_name_entry { | |||
231 | struct tomoyo_path_info entry; | 213 | struct tomoyo_path_info entry; |
232 | }; | 214 | }; |
233 | 215 | ||
234 | /* | ||
235 | * tomoyo_path_info_with_data is a structure which is used for holding a | ||
236 | * pathname obtained from "struct dentry" and "struct vfsmount" pair. | ||
237 | * | ||
238 | * "struct tomoyo_path_info_with_data" consists of "struct tomoyo_path_info" | ||
239 | * and buffer for the pathname, while "struct tomoyo_page_buffer" consists of | ||
240 | * buffer for the pathname only. | ||
241 | * | ||
242 | * "struct tomoyo_path_info_with_data" is intended to allow TOMOYO to release | ||
243 | * both "struct tomoyo_path_info" and buffer for the pathname by single kfree() | ||
244 | * so that we don't need to return two pointers to the caller. If the caller | ||
245 | * puts "struct tomoyo_path_info" on stack memory, we will be able to remove | ||
246 | * "struct tomoyo_path_info_with_data". | ||
247 | */ | ||
248 | struct tomoyo_path_info_with_data { | ||
249 | /* Keep "head" first, for this pointer is passed to kfree(). */ | ||
250 | struct tomoyo_path_info head; | ||
251 | char barrier1[16]; /* Safeguard for overrun. */ | ||
252 | char body[TOMOYO_MAX_PATHNAME_LEN]; | ||
253 | char barrier2[16]; /* Safeguard for overrun. */ | ||
254 | }; | ||
255 | |||
256 | struct tomoyo_name_union { | 216 | struct tomoyo_name_union { |
257 | const struct tomoyo_path_info *filename; | 217 | const struct tomoyo_path_info *filename; |
258 | struct tomoyo_path_group *group; | 218 | struct tomoyo_path_group *group; |
@@ -827,11 +787,7 @@ void tomoyo_load_policy(const char *filename); | |||
827 | void tomoyo_put_number_union(struct tomoyo_number_union *ptr); | 787 | void tomoyo_put_number_union(struct tomoyo_number_union *ptr); |
828 | 788 | ||
829 | /* Convert binary string to ascii string. */ | 789 | /* Convert binary string to ascii string. */ |
830 | int tomoyo_encode(char *buffer, int buflen, const char *str); | 790 | char *tomoyo_encode(const char *str); |
831 | |||
832 | /* Returns realpath(3) of the given pathname but ignores chroot'ed root. */ | ||
833 | int tomoyo_realpath_from_path2(struct path *path, char *newname, | ||
834 | int newname_len); | ||
835 | 791 | ||
836 | /* | 792 | /* |
837 | * Returns realpath(3) of the given pathname but ignores chroot'ed root. | 793 | * Returns realpath(3) of the given pathname but ignores chroot'ed root. |
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 08428bc082df..7b8693e29a13 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c | |||
@@ -676,47 +676,43 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * | |||
676 | int tomoyo_find_next_domain(struct linux_binprm *bprm) | 676 | int tomoyo_find_next_domain(struct linux_binprm *bprm) |
677 | { | 677 | { |
678 | struct tomoyo_request_info r; | 678 | struct tomoyo_request_info r; |
679 | /* | 679 | char *tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS); |
680 | * This function assumes that the size of buffer returned by | ||
681 | * tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN. | ||
682 | */ | ||
683 | struct tomoyo_page_buffer *tmp = kzalloc(sizeof(*tmp), GFP_NOFS); | ||
684 | struct tomoyo_domain_info *old_domain = tomoyo_domain(); | 680 | struct tomoyo_domain_info *old_domain = tomoyo_domain(); |
685 | struct tomoyo_domain_info *domain = NULL; | 681 | struct tomoyo_domain_info *domain = NULL; |
686 | const char *old_domain_name = old_domain->domainname->name; | 682 | const char *old_domain_name = old_domain->domainname->name; |
687 | const char *original_name = bprm->filename; | 683 | const char *original_name = bprm->filename; |
688 | char *new_domain_name = NULL; | ||
689 | char *real_program_name = NULL; | ||
690 | char *symlink_program_name = NULL; | ||
691 | const u8 mode = tomoyo_check_flags(old_domain, TOMOYO_MAC_FOR_FILE); | 684 | const u8 mode = tomoyo_check_flags(old_domain, TOMOYO_MAC_FOR_FILE); |
692 | const bool is_enforce = (mode == TOMOYO_CONFIG_ENFORCING); | 685 | const bool is_enforce = (mode == TOMOYO_CONFIG_ENFORCING); |
693 | int retval = -ENOMEM; | 686 | int retval = -ENOMEM; |
694 | struct tomoyo_path_info rn; /* real name */ | 687 | bool need_kfree = false; |
695 | struct tomoyo_path_info sn; /* symlink name */ | 688 | struct tomoyo_path_info rn = { }; /* real name */ |
689 | struct tomoyo_path_info sn = { }; /* symlink name */ | ||
696 | struct tomoyo_path_info ln; /* last name */ | 690 | struct tomoyo_path_info ln; /* last name */ |
697 | 691 | ||
692 | ln.name = tomoyo_get_last_name(old_domain); | ||
693 | tomoyo_fill_path_info(&ln); | ||
698 | tomoyo_init_request_info(&r, NULL); | 694 | tomoyo_init_request_info(&r, NULL); |
699 | if (!tmp) | 695 | if (!tmp) |
700 | goto out; | 696 | goto out; |
701 | 697 | ||
702 | retry: | 698 | retry: |
699 | if (need_kfree) { | ||
700 | kfree(rn.name); | ||
701 | need_kfree = false; | ||
702 | } | ||
703 | /* Get tomoyo_realpath of program. */ | 703 | /* Get tomoyo_realpath of program. */ |
704 | retval = -ENOENT; | 704 | retval = -ENOENT; |
705 | /* I hope tomoyo_realpath() won't fail with -ENOMEM. */ | 705 | rn.name = tomoyo_realpath(original_name); |
706 | real_program_name = tomoyo_realpath(original_name); | 706 | if (!rn.name) |
707 | if (!real_program_name) | ||
708 | goto out; | 707 | goto out; |
708 | tomoyo_fill_path_info(&rn); | ||
709 | need_kfree = true; | ||
710 | |||
709 | /* Get tomoyo_realpath of symbolic link. */ | 711 | /* Get tomoyo_realpath of symbolic link. */ |
710 | symlink_program_name = tomoyo_realpath_nofollow(original_name); | 712 | sn.name = tomoyo_realpath_nofollow(original_name); |
711 | if (!symlink_program_name) | 713 | if (!sn.name) |
712 | goto out; | 714 | goto out; |
713 | |||
714 | rn.name = real_program_name; | ||
715 | tomoyo_fill_path_info(&rn); | ||
716 | sn.name = symlink_program_name; | ||
717 | tomoyo_fill_path_info(&sn); | 715 | tomoyo_fill_path_info(&sn); |
718 | ln.name = tomoyo_get_last_name(old_domain); | ||
719 | tomoyo_fill_path_info(&ln); | ||
720 | 716 | ||
721 | /* Check 'alias' directive. */ | 717 | /* Check 'alias' directive. */ |
722 | if (tomoyo_pathcmp(&rn, &sn)) { | 718 | if (tomoyo_pathcmp(&rn, &sn)) { |
@@ -727,10 +723,10 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
727 | tomoyo_pathcmp(&rn, ptr->original_name) || | 723 | tomoyo_pathcmp(&rn, ptr->original_name) || |
728 | tomoyo_pathcmp(&sn, ptr->aliased_name)) | 724 | tomoyo_pathcmp(&sn, ptr->aliased_name)) |
729 | continue; | 725 | continue; |
730 | memset(real_program_name, 0, TOMOYO_MAX_PATHNAME_LEN); | 726 | kfree(rn.name); |
731 | strncpy(real_program_name, ptr->aliased_name->name, | 727 | need_kfree = false; |
732 | TOMOYO_MAX_PATHNAME_LEN - 1); | 728 | /* This is OK because it is read only. */ |
733 | tomoyo_fill_path_info(&rn); | 729 | rn = *ptr->aliased_name; |
734 | break; | 730 | break; |
735 | } | 731 | } |
736 | } | 732 | } |
@@ -742,11 +738,10 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
742 | if (retval < 0) | 738 | if (retval < 0) |
743 | goto out; | 739 | goto out; |
744 | 740 | ||
745 | new_domain_name = tmp->buffer; | ||
746 | if (tomoyo_is_domain_initializer(old_domain->domainname, &rn, &ln)) { | 741 | if (tomoyo_is_domain_initializer(old_domain->domainname, &rn, &ln)) { |
747 | /* Transit to the child of tomoyo_kernel_domain domain. */ | 742 | /* Transit to the child of tomoyo_kernel_domain domain. */ |
748 | snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1, | 743 | snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, |
749 | TOMOYO_ROOT_NAME " " "%s", real_program_name); | 744 | TOMOYO_ROOT_NAME " " "%s", rn.name); |
750 | } else if (old_domain == &tomoyo_kernel_domain && | 745 | } else if (old_domain == &tomoyo_kernel_domain && |
751 | !tomoyo_policy_loaded) { | 746 | !tomoyo_policy_loaded) { |
752 | /* | 747 | /* |
@@ -760,29 +755,27 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
760 | domain = old_domain; | 755 | domain = old_domain; |
761 | } else { | 756 | } else { |
762 | /* Normal domain transition. */ | 757 | /* Normal domain transition. */ |
763 | snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1, | 758 | snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, |
764 | "%s %s", old_domain_name, real_program_name); | 759 | "%s %s", old_domain_name, rn.name); |
765 | } | 760 | } |
766 | if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN) | 761 | if (domain || strlen(tmp) >= TOMOYO_EXEC_TMPSIZE - 10) |
767 | goto done; | 762 | goto done; |
768 | domain = tomoyo_find_domain(new_domain_name); | 763 | domain = tomoyo_find_domain(tmp); |
769 | if (domain) | 764 | if (domain) |
770 | goto done; | 765 | goto done; |
771 | if (is_enforce) { | 766 | if (is_enforce) { |
772 | int error = tomoyo_supervisor(&r, "# wants to create domain\n" | 767 | int error = tomoyo_supervisor(&r, "# wants to create domain\n" |
773 | "%s\n", new_domain_name); | 768 | "%s\n", tmp); |
774 | if (error == TOMOYO_RETRY_REQUEST) | 769 | if (error == TOMOYO_RETRY_REQUEST) |
775 | goto retry; | 770 | goto retry; |
776 | if (error < 0) | 771 | if (error < 0) |
777 | goto done; | 772 | goto done; |
778 | } | 773 | } |
779 | domain = tomoyo_find_or_assign_new_domain(new_domain_name, | 774 | domain = tomoyo_find_or_assign_new_domain(tmp, old_domain->profile); |
780 | old_domain->profile); | ||
781 | done: | 775 | done: |
782 | if (domain) | 776 | if (domain) |
783 | goto out; | 777 | goto out; |
784 | printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n", | 778 | printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n", tmp); |
785 | new_domain_name); | ||
786 | if (is_enforce) | 779 | if (is_enforce) |
787 | retval = -EPERM; | 780 | retval = -EPERM; |
788 | else | 781 | else |
@@ -793,8 +786,9 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
793 | /* Update reference count on "struct tomoyo_domain_info". */ | 786 | /* Update reference count on "struct tomoyo_domain_info". */ |
794 | atomic_inc(&domain->users); | 787 | atomic_inc(&domain->users); |
795 | bprm->cred->security = domain; | 788 | bprm->cred->security = domain; |
796 | kfree(real_program_name); | 789 | if (need_kfree) |
797 | kfree(symlink_program_name); | 790 | kfree(rn.name); |
791 | kfree(sn.name); | ||
798 | kfree(tmp); | 792 | kfree(tmp); |
799 | return retval; | 793 | return retval; |
800 | } | 794 | } |
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index c13806937dc6..cef685415df1 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c | |||
@@ -148,6 +148,17 @@ const char *tomoyo_path_number2keyword(const u8 operation) | |||
148 | ? tomoyo_path_number_keyword[operation] : NULL; | 148 | ? tomoyo_path_number_keyword[operation] : NULL; |
149 | } | 149 | } |
150 | 150 | ||
151 | static void tomoyo_add_slash(struct tomoyo_path_info *buf) | ||
152 | { | ||
153 | if (buf->is_dir) | ||
154 | return; | ||
155 | /* | ||
156 | * This is OK because tomoyo_encode() reserves space for appending "/". | ||
157 | */ | ||
158 | strcat((char *) buf->name, "/"); | ||
159 | tomoyo_fill_path_info(buf); | ||
160 | } | ||
161 | |||
151 | /** | 162 | /** |
152 | * tomoyo_strendswith - Check whether the token ends with the given token. | 163 | * tomoyo_strendswith - Check whether the token ends with the given token. |
153 | * | 164 | * |
@@ -167,30 +178,21 @@ static bool tomoyo_strendswith(const char *name, const char *tail) | |||
167 | } | 178 | } |
168 | 179 | ||
169 | /** | 180 | /** |
170 | * tomoyo_get_path - Get realpath. | 181 | * tomoyo_get_realpath - Get realpath. |
171 | * | 182 | * |
183 | * @buf: Pointer to "struct tomoyo_path_info". | ||
172 | * @path: Pointer to "struct path". | 184 | * @path: Pointer to "struct path". |
173 | * | 185 | * |
174 | * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. | 186 | * Returns true on success, false otherwise. |
175 | */ | 187 | */ |
176 | static struct tomoyo_path_info *tomoyo_get_path(struct path *path) | 188 | static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path) |
177 | { | 189 | { |
178 | int error; | 190 | buf->name = tomoyo_realpath_from_path(path); |
179 | struct tomoyo_path_info_with_data *buf = kzalloc(sizeof(*buf), | 191 | if (buf->name) { |
180 | GFP_NOFS); | 192 | tomoyo_fill_path_info(buf); |
181 | 193 | return true; | |
182 | if (!buf) | ||
183 | return NULL; | ||
184 | /* Reserve one byte for appending "/". */ | ||
185 | error = tomoyo_realpath_from_path2(path, buf->body, | ||
186 | sizeof(buf->body) - 2); | ||
187 | if (!error) { | ||
188 | buf->head.name = buf->body; | ||
189 | tomoyo_fill_path_info(&buf->head); | ||
190 | return &buf->head; | ||
191 | } | 194 | } |
192 | kfree(buf); | 195 | return false; |
193 | return NULL; | ||
194 | } | 196 | } |
195 | 197 | ||
196 | static int tomoyo_update_path2_acl(const u8 type, const char *filename1, | 198 | static int tomoyo_update_path2_acl(const u8 type, const char *filename1, |
@@ -1259,26 +1261,20 @@ int tomoyo_path_number_perm(const u8 type, struct path *path, | |||
1259 | { | 1261 | { |
1260 | struct tomoyo_request_info r; | 1262 | struct tomoyo_request_info r; |
1261 | int error = -ENOMEM; | 1263 | int error = -ENOMEM; |
1262 | struct tomoyo_path_info *buf; | 1264 | struct tomoyo_path_info buf; |
1263 | int idx; | 1265 | int idx; |
1264 | 1266 | ||
1265 | if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED || | 1267 | if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED || |
1266 | !path->mnt || !path->dentry) | 1268 | !path->mnt || !path->dentry) |
1267 | return 0; | 1269 | return 0; |
1268 | idx = tomoyo_read_lock(); | 1270 | idx = tomoyo_read_lock(); |
1269 | buf = tomoyo_get_path(path); | 1271 | if (!tomoyo_get_realpath(&buf, path)) |
1270 | if (!buf) | ||
1271 | goto out; | 1272 | goto out; |
1272 | if (type == TOMOYO_TYPE_MKDIR && !buf->is_dir) { | 1273 | if (type == TOMOYO_TYPE_MKDIR) |
1273 | /* | 1274 | tomoyo_add_slash(&buf); |
1274 | * tomoyo_get_path() reserves space for appending "/." | 1275 | error = tomoyo_path_number_perm2(&r, type, &buf, number); |
1275 | */ | ||
1276 | strcat((char *) buf->name, "/"); | ||
1277 | tomoyo_fill_path_info(buf); | ||
1278 | } | ||
1279 | error = tomoyo_path_number_perm2(&r, type, buf, number); | ||
1280 | out: | 1276 | out: |
1281 | kfree(buf); | 1277 | kfree(buf.name); |
1282 | tomoyo_read_unlock(idx); | 1278 | tomoyo_read_unlock(idx); |
1283 | if (r.mode != TOMOYO_CONFIG_ENFORCING) | 1279 | if (r.mode != TOMOYO_CONFIG_ENFORCING) |
1284 | error = 0; | 1280 | error = 0; |
@@ -1319,7 +1315,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | |||
1319 | { | 1315 | { |
1320 | const u8 acc_mode = ACC_MODE(flag); | 1316 | const u8 acc_mode = ACC_MODE(flag); |
1321 | int error = -ENOMEM; | 1317 | int error = -ENOMEM; |
1322 | struct tomoyo_path_info *buf; | 1318 | struct tomoyo_path_info buf; |
1323 | struct tomoyo_request_info r; | 1319 | struct tomoyo_request_info r; |
1324 | int idx; | 1320 | int idx; |
1325 | 1321 | ||
@@ -1335,8 +1331,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | |||
1335 | */ | 1331 | */ |
1336 | return 0; | 1332 | return 0; |
1337 | idx = tomoyo_read_lock(); | 1333 | idx = tomoyo_read_lock(); |
1338 | buf = tomoyo_get_path(path); | 1334 | if (!tomoyo_get_realpath(&buf, path)) |
1339 | if (!buf) | ||
1340 | goto out; | 1335 | goto out; |
1341 | error = 0; | 1336 | error = 0; |
1342 | /* | 1337 | /* |
@@ -1346,15 +1341,15 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | |||
1346 | */ | 1341 | */ |
1347 | if ((acc_mode & MAY_WRITE) && | 1342 | if ((acc_mode & MAY_WRITE) && |
1348 | ((flag & O_TRUNC) || !(flag & O_APPEND)) && | 1343 | ((flag & O_TRUNC) || !(flag & O_APPEND)) && |
1349 | (tomoyo_is_no_rewrite_file(buf))) { | 1344 | (tomoyo_is_no_rewrite_file(&buf))) { |
1350 | error = tomoyo_path_permission(&r, TOMOYO_TYPE_REWRITE, buf); | 1345 | error = tomoyo_path_permission(&r, TOMOYO_TYPE_REWRITE, &buf); |
1351 | } | 1346 | } |
1352 | if (!error) | 1347 | if (!error) |
1353 | error = tomoyo_file_perm(&r, buf, acc_mode); | 1348 | error = tomoyo_file_perm(&r, &buf, acc_mode); |
1354 | if (!error && (flag & O_TRUNC)) | 1349 | if (!error && (flag & O_TRUNC)) |
1355 | error = tomoyo_path_permission(&r, TOMOYO_TYPE_TRUNCATE, buf); | 1350 | error = tomoyo_path_permission(&r, TOMOYO_TYPE_TRUNCATE, &buf); |
1356 | out: | 1351 | out: |
1357 | kfree(buf); | 1352 | kfree(buf.name); |
1358 | tomoyo_read_unlock(idx); | 1353 | tomoyo_read_unlock(idx); |
1359 | if (r.mode != TOMOYO_CONFIG_ENFORCING) | 1354 | if (r.mode != TOMOYO_CONFIG_ENFORCING) |
1360 | error = 0; | 1355 | error = 0; |
@@ -1372,7 +1367,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | |||
1372 | int tomoyo_path_perm(const u8 operation, struct path *path) | 1367 | int tomoyo_path_perm(const u8 operation, struct path *path) |
1373 | { | 1368 | { |
1374 | int error = -ENOMEM; | 1369 | int error = -ENOMEM; |
1375 | struct tomoyo_path_info *buf; | 1370 | struct tomoyo_path_info buf; |
1376 | struct tomoyo_request_info r; | 1371 | struct tomoyo_request_info r; |
1377 | int idx; | 1372 | int idx; |
1378 | 1373 | ||
@@ -1380,29 +1375,23 @@ int tomoyo_path_perm(const u8 operation, struct path *path) | |||
1380 | !path->mnt) | 1375 | !path->mnt) |
1381 | return 0; | 1376 | return 0; |
1382 | idx = tomoyo_read_lock(); | 1377 | idx = tomoyo_read_lock(); |
1383 | buf = tomoyo_get_path(path); | 1378 | if (!tomoyo_get_realpath(&buf, path)) |
1384 | if (!buf) | ||
1385 | goto out; | 1379 | goto out; |
1386 | switch (operation) { | 1380 | switch (operation) { |
1387 | case TOMOYO_TYPE_REWRITE: | 1381 | case TOMOYO_TYPE_REWRITE: |
1388 | if (!tomoyo_is_no_rewrite_file(buf)) { | 1382 | if (!tomoyo_is_no_rewrite_file(&buf)) { |
1389 | error = 0; | 1383 | error = 0; |
1390 | goto out; | 1384 | goto out; |
1391 | } | 1385 | } |
1392 | break; | 1386 | break; |
1393 | case TOMOYO_TYPE_RMDIR: | 1387 | case TOMOYO_TYPE_RMDIR: |
1394 | case TOMOYO_TYPE_CHROOT: | 1388 | case TOMOYO_TYPE_CHROOT: |
1395 | if (!buf->is_dir) { | 1389 | tomoyo_add_slash(&buf); |
1396 | /* | 1390 | break; |
1397 | * tomoyo_get_path() reserves space for appending "/." | ||
1398 | */ | ||
1399 | strcat((char *) buf->name, "/"); | ||
1400 | tomoyo_fill_path_info(buf); | ||
1401 | } | ||
1402 | } | 1391 | } |
1403 | error = tomoyo_path_permission(&r, operation, buf); | 1392 | error = tomoyo_path_permission(&r, operation, &buf); |
1404 | out: | 1393 | out: |
1405 | kfree(buf); | 1394 | kfree(buf.name); |
1406 | tomoyo_read_unlock(idx); | 1395 | tomoyo_read_unlock(idx); |
1407 | if (r.mode != TOMOYO_CONFIG_ENFORCING) | 1396 | if (r.mode != TOMOYO_CONFIG_ENFORCING) |
1408 | error = 0; | 1397 | error = 0; |
@@ -1465,7 +1454,7 @@ int tomoyo_path_number3_perm(const u8 operation, struct path *path, | |||
1465 | { | 1454 | { |
1466 | struct tomoyo_request_info r; | 1455 | struct tomoyo_request_info r; |
1467 | int error = -ENOMEM; | 1456 | int error = -ENOMEM; |
1468 | struct tomoyo_path_info *buf; | 1457 | struct tomoyo_path_info buf; |
1469 | int idx; | 1458 | int idx; |
1470 | 1459 | ||
1471 | if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED || | 1460 | if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED || |
@@ -1473,11 +1462,10 @@ int tomoyo_path_number3_perm(const u8 operation, struct path *path, | |||
1473 | return 0; | 1462 | return 0; |
1474 | idx = tomoyo_read_lock(); | 1463 | idx = tomoyo_read_lock(); |
1475 | error = -ENOMEM; | 1464 | error = -ENOMEM; |
1476 | buf = tomoyo_get_path(path); | 1465 | if (tomoyo_get_realpath(&buf, path)) { |
1477 | if (buf) { | 1466 | error = tomoyo_path_number3_perm2(&r, operation, &buf, mode, |
1478 | error = tomoyo_path_number3_perm2(&r, operation, buf, mode, | ||
1479 | new_decode_dev(dev)); | 1467 | new_decode_dev(dev)); |
1480 | kfree(buf); | 1468 | kfree(buf.name); |
1481 | } | 1469 | } |
1482 | tomoyo_read_unlock(idx); | 1470 | tomoyo_read_unlock(idx); |
1483 | if (r.mode != TOMOYO_CONFIG_ENFORCING) | 1471 | if (r.mode != TOMOYO_CONFIG_ENFORCING) |
@@ -1499,48 +1487,40 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1, | |||
1499 | { | 1487 | { |
1500 | int error = -ENOMEM; | 1488 | int error = -ENOMEM; |
1501 | const char *msg; | 1489 | const char *msg; |
1502 | struct tomoyo_path_info *buf1; | 1490 | struct tomoyo_path_info buf1; |
1503 | struct tomoyo_path_info *buf2; | 1491 | struct tomoyo_path_info buf2; |
1504 | struct tomoyo_request_info r; | 1492 | struct tomoyo_request_info r; |
1505 | int idx; | 1493 | int idx; |
1506 | 1494 | ||
1507 | if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED || | 1495 | if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED || |
1508 | !path1->mnt || !path2->mnt) | 1496 | !path1->mnt || !path2->mnt) |
1509 | return 0; | 1497 | return 0; |
1498 | buf1.name = NULL; | ||
1499 | buf2.name = NULL; | ||
1510 | idx = tomoyo_read_lock(); | 1500 | idx = tomoyo_read_lock(); |
1511 | buf1 = tomoyo_get_path(path1); | 1501 | if (!tomoyo_get_realpath(&buf1, path1) || |
1512 | buf2 = tomoyo_get_path(path2); | 1502 | !tomoyo_get_realpath(&buf2, path2)) |
1513 | if (!buf1 || !buf2) | ||
1514 | goto out; | 1503 | goto out; |
1515 | { | 1504 | { |
1516 | struct dentry *dentry = path1->dentry; | 1505 | struct dentry *dentry = path1->dentry; |
1517 | if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) { | 1506 | if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) { |
1518 | /* | 1507 | tomoyo_add_slash(&buf1); |
1519 | * tomoyo_get_path() reserves space for appending "/." | 1508 | tomoyo_add_slash(&buf2); |
1520 | */ | ||
1521 | if (!buf1->is_dir) { | ||
1522 | strcat((char *) buf1->name, "/"); | ||
1523 | tomoyo_fill_path_info(buf1); | ||
1524 | } | ||
1525 | if (!buf2->is_dir) { | ||
1526 | strcat((char *) buf2->name, "/"); | ||
1527 | tomoyo_fill_path_info(buf2); | ||
1528 | } | ||
1529 | } | 1509 | } |
1530 | } | 1510 | } |
1531 | do { | 1511 | do { |
1532 | error = tomoyo_path2_acl(&r, operation, buf1, buf2); | 1512 | error = tomoyo_path2_acl(&r, operation, &buf1, &buf2); |
1533 | if (!error) | 1513 | if (!error) |
1534 | break; | 1514 | break; |
1535 | msg = tomoyo_path22keyword(operation); | 1515 | msg = tomoyo_path22keyword(operation); |
1536 | tomoyo_warn_log(&r, "%s %s %s", msg, buf1->name, buf2->name); | 1516 | tomoyo_warn_log(&r, "%s %s %s", msg, buf1.name, buf2.name); |
1537 | error = tomoyo_supervisor(&r, "allow_%s %s %s\n", msg, | 1517 | error = tomoyo_supervisor(&r, "allow_%s %s %s\n", msg, |
1538 | tomoyo_file_pattern(buf1), | 1518 | tomoyo_file_pattern(&buf1), |
1539 | tomoyo_file_pattern(buf2)); | 1519 | tomoyo_file_pattern(&buf2)); |
1540 | } while (error == TOMOYO_RETRY_REQUEST); | 1520 | } while (error == TOMOYO_RETRY_REQUEST); |
1541 | out: | 1521 | out: |
1542 | kfree(buf1); | 1522 | kfree(buf1.name); |
1543 | kfree(buf2); | 1523 | kfree(buf2.name); |
1544 | tomoyo_read_unlock(idx); | 1524 | tomoyo_read_unlock(idx); |
1545 | if (r.mode != TOMOYO_CONFIG_ENFORCING) | 1525 | if (r.mode != TOMOYO_CONFIG_ENFORCING) |
1546 | error = 0; | 1526 | error = 0; |
diff --git a/security/tomoyo/memory.c b/security/tomoyo/memory.c index 8fb73ff5cb63..4809febc1acb 100644 --- a/security/tomoyo/memory.c +++ b/security/tomoyo/memory.c | |||
@@ -153,7 +153,6 @@ void __init tomoyo_mm_init(void) | |||
153 | { | 153 | { |
154 | int idx; | 154 | int idx; |
155 | 155 | ||
156 | BUILD_BUG_ON(TOMOYO_MAX_PATHNAME_LEN > PATH_MAX); | ||
157 | for (idx = 0; idx < TOMOYO_MAX_HASH; idx++) | 156 | for (idx = 0; idx < TOMOYO_MAX_HASH; idx++) |
158 | INIT_LIST_HEAD(&tomoyo_name_list[idx]); | 157 | INIT_LIST_HEAD(&tomoyo_name_list[idx]); |
159 | INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list); | 158 | INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list); |
diff --git a/security/tomoyo/mount.c b/security/tomoyo/mount.c index aeac619f787d..7c1c7fdd3681 100644 --- a/security/tomoyo/mount.c +++ b/security/tomoyo/mount.c | |||
@@ -25,57 +25,6 @@ | |||
25 | #define TOMOYO_MOUNT_MAKE_SHARED_KEYWORD "--make-shared" | 25 | #define TOMOYO_MOUNT_MAKE_SHARED_KEYWORD "--make-shared" |
26 | 26 | ||
27 | /** | 27 | /** |
28 | * tomoyo_encode2: Encode binary string to ascii string. | ||
29 | * | ||
30 | * @str: String in binary format. | ||
31 | * | ||
32 | * Returns pointer to @str in ascii format on success, NULL otherwise. | ||
33 | * | ||
34 | * This function uses kzalloc(), so caller must kfree() if this function | ||
35 | * didn't return NULL. | ||
36 | */ | ||
37 | static char *tomoyo_encode2(const char *str) | ||
38 | { | ||
39 | int len = 0; | ||
40 | const char *p = str; | ||
41 | char *cp; | ||
42 | char *cp0; | ||
43 | if (!p) | ||
44 | return NULL; | ||
45 | while (*p) { | ||
46 | const unsigned char c = *p++; | ||
47 | if (c == '\\') | ||
48 | len += 2; | ||
49 | else if (c > ' ' && c < 127) | ||
50 | len++; | ||
51 | else | ||
52 | len += 4; | ||
53 | } | ||
54 | len++; | ||
55 | /* Reserve space for appending "/". */ | ||
56 | cp = kzalloc(len + 10, GFP_NOFS); | ||
57 | if (!cp) | ||
58 | return NULL; | ||
59 | cp0 = cp; | ||
60 | p = str; | ||
61 | while (*p) { | ||
62 | const unsigned char c = *p++; | ||
63 | if (c == '\\') { | ||
64 | *cp++ = '\\'; | ||
65 | *cp++ = '\\'; | ||
66 | } else if (c > ' ' && c < 127) { | ||
67 | *cp++ = c; | ||
68 | } else { | ||
69 | *cp++ = '\\'; | ||
70 | *cp++ = (c >> 6) + '0'; | ||
71 | *cp++ = ((c >> 3) & 7) + '0'; | ||
72 | *cp++ = (c & 7) + '0'; | ||
73 | } | ||
74 | } | ||
75 | return cp0; | ||
76 | } | ||
77 | |||
78 | /** | ||
79 | * tomoyo_mount_acl2 - Check permission for mount() operation. | 28 | * tomoyo_mount_acl2 - Check permission for mount() operation. |
80 | * | 29 | * |
81 | * @r: Pointer to "struct tomoyo_request_info". | 30 | * @r: Pointer to "struct tomoyo_request_info". |
@@ -104,7 +53,7 @@ static int tomoyo_mount_acl2(struct tomoyo_request_info *r, char *dev_name, | |||
104 | int error = -ENOMEM; | 53 | int error = -ENOMEM; |
105 | 54 | ||
106 | /* Get fstype. */ | 55 | /* Get fstype. */ |
107 | requested_type = tomoyo_encode2(type); | 56 | requested_type = tomoyo_encode(type); |
108 | if (!requested_type) | 57 | if (!requested_type) |
109 | goto out; | 58 | goto out; |
110 | rtype.name = requested_type; | 59 | rtype.name = requested_type; |
@@ -155,7 +104,7 @@ static int tomoyo_mount_acl2(struct tomoyo_request_info *r, char *dev_name, | |||
155 | /* Map dev_name to "<NULL>" if no dev_name given. */ | 104 | /* Map dev_name to "<NULL>" if no dev_name given. */ |
156 | if (!dev_name) | 105 | if (!dev_name) |
157 | dev_name = "<NULL>"; | 106 | dev_name = "<NULL>"; |
158 | requested_dev_name = tomoyo_encode2(dev_name); | 107 | requested_dev_name = tomoyo_encode(dev_name); |
159 | if (!requested_dev_name) { | 108 | if (!requested_dev_name) { |
160 | error = -ENOMEM; | 109 | error = -ENOMEM; |
161 | goto out; | 110 | goto out; |
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index 1fd685a94ad1..153fa23a05cc 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c | |||
@@ -12,141 +12,153 @@ | |||
12 | #include <linux/fs_struct.h> | 12 | #include <linux/fs_struct.h> |
13 | #include <linux/magic.h> | 13 | #include <linux/magic.h> |
14 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
15 | #include <net/sock.h> | ||
15 | #include "common.h" | 16 | #include "common.h" |
16 | 17 | ||
17 | /** | 18 | /** |
18 | * tomoyo_encode: Convert binary string to ascii string. | 19 | * tomoyo_encode: Convert binary string to ascii string. |
19 | * | 20 | * |
20 | * @buffer: Buffer for ASCII string. | 21 | * @str: String in binary format. |
21 | * @buflen: Size of @buffer. | ||
22 | * @str: Binary string. | ||
23 | * | 22 | * |
24 | * Returns 0 on success, -ENOMEM otherwise. | 23 | * Returns pointer to @str in ascii format on success, NULL otherwise. |
24 | * | ||
25 | * This function uses kzalloc(), so caller must kfree() if this function | ||
26 | * didn't return NULL. | ||
25 | */ | 27 | */ |
26 | int tomoyo_encode(char *buffer, int buflen, const char *str) | 28 | char *tomoyo_encode(const char *str) |
27 | { | 29 | { |
28 | while (1) { | 30 | int len = 0; |
29 | const unsigned char c = *(unsigned char *) str++; | 31 | const char *p = str; |
32 | char *cp; | ||
33 | char *cp0; | ||
30 | 34 | ||
31 | if (tomoyo_is_valid(c)) { | 35 | if (!p) |
32 | if (--buflen <= 0) | 36 | return NULL; |
33 | break; | 37 | while (*p) { |
34 | *buffer++ = (char) c; | 38 | const unsigned char c = *p++; |
35 | if (c != '\\') | 39 | if (c == '\\') |
36 | continue; | 40 | len += 2; |
37 | if (--buflen <= 0) | 41 | else if (c > ' ' && c < 127) |
38 | break; | 42 | len++; |
39 | *buffer++ = (char) c; | 43 | else |
40 | continue; | 44 | len += 4; |
41 | } | 45 | } |
42 | if (!c) { | 46 | len++; |
43 | if (--buflen <= 0) | 47 | /* Reserve space for appending "/". */ |
44 | break; | 48 | cp = kzalloc(len + 10, GFP_NOFS); |
45 | *buffer = '\0'; | 49 | if (!cp) |
46 | return 0; | 50 | return NULL; |
51 | cp0 = cp; | ||
52 | p = str; | ||
53 | while (*p) { | ||
54 | const unsigned char c = *p++; | ||
55 | |||
56 | if (c == '\\') { | ||
57 | *cp++ = '\\'; | ||
58 | *cp++ = '\\'; | ||
59 | } else if (c > ' ' && c < 127) { | ||
60 | *cp++ = c; | ||
61 | } else { | ||
62 | *cp++ = '\\'; | ||
63 | *cp++ = (c >> 6) + '0'; | ||
64 | *cp++ = ((c >> 3) & 7) + '0'; | ||
65 | *cp++ = (c & 7) + '0'; | ||
47 | } | 66 | } |
48 | buflen -= 4; | ||
49 | if (buflen <= 0) | ||
50 | break; | ||
51 | *buffer++ = '\\'; | ||
52 | *buffer++ = (c >> 6) + '0'; | ||
53 | *buffer++ = ((c >> 3) & 7) + '0'; | ||
54 | *buffer++ = (c & 7) + '0'; | ||
55 | } | 67 | } |
56 | return -ENOMEM; | 68 | return cp0; |
57 | } | 69 | } |
58 | 70 | ||
59 | /** | 71 | /** |
60 | * tomoyo_realpath_from_path2 - Returns realpath(3) of the given dentry but ignores chroot'ed root. | 72 | * tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root. |
61 | * | 73 | * |
62 | * @path: Pointer to "struct path". | 74 | * @path: Pointer to "struct path". |
63 | * @newname: Pointer to buffer to return value in. | ||
64 | * @newname_len: Size of @newname. | ||
65 | * | 75 | * |
66 | * Returns 0 on success, negative value otherwise. | 76 | * Returns the realpath of the given @path on success, NULL otherwise. |
67 | * | 77 | * |
68 | * If dentry is a directory, trailing '/' is appended. | 78 | * If dentry is a directory, trailing '/' is appended. |
69 | * Characters out of 0x20 < c < 0x7F range are converted to | 79 | * Characters out of 0x20 < c < 0x7F range are converted to |
70 | * \ooo style octal string. | 80 | * \ooo style octal string. |
71 | * Character \ is converted to \\ string. | 81 | * Character \ is converted to \\ string. |
82 | * | ||
83 | * These functions use kzalloc(), so the caller must call kfree() | ||
84 | * if these functions didn't return NULL. | ||
72 | */ | 85 | */ |
73 | int tomoyo_realpath_from_path2(struct path *path, char *newname, | 86 | char *tomoyo_realpath_from_path(struct path *path) |
74 | int newname_len) | ||
75 | { | 87 | { |
76 | int error = -ENOMEM; | 88 | char *buf = NULL; |
89 | char *name = NULL; | ||
90 | unsigned int buf_len = PAGE_SIZE / 2; | ||
77 | struct dentry *dentry = path->dentry; | 91 | struct dentry *dentry = path->dentry; |
78 | char *sp; | 92 | bool is_dir; |
79 | 93 | if (!dentry) | |
80 | if (!dentry || !path->mnt || !newname || newname_len <= 2048) | 94 | return NULL; |
81 | return -EINVAL; | 95 | is_dir = dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode); |
82 | if (dentry->d_op && dentry->d_op->d_dname) { | 96 | while (1) { |
97 | struct path ns_root = { .mnt = NULL, .dentry = NULL }; | ||
98 | char *pos; | ||
99 | buf_len <<= 1; | ||
100 | kfree(buf); | ||
101 | buf = kmalloc(buf_len, GFP_NOFS); | ||
102 | if (!buf) | ||
103 | break; | ||
104 | /* Get better name for socket. */ | ||
105 | if (dentry->d_sb && dentry->d_sb->s_magic == SOCKFS_MAGIC) { | ||
106 | struct inode *inode = dentry->d_inode; | ||
107 | struct socket *sock = inode ? SOCKET_I(inode) : NULL; | ||
108 | struct sock *sk = sock ? sock->sk : NULL; | ||
109 | if (sk) { | ||
110 | snprintf(buf, buf_len - 1, "socket:[family=%u:" | ||
111 | "type=%u:protocol=%u]", sk->sk_family, | ||
112 | sk->sk_type, sk->sk_protocol); | ||
113 | } else { | ||
114 | snprintf(buf, buf_len - 1, "socket:[unknown]"); | ||
115 | } | ||
116 | name = tomoyo_encode(buf); | ||
117 | break; | ||
118 | } | ||
83 | /* For "socket:[\$]" and "pipe:[\$]". */ | 119 | /* For "socket:[\$]" and "pipe:[\$]". */ |
84 | static const int offset = 1536; | 120 | if (dentry->d_op && dentry->d_op->d_dname) { |
85 | sp = dentry->d_op->d_dname(dentry, newname + offset, | 121 | pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1); |
86 | newname_len - offset); | 122 | if (IS_ERR(pos)) |
87 | } else { | 123 | continue; |
88 | struct path ns_root = {.mnt = NULL, .dentry = NULL}; | 124 | name = tomoyo_encode(pos); |
89 | 125 | break; | |
126 | } | ||
127 | /* If we don't have a vfsmount, we can't calculate. */ | ||
128 | if (!path->mnt) | ||
129 | break; | ||
90 | spin_lock(&dcache_lock); | 130 | spin_lock(&dcache_lock); |
91 | /* go to whatever namespace root we are under */ | 131 | /* go to whatever namespace root we are under */ |
92 | sp = __d_path(path, &ns_root, newname, newname_len); | 132 | pos = __d_path(path, &ns_root, buf, buf_len); |
93 | spin_unlock(&dcache_lock); | 133 | spin_unlock(&dcache_lock); |
94 | /* Prepend "/proc" prefix if using internal proc vfs mount. */ | 134 | /* Prepend "/proc" prefix if using internal proc vfs mount. */ |
95 | if (!IS_ERR(sp) && (path->mnt->mnt_flags & MNT_INTERNAL) && | 135 | if (!IS_ERR(pos) && (path->mnt->mnt_flags & MNT_INTERNAL) && |
96 | (path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC)) { | 136 | (path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC)) { |
97 | sp -= 5; | 137 | pos -= 5; |
98 | if (sp >= newname) | 138 | if (pos >= buf) |
99 | memcpy(sp, "/proc", 5); | 139 | memcpy(pos, "/proc", 5); |
100 | else | 140 | else |
101 | sp = ERR_PTR(-ENOMEM); | 141 | pos = ERR_PTR(-ENOMEM); |
102 | } | ||
103 | } | ||
104 | if (IS_ERR(sp)) | ||
105 | error = PTR_ERR(sp); | ||
106 | else | ||
107 | error = tomoyo_encode(newname, sp - newname, sp); | ||
108 | /* Append trailing '/' if dentry is a directory. */ | ||
109 | if (!error && dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode) | ||
110 | && *newname) { | ||
111 | sp = newname + strlen(newname); | ||
112 | if (*(sp - 1) != '/') { | ||
113 | if (sp < newname + newname_len - 4) { | ||
114 | *sp++ = '/'; | ||
115 | *sp = '\0'; | ||
116 | } else { | ||
117 | error = -ENOMEM; | ||
118 | } | ||
119 | } | 142 | } |
143 | if (IS_ERR(pos)) | ||
144 | continue; | ||
145 | name = tomoyo_encode(pos); | ||
146 | break; | ||
120 | } | 147 | } |
121 | if (error) | ||
122 | tomoyo_warn_oom(__func__); | ||
123 | return error; | ||
124 | } | ||
125 | |||
126 | /** | ||
127 | * tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root. | ||
128 | * | ||
129 | * @path: Pointer to "struct path". | ||
130 | * | ||
131 | * Returns the realpath of the given @path on success, NULL otherwise. | ||
132 | * | ||
133 | * These functions use kzalloc(), so the caller must call kfree() | ||
134 | * if these functions didn't return NULL. | ||
135 | */ | ||
136 | char *tomoyo_realpath_from_path(struct path *path) | ||
137 | { | ||
138 | char *buf = kzalloc(sizeof(struct tomoyo_page_buffer), GFP_NOFS); | ||
139 | |||
140 | BUILD_BUG_ON(TOMOYO_MAX_PATHNAME_LEN > PATH_MAX); | ||
141 | BUILD_BUG_ON(sizeof(struct tomoyo_page_buffer) | ||
142 | <= TOMOYO_MAX_PATHNAME_LEN - 1); | ||
143 | if (!buf) | ||
144 | return NULL; | ||
145 | if (tomoyo_realpath_from_path2(path, buf, | ||
146 | TOMOYO_MAX_PATHNAME_LEN - 1) == 0) | ||
147 | return buf; | ||
148 | kfree(buf); | 148 | kfree(buf); |
149 | return NULL; | 149 | if (!name) |
150 | tomoyo_warn_oom(__func__); | ||
151 | else if (is_dir && *name) { | ||
152 | /* Append trailing '/' if dentry is a directory. */ | ||
153 | char *pos = name + strlen(name) - 1; | ||
154 | if (*pos != '/') | ||
155 | /* | ||
156 | * This is OK because tomoyo_encode() reserves space | ||
157 | * for appending "/". | ||
158 | */ | ||
159 | *++pos = '/'; | ||
160 | } | ||
161 | return name; | ||
150 | } | 162 | } |
151 | 163 | ||
152 | /** | 164 | /** |