linux/security/tomoyo/file.c
<<
>>
Prefs
   1/*
   2 * security/tomoyo/file.c
   3 *
   4 * Pathname restriction functions.
   5 *
   6 * Copyright (C) 2005-2010  NTT DATA CORPORATION
   7 */
   8
   9#include "common.h"
  10#include <linux/slab.h>
  11
  12/* Keyword array for operations with one pathname. */
  13const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = {
  14        [TOMOYO_TYPE_READ_WRITE] = "read/write",
  15        [TOMOYO_TYPE_EXECUTE]    = "execute",
  16        [TOMOYO_TYPE_READ]       = "read",
  17        [TOMOYO_TYPE_WRITE]      = "write",
  18        [TOMOYO_TYPE_UNLINK]     = "unlink",
  19        [TOMOYO_TYPE_RMDIR]      = "rmdir",
  20        [TOMOYO_TYPE_TRUNCATE]   = "truncate",
  21        [TOMOYO_TYPE_SYMLINK]    = "symlink",
  22        [TOMOYO_TYPE_REWRITE]    = "rewrite",
  23        [TOMOYO_TYPE_CHROOT]     = "chroot",
  24        [TOMOYO_TYPE_UMOUNT]     = "unmount",
  25};
  26
  27/* Keyword array for operations with one pathname and three numbers. */
  28const char *tomoyo_mkdev_keyword[TOMOYO_MAX_MKDEV_OPERATION] = {
  29        [TOMOYO_TYPE_MKBLOCK]    = "mkblock",
  30        [TOMOYO_TYPE_MKCHAR]     = "mkchar",
  31};
  32
  33/* Keyword array for operations with two pathnames. */
  34const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = {
  35        [TOMOYO_TYPE_LINK]       = "link",
  36        [TOMOYO_TYPE_RENAME]     = "rename",
  37        [TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root",
  38};
  39
  40/* Keyword array for operations with one pathname and one number. */
  41const char *tomoyo_path_number_keyword[TOMOYO_MAX_PATH_NUMBER_OPERATION] = {
  42        [TOMOYO_TYPE_CREATE]     = "create",
  43        [TOMOYO_TYPE_MKDIR]      = "mkdir",
  44        [TOMOYO_TYPE_MKFIFO]     = "mkfifo",
  45        [TOMOYO_TYPE_MKSOCK]     = "mksock",
  46        [TOMOYO_TYPE_IOCTL]      = "ioctl",
  47        [TOMOYO_TYPE_CHMOD]      = "chmod",
  48        [TOMOYO_TYPE_CHOWN]      = "chown",
  49        [TOMOYO_TYPE_CHGRP]      = "chgrp",
  50};
  51
  52static const u8 tomoyo_p2mac[TOMOYO_MAX_PATH_OPERATION] = {
  53        [TOMOYO_TYPE_READ_WRITE] = TOMOYO_MAC_FILE_OPEN,
  54        [TOMOYO_TYPE_EXECUTE]    = TOMOYO_MAC_FILE_EXECUTE,
  55        [TOMOYO_TYPE_READ]       = TOMOYO_MAC_FILE_OPEN,
  56        [TOMOYO_TYPE_WRITE]      = TOMOYO_MAC_FILE_OPEN,
  57        [TOMOYO_TYPE_UNLINK]     = TOMOYO_MAC_FILE_UNLINK,
  58        [TOMOYO_TYPE_RMDIR]      = TOMOYO_MAC_FILE_RMDIR,
  59        [TOMOYO_TYPE_TRUNCATE]   = TOMOYO_MAC_FILE_TRUNCATE,
  60        [TOMOYO_TYPE_SYMLINK]    = TOMOYO_MAC_FILE_SYMLINK,
  61        [TOMOYO_TYPE_REWRITE]    = TOMOYO_MAC_FILE_REWRITE,
  62        [TOMOYO_TYPE_CHROOT]     = TOMOYO_MAC_FILE_CHROOT,
  63        [TOMOYO_TYPE_UMOUNT]     = TOMOYO_MAC_FILE_UMOUNT,
  64};
  65
  66static const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION] = {
  67        [TOMOYO_TYPE_MKBLOCK] = TOMOYO_MAC_FILE_MKBLOCK,
  68        [TOMOYO_TYPE_MKCHAR]  = TOMOYO_MAC_FILE_MKCHAR,
  69};
  70
  71static const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION] = {
  72        [TOMOYO_TYPE_LINK]       = TOMOYO_MAC_FILE_LINK,
  73        [TOMOYO_TYPE_RENAME]     = TOMOYO_MAC_FILE_RENAME,
  74        [TOMOYO_TYPE_PIVOT_ROOT] = TOMOYO_MAC_FILE_PIVOT_ROOT,
  75};
  76
  77static const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = {
  78        [TOMOYO_TYPE_CREATE] = TOMOYO_MAC_FILE_CREATE,
  79        [TOMOYO_TYPE_MKDIR]  = TOMOYO_MAC_FILE_MKDIR,
  80        [TOMOYO_TYPE_MKFIFO] = TOMOYO_MAC_FILE_MKFIFO,
  81        [TOMOYO_TYPE_MKSOCK] = TOMOYO_MAC_FILE_MKSOCK,
  82        [TOMOYO_TYPE_IOCTL]  = TOMOYO_MAC_FILE_IOCTL,
  83        [TOMOYO_TYPE_CHMOD]  = TOMOYO_MAC_FILE_CHMOD,
  84        [TOMOYO_TYPE_CHOWN]  = TOMOYO_MAC_FILE_CHOWN,
  85        [TOMOYO_TYPE_CHGRP]  = TOMOYO_MAC_FILE_CHGRP,
  86};
  87
  88void tomoyo_put_name_union(struct tomoyo_name_union *ptr)
  89{
  90        if (!ptr)
  91                return;
  92        if (ptr->is_group)
  93                tomoyo_put_group(ptr->group);
  94        else
  95                tomoyo_put_name(ptr->filename);
  96}
  97
  98const struct tomoyo_path_info *
  99tomoyo_compare_name_union(const struct tomoyo_path_info *name,
 100                          const struct tomoyo_name_union *ptr)
 101{
 102        if (ptr->is_group)
 103                return tomoyo_path_matches_group(name, ptr->group);
 104        if (tomoyo_path_matches_pattern(name, ptr->filename))
 105                return ptr->filename;
 106        return NULL;
 107}
 108
 109void tomoyo_put_number_union(struct tomoyo_number_union *ptr)
 110{
 111        if (ptr && ptr->is_group)
 112                tomoyo_put_group(ptr->group);
 113}
 114
 115bool tomoyo_compare_number_union(const unsigned long value,
 116                                 const struct tomoyo_number_union *ptr)
 117{
 118        if (ptr->is_group)
 119                return tomoyo_number_matches_group(value, value, ptr->group);
 120        return value >= ptr->values[0] && value <= ptr->values[1];
 121}
 122
 123static void tomoyo_add_slash(struct tomoyo_path_info *buf)
 124{
 125        if (buf->is_dir)
 126                return;
 127        /*
 128         * This is OK because tomoyo_encode() reserves space for appending "/".
 129         */
 130        strcat((char *) buf->name, "/");
 131        tomoyo_fill_path_info(buf);
 132}
 133
 134/**
 135 * tomoyo_strendswith - Check whether the token ends with the given token.
 136 *
 137 * @name: The token to check.
 138 * @tail: The token to find.
 139 *
 140 * Returns true if @name ends with @tail, false otherwise.
 141 */
 142static bool tomoyo_strendswith(const char *name, const char *tail)
 143{
 144        int len;
 145
 146        if (!name || !tail)
 147                return false;
 148        len = strlen(name) - strlen(tail);
 149        return len >= 0 && !strcmp(name + len, tail);
 150}
 151
 152/**
 153 * tomoyo_get_realpath - Get realpath.
 154 *
 155 * @buf:  Pointer to "struct tomoyo_path_info".
 156 * @path: Pointer to "struct path".
 157 *
 158 * Returns true on success, false otherwise.
 159 */
 160static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path)
 161{
 162        buf->name = tomoyo_realpath_from_path(path);
 163        if (buf->name) {
 164                tomoyo_fill_path_info(buf);
 165                return true;
 166        }
 167        return false;
 168}
 169
 170/**
 171 * tomoyo_audit_path_log - Audit path request log.
 172 *
 173 * @r: Pointer to "struct tomoyo_request_info".
 174 *
 175 * Returns 0 on success, negative value otherwise.
 176 */
 177static int tomoyo_audit_path_log(struct tomoyo_request_info *r)
 178{
 179        const char *operation = tomoyo_path_keyword[r->param.path.operation];
 180        const struct tomoyo_path_info *filename = r->param.path.filename;
 181        if (r->granted)
 182                return 0;
 183        tomoyo_warn_log(r, "%s %s", operation, filename->name);
 184        return tomoyo_supervisor(r, "allow_%s %s\n", operation,
 185                                 tomoyo_pattern(filename));
 186}
 187
 188/**
 189 * tomoyo_audit_path2_log - Audit path/path request log.
 190 *
 191 * @r: Pointer to "struct tomoyo_request_info".
 192 *
 193 * Returns 0 on success, negative value otherwise.
 194 */
 195static int tomoyo_audit_path2_log(struct tomoyo_request_info *r)
 196{
 197        const char *operation = tomoyo_path2_keyword[r->param.path2.operation];
 198        const struct tomoyo_path_info *filename1 = r->param.path2.filename1;
 199        const struct tomoyo_path_info *filename2 = r->param.path2.filename2;
 200        if (r->granted)
 201                return 0;
 202        tomoyo_warn_log(r, "%s %s %s", operation, filename1->name,
 203                        filename2->name);
 204        return tomoyo_supervisor(r, "allow_%s %s %s\n", operation,
 205                                 tomoyo_pattern(filename1),
 206                                 tomoyo_pattern(filename2));
 207}
 208
 209/**
 210 * tomoyo_audit_mkdev_log - Audit path/number/number/number request log.
 211 *
 212 * @r: Pointer to "struct tomoyo_request_info".
 213 *
 214 * Returns 0 on success, negative value otherwise.
 215 */
 216static int tomoyo_audit_mkdev_log(struct tomoyo_request_info *r)
 217{
 218        const char *operation = tomoyo_mkdev_keyword[r->param.mkdev.operation];
 219        const struct tomoyo_path_info *filename = r->param.mkdev.filename;
 220        const unsigned int major = r->param.mkdev.major;
 221        const unsigned int minor = r->param.mkdev.minor;
 222        const unsigned int mode = r->param.mkdev.mode;
 223        if (r->granted)
 224                return 0;
 225        tomoyo_warn_log(r, "%s %s 0%o %u %u", operation, filename->name, mode,
 226                        major, minor);
 227        return tomoyo_supervisor(r, "allow_%s %s 0%o %u %u\n", operation,
 228                                 tomoyo_pattern(filename), mode, major, minor);
 229}
 230
 231/**
 232 * tomoyo_audit_path_number_log - Audit path/number request log.
 233 *
 234 * @r:     Pointer to "struct tomoyo_request_info".
 235 * @error: Error code.
 236 *
 237 * Returns 0 on success, negative value otherwise.
 238 */
 239static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r)
 240{
 241        const u8 type = r->param.path_number.operation;
 242        u8 radix;
 243        const struct tomoyo_path_info *filename = r->param.path_number.filename;
 244        const char *operation = tomoyo_path_number_keyword[type];
 245        char buffer[64];
 246        if (r->granted)
 247                return 0;
 248        switch (type) {
 249        case TOMOYO_TYPE_CREATE:
 250        case TOMOYO_TYPE_MKDIR:
 251        case TOMOYO_TYPE_MKFIFO:
 252        case TOMOYO_TYPE_MKSOCK:
 253        case TOMOYO_TYPE_CHMOD:
 254                radix = TOMOYO_VALUE_TYPE_OCTAL;
 255                break;
 256        case TOMOYO_TYPE_IOCTL:
 257                radix = TOMOYO_VALUE_TYPE_HEXADECIMAL;
 258                break;
 259        default:
 260                radix = TOMOYO_VALUE_TYPE_DECIMAL;
 261                break;
 262        }
 263        tomoyo_print_ulong(buffer, sizeof(buffer), r->param.path_number.number,
 264                           radix);
 265        tomoyo_warn_log(r, "%s %s %s", operation, filename->name, buffer);
 266        return tomoyo_supervisor(r, "allow_%s %s %s\n", operation,
 267                                 tomoyo_pattern(filename), buffer);
 268}
 269
 270static bool tomoyo_same_globally_readable(const struct tomoyo_acl_head *a,
 271                                          const struct tomoyo_acl_head *b)
 272{
 273        return container_of(a, struct tomoyo_readable_file,
 274                            head)->filename ==
 275                container_of(b, struct tomoyo_readable_file,
 276                             head)->filename;
 277}
 278
 279/**
 280 * tomoyo_update_globally_readable_entry - Update "struct tomoyo_readable_file" list.
 281 *
 282 * @filename:  Filename unconditionally permitted to open() for reading.
 283 * @is_delete: True if it is a delete request.
 284 *
 285 * Returns 0 on success, negative value otherwise.
 286 *
 287 * Caller holds tomoyo_read_lock().
 288 */
 289static int tomoyo_update_globally_readable_entry(const char *filename,
 290                                                 const bool is_delete)
 291{
 292        struct tomoyo_readable_file e = { };
 293        int error;
 294
 295        if (!tomoyo_correct_word(filename))
 296                return -EINVAL;
 297        e.filename = tomoyo_get_name(filename);
 298        if (!e.filename)
 299                return -ENOMEM;
 300        error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
 301                                     &tomoyo_policy_list
 302                                     [TOMOYO_ID_GLOBALLY_READABLE],
 303                                     tomoyo_same_globally_readable);
 304        tomoyo_put_name(e.filename);
 305        return error;
 306}
 307
 308/**
 309 * tomoyo_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading.
 310 *
 311 * @filename: The filename to check.
 312 *
 313 * Returns true if any domain can open @filename for reading, false otherwise.
 314 *
 315 * Caller holds tomoyo_read_lock().
 316 */
 317static bool tomoyo_globally_readable_file(const struct tomoyo_path_info *
 318                                             filename)
 319{
 320        struct tomoyo_readable_file *ptr;
 321        bool found = false;
 322
 323        list_for_each_entry_rcu(ptr, &tomoyo_policy_list
 324                                [TOMOYO_ID_GLOBALLY_READABLE], head.list) {
 325                if (!ptr->head.is_deleted &&
 326                    tomoyo_path_matches_pattern(filename, ptr->filename)) {
 327                        found = true;
 328                        break;
 329                }
 330        }
 331        return found;
 332}
 333
 334/**
 335 * tomoyo_write_globally_readable - Write "struct tomoyo_readable_file" list.
 336 *
 337 * @data:      String to parse.
 338 * @is_delete: True if it is a delete request.
 339 *
 340 * Returns 0 on success, negative value otherwise.
 341 *
 342 * Caller holds tomoyo_read_lock().
 343 */
 344int tomoyo_write_globally_readable(char *data, const bool is_delete)
 345{
 346        return tomoyo_update_globally_readable_entry(data, is_delete);
 347}
 348
 349static bool tomoyo_same_pattern(const struct tomoyo_acl_head *a,
 350                                const struct tomoyo_acl_head *b)
 351{
 352        return container_of(a, struct tomoyo_no_pattern, head)->pattern ==
 353                container_of(b, struct tomoyo_no_pattern, head)->pattern;
 354}
 355
 356/**
 357 * tomoyo_update_file_pattern_entry - Update "struct tomoyo_no_pattern" list.
 358 *
 359 * @pattern:   Pathname pattern.
 360 * @is_delete: True if it is a delete request.
 361 *
 362 * Returns 0 on success, negative value otherwise.
 363 *
 364 * Caller holds tomoyo_read_lock().
 365 */
 366static int tomoyo_update_file_pattern_entry(const char *pattern,
 367                                            const bool is_delete)
 368{
 369        struct tomoyo_no_pattern e = { };
 370        int error;
 371
 372        if (!tomoyo_correct_word(pattern))
 373                return -EINVAL;
 374        e.pattern = tomoyo_get_name(pattern);
 375        if (!e.pattern)
 376                return -ENOMEM;
 377        error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
 378                                     &tomoyo_policy_list[TOMOYO_ID_PATTERN],
 379                                     tomoyo_same_pattern);
 380        tomoyo_put_name(e.pattern);
 381        return error;
 382}
 383
 384/**
 385 * tomoyo_pattern - Get patterned pathname.
 386 *
 387 * @filename: The filename to find patterned pathname.
 388 *
 389 * Returns pointer to pathname pattern if matched, @filename otherwise.
 390 *
 391 * Caller holds tomoyo_read_lock().
 392 */
 393const char *tomoyo_pattern(const struct tomoyo_path_info *filename)
 394{
 395        struct tomoyo_no_pattern *ptr;
 396        const struct tomoyo_path_info *pattern = NULL;
 397
 398        list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_PATTERN],
 399                                head.list) {
 400                if (ptr->head.is_deleted)
 401                        continue;
 402                if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
 403                        continue;
 404                pattern = ptr->pattern;
 405                if (tomoyo_strendswith(pattern->name, "/\\*")) {
 406                        /* Do nothing. Try to find the better match. */
 407                } else {
 408                        /* This would be the better match. Use this. */
 409                        break;
 410                }
 411        }
 412        if (pattern)
 413                filename = pattern;
 414        return filename->name;
 415}
 416
 417/**
 418 * tomoyo_write_pattern - Write "struct tomoyo_no_pattern" list.
 419 *
 420 * @data:      String to parse.
 421 * @is_delete: True if it is a delete request.
 422 *
 423 * Returns 0 on success, negative value otherwise.
 424 *
 425 * Caller holds tomoyo_read_lock().
 426 */
 427int tomoyo_write_pattern(char *data, const bool is_delete)
 428{
 429        return tomoyo_update_file_pattern_entry(data, is_delete);
 430}
 431
 432static bool tomoyo_same_no_rewrite(const struct tomoyo_acl_head *a,
 433                                   const struct tomoyo_acl_head *b)
 434{
 435        return container_of(a, struct tomoyo_no_rewrite, head)->pattern
 436                == container_of(b, struct tomoyo_no_rewrite, head)
 437                ->pattern;
 438}
 439
 440/**
 441 * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite" list.
 442 *
 443 * @pattern:   Pathname pattern that are not rewritable by default.
 444 * @is_delete: True if it is a delete request.
 445 *
 446 * Returns 0 on success, negative value otherwise.
 447 *
 448 * Caller holds tomoyo_read_lock().
 449 */
 450static int tomoyo_update_no_rewrite_entry(const char *pattern,
 451                                          const bool is_delete)
 452{
 453        struct tomoyo_no_rewrite e = { };
 454        int error;
 455
 456        if (!tomoyo_correct_word(pattern))
 457                return -EINVAL;
 458        e.pattern = tomoyo_get_name(pattern);
 459        if (!e.pattern)
 460                return -ENOMEM;
 461        error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
 462                                     &tomoyo_policy_list[TOMOYO_ID_NO_REWRITE],
 463                                     tomoyo_same_no_rewrite);
 464        tomoyo_put_name(e.pattern);
 465        return error;
 466}
 467
 468/**
 469 * tomoyo_no_rewrite_file - Check if the given pathname is not permitted to be rewrited.
 470 *
 471 * @filename: Filename to check.
 472 *
 473 * Returns true if @filename is specified by "deny_rewrite" directive,
 474 * false otherwise.
 475 *
 476 * Caller holds tomoyo_read_lock().
 477 */
 478static bool tomoyo_no_rewrite_file(const struct tomoyo_path_info *filename)
 479{
 480        struct tomoyo_no_rewrite *ptr;
 481        bool found = false;
 482
 483        list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_NO_REWRITE],
 484                                head.list) {
 485                if (ptr->head.is_deleted)
 486                        continue;
 487                if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
 488                        continue;
 489                found = true;
 490                break;
 491        }
 492        return found;
 493}
 494
 495/**
 496 * tomoyo_write_no_rewrite - Write "struct tomoyo_no_rewrite" list.
 497 *
 498 * @data:      String to parse.
 499 * @is_delete: True if it is a delete request.
 500 *
 501 * Returns 0 on success, negative value otherwise.
 502 *
 503 * Caller holds tomoyo_read_lock().
 504 */
 505int tomoyo_write_no_rewrite(char *data, const bool is_delete)
 506{
 507        return tomoyo_update_no_rewrite_entry(data, is_delete);
 508}
 509
 510static bool tomoyo_check_path_acl(struct tomoyo_request_info *r,
 511                                  const struct tomoyo_acl_info *ptr)
 512{
 513        const struct tomoyo_path_acl *acl = container_of(ptr, typeof(*acl),
 514                                                         head);
 515        if (acl->perm & (1 << r->param.path.operation)) {
 516                r->param.path.matched_path =
 517                        tomoyo_compare_name_union(r->param.path.filename,
 518                                                  &acl->name);
 519                return r->param.path.matched_path != NULL;
 520        }
 521        return false;
 522}
 523
 524static bool tomoyo_check_path_number_acl(struct tomoyo_request_info *r,
 525                                         const struct tomoyo_acl_info *ptr)
 526{
 527        const struct tomoyo_path_number_acl *acl =
 528                container_of(ptr, typeof(*acl), head);
 529        return (acl->perm & (1 << r->param.path_number.operation)) &&
 530                tomoyo_compare_number_union(r->param.path_number.number,
 531                                            &acl->number) &&
 532                tomoyo_compare_name_union(r->param.path_number.filename,
 533                                          &acl->name);
 534}
 535
 536static bool tomoyo_check_path2_acl(struct tomoyo_request_info *r,
 537                                   const struct tomoyo_acl_info *ptr)
 538{
 539        const struct tomoyo_path2_acl *acl =
 540                container_of(ptr, typeof(*acl), head);
 541        return (acl->perm & (1 << r->param.path2.operation)) &&
 542                tomoyo_compare_name_union(r->param.path2.filename1, &acl->name1)
 543                && tomoyo_compare_name_union(r->param.path2.filename2,
 544                                             &acl->name2);
 545}
 546
 547static bool tomoyo_check_mkdev_acl(struct tomoyo_request_info *r,
 548                                const struct tomoyo_acl_info *ptr)
 549{
 550        const struct tomoyo_mkdev_acl *acl =
 551                container_of(ptr, typeof(*acl), head);
 552        return (acl->perm & (1 << r->param.mkdev.operation)) &&
 553                tomoyo_compare_number_union(r->param.mkdev.mode,
 554                                            &acl->mode) &&
 555                tomoyo_compare_number_union(r->param.mkdev.major,
 556                                            &acl->major) &&
 557                tomoyo_compare_number_union(r->param.mkdev.minor,
 558                                            &acl->minor) &&
 559                tomoyo_compare_name_union(r->param.mkdev.filename,
 560                                          &acl->name);
 561}
 562
 563static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a,
 564                                 const struct tomoyo_acl_info *b)
 565{
 566        const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head);
 567        const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head);
 568        return tomoyo_same_acl_head(&p1->head, &p2->head) &&
 569                tomoyo_same_name_union(&p1->name, &p2->name);
 570}
 571
 572static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a,
 573                                  struct tomoyo_acl_info *b,
 574                                  const bool is_delete)
 575{
 576        u16 * const a_perm = &container_of(a, struct tomoyo_path_acl, head)
 577                ->perm;
 578        u16 perm = *a_perm;
 579        const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm;
 580        if (is_delete) {
 581                perm &= ~b_perm;
 582                if ((perm & TOMOYO_RW_MASK) != TOMOYO_RW_MASK)
 583                        perm &= ~(1 << TOMOYO_TYPE_READ_WRITE);
 584                else if (!(perm & (1 << TOMOYO_TYPE_READ_WRITE)))
 585                        perm &= ~TOMOYO_RW_MASK;
 586        } else {
 587                perm |= b_perm;
 588                if ((perm & TOMOYO_RW_MASK) == TOMOYO_RW_MASK)
 589                        perm |= (1 << TOMOYO_TYPE_READ_WRITE);
 590                else if (perm & (1 << TOMOYO_TYPE_READ_WRITE))
 591                        perm |= TOMOYO_RW_MASK;
 592        }
 593        *a_perm = perm;
 594        return !perm;
 595}
 596
 597/**
 598 * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list.
 599 *
 600 * @type:      Type of operation.
 601 * @filename:  Filename.
 602 * @domain:    Pointer to "struct tomoyo_domain_info".
 603 * @is_delete: True if it is a delete request.
 604 *
 605 * Returns 0 on success, negative value otherwise.
 606 *
 607 * Caller holds tomoyo_read_lock().
 608 */
 609static int tomoyo_update_path_acl(const u8 type, const char *filename,
 610                                  struct tomoyo_domain_info * const domain,
 611                                  const bool is_delete)
 612{
 613        struct tomoyo_path_acl e = {
 614                .head.type = TOMOYO_TYPE_PATH_ACL,
 615                .perm = 1 << type
 616        };
 617        int error;
 618        if (e.perm == (1 << TOMOYO_TYPE_READ_WRITE))
 619                e.perm |= TOMOYO_RW_MASK;
 620        if (!tomoyo_parse_name_union(filename, &e.name))
 621                return -EINVAL;
 622        error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
 623                                     tomoyo_same_path_acl,
 624                                     tomoyo_merge_path_acl);
 625        tomoyo_put_name_union(&e.name);
 626        return error;
 627}
 628
 629static bool tomoyo_same_mkdev_acl(const struct tomoyo_acl_info *a,
 630                                         const struct tomoyo_acl_info *b)
 631{
 632        const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1),
 633                                                                head);
 634        const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2),
 635                                                                head);
 636        return tomoyo_same_acl_head(&p1->head, &p2->head)
 637                && tomoyo_same_name_union(&p1->name, &p2->name)
 638                && tomoyo_same_number_union(&p1->mode, &p2->mode)
 639                && tomoyo_same_number_union(&p1->major, &p2->major)
 640                && tomoyo_same_number_union(&p1->minor, &p2->minor);
 641}
 642
 643static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a,
 644                                          struct tomoyo_acl_info *b,
 645                                          const bool is_delete)
 646{
 647        u8 *const a_perm = &container_of(a, struct tomoyo_mkdev_acl,
 648                                         head)->perm;
 649        u8 perm = *a_perm;
 650        const u8 b_perm = container_of(b, struct tomoyo_mkdev_acl, head)
 651                ->perm;
 652        if (is_delete)
 653                perm &= ~b_perm;
 654        else
 655                perm |= b_perm;
 656        *a_perm = perm;
 657        return !perm;
 658}
 659
 660/**
 661 * tomoyo_update_mkdev_acl - Update "struct tomoyo_mkdev_acl" list.
 662 *
 663 * @type:      Type of operation.
 664 * @filename:  Filename.
 665 * @mode:      Create mode.
 666 * @major:     Device major number.
 667 * @minor:     Device minor number.
 668 * @domain:    Pointer to "struct tomoyo_domain_info".
 669 * @is_delete: True if it is a delete request.
 670 *
 671 * Returns 0 on success, negative value otherwise.
 672 *
 673 * Caller holds tomoyo_read_lock().
 674 */
 675static int tomoyo_update_mkdev_acl(const u8 type, const char *filename,
 676                                          char *mode, char *major, char *minor,
 677                                          struct tomoyo_domain_info * const
 678                                          domain, const bool is_delete)
 679{
 680        struct tomoyo_mkdev_acl e = {
 681                .head.type = TOMOYO_TYPE_MKDEV_ACL,
 682                .perm = 1 << type
 683        };
 684        int error = is_delete ? -ENOENT : -ENOMEM;
 685        if (!tomoyo_parse_name_union(filename, &e.name) ||
 686            !tomoyo_parse_number_union(mode, &e.mode) ||
 687            !tomoyo_parse_number_union(major, &e.major) ||
 688            !tomoyo_parse_number_union(minor, &e.minor))
 689                goto out;
 690        error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
 691                                     tomoyo_same_mkdev_acl,
 692                                     tomoyo_merge_mkdev_acl);
 693 out:
 694        tomoyo_put_name_union(&e.name);
 695        tomoyo_put_number_union(&e.mode);
 696        tomoyo_put_number_union(&e.major);
 697        tomoyo_put_number_union(&e.minor);
 698        return error;
 699}
 700
 701static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a,
 702                                  const struct tomoyo_acl_info *b)
 703{
 704        const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head);
 705        const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head);
 706        return tomoyo_same_acl_head(&p1->head, &p2->head)
 707                && tomoyo_same_name_union(&p1->name1, &p2->name1)
 708                && tomoyo_same_name_union(&p1->name2, &p2->name2);
 709}
 710
 711static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a,
 712                                   struct tomoyo_acl_info *b,
 713                                   const bool is_delete)
 714{
 715        u8 * const a_perm = &container_of(a, struct tomoyo_path2_acl, head)
 716                ->perm;
 717        u8 perm = *a_perm;
 718        const u8 b_perm = container_of(b, struct tomoyo_path2_acl, head)->perm;
 719        if (is_delete)
 720                perm &= ~b_perm;
 721        else
 722                perm |= b_perm;
 723        *a_perm = perm;
 724        return !perm;
 725}
 726
 727/**
 728 * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list.
 729 *
 730 * @type:      Type of operation.
 731 * @filename1: First filename.
 732 * @filename2: Second filename.
 733 * @domain:    Pointer to "struct tomoyo_domain_info".
 734 * @is_delete: True if it is a delete request.
 735 *
 736 * Returns 0 on success, negative value otherwise.
 737 *
 738 * Caller holds tomoyo_read_lock().
 739 */
 740static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
 741                                   const char *filename2,
 742                                   struct tomoyo_domain_info * const domain,
 743                                   const bool is_delete)
 744{
 745        struct tomoyo_path2_acl e = {
 746                .head.type = TOMOYO_TYPE_PATH2_ACL,
 747                .perm = 1 << type
 748        };
 749        int error = is_delete ? -ENOENT : -ENOMEM;
 750        if (!tomoyo_parse_name_union(filename1, &e.name1) ||
 751            !tomoyo_parse_name_union(filename2, &e.name2))
 752                goto out;
 753        error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
 754                                     tomoyo_same_path2_acl,
 755                                     tomoyo_merge_path2_acl);
 756 out:
 757        tomoyo_put_name_union(&e.name1);
 758        tomoyo_put_name_union(&e.name2);
 759        return error;
 760}
 761
 762/**
 763 * tomoyo_path_permission - Check permission for single path operation.
 764 *
 765 * @r:         Pointer to "struct tomoyo_request_info".
 766 * @operation: Type of operation.
 767 * @filename:  Filename to check.
 768 *
 769 * Returns 0 on success, negative value otherwise.
 770 *
 771 * Caller holds tomoyo_read_lock().
 772 */
 773int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
 774                           const struct tomoyo_path_info *filename)
 775{
 776        int error;
 777
 778 next:
 779        r->type = tomoyo_p2mac[operation];
 780        r->mode = tomoyo_get_mode(r->profile, r->type);
 781        if (r->mode == TOMOYO_CONFIG_DISABLED)
 782                return 0;
 783        r->param_type = TOMOYO_TYPE_PATH_ACL;
 784        r->param.path.filename = filename;
 785        r->param.path.operation = operation;
 786        do {
 787                tomoyo_check_acl(r, tomoyo_check_path_acl);
 788                if (!r->granted && operation == TOMOYO_TYPE_READ &&
 789                    !r->domain->ignore_global_allow_read &&
 790                    tomoyo_globally_readable_file(filename))
 791                        r->granted = true;
 792                error = tomoyo_audit_path_log(r);
 793                /*
 794                 * Do not retry for execute request, for alias may have
 795                 * changed.
 796                 */
 797        } while (error == TOMOYO_RETRY_REQUEST &&
 798                 operation != TOMOYO_TYPE_EXECUTE);
 799        /*
 800         * Since "allow_truncate" doesn't imply "allow_rewrite" permission,
 801         * we need to check "allow_rewrite" permission if the filename is
 802         * specified by "deny_rewrite" keyword.
 803         */
 804        if (!error && operation == TOMOYO_TYPE_TRUNCATE &&
 805            tomoyo_no_rewrite_file(filename)) {
 806                operation = TOMOYO_TYPE_REWRITE;
 807                goto next;
 808        }
 809        return error;
 810}
 811
 812static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a,
 813                                        const struct tomoyo_acl_info *b)
 814{
 815        const struct tomoyo_path_number_acl *p1 = container_of(a, typeof(*p1),
 816                                                               head);
 817        const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2),
 818                                                               head);
 819        return tomoyo_same_acl_head(&p1->head, &p2->head)
 820                && tomoyo_same_name_union(&p1->name, &p2->name)
 821                && tomoyo_same_number_union(&p1->number, &p2->number);
 822}
 823
 824static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a,
 825                                         struct tomoyo_acl_info *b,
 826                                         const bool is_delete)
 827{
 828        u8 * const a_perm = &container_of(a, struct tomoyo_path_number_acl,
 829                                          head)->perm;
 830        u8 perm = *a_perm;
 831        const u8 b_perm = container_of(b, struct tomoyo_path_number_acl, head)
 832                ->perm;
 833        if (is_delete)
 834                perm &= ~b_perm;
 835        else
 836                perm |= b_perm;
 837        *a_perm = perm;
 838        return !perm;
 839}
 840
 841/**
 842 * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL.
 843 *
 844 * @type:      Type of operation.
 845 * @filename:  Filename.
 846 * @number:    Number.
 847 * @domain:    Pointer to "struct tomoyo_domain_info".
 848 * @is_delete: True if it is a delete request.
 849 *
 850 * Returns 0 on success, negative value otherwise.
 851 */
 852static int tomoyo_update_path_number_acl(const u8 type, const char *filename,
 853                                         char *number,
 854                                         struct tomoyo_domain_info * const
 855                                         domain,
 856                                         const bool is_delete)
 857{
 858        struct tomoyo_path_number_acl e = {
 859                .head.type = TOMOYO_TYPE_PATH_NUMBER_ACL,
 860                .perm = 1 << type
 861        };
 862        int error = is_delete ? -ENOENT : -ENOMEM;
 863        if (!tomoyo_parse_name_union(filename, &e.name))
 864                return -EINVAL;
 865        if (!tomoyo_parse_number_union(number, &e.number))
 866                goto out;
 867        error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
 868                                     tomoyo_same_path_number_acl,
 869                                     tomoyo_merge_path_number_acl);
 870 out:
 871        tomoyo_put_name_union(&e.name);
 872        tomoyo_put_number_union(&e.number);
 873        return error;
 874}
 875
 876/**
 877 * tomoyo_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp".
 878 *
 879 * @type:   Type of operation.
 880 * @path:   Pointer to "struct path".
 881 * @number: Number.
 882 *
 883 * Returns 0 on success, negative value otherwise.
 884 */
 885int tomoyo_path_number_perm(const u8 type, struct path *path,
 886                            unsigned long number)
 887{
 888        struct tomoyo_request_info r;
 889        int error = -ENOMEM;
 890        struct tomoyo_path_info buf;
 891        int idx;
 892
 893        if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type])
 894            == TOMOYO_CONFIG_DISABLED || !path->mnt || !path->dentry)
 895                return 0;
 896        idx = tomoyo_read_lock();
 897        if (!tomoyo_get_realpath(&buf, path))
 898                goto out;
 899        if (type == TOMOYO_TYPE_MKDIR)
 900                tomoyo_add_slash(&buf);
 901        r.param_type = TOMOYO_TYPE_PATH_NUMBER_ACL;
 902        r.param.path_number.operation = type;
 903        r.param.path_number.filename = &buf;
 904        r.param.path_number.number = number;
 905        do {
 906                tomoyo_check_acl(&r, tomoyo_check_path_number_acl);
 907                error = tomoyo_audit_path_number_log(&r);
 908        } while (error == TOMOYO_RETRY_REQUEST);
 909        kfree(buf.name);
 910 out:
 911        tomoyo_read_unlock(idx);
 912        if (r.mode != TOMOYO_CONFIG_ENFORCING)
 913                error = 0;
 914        return error;
 915}
 916
 917/**
 918 * tomoyo_check_open_permission - Check permission for "read" and "write".
 919 *
 920 * @domain: Pointer to "struct tomoyo_domain_info".
 921 * @path:   Pointer to "struct path".
 922 * @flag:   Flags for open().
 923 *
 924 * Returns 0 on success, negative value otherwise.
 925 */
 926int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
 927                                 struct path *path, const int flag)
 928{
 929        const u8 acc_mode = ACC_MODE(flag);
 930        int error = -ENOMEM;
 931        struct tomoyo_path_info buf;
 932        struct tomoyo_request_info r;
 933        int idx;
 934
 935        if (!path->mnt ||
 936            (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode)))
 937                return 0;
 938        buf.name = NULL;
 939        r.mode = TOMOYO_CONFIG_DISABLED;
 940        idx = tomoyo_read_lock();
 941        if (!tomoyo_get_realpath(&buf, path))
 942                goto out;
 943        error = 0;
 944        /*
 945         * If the filename is specified by "deny_rewrite" keyword,
 946         * we need to check "allow_rewrite" permission when the filename is not
 947         * opened for append mode or the filename is truncated at open time.
 948         */
 949        if ((acc_mode & MAY_WRITE) && !(flag & O_APPEND)
 950            && tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_REWRITE)
 951            != TOMOYO_CONFIG_DISABLED) {
 952                if (!tomoyo_get_realpath(&buf, path)) {
 953                        error = -ENOMEM;
 954                        goto out;
 955                }
 956                if (tomoyo_no_rewrite_file(&buf))
 957                        error = tomoyo_path_permission(&r, TOMOYO_TYPE_REWRITE,
 958                                                       &buf);
 959        }
 960        if (!error && acc_mode &&
 961            tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN)
 962            != TOMOYO_CONFIG_DISABLED) {
 963                u8 operation;
 964                if (!buf.name && !tomoyo_get_realpath(&buf, path)) {
 965                        error = -ENOMEM;
 966                        goto out;
 967                }
 968                if (acc_mode == (MAY_READ | MAY_WRITE))
 969                        operation = TOMOYO_TYPE_READ_WRITE;
 970                else if (acc_mode == MAY_READ)
 971                        operation = TOMOYO_TYPE_READ;
 972                else
 973                        operation = TOMOYO_TYPE_WRITE;
 974                error = tomoyo_path_permission(&r, operation, &buf);
 975        }
 976 out:
 977        kfree(buf.name);
 978        tomoyo_read_unlock(idx);
 979        if (r.mode != TOMOYO_CONFIG_ENFORCING)
 980                error = 0;
 981        return error;
 982}
 983
 984/**
 985 * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "rewrite", "chroot" and "unmount".
 986 *
 987 * @operation: Type of operation.
 988 * @path:      Pointer to "struct path".
 989 *
 990 * Returns 0 on success, negative value otherwise.
 991 */
 992int tomoyo_path_perm(const u8 operation, struct path *path)
 993{
 994        int error = -ENOMEM;
 995        struct tomoyo_path_info buf;
 996        struct tomoyo_request_info r;
 997        int idx;
 998
 999        if (!path->mnt)
1000                return 0;
1001        if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation])
1002            == TOMOYO_CONFIG_DISABLED)
1003                return 0;
1004        buf.name = NULL;
1005        idx = tomoyo_read_lock();
1006        if (!tomoyo_get_realpath(&buf, path))
1007                goto out;
1008        switch (operation) {
1009        case TOMOYO_TYPE_REWRITE:
1010                if (!tomoyo_no_rewrite_file(&buf)) {
1011                        error = 0;
1012                        goto out;
1013                }
1014                break;
1015        case TOMOYO_TYPE_RMDIR:
1016        case TOMOYO_TYPE_CHROOT:
1017        case TOMOYO_TYPE_UMOUNT:
1018                tomoyo_add_slash(&buf);
1019                break;
1020        }
1021        error = tomoyo_path_permission(&r, operation, &buf);
1022 out:
1023        kfree(buf.name);
1024        tomoyo_read_unlock(idx);
1025        if (r.mode != TOMOYO_CONFIG_ENFORCING)
1026                error = 0;
1027        return error;
1028}
1029
1030/**
1031 * tomoyo_mkdev_perm - Check permission for "mkblock" and "mkchar".
1032 *
1033 * @operation: Type of operation. (TOMOYO_TYPE_MKCHAR or TOMOYO_TYPE_MKBLOCK)
1034 * @path:      Pointer to "struct path".
1035 * @mode:      Create mode.
1036 * @dev:       Device number.
1037 *
1038 * Returns 0 on success, negative value otherwise.
1039 */
1040int tomoyo_mkdev_perm(const u8 operation, struct path *path,
1041                             const unsigned int mode, unsigned int dev)
1042{
1043        struct tomoyo_request_info r;
1044        int error = -ENOMEM;
1045        struct tomoyo_path_info buf;
1046        int idx;
1047
1048        if (!path->mnt ||
1049            tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation])
1050            == TOMOYO_CONFIG_DISABLED)
1051                return 0;
1052        idx = tomoyo_read_lock();
1053        error = -ENOMEM;
1054        if (tomoyo_get_realpath(&buf, path)) {
1055                dev = new_decode_dev(dev);
1056                r.param_type = TOMOYO_TYPE_MKDEV_ACL;
1057                r.param.mkdev.filename = &buf;
1058                r.param.mkdev.operation = operation;
1059                r.param.mkdev.mode = mode;
1060                r.param.mkdev.major = MAJOR(dev);
1061                r.param.mkdev.minor = MINOR(dev);
1062                tomoyo_check_acl(&r, tomoyo_check_mkdev_acl);
1063                error = tomoyo_audit_mkdev_log(&r);
1064                kfree(buf.name);
1065        }
1066        tomoyo_read_unlock(idx);
1067        if (r.mode != TOMOYO_CONFIG_ENFORCING)
1068                error = 0;
1069        return error;
1070}
1071
1072/**
1073 * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root".
1074 *
1075 * @operation: Type of operation.
1076 * @path1:      Pointer to "struct path".
1077 * @path2:      Pointer to "struct path".
1078 *
1079 * Returns 0 on success, negative value otherwise.
1080 */
1081int tomoyo_path2_perm(const u8 operation, struct path *path1,
1082                      struct path *path2)
1083{
1084        int error = -ENOMEM;
1085        struct tomoyo_path_info buf1;
1086        struct tomoyo_path_info buf2;
1087        struct tomoyo_request_info r;
1088        int idx;
1089
1090        if (!path1->mnt || !path2->mnt ||
1091            tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation])
1092            == TOMOYO_CONFIG_DISABLED)
1093                return 0;
1094        buf1.name = NULL;
1095        buf2.name = NULL;
1096        idx = tomoyo_read_lock();
1097        if (!tomoyo_get_realpath(&buf1, path1) ||
1098            !tomoyo_get_realpath(&buf2, path2))
1099                goto out;
1100        switch (operation) {
1101                struct dentry *dentry;
1102        case TOMOYO_TYPE_RENAME:
1103        case TOMOYO_TYPE_LINK:
1104                dentry = path1->dentry;
1105                if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode))
1106                        break;
1107                /* fall through */
1108        case TOMOYO_TYPE_PIVOT_ROOT:
1109                tomoyo_add_slash(&buf1);
1110                tomoyo_add_slash(&buf2);
1111                break;
1112        }
1113        r.param_type = TOMOYO_TYPE_PATH2_ACL;
1114        r.param.path2.operation = operation;
1115        r.param.path2.filename1 = &buf1;
1116        r.param.path2.filename2 = &buf2;
1117        do {
1118                tomoyo_check_acl(&r, tomoyo_check_path2_acl);
1119                error = tomoyo_audit_path2_log(&r);
1120        } while (error == TOMOYO_RETRY_REQUEST);
1121 out:
1122        kfree(buf1.name);
1123        kfree(buf2.name);
1124        tomoyo_read_unlock(idx);
1125        if (r.mode != TOMOYO_CONFIG_ENFORCING)
1126                error = 0;
1127        return error;
1128}
1129
1130/**
1131 * tomoyo_write_file - Update file related list.
1132 *
1133 * @data:      String to parse.
1134 * @domain:    Pointer to "struct tomoyo_domain_info".
1135 * @is_delete: True if it is a delete request.
1136 *
1137 * Returns 0 on success, negative value otherwise.
1138 *
1139 * Caller holds tomoyo_read_lock().
1140 */
1141int tomoyo_write_file(char *data, struct tomoyo_domain_info *domain,
1142                      const bool is_delete)
1143{
1144        char *w[5];
1145        u8 type;
1146        if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0])
1147                return -EINVAL;
1148        if (strncmp(w[0], "allow_", 6))
1149                goto out;
1150        w[0] += 6;
1151        for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) {
1152                if (strcmp(w[0], tomoyo_path_keyword[type]))
1153                        continue;
1154                return tomoyo_update_path_acl(type, w[1], domain, is_delete);
1155        }
1156        if (!w[2][0])
1157                goto out;
1158        for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) {
1159                if (strcmp(w[0], tomoyo_path2_keyword[type]))
1160                        continue;
1161                return tomoyo_update_path2_acl(type, w[1], w[2], domain,
1162                                               is_delete);
1163        }
1164        for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) {
1165                if (strcmp(w[0], tomoyo_path_number_keyword[type]))
1166                        continue;
1167                return tomoyo_update_path_number_acl(type, w[1], w[2], domain,
1168                                                     is_delete);
1169        }
1170        if (!w[3][0] || !w[4][0])
1171                goto out;
1172        for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++) {
1173                if (strcmp(w[0], tomoyo_mkdev_keyword[type]))
1174                        continue;
1175                return tomoyo_update_mkdev_acl(type, w[1], w[2], w[3],
1176                                               w[4], domain, is_delete);
1177        }
1178 out:
1179        return -EINVAL;
1180}
1181