1b69a54eeSKentaro Takeda /* 2b69a54eeSKentaro Takeda * security/tomoyo/file.c 3b69a54eeSKentaro Takeda * 4c3ef1500STetsuo Handa * Pathname restriction functions. 5b69a54eeSKentaro Takeda * 6c3ef1500STetsuo Handa * Copyright (C) 2005-2010 NTT DATA CORPORATION 7b69a54eeSKentaro Takeda */ 8b69a54eeSKentaro Takeda 9b69a54eeSKentaro Takeda #include "common.h" 105a0e3ad6STejun Heo #include <linux/slab.h> 11b69a54eeSKentaro Takeda 12a1f9bb6aSTetsuo Handa /* Keyword array for operations with one pathname. */ 1371c28236STetsuo Handa const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = { 147ef61233STetsuo Handa [TOMOYO_TYPE_READ_WRITE] = "read/write", 157ef61233STetsuo Handa [TOMOYO_TYPE_EXECUTE] = "execute", 167ef61233STetsuo Handa [TOMOYO_TYPE_READ] = "read", 177ef61233STetsuo Handa [TOMOYO_TYPE_WRITE] = "write", 187ef61233STetsuo Handa [TOMOYO_TYPE_UNLINK] = "unlink", 197ef61233STetsuo Handa [TOMOYO_TYPE_RMDIR] = "rmdir", 207ef61233STetsuo Handa [TOMOYO_TYPE_TRUNCATE] = "truncate", 217ef61233STetsuo Handa [TOMOYO_TYPE_SYMLINK] = "symlink", 227ef61233STetsuo Handa [TOMOYO_TYPE_REWRITE] = "rewrite", 237ef61233STetsuo Handa [TOMOYO_TYPE_CHROOT] = "chroot", 247ef61233STetsuo Handa [TOMOYO_TYPE_UMOUNT] = "unmount", 25b69a54eeSKentaro Takeda }; 26b69a54eeSKentaro Takeda 27a1f9bb6aSTetsuo Handa /* Keyword array for operations with one pathname and three numbers. */ 2871c28236STetsuo Handa const char *tomoyo_mkdev_keyword[TOMOYO_MAX_MKDEV_OPERATION] = { 29a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_MKBLOCK] = "mkblock", 30a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_MKCHAR] = "mkchar", 31a1f9bb6aSTetsuo Handa }; 32a1f9bb6aSTetsuo Handa 33a1f9bb6aSTetsuo Handa /* Keyword array for operations with two pathnames. */ 3471c28236STetsuo Handa const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = { 357ef61233STetsuo Handa [TOMOYO_TYPE_LINK] = "link", 367ef61233STetsuo Handa [TOMOYO_TYPE_RENAME] = "rename", 377ef61233STetsuo Handa [TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root", 38b69a54eeSKentaro Takeda }; 39b69a54eeSKentaro Takeda 40a1f9bb6aSTetsuo Handa /* Keyword array for operations with one pathname and one number. */ 4171c28236STetsuo Handa const char *tomoyo_path_number_keyword[TOMOYO_MAX_PATH_NUMBER_OPERATION] = { 42a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_CREATE] = "create", 43a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_MKDIR] = "mkdir", 44a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_MKFIFO] = "mkfifo", 45a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_MKSOCK] = "mksock", 46a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_IOCTL] = "ioctl", 47a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_CHMOD] = "chmod", 48a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_CHOWN] = "chown", 49a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_CHGRP] = "chgrp", 50a1f9bb6aSTetsuo Handa }; 51a1f9bb6aSTetsuo Handa 5257c2590fSTetsuo Handa static const u8 tomoyo_p2mac[TOMOYO_MAX_PATH_OPERATION] = { 5357c2590fSTetsuo Handa [TOMOYO_TYPE_READ_WRITE] = TOMOYO_MAC_FILE_OPEN, 5457c2590fSTetsuo Handa [TOMOYO_TYPE_EXECUTE] = TOMOYO_MAC_FILE_EXECUTE, 5557c2590fSTetsuo Handa [TOMOYO_TYPE_READ] = TOMOYO_MAC_FILE_OPEN, 5657c2590fSTetsuo Handa [TOMOYO_TYPE_WRITE] = TOMOYO_MAC_FILE_OPEN, 5757c2590fSTetsuo Handa [TOMOYO_TYPE_UNLINK] = TOMOYO_MAC_FILE_UNLINK, 5857c2590fSTetsuo Handa [TOMOYO_TYPE_RMDIR] = TOMOYO_MAC_FILE_RMDIR, 5957c2590fSTetsuo Handa [TOMOYO_TYPE_TRUNCATE] = TOMOYO_MAC_FILE_TRUNCATE, 6057c2590fSTetsuo Handa [TOMOYO_TYPE_SYMLINK] = TOMOYO_MAC_FILE_SYMLINK, 6157c2590fSTetsuo Handa [TOMOYO_TYPE_REWRITE] = TOMOYO_MAC_FILE_REWRITE, 6257c2590fSTetsuo Handa [TOMOYO_TYPE_CHROOT] = TOMOYO_MAC_FILE_CHROOT, 6357c2590fSTetsuo Handa [TOMOYO_TYPE_UMOUNT] = TOMOYO_MAC_FILE_UMOUNT, 6457c2590fSTetsuo Handa }; 6557c2590fSTetsuo Handa 6675093152STetsuo Handa static const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION] = { 6757c2590fSTetsuo Handa [TOMOYO_TYPE_MKBLOCK] = TOMOYO_MAC_FILE_MKBLOCK, 6857c2590fSTetsuo Handa [TOMOYO_TYPE_MKCHAR] = TOMOYO_MAC_FILE_MKCHAR, 6957c2590fSTetsuo Handa }; 7057c2590fSTetsuo Handa 7157c2590fSTetsuo Handa static const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION] = { 7257c2590fSTetsuo Handa [TOMOYO_TYPE_LINK] = TOMOYO_MAC_FILE_LINK, 7357c2590fSTetsuo Handa [TOMOYO_TYPE_RENAME] = TOMOYO_MAC_FILE_RENAME, 7457c2590fSTetsuo Handa [TOMOYO_TYPE_PIVOT_ROOT] = TOMOYO_MAC_FILE_PIVOT_ROOT, 7557c2590fSTetsuo Handa }; 7657c2590fSTetsuo Handa 7757c2590fSTetsuo Handa static const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = { 7857c2590fSTetsuo Handa [TOMOYO_TYPE_CREATE] = TOMOYO_MAC_FILE_CREATE, 7957c2590fSTetsuo Handa [TOMOYO_TYPE_MKDIR] = TOMOYO_MAC_FILE_MKDIR, 8057c2590fSTetsuo Handa [TOMOYO_TYPE_MKFIFO] = TOMOYO_MAC_FILE_MKFIFO, 8157c2590fSTetsuo Handa [TOMOYO_TYPE_MKSOCK] = TOMOYO_MAC_FILE_MKSOCK, 8257c2590fSTetsuo Handa [TOMOYO_TYPE_IOCTL] = TOMOYO_MAC_FILE_IOCTL, 8357c2590fSTetsuo Handa [TOMOYO_TYPE_CHMOD] = TOMOYO_MAC_FILE_CHMOD, 8457c2590fSTetsuo Handa [TOMOYO_TYPE_CHOWN] = TOMOYO_MAC_FILE_CHOWN, 8557c2590fSTetsuo Handa [TOMOYO_TYPE_CHGRP] = TOMOYO_MAC_FILE_CHGRP, 8657c2590fSTetsuo Handa }; 8757c2590fSTetsuo Handa 887762fbffSTetsuo Handa void tomoyo_put_name_union(struct tomoyo_name_union *ptr) 897762fbffSTetsuo Handa { 907762fbffSTetsuo Handa if (!ptr) 917762fbffSTetsuo Handa return; 927762fbffSTetsuo Handa if (ptr->is_group) 937762fbffSTetsuo Handa tomoyo_put_path_group(ptr->group); 947762fbffSTetsuo Handa else 957762fbffSTetsuo Handa tomoyo_put_name(ptr->filename); 967762fbffSTetsuo Handa } 977762fbffSTetsuo Handa 987762fbffSTetsuo Handa bool tomoyo_compare_name_union(const struct tomoyo_path_info *name, 997762fbffSTetsuo Handa const struct tomoyo_name_union *ptr) 1007762fbffSTetsuo Handa { 1017762fbffSTetsuo Handa if (ptr->is_group) 1023f629636STetsuo Handa return tomoyo_path_matches_group(name, ptr->group); 1037762fbffSTetsuo Handa return tomoyo_path_matches_pattern(name, ptr->filename); 1047762fbffSTetsuo Handa } 1057762fbffSTetsuo Handa 1064c3e9e2dSTetsuo Handa void tomoyo_put_number_union(struct tomoyo_number_union *ptr) 1074c3e9e2dSTetsuo Handa { 1084c3e9e2dSTetsuo Handa if (ptr && ptr->is_group) 1094c3e9e2dSTetsuo Handa tomoyo_put_number_group(ptr->group); 1104c3e9e2dSTetsuo Handa } 1114c3e9e2dSTetsuo Handa 1124c3e9e2dSTetsuo Handa bool tomoyo_compare_number_union(const unsigned long value, 1134c3e9e2dSTetsuo Handa const struct tomoyo_number_union *ptr) 1144c3e9e2dSTetsuo Handa { 1154c3e9e2dSTetsuo Handa if (ptr->is_group) 1164c3e9e2dSTetsuo Handa return tomoyo_number_matches_group(value, value, ptr->group); 1174c3e9e2dSTetsuo Handa return value >= ptr->values[0] && value <= ptr->values[1]; 1184c3e9e2dSTetsuo Handa } 1194c3e9e2dSTetsuo Handa 120c8c57e84STetsuo Handa static void tomoyo_add_slash(struct tomoyo_path_info *buf) 121c8c57e84STetsuo Handa { 122c8c57e84STetsuo Handa if (buf->is_dir) 123c8c57e84STetsuo Handa return; 124c8c57e84STetsuo Handa /* 125c8c57e84STetsuo Handa * This is OK because tomoyo_encode() reserves space for appending "/". 126c8c57e84STetsuo Handa */ 127c8c57e84STetsuo Handa strcat((char *) buf->name, "/"); 128c8c57e84STetsuo Handa tomoyo_fill_path_info(buf); 129c8c57e84STetsuo Handa } 130c8c57e84STetsuo Handa 131a1f9bb6aSTetsuo Handa /** 132b69a54eeSKentaro Takeda * tomoyo_strendswith - Check whether the token ends with the given token. 133b69a54eeSKentaro Takeda * 134b69a54eeSKentaro Takeda * @name: The token to check. 135b69a54eeSKentaro Takeda * @tail: The token to find. 136b69a54eeSKentaro Takeda * 137b69a54eeSKentaro Takeda * Returns true if @name ends with @tail, false otherwise. 138b69a54eeSKentaro Takeda */ 139b69a54eeSKentaro Takeda static bool tomoyo_strendswith(const char *name, const char *tail) 140b69a54eeSKentaro Takeda { 141b69a54eeSKentaro Takeda int len; 142b69a54eeSKentaro Takeda 143b69a54eeSKentaro Takeda if (!name || !tail) 144b69a54eeSKentaro Takeda return false; 145b69a54eeSKentaro Takeda len = strlen(name) - strlen(tail); 146b69a54eeSKentaro Takeda return len >= 0 && !strcmp(name + len, tail); 147b69a54eeSKentaro Takeda } 148b69a54eeSKentaro Takeda 149b69a54eeSKentaro Takeda /** 150c8c57e84STetsuo Handa * tomoyo_get_realpath - Get realpath. 151b69a54eeSKentaro Takeda * 152c8c57e84STetsuo Handa * @buf: Pointer to "struct tomoyo_path_info". 153b69a54eeSKentaro Takeda * @path: Pointer to "struct path". 154b69a54eeSKentaro Takeda * 155c8c57e84STetsuo Handa * Returns true on success, false otherwise. 156b69a54eeSKentaro Takeda */ 157c8c57e84STetsuo Handa static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path) 158b69a54eeSKentaro Takeda { 159c8c57e84STetsuo Handa buf->name = tomoyo_realpath_from_path(path); 160c8c57e84STetsuo Handa if (buf->name) { 161c8c57e84STetsuo Handa tomoyo_fill_path_info(buf); 162c8c57e84STetsuo Handa return true; 163b69a54eeSKentaro Takeda } 164c8c57e84STetsuo Handa return false; 165b69a54eeSKentaro Takeda } 166b69a54eeSKentaro Takeda 16799a85259STetsuo Handa /** 16899a85259STetsuo Handa * tomoyo_audit_path_log - Audit path request log. 16999a85259STetsuo Handa * 17099a85259STetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 17199a85259STetsuo Handa * 17299a85259STetsuo Handa * Returns 0 on success, negative value otherwise. 17399a85259STetsuo Handa */ 17499a85259STetsuo Handa static int tomoyo_audit_path_log(struct tomoyo_request_info *r) 17599a85259STetsuo Handa { 17699a85259STetsuo Handa const char *operation = tomoyo_path_keyword[r->param.path.operation]; 17799a85259STetsuo Handa const struct tomoyo_path_info *filename = r->param.path.filename; 17899a85259STetsuo Handa if (r->granted) 17999a85259STetsuo Handa return 0; 18099a85259STetsuo Handa tomoyo_warn_log(r, "%s %s", operation, filename->name); 18199a85259STetsuo Handa return tomoyo_supervisor(r, "allow_%s %s\n", operation, 18299a85259STetsuo Handa tomoyo_file_pattern(filename)); 18399a85259STetsuo Handa } 18499a85259STetsuo Handa 18599a85259STetsuo Handa /** 18699a85259STetsuo Handa * tomoyo_audit_path2_log - Audit path/path request log. 18799a85259STetsuo Handa * 18899a85259STetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 18999a85259STetsuo Handa * 19099a85259STetsuo Handa * Returns 0 on success, negative value otherwise. 19199a85259STetsuo Handa */ 19299a85259STetsuo Handa static int tomoyo_audit_path2_log(struct tomoyo_request_info *r) 19399a85259STetsuo Handa { 19499a85259STetsuo Handa const char *operation = tomoyo_path2_keyword[r->param.path2.operation]; 19599a85259STetsuo Handa const struct tomoyo_path_info *filename1 = r->param.path2.filename1; 19699a85259STetsuo Handa const struct tomoyo_path_info *filename2 = r->param.path2.filename2; 19799a85259STetsuo Handa if (r->granted) 19899a85259STetsuo Handa return 0; 19999a85259STetsuo Handa tomoyo_warn_log(r, "%s %s %s", operation, filename1->name, 20099a85259STetsuo Handa filename2->name); 20199a85259STetsuo Handa return tomoyo_supervisor(r, "allow_%s %s %s\n", operation, 20299a85259STetsuo Handa tomoyo_file_pattern(filename1), 20399a85259STetsuo Handa tomoyo_file_pattern(filename2)); 20499a85259STetsuo Handa } 20599a85259STetsuo Handa 20699a85259STetsuo Handa /** 20799a85259STetsuo Handa * tomoyo_audit_mkdev_log - Audit path/number/number/number request log. 20899a85259STetsuo Handa * 20999a85259STetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 21099a85259STetsuo Handa * 21199a85259STetsuo Handa * Returns 0 on success, negative value otherwise. 21299a85259STetsuo Handa */ 21399a85259STetsuo Handa static int tomoyo_audit_mkdev_log(struct tomoyo_request_info *r) 21499a85259STetsuo Handa { 21571c28236STetsuo Handa const char *operation = tomoyo_mkdev_keyword[r->param.mkdev.operation]; 21699a85259STetsuo Handa const struct tomoyo_path_info *filename = r->param.mkdev.filename; 21799a85259STetsuo Handa const unsigned int major = r->param.mkdev.major; 21899a85259STetsuo Handa const unsigned int minor = r->param.mkdev.minor; 21999a85259STetsuo Handa const unsigned int mode = r->param.mkdev.mode; 22099a85259STetsuo Handa if (r->granted) 22199a85259STetsuo Handa return 0; 22299a85259STetsuo Handa tomoyo_warn_log(r, "%s %s 0%o %u %u", operation, filename->name, mode, 22399a85259STetsuo Handa major, minor); 22499a85259STetsuo Handa return tomoyo_supervisor(r, "allow_%s %s 0%o %u %u\n", operation, 22599a85259STetsuo Handa tomoyo_file_pattern(filename), mode, major, 22699a85259STetsuo Handa minor); 22799a85259STetsuo Handa } 22899a85259STetsuo Handa 22999a85259STetsuo Handa /** 23099a85259STetsuo Handa * tomoyo_audit_path_number_log - Audit path/number request log. 23199a85259STetsuo Handa * 23299a85259STetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 23399a85259STetsuo Handa * @error: Error code. 23499a85259STetsuo Handa * 23599a85259STetsuo Handa * Returns 0 on success, negative value otherwise. 23699a85259STetsuo Handa */ 23799a85259STetsuo Handa static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r) 23899a85259STetsuo Handa { 23999a85259STetsuo Handa const u8 type = r->param.path_number.operation; 24099a85259STetsuo Handa u8 radix; 24199a85259STetsuo Handa const struct tomoyo_path_info *filename = r->param.path_number.filename; 24299a85259STetsuo Handa const char *operation = tomoyo_path_number_keyword[type]; 24399a85259STetsuo Handa char buffer[64]; 24499a85259STetsuo Handa if (r->granted) 24599a85259STetsuo Handa return 0; 24699a85259STetsuo Handa switch (type) { 24799a85259STetsuo Handa case TOMOYO_TYPE_CREATE: 24899a85259STetsuo Handa case TOMOYO_TYPE_MKDIR: 24999a85259STetsuo Handa case TOMOYO_TYPE_MKFIFO: 25099a85259STetsuo Handa case TOMOYO_TYPE_MKSOCK: 25199a85259STetsuo Handa case TOMOYO_TYPE_CHMOD: 25299a85259STetsuo Handa radix = TOMOYO_VALUE_TYPE_OCTAL; 25399a85259STetsuo Handa break; 25499a85259STetsuo Handa case TOMOYO_TYPE_IOCTL: 25599a85259STetsuo Handa radix = TOMOYO_VALUE_TYPE_HEXADECIMAL; 25699a85259STetsuo Handa break; 25799a85259STetsuo Handa default: 25899a85259STetsuo Handa radix = TOMOYO_VALUE_TYPE_DECIMAL; 25999a85259STetsuo Handa break; 26099a85259STetsuo Handa } 26199a85259STetsuo Handa tomoyo_print_ulong(buffer, sizeof(buffer), r->param.path_number.number, 26299a85259STetsuo Handa radix); 26399a85259STetsuo Handa tomoyo_warn_log(r, "%s %s %s", operation, filename->name, buffer); 26499a85259STetsuo Handa return tomoyo_supervisor(r, "allow_%s %s %s\n", operation, 26599a85259STetsuo Handa tomoyo_file_pattern(filename), buffer); 26699a85259STetsuo Handa } 26799a85259STetsuo Handa 2687ef61233STetsuo Handa static int tomoyo_update_path2_acl(const u8 type, const char *filename1, 269b69a54eeSKentaro Takeda const char *filename2, 2707ef61233STetsuo Handa struct tomoyo_domain_info *const domain, 2717ef61233STetsuo Handa const bool is_delete); 2727ef61233STetsuo Handa static int tomoyo_update_path_acl(const u8 type, const char *filename, 2737ef61233STetsuo Handa struct tomoyo_domain_info *const domain, 2747ef61233STetsuo Handa const bool is_delete); 275b69a54eeSKentaro Takeda 276c3fa109aSTetsuo Handa /* 277c3fa109aSTetsuo Handa * tomoyo_globally_readable_list is used for holding list of pathnames which 278c3fa109aSTetsuo Handa * are by default allowed to be open()ed for reading by any process. 279c3fa109aSTetsuo Handa * 280c3fa109aSTetsuo Handa * An entry is added by 281c3fa109aSTetsuo Handa * 282c3fa109aSTetsuo Handa * # echo 'allow_read /lib/libc-2.5.so' > \ 283c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 284c3fa109aSTetsuo Handa * 285c3fa109aSTetsuo Handa * and is deleted by 286c3fa109aSTetsuo Handa * 287c3fa109aSTetsuo Handa * # echo 'delete allow_read /lib/libc-2.5.so' > \ 288c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 289c3fa109aSTetsuo Handa * 290c3fa109aSTetsuo Handa * and all entries are retrieved by 291c3fa109aSTetsuo Handa * 292c3fa109aSTetsuo Handa * # grep ^allow_read /sys/kernel/security/tomoyo/exception_policy 293c3fa109aSTetsuo Handa * 294c3fa109aSTetsuo Handa * In the example above, any process is allowed to 295c3fa109aSTetsuo Handa * open("/lib/libc-2.5.so", O_RDONLY). 296c3fa109aSTetsuo Handa * One exception is, if the domain which current process belongs to is marked 297c3fa109aSTetsuo Handa * as "ignore_global_allow_read", current process can't do so unless explicitly 298c3fa109aSTetsuo Handa * given "allow_read /lib/libc-2.5.so" to the domain which current process 299c3fa109aSTetsuo Handa * belongs to. 300c3fa109aSTetsuo Handa */ 301847b173eSTetsuo Handa LIST_HEAD(tomoyo_globally_readable_list); 302b69a54eeSKentaro Takeda 30336f5e1ffSTetsuo Handa static bool tomoyo_same_globally_readable(const struct tomoyo_acl_head *a, 30436f5e1ffSTetsuo Handa const struct tomoyo_acl_head *b) 30536f5e1ffSTetsuo Handa { 30636f5e1ffSTetsuo Handa return container_of(a, struct tomoyo_globally_readable_file_entry, 30736f5e1ffSTetsuo Handa head)->filename == 30836f5e1ffSTetsuo Handa container_of(b, struct tomoyo_globally_readable_file_entry, 30936f5e1ffSTetsuo Handa head)->filename; 31036f5e1ffSTetsuo Handa } 31136f5e1ffSTetsuo Handa 312b69a54eeSKentaro Takeda /** 313b69a54eeSKentaro Takeda * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list. 314b69a54eeSKentaro Takeda * 315b69a54eeSKentaro Takeda * @filename: Filename unconditionally permitted to open() for reading. 316b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 317b69a54eeSKentaro Takeda * 318b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 319fdb8ebb7STetsuo Handa * 320fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 321b69a54eeSKentaro Takeda */ 322b69a54eeSKentaro Takeda static int tomoyo_update_globally_readable_entry(const char *filename, 323b69a54eeSKentaro Takeda const bool is_delete) 324b69a54eeSKentaro Takeda { 3259e4b50e9STetsuo Handa struct tomoyo_globally_readable_file_entry e = { }; 32636f5e1ffSTetsuo Handa int error; 327b69a54eeSKentaro Takeda 32875093152STetsuo Handa if (!tomoyo_correct_word(filename)) 329b69a54eeSKentaro Takeda return -EINVAL; 3309e4b50e9STetsuo Handa e.filename = tomoyo_get_name(filename); 3319e4b50e9STetsuo Handa if (!e.filename) 332b69a54eeSKentaro Takeda return -ENOMEM; 33336f5e1ffSTetsuo Handa error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, 33436f5e1ffSTetsuo Handa &tomoyo_globally_readable_list, 33536f5e1ffSTetsuo Handa tomoyo_same_globally_readable); 3369e4b50e9STetsuo Handa tomoyo_put_name(e.filename); 337b69a54eeSKentaro Takeda return error; 338b69a54eeSKentaro Takeda } 339b69a54eeSKentaro Takeda 340b69a54eeSKentaro Takeda /** 34175093152STetsuo Handa * tomoyo_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading. 342b69a54eeSKentaro Takeda * 343b69a54eeSKentaro Takeda * @filename: The filename to check. 344b69a54eeSKentaro Takeda * 345b69a54eeSKentaro Takeda * Returns true if any domain can open @filename for reading, false otherwise. 346fdb8ebb7STetsuo Handa * 347fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 348b69a54eeSKentaro Takeda */ 34975093152STetsuo Handa static bool tomoyo_globally_readable_file(const struct tomoyo_path_info * 350b69a54eeSKentaro Takeda filename) 351b69a54eeSKentaro Takeda { 352b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry *ptr; 353b69a54eeSKentaro Takeda bool found = false; 354fdb8ebb7STetsuo Handa 35582e0f001STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, 35682e0f001STetsuo Handa head.list) { 35782e0f001STetsuo Handa if (!ptr->head.is_deleted && 358b69a54eeSKentaro Takeda tomoyo_path_matches_pattern(filename, ptr->filename)) { 359b69a54eeSKentaro Takeda found = true; 360b69a54eeSKentaro Takeda break; 361b69a54eeSKentaro Takeda } 362b69a54eeSKentaro Takeda } 363b69a54eeSKentaro Takeda return found; 364b69a54eeSKentaro Takeda } 365b69a54eeSKentaro Takeda 366b69a54eeSKentaro Takeda /** 367b69a54eeSKentaro Takeda * tomoyo_write_globally_readable_policy - Write "struct tomoyo_globally_readable_file_entry" list. 368b69a54eeSKentaro Takeda * 369b69a54eeSKentaro Takeda * @data: String to parse. 370b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 371b69a54eeSKentaro Takeda * 372b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 373fdb8ebb7STetsuo Handa * 374fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 375b69a54eeSKentaro Takeda */ 376b69a54eeSKentaro Takeda int tomoyo_write_globally_readable_policy(char *data, const bool is_delete) 377b69a54eeSKentaro Takeda { 378b69a54eeSKentaro Takeda return tomoyo_update_globally_readable_entry(data, is_delete); 379b69a54eeSKentaro Takeda } 380b69a54eeSKentaro Takeda 381b69a54eeSKentaro Takeda /** 382b69a54eeSKentaro Takeda * tomoyo_read_globally_readable_policy - Read "struct tomoyo_globally_readable_file_entry" list. 383b69a54eeSKentaro Takeda * 384b69a54eeSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 385b69a54eeSKentaro Takeda * 386b69a54eeSKentaro Takeda * Returns true on success, false otherwise. 387fdb8ebb7STetsuo Handa * 388fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 389b69a54eeSKentaro Takeda */ 390b69a54eeSKentaro Takeda bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) 391b69a54eeSKentaro Takeda { 392b69a54eeSKentaro Takeda struct list_head *pos; 393b69a54eeSKentaro Takeda bool done = true; 394b69a54eeSKentaro Takeda 395b69a54eeSKentaro Takeda list_for_each_cookie(pos, head->read_var2, 396b69a54eeSKentaro Takeda &tomoyo_globally_readable_list) { 397b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry *ptr; 398b69a54eeSKentaro Takeda ptr = list_entry(pos, 399b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry, 40082e0f001STetsuo Handa head.list); 40182e0f001STetsuo Handa if (ptr->head.is_deleted) 402b69a54eeSKentaro Takeda continue; 4037d2948b1STetsuo Handa done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n", 4047d2948b1STetsuo Handa ptr->filename->name); 4057d2948b1STetsuo Handa if (!done) 406b69a54eeSKentaro Takeda break; 407b69a54eeSKentaro Takeda } 408b69a54eeSKentaro Takeda return done; 409b69a54eeSKentaro Takeda } 410b69a54eeSKentaro Takeda 411c3fa109aSTetsuo Handa /* tomoyo_pattern_list is used for holding list of pathnames which are used for 412c3fa109aSTetsuo Handa * converting pathnames to pathname patterns during learning mode. 413c3fa109aSTetsuo Handa * 414c3fa109aSTetsuo Handa * An entry is added by 415c3fa109aSTetsuo Handa * 416c3fa109aSTetsuo Handa * # echo 'file_pattern /proc/\$/mounts' > \ 417c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 418c3fa109aSTetsuo Handa * 419c3fa109aSTetsuo Handa * and is deleted by 420c3fa109aSTetsuo Handa * 421c3fa109aSTetsuo Handa * # echo 'delete file_pattern /proc/\$/mounts' > \ 422c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 423c3fa109aSTetsuo Handa * 424c3fa109aSTetsuo Handa * and all entries are retrieved by 425c3fa109aSTetsuo Handa * 426c3fa109aSTetsuo Handa * # grep ^file_pattern /sys/kernel/security/tomoyo/exception_policy 427c3fa109aSTetsuo Handa * 428c3fa109aSTetsuo Handa * In the example above, if a process which belongs to a domain which is in 429c3fa109aSTetsuo Handa * learning mode requested open("/proc/1/mounts", O_RDONLY), 430c3fa109aSTetsuo Handa * "allow_read /proc/\$/mounts" is automatically added to the domain which that 431c3fa109aSTetsuo Handa * process belongs to. 432c3fa109aSTetsuo Handa * 433c3fa109aSTetsuo Handa * It is not a desirable behavior that we have to use /proc/\$/ instead of 434c3fa109aSTetsuo Handa * /proc/self/ when current process needs to access only current process's 435c3fa109aSTetsuo Handa * information. As of now, LSM version of TOMOYO is using __d_path() for 436c3fa109aSTetsuo Handa * calculating pathname. Non LSM version of TOMOYO is using its own function 437c3fa109aSTetsuo Handa * which pretends as if /proc/self/ is not a symlink; so that we can forbid 438c3fa109aSTetsuo Handa * current process from accessing other process's information. 439c3fa109aSTetsuo Handa */ 440847b173eSTetsuo Handa LIST_HEAD(tomoyo_pattern_list); 441b69a54eeSKentaro Takeda 44236f5e1ffSTetsuo Handa static bool tomoyo_same_pattern(const struct tomoyo_acl_head *a, 44336f5e1ffSTetsuo Handa const struct tomoyo_acl_head *b) 44436f5e1ffSTetsuo Handa { 44536f5e1ffSTetsuo Handa return container_of(a, struct tomoyo_pattern_entry, head)->pattern == 44636f5e1ffSTetsuo Handa container_of(b, struct tomoyo_pattern_entry, head)->pattern; 44736f5e1ffSTetsuo Handa } 44836f5e1ffSTetsuo Handa 449b69a54eeSKentaro Takeda /** 450b69a54eeSKentaro Takeda * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list. 451b69a54eeSKentaro Takeda * 452b69a54eeSKentaro Takeda * @pattern: Pathname pattern. 453b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 454b69a54eeSKentaro Takeda * 455b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 456fdb8ebb7STetsuo Handa * 457fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 458b69a54eeSKentaro Takeda */ 459b69a54eeSKentaro Takeda static int tomoyo_update_file_pattern_entry(const char *pattern, 460b69a54eeSKentaro Takeda const bool is_delete) 461b69a54eeSKentaro Takeda { 4623f629636STetsuo Handa struct tomoyo_pattern_entry e = { }; 46336f5e1ffSTetsuo Handa int error; 464b69a54eeSKentaro Takeda 46575093152STetsuo Handa if (!tomoyo_correct_word(pattern)) 4663f629636STetsuo Handa return -EINVAL; 4673f629636STetsuo Handa e.pattern = tomoyo_get_name(pattern); 4689e4b50e9STetsuo Handa if (!e.pattern) 46936f5e1ffSTetsuo Handa return -ENOMEM; 47036f5e1ffSTetsuo Handa error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, 47136f5e1ffSTetsuo Handa &tomoyo_pattern_list, 47236f5e1ffSTetsuo Handa tomoyo_same_pattern); 4739e4b50e9STetsuo Handa tomoyo_put_name(e.pattern); 474b69a54eeSKentaro Takeda return error; 475b69a54eeSKentaro Takeda } 476b69a54eeSKentaro Takeda 477b69a54eeSKentaro Takeda /** 47817fcfbd9STetsuo Handa * tomoyo_file_pattern - Get patterned pathname. 479b69a54eeSKentaro Takeda * 480b69a54eeSKentaro Takeda * @filename: The filename to find patterned pathname. 481b69a54eeSKentaro Takeda * 482b69a54eeSKentaro Takeda * Returns pointer to pathname pattern if matched, @filename otherwise. 483fdb8ebb7STetsuo Handa * 484fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 485b69a54eeSKentaro Takeda */ 48617fcfbd9STetsuo Handa const char *tomoyo_file_pattern(const struct tomoyo_path_info *filename) 487b69a54eeSKentaro Takeda { 488b69a54eeSKentaro Takeda struct tomoyo_pattern_entry *ptr; 489b69a54eeSKentaro Takeda const struct tomoyo_path_info *pattern = NULL; 490b69a54eeSKentaro Takeda 49182e0f001STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, head.list) { 49282e0f001STetsuo Handa if (ptr->head.is_deleted) 493b69a54eeSKentaro Takeda continue; 494b69a54eeSKentaro Takeda if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) 495b69a54eeSKentaro Takeda continue; 496b69a54eeSKentaro Takeda pattern = ptr->pattern; 497b69a54eeSKentaro Takeda if (tomoyo_strendswith(pattern->name, "/\\*")) { 498b69a54eeSKentaro Takeda /* Do nothing. Try to find the better match. */ 499b69a54eeSKentaro Takeda } else { 500b69a54eeSKentaro Takeda /* This would be the better match. Use this. */ 501b69a54eeSKentaro Takeda break; 502b69a54eeSKentaro Takeda } 503b69a54eeSKentaro Takeda } 504b69a54eeSKentaro Takeda if (pattern) 505b69a54eeSKentaro Takeda filename = pattern; 50617fcfbd9STetsuo Handa return filename->name; 507b69a54eeSKentaro Takeda } 508b69a54eeSKentaro Takeda 509b69a54eeSKentaro Takeda /** 510b69a54eeSKentaro Takeda * tomoyo_write_pattern_policy - Write "struct tomoyo_pattern_entry" list. 511b69a54eeSKentaro Takeda * 512b69a54eeSKentaro Takeda * @data: String to parse. 513b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 514b69a54eeSKentaro Takeda * 515b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 516fdb8ebb7STetsuo Handa * 517fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 518b69a54eeSKentaro Takeda */ 519b69a54eeSKentaro Takeda int tomoyo_write_pattern_policy(char *data, const bool is_delete) 520b69a54eeSKentaro Takeda { 521b69a54eeSKentaro Takeda return tomoyo_update_file_pattern_entry(data, is_delete); 522b69a54eeSKentaro Takeda } 523b69a54eeSKentaro Takeda 524b69a54eeSKentaro Takeda /** 525b69a54eeSKentaro Takeda * tomoyo_read_file_pattern - Read "struct tomoyo_pattern_entry" list. 526b69a54eeSKentaro Takeda * 527b69a54eeSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 528b69a54eeSKentaro Takeda * 529b69a54eeSKentaro Takeda * Returns true on success, false otherwise. 530fdb8ebb7STetsuo Handa * 531fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 532b69a54eeSKentaro Takeda */ 533b69a54eeSKentaro Takeda bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) 534b69a54eeSKentaro Takeda { 535b69a54eeSKentaro Takeda struct list_head *pos; 536b69a54eeSKentaro Takeda bool done = true; 537b69a54eeSKentaro Takeda 538b69a54eeSKentaro Takeda list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) { 539b69a54eeSKentaro Takeda struct tomoyo_pattern_entry *ptr; 54082e0f001STetsuo Handa ptr = list_entry(pos, struct tomoyo_pattern_entry, head.list); 54182e0f001STetsuo Handa if (ptr->head.is_deleted) 542b69a54eeSKentaro Takeda continue; 5437d2948b1STetsuo Handa done = tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN 5447d2948b1STetsuo Handa "%s\n", ptr->pattern->name); 5457d2948b1STetsuo Handa if (!done) 546b69a54eeSKentaro Takeda break; 547b69a54eeSKentaro Takeda } 548b69a54eeSKentaro Takeda return done; 549b69a54eeSKentaro Takeda } 550b69a54eeSKentaro Takeda 551c3fa109aSTetsuo Handa /* 552c3fa109aSTetsuo Handa * tomoyo_no_rewrite_list is used for holding list of pathnames which are by 553c3fa109aSTetsuo Handa * default forbidden to modify already written content of a file. 554c3fa109aSTetsuo Handa * 555c3fa109aSTetsuo Handa * An entry is added by 556c3fa109aSTetsuo Handa * 557c3fa109aSTetsuo Handa * # echo 'deny_rewrite /var/log/messages' > \ 558c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 559c3fa109aSTetsuo Handa * 560c3fa109aSTetsuo Handa * and is deleted by 561c3fa109aSTetsuo Handa * 562c3fa109aSTetsuo Handa * # echo 'delete deny_rewrite /var/log/messages' > \ 563c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 564c3fa109aSTetsuo Handa * 565c3fa109aSTetsuo Handa * and all entries are retrieved by 566c3fa109aSTetsuo Handa * 567c3fa109aSTetsuo Handa * # grep ^deny_rewrite /sys/kernel/security/tomoyo/exception_policy 568c3fa109aSTetsuo Handa * 569c3fa109aSTetsuo Handa * In the example above, if a process requested to rewrite /var/log/messages , 570c3fa109aSTetsuo Handa * the process can't rewrite unless the domain which that process belongs to 571c3fa109aSTetsuo Handa * has "allow_rewrite /var/log/messages" entry. 572c3fa109aSTetsuo Handa * 573c3fa109aSTetsuo Handa * It is not a desirable behavior that we have to add "\040(deleted)" suffix 574c3fa109aSTetsuo Handa * when we want to allow rewriting already unlink()ed file. As of now, 575c3fa109aSTetsuo Handa * LSM version of TOMOYO is using __d_path() for calculating pathname. 576c3fa109aSTetsuo Handa * Non LSM version of TOMOYO is using its own function which doesn't append 577c3fa109aSTetsuo Handa * " (deleted)" suffix if the file is already unlink()ed; so that we don't 578c3fa109aSTetsuo Handa * need to worry whether the file is already unlink()ed or not. 579c3fa109aSTetsuo Handa */ 580847b173eSTetsuo Handa LIST_HEAD(tomoyo_no_rewrite_list); 581b69a54eeSKentaro Takeda 58236f5e1ffSTetsuo Handa static bool tomoyo_same_no_rewrite(const struct tomoyo_acl_head *a, 58336f5e1ffSTetsuo Handa const struct tomoyo_acl_head *b) 58436f5e1ffSTetsuo Handa { 58536f5e1ffSTetsuo Handa return container_of(a, struct tomoyo_no_rewrite_entry, head)->pattern 58636f5e1ffSTetsuo Handa == container_of(b, struct tomoyo_no_rewrite_entry, head) 58736f5e1ffSTetsuo Handa ->pattern; 58836f5e1ffSTetsuo Handa } 58936f5e1ffSTetsuo Handa 590b69a54eeSKentaro Takeda /** 591b69a54eeSKentaro Takeda * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list. 592b69a54eeSKentaro Takeda * 593b69a54eeSKentaro Takeda * @pattern: Pathname pattern that are not rewritable by default. 594b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 595b69a54eeSKentaro Takeda * 596b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 597fdb8ebb7STetsuo Handa * 598fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 599b69a54eeSKentaro Takeda */ 600b69a54eeSKentaro Takeda static int tomoyo_update_no_rewrite_entry(const char *pattern, 601b69a54eeSKentaro Takeda const bool is_delete) 602b69a54eeSKentaro Takeda { 6039e4b50e9STetsuo Handa struct tomoyo_no_rewrite_entry e = { }; 60436f5e1ffSTetsuo Handa int error; 605b69a54eeSKentaro Takeda 60675093152STetsuo Handa if (!tomoyo_correct_word(pattern)) 607b69a54eeSKentaro Takeda return -EINVAL; 6089e4b50e9STetsuo Handa e.pattern = tomoyo_get_name(pattern); 6099e4b50e9STetsuo Handa if (!e.pattern) 61036f5e1ffSTetsuo Handa return -ENOMEM; 61136f5e1ffSTetsuo Handa error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, 61236f5e1ffSTetsuo Handa &tomoyo_no_rewrite_list, 61336f5e1ffSTetsuo Handa tomoyo_same_no_rewrite); 6149e4b50e9STetsuo Handa tomoyo_put_name(e.pattern); 615b69a54eeSKentaro Takeda return error; 616b69a54eeSKentaro Takeda } 617b69a54eeSKentaro Takeda 618b69a54eeSKentaro Takeda /** 61975093152STetsuo Handa * tomoyo_no_rewrite_file - Check if the given pathname is not permitted to be rewrited. 620b69a54eeSKentaro Takeda * 621b69a54eeSKentaro Takeda * @filename: Filename to check. 622b69a54eeSKentaro Takeda * 623b69a54eeSKentaro Takeda * Returns true if @filename is specified by "deny_rewrite" directive, 624b69a54eeSKentaro Takeda * false otherwise. 625fdb8ebb7STetsuo Handa * 626fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 627b69a54eeSKentaro Takeda */ 62875093152STetsuo Handa static bool tomoyo_no_rewrite_file(const struct tomoyo_path_info *filename) 629b69a54eeSKentaro Takeda { 630b69a54eeSKentaro Takeda struct tomoyo_no_rewrite_entry *ptr; 631b69a54eeSKentaro Takeda bool found = false; 632b69a54eeSKentaro Takeda 63382e0f001STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, head.list) { 63482e0f001STetsuo Handa if (ptr->head.is_deleted) 635b69a54eeSKentaro Takeda continue; 636b69a54eeSKentaro Takeda if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) 637b69a54eeSKentaro Takeda continue; 638b69a54eeSKentaro Takeda found = true; 639b69a54eeSKentaro Takeda break; 640b69a54eeSKentaro Takeda } 641b69a54eeSKentaro Takeda return found; 642b69a54eeSKentaro Takeda } 643b69a54eeSKentaro Takeda 644b69a54eeSKentaro Takeda /** 645b69a54eeSKentaro Takeda * tomoyo_write_no_rewrite_policy - Write "struct tomoyo_no_rewrite_entry" list. 646b69a54eeSKentaro Takeda * 647b69a54eeSKentaro Takeda * @data: String to parse. 648b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 649b69a54eeSKentaro Takeda * 650b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 651fdb8ebb7STetsuo Handa * 652fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 653b69a54eeSKentaro Takeda */ 654b69a54eeSKentaro Takeda int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete) 655b69a54eeSKentaro Takeda { 656b69a54eeSKentaro Takeda return tomoyo_update_no_rewrite_entry(data, is_delete); 657b69a54eeSKentaro Takeda } 658b69a54eeSKentaro Takeda 659b69a54eeSKentaro Takeda /** 660b69a54eeSKentaro Takeda * tomoyo_read_no_rewrite_policy - Read "struct tomoyo_no_rewrite_entry" list. 661b69a54eeSKentaro Takeda * 662b69a54eeSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 663b69a54eeSKentaro Takeda * 664b69a54eeSKentaro Takeda * Returns true on success, false otherwise. 665fdb8ebb7STetsuo Handa * 666fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 667b69a54eeSKentaro Takeda */ 668b69a54eeSKentaro Takeda bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) 669b69a54eeSKentaro Takeda { 670b69a54eeSKentaro Takeda struct list_head *pos; 671b69a54eeSKentaro Takeda bool done = true; 672b69a54eeSKentaro Takeda 673b69a54eeSKentaro Takeda list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) { 674b69a54eeSKentaro Takeda struct tomoyo_no_rewrite_entry *ptr; 67582e0f001STetsuo Handa ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, 67682e0f001STetsuo Handa head.list); 67782e0f001STetsuo Handa if (ptr->head.is_deleted) 678b69a54eeSKentaro Takeda continue; 6797d2948b1STetsuo Handa done = tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE 6807d2948b1STetsuo Handa "%s\n", ptr->pattern->name); 6817d2948b1STetsuo Handa if (!done) 682b69a54eeSKentaro Takeda break; 683b69a54eeSKentaro Takeda } 684b69a54eeSKentaro Takeda return done; 685b69a54eeSKentaro Takeda } 686b69a54eeSKentaro Takeda 68799a85259STetsuo Handa static bool tomoyo_check_path_acl(const struct tomoyo_request_info *r, 68899a85259STetsuo Handa const struct tomoyo_acl_info *ptr) 689b69a54eeSKentaro Takeda { 69099a85259STetsuo Handa const struct tomoyo_path_acl *acl = container_of(ptr, typeof(*acl), 69199a85259STetsuo Handa head); 69299a85259STetsuo Handa return (acl->perm & (1 << r->param.path.operation)) && 69399a85259STetsuo Handa tomoyo_compare_name_union(r->param.path.filename, &acl->name); 694b69a54eeSKentaro Takeda } 69599a85259STetsuo Handa 69699a85259STetsuo Handa static bool tomoyo_check_path_number_acl(const struct tomoyo_request_info *r, 69799a85259STetsuo Handa const struct tomoyo_acl_info *ptr) 69899a85259STetsuo Handa { 69999a85259STetsuo Handa const struct tomoyo_path_number_acl *acl = 70099a85259STetsuo Handa container_of(ptr, typeof(*acl), head); 70199a85259STetsuo Handa return (acl->perm & (1 << r->param.path_number.operation)) && 70299a85259STetsuo Handa tomoyo_compare_number_union(r->param.path_number.number, 70399a85259STetsuo Handa &acl->number) && 70499a85259STetsuo Handa tomoyo_compare_name_union(r->param.path_number.filename, 70599a85259STetsuo Handa &acl->name); 70699a85259STetsuo Handa } 70799a85259STetsuo Handa 70899a85259STetsuo Handa static bool tomoyo_check_path2_acl(const struct tomoyo_request_info *r, 70999a85259STetsuo Handa const struct tomoyo_acl_info *ptr) 71099a85259STetsuo Handa { 71199a85259STetsuo Handa const struct tomoyo_path2_acl *acl = 71299a85259STetsuo Handa container_of(ptr, typeof(*acl), head); 71399a85259STetsuo Handa return (acl->perm & (1 << r->param.path2.operation)) && 71499a85259STetsuo Handa tomoyo_compare_name_union(r->param.path2.filename1, &acl->name1) 71599a85259STetsuo Handa && tomoyo_compare_name_union(r->param.path2.filename2, 71699a85259STetsuo Handa &acl->name2); 71799a85259STetsuo Handa } 71899a85259STetsuo Handa 71999a85259STetsuo Handa static bool tomoyo_check_mkdev_acl(const struct tomoyo_request_info *r, 72099a85259STetsuo Handa const struct tomoyo_acl_info *ptr) 72199a85259STetsuo Handa { 72275093152STetsuo Handa const struct tomoyo_mkdev_acl *acl = 72399a85259STetsuo Handa container_of(ptr, typeof(*acl), head); 72499a85259STetsuo Handa return (acl->perm & (1 << r->param.mkdev.operation)) && 72599a85259STetsuo Handa tomoyo_compare_number_union(r->param.mkdev.mode, 72699a85259STetsuo Handa &acl->mode) && 72799a85259STetsuo Handa tomoyo_compare_number_union(r->param.mkdev.major, 72899a85259STetsuo Handa &acl->major) && 72999a85259STetsuo Handa tomoyo_compare_number_union(r->param.mkdev.minor, 73099a85259STetsuo Handa &acl->minor) && 73199a85259STetsuo Handa tomoyo_compare_name_union(r->param.mkdev.filename, 73299a85259STetsuo Handa &acl->name); 733b69a54eeSKentaro Takeda } 734b69a54eeSKentaro Takeda 735237ab459STetsuo Handa static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a, 736237ab459STetsuo Handa const struct tomoyo_acl_info *b) 737237ab459STetsuo Handa { 738237ab459STetsuo Handa const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head); 739237ab459STetsuo Handa const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head); 74075093152STetsuo Handa return tomoyo_same_acl_head(&p1->head, &p2->head) && 74175093152STetsuo Handa tomoyo_same_name_union(&p1->name, &p2->name); 742237ab459STetsuo Handa } 743237ab459STetsuo Handa 744237ab459STetsuo Handa static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a, 745237ab459STetsuo Handa struct tomoyo_acl_info *b, 746237ab459STetsuo Handa const bool is_delete) 747237ab459STetsuo Handa { 748237ab459STetsuo Handa u16 * const a_perm = &container_of(a, struct tomoyo_path_acl, head) 749237ab459STetsuo Handa ->perm; 750237ab459STetsuo Handa u16 perm = *a_perm; 751237ab459STetsuo Handa const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm; 752237ab459STetsuo Handa if (is_delete) { 753237ab459STetsuo Handa perm &= ~b_perm; 754237ab459STetsuo Handa if ((perm & TOMOYO_RW_MASK) != TOMOYO_RW_MASK) 755237ab459STetsuo Handa perm &= ~(1 << TOMOYO_TYPE_READ_WRITE); 756237ab459STetsuo Handa else if (!(perm & (1 << TOMOYO_TYPE_READ_WRITE))) 757237ab459STetsuo Handa perm &= ~TOMOYO_RW_MASK; 758237ab459STetsuo Handa } else { 759237ab459STetsuo Handa perm |= b_perm; 760237ab459STetsuo Handa if ((perm & TOMOYO_RW_MASK) == TOMOYO_RW_MASK) 761237ab459STetsuo Handa perm |= (1 << TOMOYO_TYPE_READ_WRITE); 762237ab459STetsuo Handa else if (perm & (1 << TOMOYO_TYPE_READ_WRITE)) 763237ab459STetsuo Handa perm |= TOMOYO_RW_MASK; 764237ab459STetsuo Handa } 765237ab459STetsuo Handa *a_perm = perm; 766237ab459STetsuo Handa return !perm; 767237ab459STetsuo Handa } 768237ab459STetsuo Handa 769b69a54eeSKentaro Takeda /** 7707ef61233STetsuo Handa * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list. 771b69a54eeSKentaro Takeda * 772b69a54eeSKentaro Takeda * @type: Type of operation. 773b69a54eeSKentaro Takeda * @filename: Filename. 774b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 775b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 776b69a54eeSKentaro Takeda * 777b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 778fdb8ebb7STetsuo Handa * 779fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 780b69a54eeSKentaro Takeda */ 7817ef61233STetsuo Handa static int tomoyo_update_path_acl(const u8 type, const char *filename, 7827ef61233STetsuo Handa struct tomoyo_domain_info * const domain, 7837ef61233STetsuo Handa const bool is_delete) 784b69a54eeSKentaro Takeda { 7859e4b50e9STetsuo Handa struct tomoyo_path_acl e = { 7869e4b50e9STetsuo Handa .head.type = TOMOYO_TYPE_PATH_ACL, 787237ab459STetsuo Handa .perm = 1 << type 7889e4b50e9STetsuo Handa }; 789237ab459STetsuo Handa int error; 790237ab459STetsuo Handa if (e.perm == (1 << TOMOYO_TYPE_READ_WRITE)) 791237ab459STetsuo Handa e.perm |= TOMOYO_RW_MASK; 7927762fbffSTetsuo Handa if (!tomoyo_parse_name_union(filename, &e.name)) 793b69a54eeSKentaro Takeda return -EINVAL; 794237ab459STetsuo Handa error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, 795237ab459STetsuo Handa tomoyo_same_path_acl, 796237ab459STetsuo Handa tomoyo_merge_path_acl); 7977762fbffSTetsuo Handa tomoyo_put_name_union(&e.name); 798b69a54eeSKentaro Takeda return error; 799b69a54eeSKentaro Takeda } 800b69a54eeSKentaro Takeda 80175093152STetsuo Handa static bool tomoyo_same_mkdev_acl(const struct tomoyo_acl_info *a, 802237ab459STetsuo Handa const struct tomoyo_acl_info *b) 803237ab459STetsuo Handa { 80475093152STetsuo Handa const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1), 805237ab459STetsuo Handa head); 80675093152STetsuo Handa const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2), 807237ab459STetsuo Handa head); 80875093152STetsuo Handa return tomoyo_same_acl_head(&p1->head, &p2->head) 80975093152STetsuo Handa && tomoyo_same_name_union(&p1->name, &p2->name) 81075093152STetsuo Handa && tomoyo_same_number_union(&p1->mode, &p2->mode) 81175093152STetsuo Handa && tomoyo_same_number_union(&p1->major, &p2->major) 81275093152STetsuo Handa && tomoyo_same_number_union(&p1->minor, &p2->minor); 813237ab459STetsuo Handa } 814237ab459STetsuo Handa 81575093152STetsuo Handa static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a, 816237ab459STetsuo Handa struct tomoyo_acl_info *b, 817237ab459STetsuo Handa const bool is_delete) 818237ab459STetsuo Handa { 81975093152STetsuo Handa u8 *const a_perm = &container_of(a, struct tomoyo_mkdev_acl, 820237ab459STetsuo Handa head)->perm; 821237ab459STetsuo Handa u8 perm = *a_perm; 82275093152STetsuo Handa const u8 b_perm = container_of(b, struct tomoyo_mkdev_acl, head) 823237ab459STetsuo Handa ->perm; 824237ab459STetsuo Handa if (is_delete) 825237ab459STetsuo Handa perm &= ~b_perm; 826237ab459STetsuo Handa else 827237ab459STetsuo Handa perm |= b_perm; 828237ab459STetsuo Handa *a_perm = perm; 829237ab459STetsuo Handa return !perm; 830237ab459STetsuo Handa } 831237ab459STetsuo Handa 832b69a54eeSKentaro Takeda /** 83375093152STetsuo Handa * tomoyo_update_mkdev_acl - Update "struct tomoyo_mkdev_acl" list. 834a1f9bb6aSTetsuo Handa * 835a1f9bb6aSTetsuo Handa * @type: Type of operation. 836a1f9bb6aSTetsuo Handa * @filename: Filename. 837a1f9bb6aSTetsuo Handa * @mode: Create mode. 838a1f9bb6aSTetsuo Handa * @major: Device major number. 839a1f9bb6aSTetsuo Handa * @minor: Device minor number. 840a1f9bb6aSTetsuo Handa * @domain: Pointer to "struct tomoyo_domain_info". 841a1f9bb6aSTetsuo Handa * @is_delete: True if it is a delete request. 842a1f9bb6aSTetsuo Handa * 843a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 844237ab459STetsuo Handa * 845237ab459STetsuo Handa * Caller holds tomoyo_read_lock(). 846a1f9bb6aSTetsuo Handa */ 84775093152STetsuo Handa static int tomoyo_update_mkdev_acl(const u8 type, const char *filename, 848237ab459STetsuo Handa char *mode, char *major, char *minor, 849237ab459STetsuo Handa struct tomoyo_domain_info * const 850237ab459STetsuo Handa domain, const bool is_delete) 851a1f9bb6aSTetsuo Handa { 85275093152STetsuo Handa struct tomoyo_mkdev_acl e = { 85375093152STetsuo Handa .head.type = TOMOYO_TYPE_MKDEV_ACL, 854237ab459STetsuo Handa .perm = 1 << type 855a1f9bb6aSTetsuo Handa }; 856a1f9bb6aSTetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 857a1f9bb6aSTetsuo Handa if (!tomoyo_parse_name_union(filename, &e.name) || 858a1f9bb6aSTetsuo Handa !tomoyo_parse_number_union(mode, &e.mode) || 859a1f9bb6aSTetsuo Handa !tomoyo_parse_number_union(major, &e.major) || 860a1f9bb6aSTetsuo Handa !tomoyo_parse_number_union(minor, &e.minor)) 861a1f9bb6aSTetsuo Handa goto out; 862237ab459STetsuo Handa error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, 86375093152STetsuo Handa tomoyo_same_mkdev_acl, 86475093152STetsuo Handa tomoyo_merge_mkdev_acl); 865a1f9bb6aSTetsuo Handa out: 866a1f9bb6aSTetsuo Handa tomoyo_put_name_union(&e.name); 867a1f9bb6aSTetsuo Handa tomoyo_put_number_union(&e.mode); 868a1f9bb6aSTetsuo Handa tomoyo_put_number_union(&e.major); 869a1f9bb6aSTetsuo Handa tomoyo_put_number_union(&e.minor); 870a1f9bb6aSTetsuo Handa return error; 871a1f9bb6aSTetsuo Handa } 872a1f9bb6aSTetsuo Handa 873237ab459STetsuo Handa static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a, 874237ab459STetsuo Handa const struct tomoyo_acl_info *b) 875237ab459STetsuo Handa { 876237ab459STetsuo Handa const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head); 877237ab459STetsuo Handa const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head); 87875093152STetsuo Handa return tomoyo_same_acl_head(&p1->head, &p2->head) 87975093152STetsuo Handa && tomoyo_same_name_union(&p1->name1, &p2->name1) 88075093152STetsuo Handa && tomoyo_same_name_union(&p1->name2, &p2->name2); 881237ab459STetsuo Handa } 882237ab459STetsuo Handa 883237ab459STetsuo Handa static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a, 884237ab459STetsuo Handa struct tomoyo_acl_info *b, 885237ab459STetsuo Handa const bool is_delete) 886237ab459STetsuo Handa { 887237ab459STetsuo Handa u8 * const a_perm = &container_of(a, struct tomoyo_path2_acl, head) 888237ab459STetsuo Handa ->perm; 889237ab459STetsuo Handa u8 perm = *a_perm; 890237ab459STetsuo Handa const u8 b_perm = container_of(b, struct tomoyo_path2_acl, head)->perm; 891237ab459STetsuo Handa if (is_delete) 892237ab459STetsuo Handa perm &= ~b_perm; 893237ab459STetsuo Handa else 894237ab459STetsuo Handa perm |= b_perm; 895237ab459STetsuo Handa *a_perm = perm; 896237ab459STetsuo Handa return !perm; 897237ab459STetsuo Handa } 898237ab459STetsuo Handa 899a1f9bb6aSTetsuo Handa /** 9007ef61233STetsuo Handa * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list. 901b69a54eeSKentaro Takeda * 902b69a54eeSKentaro Takeda * @type: Type of operation. 903b69a54eeSKentaro Takeda * @filename1: First filename. 904b69a54eeSKentaro Takeda * @filename2: Second filename. 905b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 906b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 907b69a54eeSKentaro Takeda * 908b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 909fdb8ebb7STetsuo Handa * 910fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 911b69a54eeSKentaro Takeda */ 9127ef61233STetsuo Handa static int tomoyo_update_path2_acl(const u8 type, const char *filename1, 913b69a54eeSKentaro Takeda const char *filename2, 9147ef61233STetsuo Handa struct tomoyo_domain_info * const domain, 9157ef61233STetsuo Handa const bool is_delete) 916b69a54eeSKentaro Takeda { 9179e4b50e9STetsuo Handa struct tomoyo_path2_acl e = { 9189e4b50e9STetsuo Handa .head.type = TOMOYO_TYPE_PATH2_ACL, 919237ab459STetsuo Handa .perm = 1 << type 9209e4b50e9STetsuo Handa }; 9219e4b50e9STetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 9227762fbffSTetsuo Handa if (!tomoyo_parse_name_union(filename1, &e.name1) || 9237762fbffSTetsuo Handa !tomoyo_parse_name_union(filename2, &e.name2)) 924ca0b7df3STetsuo Handa goto out; 925237ab459STetsuo Handa error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, 926237ab459STetsuo Handa tomoyo_same_path2_acl, 927237ab459STetsuo Handa tomoyo_merge_path2_acl); 928ca0b7df3STetsuo Handa out: 9297762fbffSTetsuo Handa tomoyo_put_name_union(&e.name1); 9307762fbffSTetsuo Handa tomoyo_put_name_union(&e.name2); 931b69a54eeSKentaro Takeda return error; 932b69a54eeSKentaro Takeda } 933b69a54eeSKentaro Takeda 934b69a54eeSKentaro Takeda /** 935cb0abe6aSTetsuo Handa * tomoyo_path_permission - Check permission for single path operation. 936b69a54eeSKentaro Takeda * 937cb0abe6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 938b69a54eeSKentaro Takeda * @operation: Type of operation. 939b69a54eeSKentaro Takeda * @filename: Filename to check. 940b69a54eeSKentaro Takeda * 941b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 942fdb8ebb7STetsuo Handa * 943fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 944b69a54eeSKentaro Takeda */ 94505336deeSTetsuo Handa int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, 946cb0abe6aSTetsuo Handa const struct tomoyo_path_info *filename) 947b69a54eeSKentaro Takeda { 948b69a54eeSKentaro Takeda int error; 949b69a54eeSKentaro Takeda 950b69a54eeSKentaro Takeda next: 95157c2590fSTetsuo Handa r->type = tomoyo_p2mac[operation]; 95257c2590fSTetsuo Handa r->mode = tomoyo_get_mode(r->profile, r->type); 95357c2590fSTetsuo Handa if (r->mode == TOMOYO_CONFIG_DISABLED) 95457c2590fSTetsuo Handa return 0; 955cf6e9a64STetsuo Handa r->param_type = TOMOYO_TYPE_PATH_ACL; 956cf6e9a64STetsuo Handa r->param.path.filename = filename; 957cf6e9a64STetsuo Handa r->param.path.operation = operation; 95817fcfbd9STetsuo Handa do { 95999a85259STetsuo Handa tomoyo_check_acl(r, tomoyo_check_path_acl); 96099a85259STetsuo Handa if (!r->granted && operation == TOMOYO_TYPE_READ && 96105336deeSTetsuo Handa !r->domain->ignore_global_allow_read && 96275093152STetsuo Handa tomoyo_globally_readable_file(filename)) 96399a85259STetsuo Handa r->granted = true; 96499a85259STetsuo Handa error = tomoyo_audit_path_log(r); 96505336deeSTetsuo Handa /* 96605336deeSTetsuo Handa * Do not retry for execute request, for alias may have 96705336deeSTetsuo Handa * changed. 96805336deeSTetsuo Handa */ 96905336deeSTetsuo Handa } while (error == TOMOYO_RETRY_REQUEST && 97005336deeSTetsuo Handa operation != TOMOYO_TYPE_EXECUTE); 971b69a54eeSKentaro Takeda /* 972b69a54eeSKentaro Takeda * Since "allow_truncate" doesn't imply "allow_rewrite" permission, 973b69a54eeSKentaro Takeda * we need to check "allow_rewrite" permission if the filename is 974b69a54eeSKentaro Takeda * specified by "deny_rewrite" keyword. 975b69a54eeSKentaro Takeda */ 9767ef61233STetsuo Handa if (!error && operation == TOMOYO_TYPE_TRUNCATE && 97775093152STetsuo Handa tomoyo_no_rewrite_file(filename)) { 9787ef61233STetsuo Handa operation = TOMOYO_TYPE_REWRITE; 979b69a54eeSKentaro Takeda goto next; 980b69a54eeSKentaro Takeda } 981b69a54eeSKentaro Takeda return error; 982b69a54eeSKentaro Takeda } 983b69a54eeSKentaro Takeda 984237ab459STetsuo Handa static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a, 985237ab459STetsuo Handa const struct tomoyo_acl_info *b) 986237ab459STetsuo Handa { 987237ab459STetsuo Handa const struct tomoyo_path_number_acl *p1 = container_of(a, typeof(*p1), 988237ab459STetsuo Handa head); 989237ab459STetsuo Handa const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2), 990237ab459STetsuo Handa head); 99175093152STetsuo Handa return tomoyo_same_acl_head(&p1->head, &p2->head) 99275093152STetsuo Handa && tomoyo_same_name_union(&p1->name, &p2->name) 99375093152STetsuo Handa && tomoyo_same_number_union(&p1->number, &p2->number); 994237ab459STetsuo Handa } 995237ab459STetsuo Handa 996237ab459STetsuo Handa static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a, 997237ab459STetsuo Handa struct tomoyo_acl_info *b, 998237ab459STetsuo Handa const bool is_delete) 999237ab459STetsuo Handa { 1000237ab459STetsuo Handa u8 * const a_perm = &container_of(a, struct tomoyo_path_number_acl, 1001237ab459STetsuo Handa head)->perm; 1002237ab459STetsuo Handa u8 perm = *a_perm; 1003237ab459STetsuo Handa const u8 b_perm = container_of(b, struct tomoyo_path_number_acl, head) 1004237ab459STetsuo Handa ->perm; 1005237ab459STetsuo Handa if (is_delete) 1006237ab459STetsuo Handa perm &= ~b_perm; 1007237ab459STetsuo Handa else 1008237ab459STetsuo Handa perm |= b_perm; 1009237ab459STetsuo Handa *a_perm = perm; 1010237ab459STetsuo Handa return !perm; 1011237ab459STetsuo Handa } 1012237ab459STetsuo Handa 1013a1f9bb6aSTetsuo Handa /** 1014a1f9bb6aSTetsuo Handa * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL. 1015a1f9bb6aSTetsuo Handa * 1016a1f9bb6aSTetsuo Handa * @type: Type of operation. 1017a1f9bb6aSTetsuo Handa * @filename: Filename. 1018a1f9bb6aSTetsuo Handa * @number: Number. 1019a1f9bb6aSTetsuo Handa * @domain: Pointer to "struct tomoyo_domain_info". 1020a1f9bb6aSTetsuo Handa * @is_delete: True if it is a delete request. 1021a1f9bb6aSTetsuo Handa * 1022a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1023a1f9bb6aSTetsuo Handa */ 1024237ab459STetsuo Handa static int tomoyo_update_path_number_acl(const u8 type, const char *filename, 1025a1f9bb6aSTetsuo Handa char *number, 1026237ab459STetsuo Handa struct tomoyo_domain_info * const 1027237ab459STetsuo Handa domain, 1028a1f9bb6aSTetsuo Handa const bool is_delete) 1029a1f9bb6aSTetsuo Handa { 1030a1f9bb6aSTetsuo Handa struct tomoyo_path_number_acl e = { 1031a1f9bb6aSTetsuo Handa .head.type = TOMOYO_TYPE_PATH_NUMBER_ACL, 1032237ab459STetsuo Handa .perm = 1 << type 1033a1f9bb6aSTetsuo Handa }; 1034a1f9bb6aSTetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 1035a1f9bb6aSTetsuo Handa if (!tomoyo_parse_name_union(filename, &e.name)) 1036a1f9bb6aSTetsuo Handa return -EINVAL; 1037a1f9bb6aSTetsuo Handa if (!tomoyo_parse_number_union(number, &e.number)) 1038a1f9bb6aSTetsuo Handa goto out; 1039237ab459STetsuo Handa error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, 1040237ab459STetsuo Handa tomoyo_same_path_number_acl, 1041237ab459STetsuo Handa tomoyo_merge_path_number_acl); 1042a1f9bb6aSTetsuo Handa out: 1043a1f9bb6aSTetsuo Handa tomoyo_put_name_union(&e.name); 1044a1f9bb6aSTetsuo Handa tomoyo_put_number_union(&e.number); 1045a1f9bb6aSTetsuo Handa return error; 1046a1f9bb6aSTetsuo Handa } 1047a1f9bb6aSTetsuo Handa 1048a1f9bb6aSTetsuo Handa /** 1049a1f9bb6aSTetsuo Handa * tomoyo_path_number_perm2 - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp". 1050a1f9bb6aSTetsuo Handa * 1051a1f9bb6aSTetsuo Handa * @r: Pointer to "strct tomoyo_request_info". 1052a1f9bb6aSTetsuo Handa * @filename: Filename to check. 1053a1f9bb6aSTetsuo Handa * @number: Number. 1054a1f9bb6aSTetsuo Handa * 1055a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1056a1f9bb6aSTetsuo Handa * 1057a1f9bb6aSTetsuo Handa * Caller holds tomoyo_read_lock(). 1058a1f9bb6aSTetsuo Handa */ 1059a1f9bb6aSTetsuo Handa static int tomoyo_path_number_perm2(struct tomoyo_request_info *r, 1060a1f9bb6aSTetsuo Handa const u8 type, 1061a1f9bb6aSTetsuo Handa const struct tomoyo_path_info *filename, 1062a1f9bb6aSTetsuo Handa const unsigned long number) 1063a1f9bb6aSTetsuo Handa { 1064a1f9bb6aSTetsuo Handa int error; 1065a1f9bb6aSTetsuo Handa 1066a1f9bb6aSTetsuo Handa if (!filename) 1067a1f9bb6aSTetsuo Handa return 0; 1068cf6e9a64STetsuo Handa r->param_type = TOMOYO_TYPE_PATH_NUMBER_ACL; 1069cf6e9a64STetsuo Handa r->param.path_number.operation = type; 1070cf6e9a64STetsuo Handa r->param.path_number.filename = filename; 1071cf6e9a64STetsuo Handa r->param.path_number.number = number; 107217fcfbd9STetsuo Handa do { 107399a85259STetsuo Handa tomoyo_check_acl(r, tomoyo_check_path_number_acl); 107499a85259STetsuo Handa error = tomoyo_audit_path_number_log(r); 107517fcfbd9STetsuo Handa } while (error == TOMOYO_RETRY_REQUEST); 1076a1f9bb6aSTetsuo Handa return error; 1077a1f9bb6aSTetsuo Handa } 1078a1f9bb6aSTetsuo Handa 1079a1f9bb6aSTetsuo Handa /** 1080a1f9bb6aSTetsuo Handa * tomoyo_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp". 1081a1f9bb6aSTetsuo Handa * 1082a1f9bb6aSTetsuo Handa * @type: Type of operation. 1083a1f9bb6aSTetsuo Handa * @path: Pointer to "struct path". 1084a1f9bb6aSTetsuo Handa * @number: Number. 1085a1f9bb6aSTetsuo Handa * 1086a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1087a1f9bb6aSTetsuo Handa */ 1088a1f9bb6aSTetsuo Handa int tomoyo_path_number_perm(const u8 type, struct path *path, 1089a1f9bb6aSTetsuo Handa unsigned long number) 1090a1f9bb6aSTetsuo Handa { 1091a1f9bb6aSTetsuo Handa struct tomoyo_request_info r; 1092a1f9bb6aSTetsuo Handa int error = -ENOMEM; 1093c8c57e84STetsuo Handa struct tomoyo_path_info buf; 1094a1f9bb6aSTetsuo Handa int idx; 1095a1f9bb6aSTetsuo Handa 109657c2590fSTetsuo Handa if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type]) 109757c2590fSTetsuo Handa == TOMOYO_CONFIG_DISABLED || !path->mnt || !path->dentry) 1098a1f9bb6aSTetsuo Handa return 0; 1099a1f9bb6aSTetsuo Handa idx = tomoyo_read_lock(); 1100c8c57e84STetsuo Handa if (!tomoyo_get_realpath(&buf, path)) 1101a1f9bb6aSTetsuo Handa goto out; 1102c8c57e84STetsuo Handa if (type == TOMOYO_TYPE_MKDIR) 1103c8c57e84STetsuo Handa tomoyo_add_slash(&buf); 1104c8c57e84STetsuo Handa error = tomoyo_path_number_perm2(&r, type, &buf, number); 1105a1f9bb6aSTetsuo Handa out: 1106c8c57e84STetsuo Handa kfree(buf.name); 1107a1f9bb6aSTetsuo Handa tomoyo_read_unlock(idx); 1108a1f9bb6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 1109a1f9bb6aSTetsuo Handa error = 0; 1110a1f9bb6aSTetsuo Handa return error; 1111a1f9bb6aSTetsuo Handa } 1112a1f9bb6aSTetsuo Handa 1113a1f9bb6aSTetsuo Handa /** 1114b69a54eeSKentaro Takeda * tomoyo_check_open_permission - Check permission for "read" and "write". 1115b69a54eeSKentaro Takeda * 1116b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 1117b69a54eeSKentaro Takeda * @path: Pointer to "struct path". 1118b69a54eeSKentaro Takeda * @flag: Flags for open(). 1119b69a54eeSKentaro Takeda * 1120b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1121b69a54eeSKentaro Takeda */ 1122b69a54eeSKentaro Takeda int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, 1123b69a54eeSKentaro Takeda struct path *path, const int flag) 1124b69a54eeSKentaro Takeda { 1125b69a54eeSKentaro Takeda const u8 acc_mode = ACC_MODE(flag); 1126b69a54eeSKentaro Takeda int error = -ENOMEM; 1127c8c57e84STetsuo Handa struct tomoyo_path_info buf; 1128cb0abe6aSTetsuo Handa struct tomoyo_request_info r; 1129fdb8ebb7STetsuo Handa int idx; 1130b69a54eeSKentaro Takeda 113157c2590fSTetsuo Handa if (!path->mnt || 113257c2590fSTetsuo Handa (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode))) 1133b69a54eeSKentaro Takeda return 0; 113457c2590fSTetsuo Handa buf.name = NULL; 113557c2590fSTetsuo Handa r.mode = TOMOYO_CONFIG_DISABLED; 1136fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 1137c8c57e84STetsuo Handa if (!tomoyo_get_realpath(&buf, path)) 1138b69a54eeSKentaro Takeda goto out; 1139b69a54eeSKentaro Takeda error = 0; 1140b69a54eeSKentaro Takeda /* 1141b69a54eeSKentaro Takeda * If the filename is specified by "deny_rewrite" keyword, 1142b69a54eeSKentaro Takeda * we need to check "allow_rewrite" permission when the filename is not 1143b69a54eeSKentaro Takeda * opened for append mode or the filename is truncated at open time. 1144b69a54eeSKentaro Takeda */ 114557c2590fSTetsuo Handa if ((acc_mode & MAY_WRITE) && !(flag & O_APPEND) 114657c2590fSTetsuo Handa && tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_REWRITE) 114757c2590fSTetsuo Handa != TOMOYO_CONFIG_DISABLED) { 114857c2590fSTetsuo Handa if (!tomoyo_get_realpath(&buf, path)) { 114957c2590fSTetsuo Handa error = -ENOMEM; 115057c2590fSTetsuo Handa goto out; 1151b69a54eeSKentaro Takeda } 115275093152STetsuo Handa if (tomoyo_no_rewrite_file(&buf)) 115357c2590fSTetsuo Handa error = tomoyo_path_permission(&r, TOMOYO_TYPE_REWRITE, 115457c2590fSTetsuo Handa &buf); 115557c2590fSTetsuo Handa } 115657c2590fSTetsuo Handa if (!error && acc_mode && 115757c2590fSTetsuo Handa tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN) 115857c2590fSTetsuo Handa != TOMOYO_CONFIG_DISABLED) { 115905336deeSTetsuo Handa u8 operation; 116057c2590fSTetsuo Handa if (!buf.name && !tomoyo_get_realpath(&buf, path)) { 116157c2590fSTetsuo Handa error = -ENOMEM; 116257c2590fSTetsuo Handa goto out; 116357c2590fSTetsuo Handa } 116405336deeSTetsuo Handa if (acc_mode == (MAY_READ | MAY_WRITE)) 116505336deeSTetsuo Handa operation = TOMOYO_TYPE_READ_WRITE; 116605336deeSTetsuo Handa else if (acc_mode == MAY_READ) 116705336deeSTetsuo Handa operation = TOMOYO_TYPE_READ; 116805336deeSTetsuo Handa else 116905336deeSTetsuo Handa operation = TOMOYO_TYPE_WRITE; 117005336deeSTetsuo Handa error = tomoyo_path_permission(&r, operation, &buf); 117157c2590fSTetsuo Handa } 1172b69a54eeSKentaro Takeda out: 1173c8c57e84STetsuo Handa kfree(buf.name); 1174fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 1175cb0abe6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 1176b69a54eeSKentaro Takeda error = 0; 1177b69a54eeSKentaro Takeda return error; 1178b69a54eeSKentaro Takeda } 1179b69a54eeSKentaro Takeda 1180b69a54eeSKentaro Takeda /** 11812106ccd9STetsuo Handa * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "rewrite", "chroot" and "unmount". 1182b69a54eeSKentaro Takeda * 1183b69a54eeSKentaro Takeda * @operation: Type of operation. 1184b69a54eeSKentaro Takeda * @path: Pointer to "struct path". 1185b69a54eeSKentaro Takeda * 1186b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1187b69a54eeSKentaro Takeda */ 118897d6931eSTetsuo Handa int tomoyo_path_perm(const u8 operation, struct path *path) 1189b69a54eeSKentaro Takeda { 1190b69a54eeSKentaro Takeda int error = -ENOMEM; 1191c8c57e84STetsuo Handa struct tomoyo_path_info buf; 1192cb0abe6aSTetsuo Handa struct tomoyo_request_info r; 1193fdb8ebb7STetsuo Handa int idx; 1194b69a54eeSKentaro Takeda 119557c2590fSTetsuo Handa if (!path->mnt) 1196b69a54eeSKentaro Takeda return 0; 119757c2590fSTetsuo Handa if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation]) 119857c2590fSTetsuo Handa == TOMOYO_CONFIG_DISABLED) 119957c2590fSTetsuo Handa return 0; 120057c2590fSTetsuo Handa buf.name = NULL; 1201fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 1202c8c57e84STetsuo Handa if (!tomoyo_get_realpath(&buf, path)) 1203b69a54eeSKentaro Takeda goto out; 1204b69a54eeSKentaro Takeda switch (operation) { 1205cb0abe6aSTetsuo Handa case TOMOYO_TYPE_REWRITE: 120675093152STetsuo Handa if (!tomoyo_no_rewrite_file(&buf)) { 1207cb0abe6aSTetsuo Handa error = 0; 1208cb0abe6aSTetsuo Handa goto out; 1209cb0abe6aSTetsuo Handa } 1210cb0abe6aSTetsuo Handa break; 12117ef61233STetsuo Handa case TOMOYO_TYPE_RMDIR: 12127ef61233STetsuo Handa case TOMOYO_TYPE_CHROOT: 121357c2590fSTetsuo Handa case TOMOYO_TYPE_UMOUNT: 1214c8c57e84STetsuo Handa tomoyo_add_slash(&buf); 1215c8c57e84STetsuo Handa break; 1216b69a54eeSKentaro Takeda } 1217c8c57e84STetsuo Handa error = tomoyo_path_permission(&r, operation, &buf); 1218b69a54eeSKentaro Takeda out: 1219c8c57e84STetsuo Handa kfree(buf.name); 1220fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 1221cb0abe6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 1222b69a54eeSKentaro Takeda error = 0; 1223b69a54eeSKentaro Takeda return error; 1224b69a54eeSKentaro Takeda } 1225b69a54eeSKentaro Takeda 1226b69a54eeSKentaro Takeda /** 122775093152STetsuo Handa * tomoyo_mkdev_perm - Check permission for "mkblock" and "mkchar". 1228a1f9bb6aSTetsuo Handa * 1229a1f9bb6aSTetsuo Handa * @operation: Type of operation. (TOMOYO_TYPE_MKCHAR or TOMOYO_TYPE_MKBLOCK) 1230a1f9bb6aSTetsuo Handa * @path: Pointer to "struct path". 1231a1f9bb6aSTetsuo Handa * @mode: Create mode. 1232a1f9bb6aSTetsuo Handa * @dev: Device number. 1233a1f9bb6aSTetsuo Handa * 1234a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1235a1f9bb6aSTetsuo Handa */ 123675093152STetsuo Handa int tomoyo_mkdev_perm(const u8 operation, struct path *path, 1237a1f9bb6aSTetsuo Handa const unsigned int mode, unsigned int dev) 1238a1f9bb6aSTetsuo Handa { 1239a1f9bb6aSTetsuo Handa struct tomoyo_request_info r; 1240a1f9bb6aSTetsuo Handa int error = -ENOMEM; 1241c8c57e84STetsuo Handa struct tomoyo_path_info buf; 1242a1f9bb6aSTetsuo Handa int idx; 1243a1f9bb6aSTetsuo Handa 124457c2590fSTetsuo Handa if (!path->mnt || 124557c2590fSTetsuo Handa tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation]) 124657c2590fSTetsuo Handa == TOMOYO_CONFIG_DISABLED) 1247a1f9bb6aSTetsuo Handa return 0; 1248a1f9bb6aSTetsuo Handa idx = tomoyo_read_lock(); 1249a1f9bb6aSTetsuo Handa error = -ENOMEM; 1250c8c57e84STetsuo Handa if (tomoyo_get_realpath(&buf, path)) { 1251cf6e9a64STetsuo Handa dev = new_decode_dev(dev); 125275093152STetsuo Handa r.param_type = TOMOYO_TYPE_MKDEV_ACL; 1253cf6e9a64STetsuo Handa r.param.mkdev.filename = &buf; 1254cf6e9a64STetsuo Handa r.param.mkdev.operation = operation; 1255cf6e9a64STetsuo Handa r.param.mkdev.mode = mode; 1256cf6e9a64STetsuo Handa r.param.mkdev.major = MAJOR(dev); 1257cf6e9a64STetsuo Handa r.param.mkdev.minor = MINOR(dev); 125899a85259STetsuo Handa tomoyo_check_acl(&r, tomoyo_check_mkdev_acl); 125999a85259STetsuo Handa error = tomoyo_audit_mkdev_log(&r); 1260c8c57e84STetsuo Handa kfree(buf.name); 1261a1f9bb6aSTetsuo Handa } 1262a1f9bb6aSTetsuo Handa tomoyo_read_unlock(idx); 1263a1f9bb6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 1264a1f9bb6aSTetsuo Handa error = 0; 1265a1f9bb6aSTetsuo Handa return error; 1266a1f9bb6aSTetsuo Handa } 1267a1f9bb6aSTetsuo Handa 1268a1f9bb6aSTetsuo Handa /** 12697ef61233STetsuo Handa * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root". 1270b69a54eeSKentaro Takeda * 1271b69a54eeSKentaro Takeda * @operation: Type of operation. 1272b69a54eeSKentaro Takeda * @path1: Pointer to "struct path". 1273b69a54eeSKentaro Takeda * @path2: Pointer to "struct path". 1274b69a54eeSKentaro Takeda * 1275b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1276b69a54eeSKentaro Takeda */ 127797d6931eSTetsuo Handa int tomoyo_path2_perm(const u8 operation, struct path *path1, 1278b69a54eeSKentaro Takeda struct path *path2) 1279b69a54eeSKentaro Takeda { 1280b69a54eeSKentaro Takeda int error = -ENOMEM; 1281c8c57e84STetsuo Handa struct tomoyo_path_info buf1; 1282c8c57e84STetsuo Handa struct tomoyo_path_info buf2; 1283cb0abe6aSTetsuo Handa struct tomoyo_request_info r; 1284fdb8ebb7STetsuo Handa int idx; 1285b69a54eeSKentaro Takeda 128657c2590fSTetsuo Handa if (!path1->mnt || !path2->mnt || 128757c2590fSTetsuo Handa tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation]) 128857c2590fSTetsuo Handa == TOMOYO_CONFIG_DISABLED) 1289b69a54eeSKentaro Takeda return 0; 1290c8c57e84STetsuo Handa buf1.name = NULL; 1291c8c57e84STetsuo Handa buf2.name = NULL; 1292fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 1293c8c57e84STetsuo Handa if (!tomoyo_get_realpath(&buf1, path1) || 1294c8c57e84STetsuo Handa !tomoyo_get_realpath(&buf2, path2)) 1295b69a54eeSKentaro Takeda goto out; 129657c2590fSTetsuo Handa switch (operation) { 129757c2590fSTetsuo Handa struct dentry *dentry; 129857c2590fSTetsuo Handa case TOMOYO_TYPE_RENAME: 129957c2590fSTetsuo Handa case TOMOYO_TYPE_LINK: 130057c2590fSTetsuo Handa dentry = path1->dentry; 130157c2590fSTetsuo Handa if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode)) 130257c2590fSTetsuo Handa break; 130357c2590fSTetsuo Handa /* fall through */ 130457c2590fSTetsuo Handa case TOMOYO_TYPE_PIVOT_ROOT: 1305c8c57e84STetsuo Handa tomoyo_add_slash(&buf1); 1306c8c57e84STetsuo Handa tomoyo_add_slash(&buf2); 130757c2590fSTetsuo Handa break; 1308b69a54eeSKentaro Takeda } 1309cf6e9a64STetsuo Handa r.param_type = TOMOYO_TYPE_PATH2_ACL; 1310cf6e9a64STetsuo Handa r.param.path2.operation = operation; 1311cf6e9a64STetsuo Handa r.param.path2.filename1 = &buf1; 1312cf6e9a64STetsuo Handa r.param.path2.filename2 = &buf2; 131317fcfbd9STetsuo Handa do { 131499a85259STetsuo Handa tomoyo_check_acl(&r, tomoyo_check_path2_acl); 131599a85259STetsuo Handa error = tomoyo_audit_path2_log(&r); 131617fcfbd9STetsuo Handa } while (error == TOMOYO_RETRY_REQUEST); 1317b69a54eeSKentaro Takeda out: 1318c8c57e84STetsuo Handa kfree(buf1.name); 1319c8c57e84STetsuo Handa kfree(buf2.name); 1320fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 1321cb0abe6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 1322b69a54eeSKentaro Takeda error = 0; 1323b69a54eeSKentaro Takeda return error; 1324b69a54eeSKentaro Takeda } 1325a1f9bb6aSTetsuo Handa 1326a1f9bb6aSTetsuo Handa /** 1327a1f9bb6aSTetsuo Handa * tomoyo_write_file_policy - Update file related list. 1328a1f9bb6aSTetsuo Handa * 1329a1f9bb6aSTetsuo Handa * @data: String to parse. 1330a1f9bb6aSTetsuo Handa * @domain: Pointer to "struct tomoyo_domain_info". 1331a1f9bb6aSTetsuo Handa * @is_delete: True if it is a delete request. 1332a1f9bb6aSTetsuo Handa * 1333a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1334a1f9bb6aSTetsuo Handa * 1335a1f9bb6aSTetsuo Handa * Caller holds tomoyo_read_lock(). 1336a1f9bb6aSTetsuo Handa */ 1337a1f9bb6aSTetsuo Handa int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, 1338a1f9bb6aSTetsuo Handa const bool is_delete) 1339a1f9bb6aSTetsuo Handa { 1340a1f9bb6aSTetsuo Handa char *w[5]; 1341a1f9bb6aSTetsuo Handa u8 type; 1342a1f9bb6aSTetsuo Handa if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0]) 1343a1f9bb6aSTetsuo Handa return -EINVAL; 1344237ab459STetsuo Handa if (strncmp(w[0], "allow_", 6)) 1345a1f9bb6aSTetsuo Handa goto out; 1346a1f9bb6aSTetsuo Handa w[0] += 6; 1347a1f9bb6aSTetsuo Handa for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) { 1348a1f9bb6aSTetsuo Handa if (strcmp(w[0], tomoyo_path_keyword[type])) 1349a1f9bb6aSTetsuo Handa continue; 1350a1f9bb6aSTetsuo Handa return tomoyo_update_path_acl(type, w[1], domain, is_delete); 1351a1f9bb6aSTetsuo Handa } 1352a1f9bb6aSTetsuo Handa if (!w[2][0]) 1353a1f9bb6aSTetsuo Handa goto out; 1354a1f9bb6aSTetsuo Handa for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) { 1355a1f9bb6aSTetsuo Handa if (strcmp(w[0], tomoyo_path2_keyword[type])) 1356a1f9bb6aSTetsuo Handa continue; 1357a1f9bb6aSTetsuo Handa return tomoyo_update_path2_acl(type, w[1], w[2], domain, 1358a1f9bb6aSTetsuo Handa is_delete); 1359a1f9bb6aSTetsuo Handa } 1360a1f9bb6aSTetsuo Handa for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) { 1361a1f9bb6aSTetsuo Handa if (strcmp(w[0], tomoyo_path_number_keyword[type])) 1362a1f9bb6aSTetsuo Handa continue; 1363a1f9bb6aSTetsuo Handa return tomoyo_update_path_number_acl(type, w[1], w[2], domain, 1364a1f9bb6aSTetsuo Handa is_delete); 1365a1f9bb6aSTetsuo Handa } 1366a1f9bb6aSTetsuo Handa if (!w[3][0] || !w[4][0]) 1367a1f9bb6aSTetsuo Handa goto out; 136875093152STetsuo Handa for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++) { 136975093152STetsuo Handa if (strcmp(w[0], tomoyo_mkdev_keyword[type])) 1370a1f9bb6aSTetsuo Handa continue; 137175093152STetsuo Handa return tomoyo_update_mkdev_acl(type, w[1], w[2], w[3], 1372a1f9bb6aSTetsuo Handa w[4], domain, is_delete); 1373a1f9bb6aSTetsuo Handa } 1374a1f9bb6aSTetsuo Handa out: 1375a1f9bb6aSTetsuo Handa return -EINVAL; 1376a1f9bb6aSTetsuo Handa } 1377