Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * security/tomoyo/file.c
0004  *
0005  * Copyright (C) 2005-2011  NTT DATA CORPORATION
0006  */
0007 
0008 #include "common.h"
0009 #include <linux/slab.h>
0010 
0011 /*
0012  * Mapping table from "enum tomoyo_path_acl_index" to "enum tomoyo_mac_index".
0013  */
0014 static const u8 tomoyo_p2mac[TOMOYO_MAX_PATH_OPERATION] = {
0015     [TOMOYO_TYPE_EXECUTE]    = TOMOYO_MAC_FILE_EXECUTE,
0016     [TOMOYO_TYPE_READ]       = TOMOYO_MAC_FILE_OPEN,
0017     [TOMOYO_TYPE_WRITE]      = TOMOYO_MAC_FILE_OPEN,
0018     [TOMOYO_TYPE_APPEND]     = TOMOYO_MAC_FILE_OPEN,
0019     [TOMOYO_TYPE_UNLINK]     = TOMOYO_MAC_FILE_UNLINK,
0020     [TOMOYO_TYPE_GETATTR]    = TOMOYO_MAC_FILE_GETATTR,
0021     [TOMOYO_TYPE_RMDIR]      = TOMOYO_MAC_FILE_RMDIR,
0022     [TOMOYO_TYPE_TRUNCATE]   = TOMOYO_MAC_FILE_TRUNCATE,
0023     [TOMOYO_TYPE_SYMLINK]    = TOMOYO_MAC_FILE_SYMLINK,
0024     [TOMOYO_TYPE_CHROOT]     = TOMOYO_MAC_FILE_CHROOT,
0025     [TOMOYO_TYPE_UMOUNT]     = TOMOYO_MAC_FILE_UMOUNT,
0026 };
0027 
0028 /*
0029  * Mapping table from "enum tomoyo_mkdev_acl_index" to "enum tomoyo_mac_index".
0030  */
0031 const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION] = {
0032     [TOMOYO_TYPE_MKBLOCK] = TOMOYO_MAC_FILE_MKBLOCK,
0033     [TOMOYO_TYPE_MKCHAR]  = TOMOYO_MAC_FILE_MKCHAR,
0034 };
0035 
0036 /*
0037  * Mapping table from "enum tomoyo_path2_acl_index" to "enum tomoyo_mac_index".
0038  */
0039 const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION] = {
0040     [TOMOYO_TYPE_LINK]       = TOMOYO_MAC_FILE_LINK,
0041     [TOMOYO_TYPE_RENAME]     = TOMOYO_MAC_FILE_RENAME,
0042     [TOMOYO_TYPE_PIVOT_ROOT] = TOMOYO_MAC_FILE_PIVOT_ROOT,
0043 };
0044 
0045 /*
0046  * Mapping table from "enum tomoyo_path_number_acl_index" to
0047  * "enum tomoyo_mac_index".
0048  */
0049 const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = {
0050     [TOMOYO_TYPE_CREATE] = TOMOYO_MAC_FILE_CREATE,
0051     [TOMOYO_TYPE_MKDIR]  = TOMOYO_MAC_FILE_MKDIR,
0052     [TOMOYO_TYPE_MKFIFO] = TOMOYO_MAC_FILE_MKFIFO,
0053     [TOMOYO_TYPE_MKSOCK] = TOMOYO_MAC_FILE_MKSOCK,
0054     [TOMOYO_TYPE_IOCTL]  = TOMOYO_MAC_FILE_IOCTL,
0055     [TOMOYO_TYPE_CHMOD]  = TOMOYO_MAC_FILE_CHMOD,
0056     [TOMOYO_TYPE_CHOWN]  = TOMOYO_MAC_FILE_CHOWN,
0057     [TOMOYO_TYPE_CHGRP]  = TOMOYO_MAC_FILE_CHGRP,
0058 };
0059 
0060 /**
0061  * tomoyo_put_name_union - Drop reference on "struct tomoyo_name_union".
0062  *
0063  * @ptr: Pointer to "struct tomoyo_name_union".
0064  *
0065  * Returns nothing.
0066  */
0067 void tomoyo_put_name_union(struct tomoyo_name_union *ptr)
0068 {
0069     tomoyo_put_group(ptr->group);
0070     tomoyo_put_name(ptr->filename);
0071 }
0072 
0073 /**
0074  * tomoyo_compare_name_union - Check whether a name matches "struct tomoyo_name_union" or not.
0075  *
0076  * @name: Pointer to "struct tomoyo_path_info".
0077  * @ptr:  Pointer to "struct tomoyo_name_union".
0078  *
0079  * Returns "struct tomoyo_path_info" if @name matches @ptr, NULL otherwise.
0080  */
0081 const struct tomoyo_path_info *
0082 tomoyo_compare_name_union(const struct tomoyo_path_info *name,
0083               const struct tomoyo_name_union *ptr)
0084 {
0085     if (ptr->group)
0086         return tomoyo_path_matches_group(name, ptr->group);
0087     if (tomoyo_path_matches_pattern(name, ptr->filename))
0088         return ptr->filename;
0089     return NULL;
0090 }
0091 
0092 /**
0093  * tomoyo_put_number_union - Drop reference on "struct tomoyo_number_union".
0094  *
0095  * @ptr: Pointer to "struct tomoyo_number_union".
0096  *
0097  * Returns nothing.
0098  */
0099 void tomoyo_put_number_union(struct tomoyo_number_union *ptr)
0100 {
0101     tomoyo_put_group(ptr->group);
0102 }
0103 
0104 /**
0105  * tomoyo_compare_number_union - Check whether a value matches "struct tomoyo_number_union" or not.
0106  *
0107  * @value: Number to check.
0108  * @ptr:   Pointer to "struct tomoyo_number_union".
0109  *
0110  * Returns true if @value matches @ptr, false otherwise.
0111  */
0112 bool tomoyo_compare_number_union(const unsigned long value,
0113                  const struct tomoyo_number_union *ptr)
0114 {
0115     if (ptr->group)
0116         return tomoyo_number_matches_group(value, value, ptr->group);
0117     return value >= ptr->values[0] && value <= ptr->values[1];
0118 }
0119 
0120 /**
0121  * tomoyo_add_slash - Add trailing '/' if needed.
0122  *
0123  * @buf: Pointer to "struct tomoyo_path_info".
0124  *
0125  * Returns nothing.
0126  *
0127  * @buf must be generated by tomoyo_encode() because this function does not
0128  * allocate memory for adding '/'.
0129  */
0130 static void tomoyo_add_slash(struct tomoyo_path_info *buf)
0131 {
0132     if (buf->is_dir)
0133         return;
0134     /*
0135      * This is OK because tomoyo_encode() reserves space for appending "/".
0136      */
0137     strcat((char *) buf->name, "/");
0138     tomoyo_fill_path_info(buf);
0139 }
0140 
0141 /**
0142  * tomoyo_get_realpath - Get realpath.
0143  *
0144  * @buf:  Pointer to "struct tomoyo_path_info".
0145  * @path: Pointer to "struct path".
0146  *
0147  * Returns true on success, false otherwise.
0148  */
0149 static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, const struct path *path)
0150 {
0151     buf->name = tomoyo_realpath_from_path(path);
0152     if (buf->name) {
0153         tomoyo_fill_path_info(buf);
0154         return true;
0155     }
0156     return false;
0157 }
0158 
0159 /**
0160  * tomoyo_audit_path_log - Audit path request log.
0161  *
0162  * @r: Pointer to "struct tomoyo_request_info".
0163  *
0164  * Returns 0 on success, negative value otherwise.
0165  */
0166 static int tomoyo_audit_path_log(struct tomoyo_request_info *r)
0167 {
0168     return tomoyo_supervisor(r, "file %s %s\n", tomoyo_path_keyword
0169                  [r->param.path.operation],
0170                  r->param.path.filename->name);
0171 }
0172 
0173 /**
0174  * tomoyo_audit_path2_log - Audit path/path request log.
0175  *
0176  * @r: Pointer to "struct tomoyo_request_info".
0177  *
0178  * Returns 0 on success, negative value otherwise.
0179  */
0180 static int tomoyo_audit_path2_log(struct tomoyo_request_info *r)
0181 {
0182     return tomoyo_supervisor(r, "file %s %s %s\n", tomoyo_mac_keywords
0183                  [tomoyo_pp2mac[r->param.path2.operation]],
0184                  r->param.path2.filename1->name,
0185                  r->param.path2.filename2->name);
0186 }
0187 
0188 /**
0189  * tomoyo_audit_mkdev_log - Audit path/number/number/number request log.
0190  *
0191  * @r: Pointer to "struct tomoyo_request_info".
0192  *
0193  * Returns 0 on success, negative value otherwise.
0194  */
0195 static int tomoyo_audit_mkdev_log(struct tomoyo_request_info *r)
0196 {
0197     return tomoyo_supervisor(r, "file %s %s 0%o %u %u\n",
0198                  tomoyo_mac_keywords
0199                  [tomoyo_pnnn2mac[r->param.mkdev.operation]],
0200                  r->param.mkdev.filename->name,
0201                  r->param.mkdev.mode, r->param.mkdev.major,
0202                  r->param.mkdev.minor);
0203 }
0204 
0205 /**
0206  * tomoyo_audit_path_number_log - Audit path/number request log.
0207  *
0208  * @r: Pointer to "struct tomoyo_request_info".
0209  *
0210  * Returns 0 on success, negative value otherwise.
0211  */
0212 static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r)
0213 {
0214     const u8 type = r->param.path_number.operation;
0215     u8 radix;
0216     char buffer[64];
0217 
0218     switch (type) {
0219     case TOMOYO_TYPE_CREATE:
0220     case TOMOYO_TYPE_MKDIR:
0221     case TOMOYO_TYPE_MKFIFO:
0222     case TOMOYO_TYPE_MKSOCK:
0223     case TOMOYO_TYPE_CHMOD:
0224         radix = TOMOYO_VALUE_TYPE_OCTAL;
0225         break;
0226     case TOMOYO_TYPE_IOCTL:
0227         radix = TOMOYO_VALUE_TYPE_HEXADECIMAL;
0228         break;
0229     default:
0230         radix = TOMOYO_VALUE_TYPE_DECIMAL;
0231         break;
0232     }
0233     tomoyo_print_ulong(buffer, sizeof(buffer), r->param.path_number.number,
0234                radix);
0235     return tomoyo_supervisor(r, "file %s %s %s\n", tomoyo_mac_keywords
0236                  [tomoyo_pn2mac[type]],
0237                  r->param.path_number.filename->name, buffer);
0238 }
0239 
0240 /**
0241  * tomoyo_check_path_acl - Check permission for path operation.
0242  *
0243  * @r:   Pointer to "struct tomoyo_request_info".
0244  * @ptr: Pointer to "struct tomoyo_acl_info".
0245  *
0246  * Returns true if granted, false otherwise.
0247  *
0248  * To be able to use wildcard for domain transition, this function sets
0249  * matching entry on success. Since the caller holds tomoyo_read_lock(),
0250  * it is safe to set matching entry.
0251  */
0252 static bool tomoyo_check_path_acl(struct tomoyo_request_info *r,
0253                   const struct tomoyo_acl_info *ptr)
0254 {
0255     const struct tomoyo_path_acl *acl = container_of(ptr, typeof(*acl),
0256                              head);
0257 
0258     if (acl->perm & (1 << r->param.path.operation)) {
0259         r->param.path.matched_path =
0260             tomoyo_compare_name_union(r->param.path.filename,
0261                           &acl->name);
0262         return r->param.path.matched_path != NULL;
0263     }
0264     return false;
0265 }
0266 
0267 /**
0268  * tomoyo_check_path_number_acl - Check permission for path number operation.
0269  *
0270  * @r:   Pointer to "struct tomoyo_request_info".
0271  * @ptr: Pointer to "struct tomoyo_acl_info".
0272  *
0273  * Returns true if granted, false otherwise.
0274  */
0275 static bool tomoyo_check_path_number_acl(struct tomoyo_request_info *r,
0276                      const struct tomoyo_acl_info *ptr)
0277 {
0278     const struct tomoyo_path_number_acl *acl =
0279         container_of(ptr, typeof(*acl), head);
0280 
0281     return (acl->perm & (1 << r->param.path_number.operation)) &&
0282         tomoyo_compare_number_union(r->param.path_number.number,
0283                         &acl->number) &&
0284         tomoyo_compare_name_union(r->param.path_number.filename,
0285                       &acl->name);
0286 }
0287 
0288 /**
0289  * tomoyo_check_path2_acl - Check permission for path path operation.
0290  *
0291  * @r:   Pointer to "struct tomoyo_request_info".
0292  * @ptr: Pointer to "struct tomoyo_acl_info".
0293  *
0294  * Returns true if granted, false otherwise.
0295  */
0296 static bool tomoyo_check_path2_acl(struct tomoyo_request_info *r,
0297                    const struct tomoyo_acl_info *ptr)
0298 {
0299     const struct tomoyo_path2_acl *acl =
0300         container_of(ptr, typeof(*acl), head);
0301 
0302     return (acl->perm & (1 << r->param.path2.operation)) &&
0303         tomoyo_compare_name_union(r->param.path2.filename1, &acl->name1)
0304         && tomoyo_compare_name_union(r->param.path2.filename2,
0305                          &acl->name2);
0306 }
0307 
0308 /**
0309  * tomoyo_check_mkdev_acl - Check permission for path number number number operation.
0310  *
0311  * @r:   Pointer to "struct tomoyo_request_info".
0312  * @ptr: Pointer to "struct tomoyo_acl_info".
0313  *
0314  * Returns true if granted, false otherwise.
0315  */
0316 static bool tomoyo_check_mkdev_acl(struct tomoyo_request_info *r,
0317                    const struct tomoyo_acl_info *ptr)
0318 {
0319     const struct tomoyo_mkdev_acl *acl =
0320         container_of(ptr, typeof(*acl), head);
0321 
0322     return (acl->perm & (1 << r->param.mkdev.operation)) &&
0323         tomoyo_compare_number_union(r->param.mkdev.mode,
0324                         &acl->mode) &&
0325         tomoyo_compare_number_union(r->param.mkdev.major,
0326                         &acl->major) &&
0327         tomoyo_compare_number_union(r->param.mkdev.minor,
0328                         &acl->minor) &&
0329         tomoyo_compare_name_union(r->param.mkdev.filename,
0330                       &acl->name);
0331 }
0332 
0333 /**
0334  * tomoyo_same_path_acl - Check for duplicated "struct tomoyo_path_acl" entry.
0335  *
0336  * @a: Pointer to "struct tomoyo_acl_info".
0337  * @b: Pointer to "struct tomoyo_acl_info".
0338  *
0339  * Returns true if @a == @b except permission bits, false otherwise.
0340  */
0341 static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a,
0342                  const struct tomoyo_acl_info *b)
0343 {
0344     const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head);
0345     const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head);
0346 
0347     return tomoyo_same_name_union(&p1->name, &p2->name);
0348 }
0349 
0350 /**
0351  * tomoyo_merge_path_acl - Merge duplicated "struct tomoyo_path_acl" entry.
0352  *
0353  * @a:         Pointer to "struct tomoyo_acl_info".
0354  * @b:         Pointer to "struct tomoyo_acl_info".
0355  * @is_delete: True for @a &= ~@b, false for @a |= @b.
0356  *
0357  * Returns true if @a is empty, false otherwise.
0358  */
0359 static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a,
0360                   struct tomoyo_acl_info *b,
0361                   const bool is_delete)
0362 {
0363     u16 * const a_perm = &container_of(a, struct tomoyo_path_acl, head)
0364         ->perm;
0365     u16 perm = READ_ONCE(*a_perm);
0366     const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm;
0367 
0368     if (is_delete)
0369         perm &= ~b_perm;
0370     else
0371         perm |= b_perm;
0372     WRITE_ONCE(*a_perm, perm);
0373     return !perm;
0374 }
0375 
0376 /**
0377  * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list.
0378  *
0379  * @perm:  Permission.
0380  * @param: Pointer to "struct tomoyo_acl_param".
0381  *
0382  * Returns 0 on success, negative value otherwise.
0383  *
0384  * Caller holds tomoyo_read_lock().
0385  */
0386 static int tomoyo_update_path_acl(const u16 perm,
0387                   struct tomoyo_acl_param *param)
0388 {
0389     struct tomoyo_path_acl e = {
0390         .head.type = TOMOYO_TYPE_PATH_ACL,
0391         .perm = perm
0392     };
0393     int error;
0394 
0395     if (!tomoyo_parse_name_union(param, &e.name))
0396         error = -EINVAL;
0397     else
0398         error = tomoyo_update_domain(&e.head, sizeof(e), param,
0399                          tomoyo_same_path_acl,
0400                          tomoyo_merge_path_acl);
0401     tomoyo_put_name_union(&e.name);
0402     return error;
0403 }
0404 
0405 /**
0406  * tomoyo_same_mkdev_acl - Check for duplicated "struct tomoyo_mkdev_acl" entry.
0407  *
0408  * @a: Pointer to "struct tomoyo_acl_info".
0409  * @b: Pointer to "struct tomoyo_acl_info".
0410  *
0411  * Returns true if @a == @b except permission bits, false otherwise.
0412  */
0413 static bool tomoyo_same_mkdev_acl(const struct tomoyo_acl_info *a,
0414                      const struct tomoyo_acl_info *b)
0415 {
0416     const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1), head);
0417     const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2), head);
0418 
0419     return tomoyo_same_name_union(&p1->name, &p2->name) &&
0420         tomoyo_same_number_union(&p1->mode, &p2->mode) &&
0421         tomoyo_same_number_union(&p1->major, &p2->major) &&
0422         tomoyo_same_number_union(&p1->minor, &p2->minor);
0423 }
0424 
0425 /**
0426  * tomoyo_merge_mkdev_acl - Merge duplicated "struct tomoyo_mkdev_acl" entry.
0427  *
0428  * @a:         Pointer to "struct tomoyo_acl_info".
0429  * @b:         Pointer to "struct tomoyo_acl_info".
0430  * @is_delete: True for @a &= ~@b, false for @a |= @b.
0431  *
0432  * Returns true if @a is empty, false otherwise.
0433  */
0434 static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a,
0435                    struct tomoyo_acl_info *b,
0436                    const bool is_delete)
0437 {
0438     u8 *const a_perm = &container_of(a, struct tomoyo_mkdev_acl,
0439                      head)->perm;
0440     u8 perm = READ_ONCE(*a_perm);
0441     const u8 b_perm = container_of(b, struct tomoyo_mkdev_acl, head)
0442         ->perm;
0443 
0444     if (is_delete)
0445         perm &= ~b_perm;
0446     else
0447         perm |= b_perm;
0448     WRITE_ONCE(*a_perm, perm);
0449     return !perm;
0450 }
0451 
0452 /**
0453  * tomoyo_update_mkdev_acl - Update "struct tomoyo_mkdev_acl" list.
0454  *
0455  * @perm:  Permission.
0456  * @param: Pointer to "struct tomoyo_acl_param".
0457  *
0458  * Returns 0 on success, negative value otherwise.
0459  *
0460  * Caller holds tomoyo_read_lock().
0461  */
0462 static int tomoyo_update_mkdev_acl(const u8 perm,
0463                    struct tomoyo_acl_param *param)
0464 {
0465     struct tomoyo_mkdev_acl e = {
0466         .head.type = TOMOYO_TYPE_MKDEV_ACL,
0467         .perm = perm
0468     };
0469     int error;
0470 
0471     if (!tomoyo_parse_name_union(param, &e.name) ||
0472         !tomoyo_parse_number_union(param, &e.mode) ||
0473         !tomoyo_parse_number_union(param, &e.major) ||
0474         !tomoyo_parse_number_union(param, &e.minor))
0475         error = -EINVAL;
0476     else
0477         error = tomoyo_update_domain(&e.head, sizeof(e), param,
0478                          tomoyo_same_mkdev_acl,
0479                          tomoyo_merge_mkdev_acl);
0480     tomoyo_put_name_union(&e.name);
0481     tomoyo_put_number_union(&e.mode);
0482     tomoyo_put_number_union(&e.major);
0483     tomoyo_put_number_union(&e.minor);
0484     return error;
0485 }
0486 
0487 /**
0488  * tomoyo_same_path2_acl - Check for duplicated "struct tomoyo_path2_acl" entry.
0489  *
0490  * @a: Pointer to "struct tomoyo_acl_info".
0491  * @b: Pointer to "struct tomoyo_acl_info".
0492  *
0493  * Returns true if @a == @b except permission bits, false otherwise.
0494  */
0495 static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a,
0496                   const struct tomoyo_acl_info *b)
0497 {
0498     const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head);
0499     const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head);
0500 
0501     return tomoyo_same_name_union(&p1->name1, &p2->name1) &&
0502         tomoyo_same_name_union(&p1->name2, &p2->name2);
0503 }
0504 
0505 /**
0506  * tomoyo_merge_path2_acl - Merge duplicated "struct tomoyo_path2_acl" entry.
0507  *
0508  * @a:         Pointer to "struct tomoyo_acl_info".
0509  * @b:         Pointer to "struct tomoyo_acl_info".
0510  * @is_delete: True for @a &= ~@b, false for @a |= @b.
0511  *
0512  * Returns true if @a is empty, false otherwise.
0513  */
0514 static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a,
0515                    struct tomoyo_acl_info *b,
0516                    const bool is_delete)
0517 {
0518     u8 * const a_perm = &container_of(a, struct tomoyo_path2_acl, head)
0519         ->perm;
0520     u8 perm = READ_ONCE(*a_perm);
0521     const u8 b_perm = container_of(b, struct tomoyo_path2_acl, head)->perm;
0522 
0523     if (is_delete)
0524         perm &= ~b_perm;
0525     else
0526         perm |= b_perm;
0527     WRITE_ONCE(*a_perm, perm);
0528     return !perm;
0529 }
0530 
0531 /**
0532  * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list.
0533  *
0534  * @perm:  Permission.
0535  * @param: Pointer to "struct tomoyo_acl_param".
0536  *
0537  * Returns 0 on success, negative value otherwise.
0538  *
0539  * Caller holds tomoyo_read_lock().
0540  */
0541 static int tomoyo_update_path2_acl(const u8 perm,
0542                    struct tomoyo_acl_param *param)
0543 {
0544     struct tomoyo_path2_acl e = {
0545         .head.type = TOMOYO_TYPE_PATH2_ACL,
0546         .perm = perm
0547     };
0548     int error;
0549 
0550     if (!tomoyo_parse_name_union(param, &e.name1) ||
0551         !tomoyo_parse_name_union(param, &e.name2))
0552         error = -EINVAL;
0553     else
0554         error = tomoyo_update_domain(&e.head, sizeof(e), param,
0555                          tomoyo_same_path2_acl,
0556                          tomoyo_merge_path2_acl);
0557     tomoyo_put_name_union(&e.name1);
0558     tomoyo_put_name_union(&e.name2);
0559     return error;
0560 }
0561 
0562 /**
0563  * tomoyo_path_permission - Check permission for single path operation.
0564  *
0565  * @r:         Pointer to "struct tomoyo_request_info".
0566  * @operation: Type of operation.
0567  * @filename:  Filename to check.
0568  *
0569  * Returns 0 on success, negative value otherwise.
0570  *
0571  * Caller holds tomoyo_read_lock().
0572  */
0573 static int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
0574                   const struct tomoyo_path_info *filename)
0575 {
0576     int error;
0577 
0578     r->type = tomoyo_p2mac[operation];
0579     r->mode = tomoyo_get_mode(r->domain->ns, r->profile, r->type);
0580     if (r->mode == TOMOYO_CONFIG_DISABLED)
0581         return 0;
0582     r->param_type = TOMOYO_TYPE_PATH_ACL;
0583     r->param.path.filename = filename;
0584     r->param.path.operation = operation;
0585     do {
0586         tomoyo_check_acl(r, tomoyo_check_path_acl);
0587         error = tomoyo_audit_path_log(r);
0588     } while (error == TOMOYO_RETRY_REQUEST);
0589     return error;
0590 }
0591 
0592 /**
0593  * tomoyo_execute_permission - Check permission for execute operation.
0594  *
0595  * @r:         Pointer to "struct tomoyo_request_info".
0596  * @filename:  Filename to check.
0597  *
0598  * Returns 0 on success, negative value otherwise.
0599  *
0600  * Caller holds tomoyo_read_lock().
0601  */
0602 int tomoyo_execute_permission(struct tomoyo_request_info *r,
0603                   const struct tomoyo_path_info *filename)
0604 {
0605     /*
0606      * Unlike other permission checks, this check is done regardless of
0607      * profile mode settings in order to check for domain transition
0608      * preference.
0609      */
0610     r->type = TOMOYO_MAC_FILE_EXECUTE;
0611     r->mode = tomoyo_get_mode(r->domain->ns, r->profile, r->type);
0612     r->param_type = TOMOYO_TYPE_PATH_ACL;
0613     r->param.path.filename = filename;
0614     r->param.path.operation = TOMOYO_TYPE_EXECUTE;
0615     tomoyo_check_acl(r, tomoyo_check_path_acl);
0616     r->ee->transition = r->matched_acl && r->matched_acl->cond ?
0617         r->matched_acl->cond->transit : NULL;
0618     if (r->mode != TOMOYO_CONFIG_DISABLED)
0619         return tomoyo_audit_path_log(r);
0620     return 0;
0621 }
0622 
0623 /**
0624  * tomoyo_same_path_number_acl - Check for duplicated "struct tomoyo_path_number_acl" entry.
0625  *
0626  * @a: Pointer to "struct tomoyo_acl_info".
0627  * @b: Pointer to "struct tomoyo_acl_info".
0628  *
0629  * Returns true if @a == @b except permission bits, false otherwise.
0630  */
0631 static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a,
0632                     const struct tomoyo_acl_info *b)
0633 {
0634     const struct tomoyo_path_number_acl *p1 = container_of(a, typeof(*p1),
0635                                    head);
0636     const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2),
0637                                    head);
0638 
0639     return tomoyo_same_name_union(&p1->name, &p2->name) &&
0640         tomoyo_same_number_union(&p1->number, &p2->number);
0641 }
0642 
0643 /**
0644  * tomoyo_merge_path_number_acl - Merge duplicated "struct tomoyo_path_number_acl" entry.
0645  *
0646  * @a:         Pointer to "struct tomoyo_acl_info".
0647  * @b:         Pointer to "struct tomoyo_acl_info".
0648  * @is_delete: True for @a &= ~@b, false for @a |= @b.
0649  *
0650  * Returns true if @a is empty, false otherwise.
0651  */
0652 static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a,
0653                      struct tomoyo_acl_info *b,
0654                      const bool is_delete)
0655 {
0656     u8 * const a_perm = &container_of(a, struct tomoyo_path_number_acl,
0657                       head)->perm;
0658     u8 perm = READ_ONCE(*a_perm);
0659     const u8 b_perm = container_of(b, struct tomoyo_path_number_acl, head)
0660         ->perm;
0661 
0662     if (is_delete)
0663         perm &= ~b_perm;
0664     else
0665         perm |= b_perm;
0666     WRITE_ONCE(*a_perm, perm);
0667     return !perm;
0668 }
0669 
0670 /**
0671  * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL.
0672  *
0673  * @perm:  Permission.
0674  * @param: Pointer to "struct tomoyo_acl_param".
0675  *
0676  * Returns 0 on success, negative value otherwise.
0677  */
0678 static int tomoyo_update_path_number_acl(const u8 perm,
0679                      struct tomoyo_acl_param *param)
0680 {
0681     struct tomoyo_path_number_acl e = {
0682         .head.type = TOMOYO_TYPE_PATH_NUMBER_ACL,
0683         .perm = perm
0684     };
0685     int error;
0686 
0687     if (!tomoyo_parse_name_union(param, &e.name) ||
0688         !tomoyo_parse_number_union(param, &e.number))
0689         error = -EINVAL;
0690     else
0691         error = tomoyo_update_domain(&e.head, sizeof(e), param,
0692                          tomoyo_same_path_number_acl,
0693                          tomoyo_merge_path_number_acl);
0694     tomoyo_put_name_union(&e.name);
0695     tomoyo_put_number_union(&e.number);
0696     return error;
0697 }
0698 
0699 /**
0700  * tomoyo_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp".
0701  *
0702  * @type:   Type of operation.
0703  * @path:   Pointer to "struct path".
0704  * @number: Number.
0705  *
0706  * Returns 0 on success, negative value otherwise.
0707  */
0708 int tomoyo_path_number_perm(const u8 type, const struct path *path,
0709                 unsigned long number)
0710 {
0711     struct tomoyo_request_info r;
0712     struct tomoyo_obj_info obj = {
0713         .path1 = { .mnt = path->mnt, .dentry = path->dentry },
0714     };
0715     int error = -ENOMEM;
0716     struct tomoyo_path_info buf;
0717     int idx;
0718 
0719     if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type])
0720         == TOMOYO_CONFIG_DISABLED || !path->dentry)
0721         return 0;
0722     idx = tomoyo_read_lock();
0723     if (!tomoyo_get_realpath(&buf, path))
0724         goto out;
0725     r.obj = &obj;
0726     if (type == TOMOYO_TYPE_MKDIR)
0727         tomoyo_add_slash(&buf);
0728     r.param_type = TOMOYO_TYPE_PATH_NUMBER_ACL;
0729     r.param.path_number.operation = type;
0730     r.param.path_number.filename = &buf;
0731     r.param.path_number.number = number;
0732     do {
0733         tomoyo_check_acl(&r, tomoyo_check_path_number_acl);
0734         error = tomoyo_audit_path_number_log(&r);
0735     } while (error == TOMOYO_RETRY_REQUEST);
0736     kfree(buf.name);
0737  out:
0738     tomoyo_read_unlock(idx);
0739     if (r.mode != TOMOYO_CONFIG_ENFORCING)
0740         error = 0;
0741     return error;
0742 }
0743 
0744 /**
0745  * tomoyo_check_open_permission - Check permission for "read" and "write".
0746  *
0747  * @domain: Pointer to "struct tomoyo_domain_info".
0748  * @path:   Pointer to "struct path".
0749  * @flag:   Flags for open().
0750  *
0751  * Returns 0 on success, negative value otherwise.
0752  */
0753 int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
0754                  const struct path *path, const int flag)
0755 {
0756     const u8 acc_mode = ACC_MODE(flag);
0757     int error = 0;
0758     struct tomoyo_path_info buf;
0759     struct tomoyo_request_info r;
0760     struct tomoyo_obj_info obj = {
0761         .path1 = { .mnt = path->mnt, .dentry = path->dentry },
0762     };
0763     int idx;
0764 
0765     buf.name = NULL;
0766     r.mode = TOMOYO_CONFIG_DISABLED;
0767     idx = tomoyo_read_lock();
0768     if (acc_mode &&
0769         tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN)
0770         != TOMOYO_CONFIG_DISABLED) {
0771         if (!tomoyo_get_realpath(&buf, path)) {
0772             error = -ENOMEM;
0773             goto out;
0774         }
0775         r.obj = &obj;
0776         if (acc_mode & MAY_READ)
0777             error = tomoyo_path_permission(&r, TOMOYO_TYPE_READ,
0778                                &buf);
0779         if (!error && (acc_mode & MAY_WRITE))
0780             error = tomoyo_path_permission(&r, (flag & O_APPEND) ?
0781                                TOMOYO_TYPE_APPEND :
0782                                TOMOYO_TYPE_WRITE,
0783                                &buf);
0784     }
0785  out:
0786     kfree(buf.name);
0787     tomoyo_read_unlock(idx);
0788     if (r.mode != TOMOYO_CONFIG_ENFORCING)
0789         error = 0;
0790     return error;
0791 }
0792 
0793 /**
0794  * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "append", "chroot" and "unmount".
0795  *
0796  * @operation: Type of operation.
0797  * @path:      Pointer to "struct path".
0798  * @target:    Symlink's target if @operation is TOMOYO_TYPE_SYMLINK,
0799  *             NULL otherwise.
0800  *
0801  * Returns 0 on success, negative value otherwise.
0802  */
0803 int tomoyo_path_perm(const u8 operation, const struct path *path, const char *target)
0804 {
0805     struct tomoyo_request_info r;
0806     struct tomoyo_obj_info obj = {
0807         .path1 = { .mnt = path->mnt, .dentry = path->dentry },
0808     };
0809     int error;
0810     struct tomoyo_path_info buf;
0811     bool is_enforce;
0812     struct tomoyo_path_info symlink_target;
0813     int idx;
0814 
0815     if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation])
0816         == TOMOYO_CONFIG_DISABLED)
0817         return 0;
0818     is_enforce = (r.mode == TOMOYO_CONFIG_ENFORCING);
0819     error = -ENOMEM;
0820     buf.name = NULL;
0821     idx = tomoyo_read_lock();
0822     if (!tomoyo_get_realpath(&buf, path))
0823         goto out;
0824     r.obj = &obj;
0825     switch (operation) {
0826     case TOMOYO_TYPE_RMDIR:
0827     case TOMOYO_TYPE_CHROOT:
0828         tomoyo_add_slash(&buf);
0829         break;
0830     case TOMOYO_TYPE_SYMLINK:
0831         symlink_target.name = tomoyo_encode(target);
0832         if (!symlink_target.name)
0833             goto out;
0834         tomoyo_fill_path_info(&symlink_target);
0835         obj.symlink_target = &symlink_target;
0836         break;
0837     }
0838     error = tomoyo_path_permission(&r, operation, &buf);
0839     if (operation == TOMOYO_TYPE_SYMLINK)
0840         kfree(symlink_target.name);
0841  out:
0842     kfree(buf.name);
0843     tomoyo_read_unlock(idx);
0844     if (!is_enforce)
0845         error = 0;
0846     return error;
0847 }
0848 
0849 /**
0850  * tomoyo_mkdev_perm - Check permission for "mkblock" and "mkchar".
0851  *
0852  * @operation: Type of operation. (TOMOYO_TYPE_MKCHAR or TOMOYO_TYPE_MKBLOCK)
0853  * @path:      Pointer to "struct path".
0854  * @mode:      Create mode.
0855  * @dev:       Device number.
0856  *
0857  * Returns 0 on success, negative value otherwise.
0858  */
0859 int tomoyo_mkdev_perm(const u8 operation, const struct path *path,
0860               const unsigned int mode, unsigned int dev)
0861 {
0862     struct tomoyo_request_info r;
0863     struct tomoyo_obj_info obj = {
0864         .path1 = { .mnt = path->mnt, .dentry = path->dentry },
0865     };
0866     int error = -ENOMEM;
0867     struct tomoyo_path_info buf;
0868     int idx;
0869 
0870     if (tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation])
0871         == TOMOYO_CONFIG_DISABLED)
0872         return 0;
0873     idx = tomoyo_read_lock();
0874     error = -ENOMEM;
0875     if (tomoyo_get_realpath(&buf, path)) {
0876         r.obj = &obj;
0877         dev = new_decode_dev(dev);
0878         r.param_type = TOMOYO_TYPE_MKDEV_ACL;
0879         r.param.mkdev.filename = &buf;
0880         r.param.mkdev.operation = operation;
0881         r.param.mkdev.mode = mode;
0882         r.param.mkdev.major = MAJOR(dev);
0883         r.param.mkdev.minor = MINOR(dev);
0884         tomoyo_check_acl(&r, tomoyo_check_mkdev_acl);
0885         error = tomoyo_audit_mkdev_log(&r);
0886         kfree(buf.name);
0887     }
0888     tomoyo_read_unlock(idx);
0889     if (r.mode != TOMOYO_CONFIG_ENFORCING)
0890         error = 0;
0891     return error;
0892 }
0893 
0894 /**
0895  * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root".
0896  *
0897  * @operation: Type of operation.
0898  * @path1:      Pointer to "struct path".
0899  * @path2:      Pointer to "struct path".
0900  *
0901  * Returns 0 on success, negative value otherwise.
0902  */
0903 int tomoyo_path2_perm(const u8 operation, const struct path *path1,
0904               const struct path *path2)
0905 {
0906     int error = -ENOMEM;
0907     struct tomoyo_path_info buf1;
0908     struct tomoyo_path_info buf2;
0909     struct tomoyo_request_info r;
0910     struct tomoyo_obj_info obj = {
0911         .path1 = { .mnt = path1->mnt, .dentry = path1->dentry },
0912         .path2 = { .mnt = path2->mnt, .dentry = path2->dentry }
0913     };
0914     int idx;
0915 
0916     if (tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation])
0917         == TOMOYO_CONFIG_DISABLED)
0918         return 0;
0919     buf1.name = NULL;
0920     buf2.name = NULL;
0921     idx = tomoyo_read_lock();
0922     if (!tomoyo_get_realpath(&buf1, path1) ||
0923         !tomoyo_get_realpath(&buf2, path2))
0924         goto out;
0925     switch (operation) {
0926     case TOMOYO_TYPE_RENAME:
0927     case TOMOYO_TYPE_LINK:
0928         if (!d_is_dir(path1->dentry))
0929             break;
0930         fallthrough;
0931     case TOMOYO_TYPE_PIVOT_ROOT:
0932         tomoyo_add_slash(&buf1);
0933         tomoyo_add_slash(&buf2);
0934         break;
0935     }
0936     r.obj = &obj;
0937     r.param_type = TOMOYO_TYPE_PATH2_ACL;
0938     r.param.path2.operation = operation;
0939     r.param.path2.filename1 = &buf1;
0940     r.param.path2.filename2 = &buf2;
0941     do {
0942         tomoyo_check_acl(&r, tomoyo_check_path2_acl);
0943         error = tomoyo_audit_path2_log(&r);
0944     } while (error == TOMOYO_RETRY_REQUEST);
0945  out:
0946     kfree(buf1.name);
0947     kfree(buf2.name);
0948     tomoyo_read_unlock(idx);
0949     if (r.mode != TOMOYO_CONFIG_ENFORCING)
0950         error = 0;
0951     return error;
0952 }
0953 
0954 /**
0955  * tomoyo_same_mount_acl - Check for duplicated "struct tomoyo_mount_acl" entry.
0956  *
0957  * @a: Pointer to "struct tomoyo_acl_info".
0958  * @b: Pointer to "struct tomoyo_acl_info".
0959  *
0960  * Returns true if @a == @b, false otherwise.
0961  */
0962 static bool tomoyo_same_mount_acl(const struct tomoyo_acl_info *a,
0963                   const struct tomoyo_acl_info *b)
0964 {
0965     const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head);
0966     const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head);
0967 
0968     return tomoyo_same_name_union(&p1->dev_name, &p2->dev_name) &&
0969         tomoyo_same_name_union(&p1->dir_name, &p2->dir_name) &&
0970         tomoyo_same_name_union(&p1->fs_type, &p2->fs_type) &&
0971         tomoyo_same_number_union(&p1->flags, &p2->flags);
0972 }
0973 
0974 /**
0975  * tomoyo_update_mount_acl - Write "struct tomoyo_mount_acl" list.
0976  *
0977  * @param: Pointer to "struct tomoyo_acl_param".
0978  *
0979  * Returns 0 on success, negative value otherwise.
0980  *
0981  * Caller holds tomoyo_read_lock().
0982  */
0983 static int tomoyo_update_mount_acl(struct tomoyo_acl_param *param)
0984 {
0985     struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL };
0986     int error;
0987 
0988     if (!tomoyo_parse_name_union(param, &e.dev_name) ||
0989         !tomoyo_parse_name_union(param, &e.dir_name) ||
0990         !tomoyo_parse_name_union(param, &e.fs_type) ||
0991         !tomoyo_parse_number_union(param, &e.flags))
0992         error = -EINVAL;
0993     else
0994         error = tomoyo_update_domain(&e.head, sizeof(e), param,
0995                          tomoyo_same_mount_acl, NULL);
0996     tomoyo_put_name_union(&e.dev_name);
0997     tomoyo_put_name_union(&e.dir_name);
0998     tomoyo_put_name_union(&e.fs_type);
0999     tomoyo_put_number_union(&e.flags);
1000     return error;
1001 }
1002 
1003 /**
1004  * tomoyo_write_file - Update file related list.
1005  *
1006  * @param: Pointer to "struct tomoyo_acl_param".
1007  *
1008  * Returns 0 on success, negative value otherwise.
1009  *
1010  * Caller holds tomoyo_read_lock().
1011  */
1012 int tomoyo_write_file(struct tomoyo_acl_param *param)
1013 {
1014     u16 perm = 0;
1015     u8 type;
1016     const char *operation = tomoyo_read_token(param);
1017 
1018     for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++)
1019         if (tomoyo_permstr(operation, tomoyo_path_keyword[type]))
1020             perm |= 1 << type;
1021     if (perm)
1022         return tomoyo_update_path_acl(perm, param);
1023     for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++)
1024         if (tomoyo_permstr(operation,
1025                    tomoyo_mac_keywords[tomoyo_pp2mac[type]]))
1026             perm |= 1 << type;
1027     if (perm)
1028         return tomoyo_update_path2_acl(perm, param);
1029     for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++)
1030         if (tomoyo_permstr(operation,
1031                    tomoyo_mac_keywords[tomoyo_pn2mac[type]]))
1032             perm |= 1 << type;
1033     if (perm)
1034         return tomoyo_update_path_number_acl(perm, param);
1035     for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++)
1036         if (tomoyo_permstr(operation,
1037                    tomoyo_mac_keywords[tomoyo_pnnn2mac[type]]))
1038             perm |= 1 << type;
1039     if (perm)
1040         return tomoyo_update_mkdev_acl(perm, param);
1041     if (tomoyo_permstr(operation,
1042                tomoyo_mac_keywords[TOMOYO_MAC_FILE_MOUNT]))
1043         return tomoyo_update_mount_acl(param);
1044     return -EINVAL;
1045 }