1b69a54eeSKentaro Takeda /* 2b69a54eeSKentaro Takeda * security/tomoyo/file.c 3b69a54eeSKentaro Takeda * 4b69a54eeSKentaro Takeda * Implementation of the Domain-Based Mandatory Access Control. 5b69a54eeSKentaro Takeda * 6b69a54eeSKentaro Takeda * Copyright (C) 2005-2009 NTT DATA CORPORATION 7b69a54eeSKentaro Takeda * 839826a1eSTetsuo Handa * Version: 2.2.0 2009/04/01 9b69a54eeSKentaro Takeda * 10b69a54eeSKentaro Takeda */ 11b69a54eeSKentaro Takeda 12b69a54eeSKentaro Takeda #include "common.h" 135a0e3ad6STejun Heo #include <linux/slab.h> 14b69a54eeSKentaro Takeda 15a1f9bb6aSTetsuo Handa /* Keyword array for operations with one pathname. */ 167ef61233STetsuo Handa static const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = { 177ef61233STetsuo Handa [TOMOYO_TYPE_READ_WRITE] = "read/write", 187ef61233STetsuo Handa [TOMOYO_TYPE_EXECUTE] = "execute", 197ef61233STetsuo Handa [TOMOYO_TYPE_READ] = "read", 207ef61233STetsuo Handa [TOMOYO_TYPE_WRITE] = "write", 217ef61233STetsuo Handa [TOMOYO_TYPE_UNLINK] = "unlink", 227ef61233STetsuo Handa [TOMOYO_TYPE_RMDIR] = "rmdir", 237ef61233STetsuo Handa [TOMOYO_TYPE_TRUNCATE] = "truncate", 247ef61233STetsuo Handa [TOMOYO_TYPE_SYMLINK] = "symlink", 257ef61233STetsuo Handa [TOMOYO_TYPE_REWRITE] = "rewrite", 267ef61233STetsuo Handa [TOMOYO_TYPE_CHROOT] = "chroot", 277ef61233STetsuo Handa [TOMOYO_TYPE_UMOUNT] = "unmount", 28b69a54eeSKentaro Takeda }; 29b69a54eeSKentaro Takeda 30a1f9bb6aSTetsuo Handa /* Keyword array for operations with one pathname and three numbers. */ 31a1f9bb6aSTetsuo Handa static const char *tomoyo_path_number3_keyword 32a1f9bb6aSTetsuo Handa [TOMOYO_MAX_PATH_NUMBER3_OPERATION] = { 33a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_MKBLOCK] = "mkblock", 34a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_MKCHAR] = "mkchar", 35a1f9bb6aSTetsuo Handa }; 36a1f9bb6aSTetsuo Handa 37a1f9bb6aSTetsuo Handa /* Keyword array for operations with two pathnames. */ 387ef61233STetsuo Handa static const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = { 397ef61233STetsuo Handa [TOMOYO_TYPE_LINK] = "link", 407ef61233STetsuo Handa [TOMOYO_TYPE_RENAME] = "rename", 417ef61233STetsuo Handa [TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root", 42b69a54eeSKentaro Takeda }; 43b69a54eeSKentaro Takeda 44a1f9bb6aSTetsuo Handa /* Keyword array for operations with one pathname and one number. */ 45a1f9bb6aSTetsuo Handa static const char *tomoyo_path_number_keyword 46a1f9bb6aSTetsuo Handa [TOMOYO_MAX_PATH_NUMBER_OPERATION] = { 47a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_CREATE] = "create", 48a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_MKDIR] = "mkdir", 49a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_MKFIFO] = "mkfifo", 50a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_MKSOCK] = "mksock", 51a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_IOCTL] = "ioctl", 52a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_CHMOD] = "chmod", 53a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_CHOWN] = "chown", 54a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_CHGRP] = "chgrp", 55a1f9bb6aSTetsuo Handa }; 56a1f9bb6aSTetsuo Handa 577762fbffSTetsuo Handa void tomoyo_put_name_union(struct tomoyo_name_union *ptr) 587762fbffSTetsuo Handa { 597762fbffSTetsuo Handa if (!ptr) 607762fbffSTetsuo Handa return; 617762fbffSTetsuo Handa if (ptr->is_group) 627762fbffSTetsuo Handa tomoyo_put_path_group(ptr->group); 637762fbffSTetsuo Handa else 647762fbffSTetsuo Handa tomoyo_put_name(ptr->filename); 657762fbffSTetsuo Handa } 667762fbffSTetsuo Handa 677762fbffSTetsuo Handa bool tomoyo_compare_name_union(const struct tomoyo_path_info *name, 687762fbffSTetsuo Handa const struct tomoyo_name_union *ptr) 697762fbffSTetsuo Handa { 707762fbffSTetsuo Handa if (ptr->is_group) 717762fbffSTetsuo Handa return tomoyo_path_matches_group(name, ptr->group, 1); 727762fbffSTetsuo Handa return tomoyo_path_matches_pattern(name, ptr->filename); 737762fbffSTetsuo Handa } 747762fbffSTetsuo Handa 757762fbffSTetsuo Handa static bool tomoyo_compare_name_union_pattern(const struct tomoyo_path_info 767762fbffSTetsuo Handa *name, 777762fbffSTetsuo Handa const struct tomoyo_name_union 787762fbffSTetsuo Handa *ptr, const bool may_use_pattern) 797762fbffSTetsuo Handa { 807762fbffSTetsuo Handa if (ptr->is_group) 817762fbffSTetsuo Handa return tomoyo_path_matches_group(name, ptr->group, 827762fbffSTetsuo Handa may_use_pattern); 837762fbffSTetsuo Handa if (may_use_pattern || !ptr->filename->is_patterned) 847762fbffSTetsuo Handa return tomoyo_path_matches_pattern(name, ptr->filename); 857762fbffSTetsuo Handa return false; 867762fbffSTetsuo Handa } 877762fbffSTetsuo Handa 884c3e9e2dSTetsuo Handa void tomoyo_put_number_union(struct tomoyo_number_union *ptr) 894c3e9e2dSTetsuo Handa { 904c3e9e2dSTetsuo Handa if (ptr && ptr->is_group) 914c3e9e2dSTetsuo Handa tomoyo_put_number_group(ptr->group); 924c3e9e2dSTetsuo Handa } 934c3e9e2dSTetsuo Handa 944c3e9e2dSTetsuo Handa bool tomoyo_compare_number_union(const unsigned long value, 954c3e9e2dSTetsuo Handa const struct tomoyo_number_union *ptr) 964c3e9e2dSTetsuo Handa { 974c3e9e2dSTetsuo Handa if (ptr->is_group) 984c3e9e2dSTetsuo Handa return tomoyo_number_matches_group(value, value, ptr->group); 994c3e9e2dSTetsuo Handa return value >= ptr->values[0] && value <= ptr->values[1]; 1004c3e9e2dSTetsuo Handa } 1014c3e9e2dSTetsuo Handa 102b69a54eeSKentaro Takeda /** 103cb0abe6aSTetsuo Handa * tomoyo_init_request_info - Initialize "struct tomoyo_request_info" members. 104cb0abe6aSTetsuo Handa * 105cb0abe6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info" to initialize. 106cb0abe6aSTetsuo Handa * @domain: Pointer to "struct tomoyo_domain_info". NULL for tomoyo_domain(). 107cb0abe6aSTetsuo Handa * 108cb0abe6aSTetsuo Handa * Returns mode. 109cb0abe6aSTetsuo Handa */ 1102106ccd9STetsuo Handa int tomoyo_init_request_info(struct tomoyo_request_info *r, 111cb0abe6aSTetsuo Handa struct tomoyo_domain_info *domain) 112cb0abe6aSTetsuo Handa { 113cb0abe6aSTetsuo Handa memset(r, 0, sizeof(*r)); 114cb0abe6aSTetsuo Handa if (!domain) 115cb0abe6aSTetsuo Handa domain = tomoyo_domain(); 116cb0abe6aSTetsuo Handa r->domain = domain; 117cb0abe6aSTetsuo Handa r->mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); 118cb0abe6aSTetsuo Handa return r->mode; 119cb0abe6aSTetsuo Handa } 120cb0abe6aSTetsuo Handa 121cb0abe6aSTetsuo Handa static void tomoyo_warn_log(struct tomoyo_request_info *r, const char *fmt, ...) 122cb0abe6aSTetsuo Handa __attribute__ ((format(printf, 2, 3))); 123cb0abe6aSTetsuo Handa /** 124cb0abe6aSTetsuo Handa * tomoyo_warn_log - Print warning or error message on console. 125cb0abe6aSTetsuo Handa * 126cb0abe6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 127cb0abe6aSTetsuo Handa * @fmt: The printf()'s format string, followed by parameters. 128cb0abe6aSTetsuo Handa */ 129cb0abe6aSTetsuo Handa static void tomoyo_warn_log(struct tomoyo_request_info *r, const char *fmt, ...) 130cb0abe6aSTetsuo Handa { 131cb0abe6aSTetsuo Handa int len = PAGE_SIZE; 132cb0abe6aSTetsuo Handa va_list args; 133cb0abe6aSTetsuo Handa char *buffer; 134cb0abe6aSTetsuo Handa if (!tomoyo_verbose_mode(r->domain)) 135cb0abe6aSTetsuo Handa return; 136cb0abe6aSTetsuo Handa while (1) { 137cb0abe6aSTetsuo Handa int len2; 138cb0abe6aSTetsuo Handa buffer = kmalloc(len, GFP_NOFS); 139cb0abe6aSTetsuo Handa if (!buffer) 140cb0abe6aSTetsuo Handa return; 141cb0abe6aSTetsuo Handa va_start(args, fmt); 142cb0abe6aSTetsuo Handa len2 = vsnprintf(buffer, len - 1, fmt, args); 143cb0abe6aSTetsuo Handa va_end(args); 144cb0abe6aSTetsuo Handa if (len2 <= len - 1) { 145cb0abe6aSTetsuo Handa buffer[len2] = '\0'; 146cb0abe6aSTetsuo Handa break; 147cb0abe6aSTetsuo Handa } 148cb0abe6aSTetsuo Handa len = len2 + 1; 149cb0abe6aSTetsuo Handa kfree(buffer); 150cb0abe6aSTetsuo Handa } 151cb0abe6aSTetsuo Handa printk(KERN_WARNING "TOMOYO-%s: Access %s denied for %s\n", 152cb0abe6aSTetsuo Handa r->mode == TOMOYO_CONFIG_ENFORCING ? "ERROR" : "WARNING", 153cb0abe6aSTetsuo Handa buffer, tomoyo_get_last_name(r->domain)); 154cb0abe6aSTetsuo Handa kfree(buffer); 155cb0abe6aSTetsuo Handa } 156cb0abe6aSTetsuo Handa 157cb0abe6aSTetsuo Handa /** 1587ef61233STetsuo Handa * tomoyo_path2keyword - Get the name of single path operation. 159b69a54eeSKentaro Takeda * 160b69a54eeSKentaro Takeda * @operation: Type of operation. 161b69a54eeSKentaro Takeda * 162b69a54eeSKentaro Takeda * Returns the name of single path operation. 163b69a54eeSKentaro Takeda */ 1647ef61233STetsuo Handa const char *tomoyo_path2keyword(const u8 operation) 165b69a54eeSKentaro Takeda { 1667ef61233STetsuo Handa return (operation < TOMOYO_MAX_PATH_OPERATION) 1677ef61233STetsuo Handa ? tomoyo_path_keyword[operation] : NULL; 168b69a54eeSKentaro Takeda } 169b69a54eeSKentaro Takeda 170b69a54eeSKentaro Takeda /** 171a1f9bb6aSTetsuo Handa * tomoyo_path_number32keyword - Get the name of path/number/number/number operations. 172a1f9bb6aSTetsuo Handa * 173a1f9bb6aSTetsuo Handa * @operation: Type of operation. 174a1f9bb6aSTetsuo Handa * 175a1f9bb6aSTetsuo Handa * Returns the name of path/number/number/number operation. 176a1f9bb6aSTetsuo Handa */ 177a1f9bb6aSTetsuo Handa const char *tomoyo_path_number32keyword(const u8 operation) 178a1f9bb6aSTetsuo Handa { 179a1f9bb6aSTetsuo Handa return (operation < TOMOYO_MAX_PATH_NUMBER3_OPERATION) 180a1f9bb6aSTetsuo Handa ? tomoyo_path_number3_keyword[operation] : NULL; 181a1f9bb6aSTetsuo Handa } 182a1f9bb6aSTetsuo Handa 183a1f9bb6aSTetsuo Handa /** 1847ef61233STetsuo Handa * tomoyo_path22keyword - Get the name of double path operation. 185b69a54eeSKentaro Takeda * 186b69a54eeSKentaro Takeda * @operation: Type of operation. 187b69a54eeSKentaro Takeda * 188b69a54eeSKentaro Takeda * Returns the name of double path operation. 189b69a54eeSKentaro Takeda */ 1907ef61233STetsuo Handa const char *tomoyo_path22keyword(const u8 operation) 191b69a54eeSKentaro Takeda { 1927ef61233STetsuo Handa return (operation < TOMOYO_MAX_PATH2_OPERATION) 1937ef61233STetsuo Handa ? tomoyo_path2_keyword[operation] : NULL; 194b69a54eeSKentaro Takeda } 195b69a54eeSKentaro Takeda 196b69a54eeSKentaro Takeda /** 197a1f9bb6aSTetsuo Handa * tomoyo_path_number2keyword - Get the name of path/number operations. 198a1f9bb6aSTetsuo Handa * 199a1f9bb6aSTetsuo Handa * @operation: Type of operation. 200a1f9bb6aSTetsuo Handa * 201a1f9bb6aSTetsuo Handa * Returns the name of path/number operation. 202a1f9bb6aSTetsuo Handa */ 203a1f9bb6aSTetsuo Handa const char *tomoyo_path_number2keyword(const u8 operation) 204a1f9bb6aSTetsuo Handa { 205a1f9bb6aSTetsuo Handa return (operation < TOMOYO_MAX_PATH_NUMBER_OPERATION) 206a1f9bb6aSTetsuo Handa ? tomoyo_path_number_keyword[operation] : NULL; 207a1f9bb6aSTetsuo Handa } 208a1f9bb6aSTetsuo Handa 209a1f9bb6aSTetsuo Handa /** 210b69a54eeSKentaro Takeda * tomoyo_strendswith - Check whether the token ends with the given token. 211b69a54eeSKentaro Takeda * 212b69a54eeSKentaro Takeda * @name: The token to check. 213b69a54eeSKentaro Takeda * @tail: The token to find. 214b69a54eeSKentaro Takeda * 215b69a54eeSKentaro Takeda * Returns true if @name ends with @tail, false otherwise. 216b69a54eeSKentaro Takeda */ 217b69a54eeSKentaro Takeda static bool tomoyo_strendswith(const char *name, const char *tail) 218b69a54eeSKentaro Takeda { 219b69a54eeSKentaro Takeda int len; 220b69a54eeSKentaro Takeda 221b69a54eeSKentaro Takeda if (!name || !tail) 222b69a54eeSKentaro Takeda return false; 223b69a54eeSKentaro Takeda len = strlen(name) - strlen(tail); 224b69a54eeSKentaro Takeda return len >= 0 && !strcmp(name + len, tail); 225b69a54eeSKentaro Takeda } 226b69a54eeSKentaro Takeda 227b69a54eeSKentaro Takeda /** 228b69a54eeSKentaro Takeda * tomoyo_get_path - Get realpath. 229b69a54eeSKentaro Takeda * 230b69a54eeSKentaro Takeda * @path: Pointer to "struct path". 231b69a54eeSKentaro Takeda * 232b69a54eeSKentaro Takeda * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. 233b69a54eeSKentaro Takeda */ 234b69a54eeSKentaro Takeda static struct tomoyo_path_info *tomoyo_get_path(struct path *path) 235b69a54eeSKentaro Takeda { 236b69a54eeSKentaro Takeda int error; 2378e2d39a1STetsuo Handa struct tomoyo_path_info_with_data *buf = kzalloc(sizeof(*buf), 2384e5d6f7eSTetsuo Handa GFP_NOFS); 239b69a54eeSKentaro Takeda 240b69a54eeSKentaro Takeda if (!buf) 241b69a54eeSKentaro Takeda return NULL; 242b69a54eeSKentaro Takeda /* Reserve one byte for appending "/". */ 243b69a54eeSKentaro Takeda error = tomoyo_realpath_from_path2(path, buf->body, 244b69a54eeSKentaro Takeda sizeof(buf->body) - 2); 245b69a54eeSKentaro Takeda if (!error) { 246b69a54eeSKentaro Takeda buf->head.name = buf->body; 247b69a54eeSKentaro Takeda tomoyo_fill_path_info(&buf->head); 248b69a54eeSKentaro Takeda return &buf->head; 249b69a54eeSKentaro Takeda } 2508e2d39a1STetsuo Handa kfree(buf); 251b69a54eeSKentaro Takeda return NULL; 252b69a54eeSKentaro Takeda } 253b69a54eeSKentaro Takeda 2547ef61233STetsuo Handa static int tomoyo_update_path2_acl(const u8 type, const char *filename1, 255b69a54eeSKentaro Takeda const char *filename2, 2567ef61233STetsuo Handa struct tomoyo_domain_info *const domain, 2577ef61233STetsuo Handa const bool is_delete); 2587ef61233STetsuo Handa static int tomoyo_update_path_acl(const u8 type, const char *filename, 2597ef61233STetsuo Handa struct tomoyo_domain_info *const domain, 2607ef61233STetsuo Handa const bool is_delete); 261b69a54eeSKentaro Takeda 262c3fa109aSTetsuo Handa /* 263c3fa109aSTetsuo Handa * tomoyo_globally_readable_list is used for holding list of pathnames which 264c3fa109aSTetsuo Handa * are by default allowed to be open()ed for reading by any process. 265c3fa109aSTetsuo Handa * 266c3fa109aSTetsuo Handa * An entry is added by 267c3fa109aSTetsuo Handa * 268c3fa109aSTetsuo Handa * # echo 'allow_read /lib/libc-2.5.so' > \ 269c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 270c3fa109aSTetsuo Handa * 271c3fa109aSTetsuo Handa * and is deleted by 272c3fa109aSTetsuo Handa * 273c3fa109aSTetsuo Handa * # echo 'delete allow_read /lib/libc-2.5.so' > \ 274c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 275c3fa109aSTetsuo Handa * 276c3fa109aSTetsuo Handa * and all entries are retrieved by 277c3fa109aSTetsuo Handa * 278c3fa109aSTetsuo Handa * # grep ^allow_read /sys/kernel/security/tomoyo/exception_policy 279c3fa109aSTetsuo Handa * 280c3fa109aSTetsuo Handa * In the example above, any process is allowed to 281c3fa109aSTetsuo Handa * open("/lib/libc-2.5.so", O_RDONLY). 282c3fa109aSTetsuo Handa * One exception is, if the domain which current process belongs to is marked 283c3fa109aSTetsuo Handa * as "ignore_global_allow_read", current process can't do so unless explicitly 284c3fa109aSTetsuo Handa * given "allow_read /lib/libc-2.5.so" to the domain which current process 285c3fa109aSTetsuo Handa * belongs to. 286c3fa109aSTetsuo Handa */ 287847b173eSTetsuo Handa LIST_HEAD(tomoyo_globally_readable_list); 288b69a54eeSKentaro Takeda 289b69a54eeSKentaro Takeda /** 290b69a54eeSKentaro Takeda * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list. 291b69a54eeSKentaro Takeda * 292b69a54eeSKentaro Takeda * @filename: Filename unconditionally permitted to open() for reading. 293b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 294b69a54eeSKentaro Takeda * 295b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 296fdb8ebb7STetsuo Handa * 297fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 298b69a54eeSKentaro Takeda */ 299b69a54eeSKentaro Takeda static int tomoyo_update_globally_readable_entry(const char *filename, 300b69a54eeSKentaro Takeda const bool is_delete) 301b69a54eeSKentaro Takeda { 302b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry *ptr; 3039e4b50e9STetsuo Handa struct tomoyo_globally_readable_file_entry e = { }; 304ca0b7df3STetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 305b69a54eeSKentaro Takeda 30617080008STetsuo Handa if (!tomoyo_is_correct_path(filename, 1, 0, -1)) 307b69a54eeSKentaro Takeda return -EINVAL; 3089e4b50e9STetsuo Handa e.filename = tomoyo_get_name(filename); 3099e4b50e9STetsuo Handa if (!e.filename) 310b69a54eeSKentaro Takeda return -ENOMEM; 31129282381STetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 31229282381STetsuo Handa goto out; 313fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) { 3149e4b50e9STetsuo Handa if (ptr->filename != e.filename) 315b69a54eeSKentaro Takeda continue; 316b69a54eeSKentaro Takeda ptr->is_deleted = is_delete; 317b69a54eeSKentaro Takeda error = 0; 318ca0b7df3STetsuo Handa break; 319b69a54eeSKentaro Takeda } 3209e4b50e9STetsuo Handa if (!is_delete && error) { 3219e4b50e9STetsuo Handa struct tomoyo_globally_readable_file_entry *entry = 3229e4b50e9STetsuo Handa tomoyo_commit_ok(&e, sizeof(e)); 3239e4b50e9STetsuo Handa if (entry) { 3249e4b50e9STetsuo Handa list_add_tail_rcu(&entry->list, 3259e4b50e9STetsuo Handa &tomoyo_globally_readable_list); 326b69a54eeSKentaro Takeda error = 0; 327ca0b7df3STetsuo Handa } 3289e4b50e9STetsuo Handa } 329f737d95dSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 33029282381STetsuo Handa out: 3319e4b50e9STetsuo Handa tomoyo_put_name(e.filename); 332b69a54eeSKentaro Takeda return error; 333b69a54eeSKentaro Takeda } 334b69a54eeSKentaro Takeda 335b69a54eeSKentaro Takeda /** 336b69a54eeSKentaro Takeda * tomoyo_is_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading. 337b69a54eeSKentaro Takeda * 338b69a54eeSKentaro Takeda * @filename: The filename to check. 339b69a54eeSKentaro Takeda * 340b69a54eeSKentaro Takeda * Returns true if any domain can open @filename for reading, false otherwise. 341fdb8ebb7STetsuo Handa * 342fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 343b69a54eeSKentaro Takeda */ 344b69a54eeSKentaro Takeda static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info * 345b69a54eeSKentaro Takeda filename) 346b69a54eeSKentaro Takeda { 347b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry *ptr; 348b69a54eeSKentaro Takeda bool found = false; 349fdb8ebb7STetsuo Handa 350fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) { 351b69a54eeSKentaro Takeda if (!ptr->is_deleted && 352b69a54eeSKentaro Takeda tomoyo_path_matches_pattern(filename, ptr->filename)) { 353b69a54eeSKentaro Takeda found = true; 354b69a54eeSKentaro Takeda break; 355b69a54eeSKentaro Takeda } 356b69a54eeSKentaro Takeda } 357b69a54eeSKentaro Takeda return found; 358b69a54eeSKentaro Takeda } 359b69a54eeSKentaro Takeda 360b69a54eeSKentaro Takeda /** 361b69a54eeSKentaro Takeda * tomoyo_write_globally_readable_policy - Write "struct tomoyo_globally_readable_file_entry" list. 362b69a54eeSKentaro Takeda * 363b69a54eeSKentaro Takeda * @data: String to parse. 364b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 365b69a54eeSKentaro Takeda * 366b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 367fdb8ebb7STetsuo Handa * 368fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 369b69a54eeSKentaro Takeda */ 370b69a54eeSKentaro Takeda int tomoyo_write_globally_readable_policy(char *data, const bool is_delete) 371b69a54eeSKentaro Takeda { 372b69a54eeSKentaro Takeda return tomoyo_update_globally_readable_entry(data, is_delete); 373b69a54eeSKentaro Takeda } 374b69a54eeSKentaro Takeda 375b69a54eeSKentaro Takeda /** 376b69a54eeSKentaro Takeda * tomoyo_read_globally_readable_policy - Read "struct tomoyo_globally_readable_file_entry" list. 377b69a54eeSKentaro Takeda * 378b69a54eeSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 379b69a54eeSKentaro Takeda * 380b69a54eeSKentaro Takeda * Returns true on success, false otherwise. 381fdb8ebb7STetsuo Handa * 382fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 383b69a54eeSKentaro Takeda */ 384b69a54eeSKentaro Takeda bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) 385b69a54eeSKentaro Takeda { 386b69a54eeSKentaro Takeda struct list_head *pos; 387b69a54eeSKentaro Takeda bool done = true; 388b69a54eeSKentaro Takeda 389b69a54eeSKentaro Takeda list_for_each_cookie(pos, head->read_var2, 390b69a54eeSKentaro Takeda &tomoyo_globally_readable_list) { 391b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry *ptr; 392b69a54eeSKentaro Takeda ptr = list_entry(pos, 393b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry, 394b69a54eeSKentaro Takeda list); 395b69a54eeSKentaro Takeda if (ptr->is_deleted) 396b69a54eeSKentaro Takeda continue; 3977d2948b1STetsuo Handa done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n", 3987d2948b1STetsuo Handa ptr->filename->name); 3997d2948b1STetsuo Handa if (!done) 400b69a54eeSKentaro Takeda break; 401b69a54eeSKentaro Takeda } 402b69a54eeSKentaro Takeda return done; 403b69a54eeSKentaro Takeda } 404b69a54eeSKentaro Takeda 405c3fa109aSTetsuo Handa /* tomoyo_pattern_list is used for holding list of pathnames which are used for 406c3fa109aSTetsuo Handa * converting pathnames to pathname patterns during learning mode. 407c3fa109aSTetsuo Handa * 408c3fa109aSTetsuo Handa * An entry is added by 409c3fa109aSTetsuo Handa * 410c3fa109aSTetsuo Handa * # echo 'file_pattern /proc/\$/mounts' > \ 411c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 412c3fa109aSTetsuo Handa * 413c3fa109aSTetsuo Handa * and is deleted by 414c3fa109aSTetsuo Handa * 415c3fa109aSTetsuo Handa * # echo 'delete file_pattern /proc/\$/mounts' > \ 416c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 417c3fa109aSTetsuo Handa * 418c3fa109aSTetsuo Handa * and all entries are retrieved by 419c3fa109aSTetsuo Handa * 420c3fa109aSTetsuo Handa * # grep ^file_pattern /sys/kernel/security/tomoyo/exception_policy 421c3fa109aSTetsuo Handa * 422c3fa109aSTetsuo Handa * In the example above, if a process which belongs to a domain which is in 423c3fa109aSTetsuo Handa * learning mode requested open("/proc/1/mounts", O_RDONLY), 424c3fa109aSTetsuo Handa * "allow_read /proc/\$/mounts" is automatically added to the domain which that 425c3fa109aSTetsuo Handa * process belongs to. 426c3fa109aSTetsuo Handa * 427c3fa109aSTetsuo Handa * It is not a desirable behavior that we have to use /proc/\$/ instead of 428c3fa109aSTetsuo Handa * /proc/self/ when current process needs to access only current process's 429c3fa109aSTetsuo Handa * information. As of now, LSM version of TOMOYO is using __d_path() for 430c3fa109aSTetsuo Handa * calculating pathname. Non LSM version of TOMOYO is using its own function 431c3fa109aSTetsuo Handa * which pretends as if /proc/self/ is not a symlink; so that we can forbid 432c3fa109aSTetsuo Handa * current process from accessing other process's information. 433c3fa109aSTetsuo Handa */ 434847b173eSTetsuo Handa LIST_HEAD(tomoyo_pattern_list); 435b69a54eeSKentaro Takeda 436b69a54eeSKentaro Takeda /** 437b69a54eeSKentaro Takeda * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list. 438b69a54eeSKentaro Takeda * 439b69a54eeSKentaro Takeda * @pattern: Pathname pattern. 440b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 441b69a54eeSKentaro Takeda * 442b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 443fdb8ebb7STetsuo Handa * 444fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 445b69a54eeSKentaro Takeda */ 446b69a54eeSKentaro Takeda static int tomoyo_update_file_pattern_entry(const char *pattern, 447b69a54eeSKentaro Takeda const bool is_delete) 448b69a54eeSKentaro Takeda { 449b69a54eeSKentaro Takeda struct tomoyo_pattern_entry *ptr; 4509e4b50e9STetsuo Handa struct tomoyo_pattern_entry e = { .pattern = tomoyo_get_name(pattern) }; 451ca0b7df3STetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 452b69a54eeSKentaro Takeda 4539e4b50e9STetsuo Handa if (!e.pattern) 454ca0b7df3STetsuo Handa return error; 4559e4b50e9STetsuo Handa if (!e.pattern->is_patterned) 456ca0b7df3STetsuo Handa goto out; 45729282381STetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 45829282381STetsuo Handa goto out; 459fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { 4609e4b50e9STetsuo Handa if (e.pattern != ptr->pattern) 461b69a54eeSKentaro Takeda continue; 462b69a54eeSKentaro Takeda ptr->is_deleted = is_delete; 463b69a54eeSKentaro Takeda error = 0; 464ca0b7df3STetsuo Handa break; 465b69a54eeSKentaro Takeda } 4669e4b50e9STetsuo Handa if (!is_delete && error) { 4679e4b50e9STetsuo Handa struct tomoyo_pattern_entry *entry = 4689e4b50e9STetsuo Handa tomoyo_commit_ok(&e, sizeof(e)); 4699e4b50e9STetsuo Handa if (entry) { 470ca0b7df3STetsuo Handa list_add_tail_rcu(&entry->list, &tomoyo_pattern_list); 471b69a54eeSKentaro Takeda error = 0; 472ca0b7df3STetsuo Handa } 4739e4b50e9STetsuo Handa } 474f737d95dSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 475ca0b7df3STetsuo Handa out: 4769e4b50e9STetsuo Handa tomoyo_put_name(e.pattern); 477b69a54eeSKentaro Takeda return error; 478b69a54eeSKentaro Takeda } 479b69a54eeSKentaro Takeda 480b69a54eeSKentaro Takeda /** 481b69a54eeSKentaro Takeda * tomoyo_get_file_pattern - Get patterned pathname. 482b69a54eeSKentaro Takeda * 483b69a54eeSKentaro Takeda * @filename: The filename to find patterned pathname. 484b69a54eeSKentaro Takeda * 485b69a54eeSKentaro Takeda * Returns pointer to pathname pattern if matched, @filename otherwise. 486fdb8ebb7STetsuo Handa * 487fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 488b69a54eeSKentaro Takeda */ 4892106ccd9STetsuo Handa const struct tomoyo_path_info * 490b69a54eeSKentaro Takeda tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) 491b69a54eeSKentaro Takeda { 492b69a54eeSKentaro Takeda struct tomoyo_pattern_entry *ptr; 493b69a54eeSKentaro Takeda const struct tomoyo_path_info *pattern = NULL; 494b69a54eeSKentaro Takeda 495fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { 496b69a54eeSKentaro Takeda if (ptr->is_deleted) 497b69a54eeSKentaro Takeda continue; 498b69a54eeSKentaro Takeda if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) 499b69a54eeSKentaro Takeda continue; 500b69a54eeSKentaro Takeda pattern = ptr->pattern; 501b69a54eeSKentaro Takeda if (tomoyo_strendswith(pattern->name, "/\\*")) { 502b69a54eeSKentaro Takeda /* Do nothing. Try to find the better match. */ 503b69a54eeSKentaro Takeda } else { 504b69a54eeSKentaro Takeda /* This would be the better match. Use this. */ 505b69a54eeSKentaro Takeda break; 506b69a54eeSKentaro Takeda } 507b69a54eeSKentaro Takeda } 508b69a54eeSKentaro Takeda if (pattern) 509b69a54eeSKentaro Takeda filename = pattern; 510b69a54eeSKentaro Takeda return filename; 511b69a54eeSKentaro Takeda } 512b69a54eeSKentaro Takeda 513b69a54eeSKentaro Takeda /** 514b69a54eeSKentaro Takeda * tomoyo_write_pattern_policy - Write "struct tomoyo_pattern_entry" list. 515b69a54eeSKentaro Takeda * 516b69a54eeSKentaro Takeda * @data: String to parse. 517b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 518b69a54eeSKentaro Takeda * 519b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 520fdb8ebb7STetsuo Handa * 521fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 522b69a54eeSKentaro Takeda */ 523b69a54eeSKentaro Takeda int tomoyo_write_pattern_policy(char *data, const bool is_delete) 524b69a54eeSKentaro Takeda { 525b69a54eeSKentaro Takeda return tomoyo_update_file_pattern_entry(data, is_delete); 526b69a54eeSKentaro Takeda } 527b69a54eeSKentaro Takeda 528b69a54eeSKentaro Takeda /** 529b69a54eeSKentaro Takeda * tomoyo_read_file_pattern - Read "struct tomoyo_pattern_entry" list. 530b69a54eeSKentaro Takeda * 531b69a54eeSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 532b69a54eeSKentaro Takeda * 533b69a54eeSKentaro Takeda * Returns true on success, false otherwise. 534fdb8ebb7STetsuo Handa * 535fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 536b69a54eeSKentaro Takeda */ 537b69a54eeSKentaro Takeda bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) 538b69a54eeSKentaro Takeda { 539b69a54eeSKentaro Takeda struct list_head *pos; 540b69a54eeSKentaro Takeda bool done = true; 541b69a54eeSKentaro Takeda 542b69a54eeSKentaro Takeda list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) { 543b69a54eeSKentaro Takeda struct tomoyo_pattern_entry *ptr; 544b69a54eeSKentaro Takeda ptr = list_entry(pos, struct tomoyo_pattern_entry, list); 545b69a54eeSKentaro Takeda if (ptr->is_deleted) 546b69a54eeSKentaro Takeda continue; 5477d2948b1STetsuo Handa done = tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN 5487d2948b1STetsuo Handa "%s\n", ptr->pattern->name); 5497d2948b1STetsuo Handa if (!done) 550b69a54eeSKentaro Takeda break; 551b69a54eeSKentaro Takeda } 552b69a54eeSKentaro Takeda return done; 553b69a54eeSKentaro Takeda } 554b69a54eeSKentaro Takeda 555c3fa109aSTetsuo Handa /* 556c3fa109aSTetsuo Handa * tomoyo_no_rewrite_list is used for holding list of pathnames which are by 557c3fa109aSTetsuo Handa * default forbidden to modify already written content of a file. 558c3fa109aSTetsuo Handa * 559c3fa109aSTetsuo Handa * An entry is added by 560c3fa109aSTetsuo Handa * 561c3fa109aSTetsuo Handa * # echo 'deny_rewrite /var/log/messages' > \ 562c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 563c3fa109aSTetsuo Handa * 564c3fa109aSTetsuo Handa * and is deleted by 565c3fa109aSTetsuo Handa * 566c3fa109aSTetsuo Handa * # echo 'delete deny_rewrite /var/log/messages' > \ 567c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 568c3fa109aSTetsuo Handa * 569c3fa109aSTetsuo Handa * and all entries are retrieved by 570c3fa109aSTetsuo Handa * 571c3fa109aSTetsuo Handa * # grep ^deny_rewrite /sys/kernel/security/tomoyo/exception_policy 572c3fa109aSTetsuo Handa * 573c3fa109aSTetsuo Handa * In the example above, if a process requested to rewrite /var/log/messages , 574c3fa109aSTetsuo Handa * the process can't rewrite unless the domain which that process belongs to 575c3fa109aSTetsuo Handa * has "allow_rewrite /var/log/messages" entry. 576c3fa109aSTetsuo Handa * 577c3fa109aSTetsuo Handa * It is not a desirable behavior that we have to add "\040(deleted)" suffix 578c3fa109aSTetsuo Handa * when we want to allow rewriting already unlink()ed file. As of now, 579c3fa109aSTetsuo Handa * LSM version of TOMOYO is using __d_path() for calculating pathname. 580c3fa109aSTetsuo Handa * Non LSM version of TOMOYO is using its own function which doesn't append 581c3fa109aSTetsuo Handa * " (deleted)" suffix if the file is already unlink()ed; so that we don't 582c3fa109aSTetsuo Handa * need to worry whether the file is already unlink()ed or not. 583c3fa109aSTetsuo Handa */ 584847b173eSTetsuo Handa LIST_HEAD(tomoyo_no_rewrite_list); 585b69a54eeSKentaro Takeda 586b69a54eeSKentaro Takeda /** 587b69a54eeSKentaro Takeda * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list. 588b69a54eeSKentaro Takeda * 589b69a54eeSKentaro Takeda * @pattern: Pathname pattern that are not rewritable by default. 590b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 591b69a54eeSKentaro Takeda * 592b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 593fdb8ebb7STetsuo Handa * 594fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 595b69a54eeSKentaro Takeda */ 596b69a54eeSKentaro Takeda static int tomoyo_update_no_rewrite_entry(const char *pattern, 597b69a54eeSKentaro Takeda const bool is_delete) 598b69a54eeSKentaro Takeda { 599ca0b7df3STetsuo Handa struct tomoyo_no_rewrite_entry *ptr; 6009e4b50e9STetsuo Handa struct tomoyo_no_rewrite_entry e = { }; 601ca0b7df3STetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 602b69a54eeSKentaro Takeda 60317080008STetsuo Handa if (!tomoyo_is_correct_path(pattern, 0, 0, 0)) 604b69a54eeSKentaro Takeda return -EINVAL; 6059e4b50e9STetsuo Handa e.pattern = tomoyo_get_name(pattern); 6069e4b50e9STetsuo Handa if (!e.pattern) 607ca0b7df3STetsuo Handa return error; 60829282381STetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 60929282381STetsuo Handa goto out; 610fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { 6119e4b50e9STetsuo Handa if (ptr->pattern != e.pattern) 612b69a54eeSKentaro Takeda continue; 613b69a54eeSKentaro Takeda ptr->is_deleted = is_delete; 614b69a54eeSKentaro Takeda error = 0; 615ca0b7df3STetsuo Handa break; 616b69a54eeSKentaro Takeda } 6179e4b50e9STetsuo Handa if (!is_delete && error) { 6189e4b50e9STetsuo Handa struct tomoyo_no_rewrite_entry *entry = 6199e4b50e9STetsuo Handa tomoyo_commit_ok(&e, sizeof(e)); 6209e4b50e9STetsuo Handa if (entry) { 6219e4b50e9STetsuo Handa list_add_tail_rcu(&entry->list, 6229e4b50e9STetsuo Handa &tomoyo_no_rewrite_list); 623b69a54eeSKentaro Takeda error = 0; 624ca0b7df3STetsuo Handa } 6259e4b50e9STetsuo Handa } 626f737d95dSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 62729282381STetsuo Handa out: 6289e4b50e9STetsuo Handa tomoyo_put_name(e.pattern); 629b69a54eeSKentaro Takeda return error; 630b69a54eeSKentaro Takeda } 631b69a54eeSKentaro Takeda 632b69a54eeSKentaro Takeda /** 633b69a54eeSKentaro Takeda * tomoyo_is_no_rewrite_file - Check if the given pathname is not permitted to be rewrited. 634b69a54eeSKentaro Takeda * 635b69a54eeSKentaro Takeda * @filename: Filename to check. 636b69a54eeSKentaro Takeda * 637b69a54eeSKentaro Takeda * Returns true if @filename is specified by "deny_rewrite" directive, 638b69a54eeSKentaro Takeda * false otherwise. 639fdb8ebb7STetsuo Handa * 640fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 641b69a54eeSKentaro Takeda */ 642b69a54eeSKentaro Takeda static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) 643b69a54eeSKentaro Takeda { 644b69a54eeSKentaro Takeda struct tomoyo_no_rewrite_entry *ptr; 645b69a54eeSKentaro Takeda bool found = false; 646b69a54eeSKentaro Takeda 647fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { 648b69a54eeSKentaro Takeda if (ptr->is_deleted) 649b69a54eeSKentaro Takeda continue; 650b69a54eeSKentaro Takeda if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) 651b69a54eeSKentaro Takeda continue; 652b69a54eeSKentaro Takeda found = true; 653b69a54eeSKentaro Takeda break; 654b69a54eeSKentaro Takeda } 655b69a54eeSKentaro Takeda return found; 656b69a54eeSKentaro Takeda } 657b69a54eeSKentaro Takeda 658b69a54eeSKentaro Takeda /** 659b69a54eeSKentaro Takeda * tomoyo_write_no_rewrite_policy - Write "struct tomoyo_no_rewrite_entry" list. 660b69a54eeSKentaro Takeda * 661b69a54eeSKentaro Takeda * @data: String to parse. 662b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 663b69a54eeSKentaro Takeda * 664b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 665fdb8ebb7STetsuo Handa * 666fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 667b69a54eeSKentaro Takeda */ 668b69a54eeSKentaro Takeda int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete) 669b69a54eeSKentaro Takeda { 670b69a54eeSKentaro Takeda return tomoyo_update_no_rewrite_entry(data, is_delete); 671b69a54eeSKentaro Takeda } 672b69a54eeSKentaro Takeda 673b69a54eeSKentaro Takeda /** 674b69a54eeSKentaro Takeda * tomoyo_read_no_rewrite_policy - Read "struct tomoyo_no_rewrite_entry" list. 675b69a54eeSKentaro Takeda * 676b69a54eeSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 677b69a54eeSKentaro Takeda * 678b69a54eeSKentaro Takeda * Returns true on success, false otherwise. 679fdb8ebb7STetsuo Handa * 680fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 681b69a54eeSKentaro Takeda */ 682b69a54eeSKentaro Takeda bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) 683b69a54eeSKentaro Takeda { 684b69a54eeSKentaro Takeda struct list_head *pos; 685b69a54eeSKentaro Takeda bool done = true; 686b69a54eeSKentaro Takeda 687b69a54eeSKentaro Takeda list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) { 688b69a54eeSKentaro Takeda struct tomoyo_no_rewrite_entry *ptr; 689b69a54eeSKentaro Takeda ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list); 690b69a54eeSKentaro Takeda if (ptr->is_deleted) 691b69a54eeSKentaro Takeda continue; 6927d2948b1STetsuo Handa done = tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE 6937d2948b1STetsuo Handa "%s\n", ptr->pattern->name); 6947d2948b1STetsuo Handa if (!done) 695b69a54eeSKentaro Takeda break; 696b69a54eeSKentaro Takeda } 697b69a54eeSKentaro Takeda return done; 698b69a54eeSKentaro Takeda } 699b69a54eeSKentaro Takeda 700b69a54eeSKentaro Takeda /** 701b69a54eeSKentaro Takeda * tomoyo_update_file_acl - Update file's read/write/execute ACL. 702b69a54eeSKentaro Takeda * 703b69a54eeSKentaro Takeda * @perm: Permission (between 1 to 7). 704a1f9bb6aSTetsuo Handa * @filename: Filename. 705b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 706b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 707b69a54eeSKentaro Takeda * 708b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 709b69a54eeSKentaro Takeda * 710b69a54eeSKentaro Takeda * This is legacy support interface for older policy syntax. 711b69a54eeSKentaro Takeda * Current policy syntax uses "allow_read/write" instead of "6", 712b69a54eeSKentaro Takeda * "allow_read" instead of "4", "allow_write" instead of "2", 713b69a54eeSKentaro Takeda * "allow_execute" instead of "1". 714fdb8ebb7STetsuo Handa * 715fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 716b69a54eeSKentaro Takeda */ 717a1f9bb6aSTetsuo Handa static int tomoyo_update_file_acl(u8 perm, const char *filename, 718b69a54eeSKentaro Takeda struct tomoyo_domain_info * const domain, 719b69a54eeSKentaro Takeda const bool is_delete) 720b69a54eeSKentaro Takeda { 721b69a54eeSKentaro Takeda if (perm > 7 || !perm) { 722b69a54eeSKentaro Takeda printk(KERN_DEBUG "%s: Invalid permission '%d %s'\n", 723b69a54eeSKentaro Takeda __func__, perm, filename); 724b69a54eeSKentaro Takeda return -EINVAL; 725b69a54eeSKentaro Takeda } 726b69a54eeSKentaro Takeda if (filename[0] != '@' && tomoyo_strendswith(filename, "/")) 727b69a54eeSKentaro Takeda /* 728b69a54eeSKentaro Takeda * Only 'allow_mkdir' and 'allow_rmdir' are valid for 729b69a54eeSKentaro Takeda * directory permissions. 730b69a54eeSKentaro Takeda */ 731b69a54eeSKentaro Takeda return 0; 732b69a54eeSKentaro Takeda if (perm & 4) 7337ef61233STetsuo Handa tomoyo_update_path_acl(TOMOYO_TYPE_READ, filename, domain, 7347ef61233STetsuo Handa is_delete); 735b69a54eeSKentaro Takeda if (perm & 2) 7367ef61233STetsuo Handa tomoyo_update_path_acl(TOMOYO_TYPE_WRITE, filename, domain, 7377ef61233STetsuo Handa is_delete); 738b69a54eeSKentaro Takeda if (perm & 1) 7397ef61233STetsuo Handa tomoyo_update_path_acl(TOMOYO_TYPE_EXECUTE, filename, domain, 7407ef61233STetsuo Handa is_delete); 741b69a54eeSKentaro Takeda return 0; 742b69a54eeSKentaro Takeda } 743b69a54eeSKentaro Takeda 744b69a54eeSKentaro Takeda /** 745cb0abe6aSTetsuo Handa * tomoyo_path_acl - Check permission for single path operation. 746b69a54eeSKentaro Takeda * 747cb0abe6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 748b69a54eeSKentaro Takeda * @filename: Filename to check. 749b69a54eeSKentaro Takeda * @perm: Permission. 750b69a54eeSKentaro Takeda * @may_use_pattern: True if patterned ACL is permitted. 751b69a54eeSKentaro Takeda * 752b69a54eeSKentaro Takeda * Returns 0 on success, -EPERM otherwise. 753fdb8ebb7STetsuo Handa * 754fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 755b69a54eeSKentaro Takeda */ 756cb0abe6aSTetsuo Handa static int tomoyo_path_acl(const struct tomoyo_request_info *r, 7577ef61233STetsuo Handa const struct tomoyo_path_info *filename, 7587ef61233STetsuo Handa const u32 perm, const bool may_use_pattern) 759b69a54eeSKentaro Takeda { 760cb0abe6aSTetsuo Handa struct tomoyo_domain_info *domain = r->domain; 761b69a54eeSKentaro Takeda struct tomoyo_acl_info *ptr; 762b69a54eeSKentaro Takeda int error = -EPERM; 763b69a54eeSKentaro Takeda 764fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 7657ef61233STetsuo Handa struct tomoyo_path_acl *acl; 7667ef61233STetsuo Handa if (ptr->type != TOMOYO_TYPE_PATH_ACL) 767b69a54eeSKentaro Takeda continue; 7687ef61233STetsuo Handa acl = container_of(ptr, struct tomoyo_path_acl, head); 769a1f9bb6aSTetsuo Handa if (!(acl->perm & perm) || 770a1f9bb6aSTetsuo Handa !tomoyo_compare_name_union_pattern(filename, &acl->name, 7717762fbffSTetsuo Handa may_use_pattern)) 772b69a54eeSKentaro Takeda continue; 773b69a54eeSKentaro Takeda error = 0; 774b69a54eeSKentaro Takeda break; 775b69a54eeSKentaro Takeda } 776b69a54eeSKentaro Takeda return error; 777b69a54eeSKentaro Takeda } 778b69a54eeSKentaro Takeda 779b69a54eeSKentaro Takeda /** 780cb0abe6aSTetsuo Handa * tomoyo_file_perm - Check permission for opening files. 781b69a54eeSKentaro Takeda * 782cb0abe6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 783b69a54eeSKentaro Takeda * @filename: Filename to check. 784cb0abe6aSTetsuo Handa * @mode: Mode ("read" or "write" or "read/write" or "execute"). 785b69a54eeSKentaro Takeda * 786b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 787fdb8ebb7STetsuo Handa * 788fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 789b69a54eeSKentaro Takeda */ 790cb0abe6aSTetsuo Handa static int tomoyo_file_perm(struct tomoyo_request_info *r, 791b69a54eeSKentaro Takeda const struct tomoyo_path_info *filename, 792b69a54eeSKentaro Takeda const u8 mode) 793b69a54eeSKentaro Takeda { 794b69a54eeSKentaro Takeda const char *msg = "<unknown>"; 795b69a54eeSKentaro Takeda int error = 0; 796cb0abe6aSTetsuo Handa u32 perm = 0; 797b69a54eeSKentaro Takeda 798b69a54eeSKentaro Takeda if (!filename) 799b69a54eeSKentaro Takeda return 0; 800cb0abe6aSTetsuo Handa 801cb0abe6aSTetsuo Handa if (mode == 6) { 802cb0abe6aSTetsuo Handa msg = tomoyo_path2keyword(TOMOYO_TYPE_READ_WRITE); 803cb0abe6aSTetsuo Handa perm = 1 << TOMOYO_TYPE_READ_WRITE; 804cb0abe6aSTetsuo Handa } else if (mode == 4) { 805cb0abe6aSTetsuo Handa msg = tomoyo_path2keyword(TOMOYO_TYPE_READ); 806cb0abe6aSTetsuo Handa perm = 1 << TOMOYO_TYPE_READ; 807cb0abe6aSTetsuo Handa } else if (mode == 2) { 808cb0abe6aSTetsuo Handa msg = tomoyo_path2keyword(TOMOYO_TYPE_WRITE); 809cb0abe6aSTetsuo Handa perm = 1 << TOMOYO_TYPE_WRITE; 810cb0abe6aSTetsuo Handa } else if (mode == 1) { 811cb0abe6aSTetsuo Handa msg = tomoyo_path2keyword(TOMOYO_TYPE_EXECUTE); 812cb0abe6aSTetsuo Handa perm = 1 << TOMOYO_TYPE_EXECUTE; 813cb0abe6aSTetsuo Handa } else 814cb0abe6aSTetsuo Handa BUG(); 815cb0abe6aSTetsuo Handa error = tomoyo_path_acl(r, filename, perm, mode != 1); 816cb0abe6aSTetsuo Handa if (error && mode == 4 && !r->domain->ignore_global_allow_read 817b69a54eeSKentaro Takeda && tomoyo_is_globally_readable_file(filename)) 818b69a54eeSKentaro Takeda error = 0; 819b69a54eeSKentaro Takeda if (!error) 820b69a54eeSKentaro Takeda return 0; 821cb0abe6aSTetsuo Handa tomoyo_warn_log(r, "%s %s", msg, filename->name); 822cb0abe6aSTetsuo Handa if (r->mode == TOMOYO_CONFIG_ENFORCING) 823b69a54eeSKentaro Takeda return error; 824cb0abe6aSTetsuo Handa if (tomoyo_domain_quota_is_ok(r)) { 825b69a54eeSKentaro Takeda /* Don't use patterns for execute permission. */ 826cb0abe6aSTetsuo Handa const struct tomoyo_path_info *patterned_file = (mode != 1) ? 827b69a54eeSKentaro Takeda tomoyo_get_file_pattern(filename) : filename; 828a1f9bb6aSTetsuo Handa tomoyo_update_file_acl(mode, patterned_file->name, r->domain, 829a1f9bb6aSTetsuo Handa false); 830b69a54eeSKentaro Takeda } 831b69a54eeSKentaro Takeda return 0; 832b69a54eeSKentaro Takeda } 833b69a54eeSKentaro Takeda 834b69a54eeSKentaro Takeda /** 8357ef61233STetsuo Handa * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list. 836b69a54eeSKentaro Takeda * 837b69a54eeSKentaro Takeda * @type: Type of operation. 838b69a54eeSKentaro Takeda * @filename: Filename. 839b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 840b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 841b69a54eeSKentaro Takeda * 842b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 843fdb8ebb7STetsuo Handa * 844fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 845b69a54eeSKentaro Takeda */ 8467ef61233STetsuo Handa static int tomoyo_update_path_acl(const u8 type, const char *filename, 8477ef61233STetsuo Handa struct tomoyo_domain_info *const domain, 8487ef61233STetsuo Handa const bool is_delete) 849b69a54eeSKentaro Takeda { 850a1f9bb6aSTetsuo Handa static const u16 tomoyo_rw_mask = 8517ef61233STetsuo Handa (1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE); 852a1f9bb6aSTetsuo Handa const u16 perm = 1 << type; 8539e4b50e9STetsuo Handa struct tomoyo_acl_info *ptr; 8549e4b50e9STetsuo Handa struct tomoyo_path_acl e = { 8559e4b50e9STetsuo Handa .head.type = TOMOYO_TYPE_PATH_ACL, 8569e4b50e9STetsuo Handa .perm = perm 8579e4b50e9STetsuo Handa }; 8589e4b50e9STetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 859b69a54eeSKentaro Takeda 8609e4b50e9STetsuo Handa if (type == TOMOYO_TYPE_READ_WRITE) 8619e4b50e9STetsuo Handa e.perm |= tomoyo_rw_mask; 862b69a54eeSKentaro Takeda if (!domain) 863b69a54eeSKentaro Takeda return -EINVAL; 8647762fbffSTetsuo Handa if (!tomoyo_parse_name_union(filename, &e.name)) 865b69a54eeSKentaro Takeda return -EINVAL; 86629282381STetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 86729282381STetsuo Handa goto out; 868fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 8697ef61233STetsuo Handa struct tomoyo_path_acl *acl = 8707ef61233STetsuo Handa container_of(ptr, struct tomoyo_path_acl, head); 8717762fbffSTetsuo Handa if (!tomoyo_is_same_path_acl(acl, &e)) 872b69a54eeSKentaro Takeda continue; 873ca0b7df3STetsuo Handa if (is_delete) { 874ca0b7df3STetsuo Handa acl->perm &= ~perm; 8759e4b50e9STetsuo Handa if ((acl->perm & tomoyo_rw_mask) != tomoyo_rw_mask) 8767ef61233STetsuo Handa acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE); 8777ef61233STetsuo Handa else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE))) 8789e4b50e9STetsuo Handa acl->perm &= ~tomoyo_rw_mask; 879ca0b7df3STetsuo Handa } else { 880b69a54eeSKentaro Takeda acl->perm |= perm; 8819e4b50e9STetsuo Handa if ((acl->perm & tomoyo_rw_mask) == tomoyo_rw_mask) 8827ef61233STetsuo Handa acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE; 8837ef61233STetsuo Handa else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE)) 8849e4b50e9STetsuo Handa acl->perm |= tomoyo_rw_mask; 885b69a54eeSKentaro Takeda } 886b69a54eeSKentaro Takeda error = 0; 887b69a54eeSKentaro Takeda break; 888b69a54eeSKentaro Takeda } 8899e4b50e9STetsuo Handa if (!is_delete && error) { 8909e4b50e9STetsuo Handa struct tomoyo_path_acl *entry = 8919e4b50e9STetsuo Handa tomoyo_commit_ok(&e, sizeof(e)); 8929e4b50e9STetsuo Handa if (entry) { 8939e4b50e9STetsuo Handa list_add_tail_rcu(&entry->head.list, 8949e4b50e9STetsuo Handa &domain->acl_info_list); 895ca0b7df3STetsuo Handa error = 0; 896ca0b7df3STetsuo Handa } 8979e4b50e9STetsuo Handa } 898f737d95dSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 89929282381STetsuo Handa out: 9007762fbffSTetsuo Handa tomoyo_put_name_union(&e.name); 901b69a54eeSKentaro Takeda return error; 902b69a54eeSKentaro Takeda } 903b69a54eeSKentaro Takeda 904b69a54eeSKentaro Takeda /** 905a1f9bb6aSTetsuo Handa * tomoyo_update_path_number3_acl - Update "struct tomoyo_path_number3_acl" list. 906a1f9bb6aSTetsuo Handa * 907a1f9bb6aSTetsuo Handa * @type: Type of operation. 908a1f9bb6aSTetsuo Handa * @filename: Filename. 909a1f9bb6aSTetsuo Handa * @mode: Create mode. 910a1f9bb6aSTetsuo Handa * @major: Device major number. 911a1f9bb6aSTetsuo Handa * @minor: Device minor number. 912a1f9bb6aSTetsuo Handa * @domain: Pointer to "struct tomoyo_domain_info". 913a1f9bb6aSTetsuo Handa * @is_delete: True if it is a delete request. 914a1f9bb6aSTetsuo Handa * 915a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 916a1f9bb6aSTetsuo Handa */ 917a1f9bb6aSTetsuo Handa static inline int tomoyo_update_path_number3_acl(const u8 type, 918a1f9bb6aSTetsuo Handa const char *filename, 919a1f9bb6aSTetsuo Handa char *mode, 920a1f9bb6aSTetsuo Handa char *major, char *minor, 921a1f9bb6aSTetsuo Handa struct tomoyo_domain_info * 922a1f9bb6aSTetsuo Handa const domain, 923a1f9bb6aSTetsuo Handa const bool is_delete) 924a1f9bb6aSTetsuo Handa { 925a1f9bb6aSTetsuo Handa const u8 perm = 1 << type; 926a1f9bb6aSTetsuo Handa struct tomoyo_acl_info *ptr; 927a1f9bb6aSTetsuo Handa struct tomoyo_path_number3_acl e = { 928a1f9bb6aSTetsuo Handa .head.type = TOMOYO_TYPE_PATH_NUMBER3_ACL, 929a1f9bb6aSTetsuo Handa .perm = perm 930a1f9bb6aSTetsuo Handa }; 931a1f9bb6aSTetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 932a1f9bb6aSTetsuo Handa if (!tomoyo_parse_name_union(filename, &e.name) || 933a1f9bb6aSTetsuo Handa !tomoyo_parse_number_union(mode, &e.mode) || 934a1f9bb6aSTetsuo Handa !tomoyo_parse_number_union(major, &e.major) || 935a1f9bb6aSTetsuo Handa !tomoyo_parse_number_union(minor, &e.minor)) 936a1f9bb6aSTetsuo Handa goto out; 937a1f9bb6aSTetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 938a1f9bb6aSTetsuo Handa goto out; 939a1f9bb6aSTetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 940a1f9bb6aSTetsuo Handa struct tomoyo_path_number3_acl *acl = 941a1f9bb6aSTetsuo Handa container_of(ptr, struct tomoyo_path_number3_acl, head); 942a1f9bb6aSTetsuo Handa if (!tomoyo_is_same_path_number3_acl(acl, &e)) 943a1f9bb6aSTetsuo Handa continue; 944a1f9bb6aSTetsuo Handa if (is_delete) 945a1f9bb6aSTetsuo Handa acl->perm &= ~perm; 946a1f9bb6aSTetsuo Handa else 947a1f9bb6aSTetsuo Handa acl->perm |= perm; 948a1f9bb6aSTetsuo Handa error = 0; 949a1f9bb6aSTetsuo Handa break; 950a1f9bb6aSTetsuo Handa } 951a1f9bb6aSTetsuo Handa if (!is_delete && error) { 952a1f9bb6aSTetsuo Handa struct tomoyo_path_number3_acl *entry = 953a1f9bb6aSTetsuo Handa tomoyo_commit_ok(&e, sizeof(e)); 954a1f9bb6aSTetsuo Handa if (entry) { 955a1f9bb6aSTetsuo Handa list_add_tail_rcu(&entry->head.list, 956a1f9bb6aSTetsuo Handa &domain->acl_info_list); 957a1f9bb6aSTetsuo Handa error = 0; 958a1f9bb6aSTetsuo Handa } 959a1f9bb6aSTetsuo Handa } 960a1f9bb6aSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 961a1f9bb6aSTetsuo Handa out: 962a1f9bb6aSTetsuo Handa tomoyo_put_name_union(&e.name); 963a1f9bb6aSTetsuo Handa tomoyo_put_number_union(&e.mode); 964a1f9bb6aSTetsuo Handa tomoyo_put_number_union(&e.major); 965a1f9bb6aSTetsuo Handa tomoyo_put_number_union(&e.minor); 966a1f9bb6aSTetsuo Handa return error; 967a1f9bb6aSTetsuo Handa } 968a1f9bb6aSTetsuo Handa 969a1f9bb6aSTetsuo Handa /** 9707ef61233STetsuo Handa * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list. 971b69a54eeSKentaro Takeda * 972b69a54eeSKentaro Takeda * @type: Type of operation. 973b69a54eeSKentaro Takeda * @filename1: First filename. 974b69a54eeSKentaro Takeda * @filename2: Second filename. 975b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 976b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 977b69a54eeSKentaro Takeda * 978b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 979fdb8ebb7STetsuo Handa * 980fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 981b69a54eeSKentaro Takeda */ 9827ef61233STetsuo Handa static int tomoyo_update_path2_acl(const u8 type, const char *filename1, 983b69a54eeSKentaro Takeda const char *filename2, 9847ef61233STetsuo Handa struct tomoyo_domain_info *const domain, 9857ef61233STetsuo Handa const bool is_delete) 986b69a54eeSKentaro Takeda { 987b69a54eeSKentaro Takeda const u8 perm = 1 << type; 9889e4b50e9STetsuo Handa struct tomoyo_path2_acl e = { 9899e4b50e9STetsuo Handa .head.type = TOMOYO_TYPE_PATH2_ACL, 9909e4b50e9STetsuo Handa .perm = perm 9919e4b50e9STetsuo Handa }; 9929e4b50e9STetsuo Handa struct tomoyo_acl_info *ptr; 9939e4b50e9STetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 994b69a54eeSKentaro Takeda 995b69a54eeSKentaro Takeda if (!domain) 996b69a54eeSKentaro Takeda return -EINVAL; 9977762fbffSTetsuo Handa if (!tomoyo_parse_name_union(filename1, &e.name1) || 9987762fbffSTetsuo Handa !tomoyo_parse_name_union(filename2, &e.name2)) 999ca0b7df3STetsuo Handa goto out; 100029282381STetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 100129282381STetsuo Handa goto out; 1002ca0b7df3STetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 10037ef61233STetsuo Handa struct tomoyo_path2_acl *acl = 10047ef61233STetsuo Handa container_of(ptr, struct tomoyo_path2_acl, head); 10057762fbffSTetsuo Handa if (!tomoyo_is_same_path2_acl(acl, &e)) 1006ca0b7df3STetsuo Handa continue; 1007b69a54eeSKentaro Takeda if (is_delete) 1008b69a54eeSKentaro Takeda acl->perm &= ~perm; 1009ca0b7df3STetsuo Handa else 1010ca0b7df3STetsuo Handa acl->perm |= perm; 1011b69a54eeSKentaro Takeda error = 0; 1012b69a54eeSKentaro Takeda break; 1013b69a54eeSKentaro Takeda } 10149e4b50e9STetsuo Handa if (!is_delete && error) { 10159e4b50e9STetsuo Handa struct tomoyo_path2_acl *entry = 10169e4b50e9STetsuo Handa tomoyo_commit_ok(&e, sizeof(e)); 10179e4b50e9STetsuo Handa if (entry) { 10189e4b50e9STetsuo Handa list_add_tail_rcu(&entry->head.list, 10199e4b50e9STetsuo Handa &domain->acl_info_list); 1020ca0b7df3STetsuo Handa error = 0; 1021ca0b7df3STetsuo Handa } 10229e4b50e9STetsuo Handa } 1023f737d95dSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 1024ca0b7df3STetsuo Handa out: 10257762fbffSTetsuo Handa tomoyo_put_name_union(&e.name1); 10267762fbffSTetsuo Handa tomoyo_put_name_union(&e.name2); 1027b69a54eeSKentaro Takeda return error; 1028b69a54eeSKentaro Takeda } 1029b69a54eeSKentaro Takeda 1030b69a54eeSKentaro Takeda /** 1031a1f9bb6aSTetsuo Handa * tomoyo_path_number3_acl - Check permission for path/number/number/number operation. 1032a1f9bb6aSTetsuo Handa * 1033a1f9bb6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 1034a1f9bb6aSTetsuo Handa * @filename: Filename to check. 1035a1f9bb6aSTetsuo Handa * @perm: Permission. 1036a1f9bb6aSTetsuo Handa * @mode: Create mode. 1037a1f9bb6aSTetsuo Handa * @major: Device major number. 1038a1f9bb6aSTetsuo Handa * @minor: Device minor number. 1039a1f9bb6aSTetsuo Handa * 1040a1f9bb6aSTetsuo Handa * Returns 0 on success, -EPERM otherwise. 1041a1f9bb6aSTetsuo Handa * 1042a1f9bb6aSTetsuo Handa * Caller holds tomoyo_read_lock(). 1043a1f9bb6aSTetsuo Handa */ 1044a1f9bb6aSTetsuo Handa static int tomoyo_path_number3_acl(struct tomoyo_request_info *r, 1045a1f9bb6aSTetsuo Handa const struct tomoyo_path_info *filename, 1046a1f9bb6aSTetsuo Handa const u16 perm, const unsigned int mode, 1047a1f9bb6aSTetsuo Handa const unsigned int major, 1048a1f9bb6aSTetsuo Handa const unsigned int minor) 1049a1f9bb6aSTetsuo Handa { 1050a1f9bb6aSTetsuo Handa struct tomoyo_domain_info *domain = r->domain; 1051a1f9bb6aSTetsuo Handa struct tomoyo_acl_info *ptr; 1052a1f9bb6aSTetsuo Handa int error = -EPERM; 1053a1f9bb6aSTetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 1054a1f9bb6aSTetsuo Handa struct tomoyo_path_number3_acl *acl; 1055a1f9bb6aSTetsuo Handa if (ptr->type != TOMOYO_TYPE_PATH_NUMBER3_ACL) 1056a1f9bb6aSTetsuo Handa continue; 1057a1f9bb6aSTetsuo Handa acl = container_of(ptr, struct tomoyo_path_number3_acl, head); 1058a1f9bb6aSTetsuo Handa if (!tomoyo_compare_number_union(mode, &acl->mode)) 1059a1f9bb6aSTetsuo Handa continue; 1060a1f9bb6aSTetsuo Handa if (!tomoyo_compare_number_union(major, &acl->major)) 1061a1f9bb6aSTetsuo Handa continue; 1062a1f9bb6aSTetsuo Handa if (!tomoyo_compare_number_union(minor, &acl->minor)) 1063a1f9bb6aSTetsuo Handa continue; 1064a1f9bb6aSTetsuo Handa if (!(acl->perm & perm)) 1065a1f9bb6aSTetsuo Handa continue; 1066a1f9bb6aSTetsuo Handa if (!tomoyo_compare_name_union(filename, &acl->name)) 1067a1f9bb6aSTetsuo Handa continue; 1068a1f9bb6aSTetsuo Handa error = 0; 1069a1f9bb6aSTetsuo Handa break; 1070a1f9bb6aSTetsuo Handa } 1071a1f9bb6aSTetsuo Handa return error; 1072a1f9bb6aSTetsuo Handa } 1073a1f9bb6aSTetsuo Handa 1074a1f9bb6aSTetsuo Handa /** 10757ef61233STetsuo Handa * tomoyo_path2_acl - Check permission for double path operation. 1076b69a54eeSKentaro Takeda * 1077cb0abe6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 1078b69a54eeSKentaro Takeda * @type: Type of operation. 1079b69a54eeSKentaro Takeda * @filename1: First filename to check. 1080b69a54eeSKentaro Takeda * @filename2: Second filename to check. 1081b69a54eeSKentaro Takeda * 1082b69a54eeSKentaro Takeda * Returns 0 on success, -EPERM otherwise. 1083fdb8ebb7STetsuo Handa * 1084fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 1085b69a54eeSKentaro Takeda */ 1086cb0abe6aSTetsuo Handa static int tomoyo_path2_acl(const struct tomoyo_request_info *r, const u8 type, 10877ef61233STetsuo Handa const struct tomoyo_path_info *filename1, 10887ef61233STetsuo Handa const struct tomoyo_path_info *filename2) 1089b69a54eeSKentaro Takeda { 1090cb0abe6aSTetsuo Handa const struct tomoyo_domain_info *domain = r->domain; 1091b69a54eeSKentaro Takeda struct tomoyo_acl_info *ptr; 1092b69a54eeSKentaro Takeda const u8 perm = 1 << type; 1093b69a54eeSKentaro Takeda int error = -EPERM; 1094b69a54eeSKentaro Takeda 1095fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 10967ef61233STetsuo Handa struct tomoyo_path2_acl *acl; 10977ef61233STetsuo Handa if (ptr->type != TOMOYO_TYPE_PATH2_ACL) 1098b69a54eeSKentaro Takeda continue; 10997ef61233STetsuo Handa acl = container_of(ptr, struct tomoyo_path2_acl, head); 1100b69a54eeSKentaro Takeda if (!(acl->perm & perm)) 1101b69a54eeSKentaro Takeda continue; 11027762fbffSTetsuo Handa if (!tomoyo_compare_name_union(filename1, &acl->name1)) 1103b69a54eeSKentaro Takeda continue; 11047762fbffSTetsuo Handa if (!tomoyo_compare_name_union(filename2, &acl->name2)) 1105b69a54eeSKentaro Takeda continue; 1106b69a54eeSKentaro Takeda error = 0; 1107b69a54eeSKentaro Takeda break; 1108b69a54eeSKentaro Takeda } 1109b69a54eeSKentaro Takeda return error; 1110b69a54eeSKentaro Takeda } 1111b69a54eeSKentaro Takeda 1112b69a54eeSKentaro Takeda /** 1113cb0abe6aSTetsuo Handa * tomoyo_path_permission - Check permission for single path operation. 1114b69a54eeSKentaro Takeda * 1115cb0abe6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 1116b69a54eeSKentaro Takeda * @operation: Type of operation. 1117b69a54eeSKentaro Takeda * @filename: Filename to check. 1118b69a54eeSKentaro Takeda * 1119b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1120fdb8ebb7STetsuo Handa * 1121fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 1122b69a54eeSKentaro Takeda */ 1123cb0abe6aSTetsuo Handa static int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, 1124cb0abe6aSTetsuo Handa const struct tomoyo_path_info *filename) 1125b69a54eeSKentaro Takeda { 1126b69a54eeSKentaro Takeda int error; 1127b69a54eeSKentaro Takeda 1128b69a54eeSKentaro Takeda next: 1129cb0abe6aSTetsuo Handa error = tomoyo_path_acl(r, filename, 1 << operation, 1); 1130b69a54eeSKentaro Takeda if (!error) 1131b69a54eeSKentaro Takeda goto ok; 1132cb0abe6aSTetsuo Handa tomoyo_warn_log(r, "%s %s", tomoyo_path2keyword(operation), 1133cb0abe6aSTetsuo Handa filename->name); 1134cb0abe6aSTetsuo Handa if (tomoyo_domain_quota_is_ok(r)) { 1135b69a54eeSKentaro Takeda const char *name = tomoyo_get_file_pattern(filename)->name; 1136cb0abe6aSTetsuo Handa tomoyo_update_path_acl(operation, name, r->domain, false); 1137b69a54eeSKentaro Takeda } 1138cb0abe6aSTetsuo Handa if (r->mode != TOMOYO_CONFIG_ENFORCING) 1139b69a54eeSKentaro Takeda error = 0; 1140b69a54eeSKentaro Takeda ok: 1141b69a54eeSKentaro Takeda /* 1142b69a54eeSKentaro Takeda * Since "allow_truncate" doesn't imply "allow_rewrite" permission, 1143b69a54eeSKentaro Takeda * we need to check "allow_rewrite" permission if the filename is 1144b69a54eeSKentaro Takeda * specified by "deny_rewrite" keyword. 1145b69a54eeSKentaro Takeda */ 11467ef61233STetsuo Handa if (!error && operation == TOMOYO_TYPE_TRUNCATE && 1147b69a54eeSKentaro Takeda tomoyo_is_no_rewrite_file(filename)) { 11487ef61233STetsuo Handa operation = TOMOYO_TYPE_REWRITE; 1149b69a54eeSKentaro Takeda goto next; 1150b69a54eeSKentaro Takeda } 1151b69a54eeSKentaro Takeda return error; 1152b69a54eeSKentaro Takeda } 1153b69a54eeSKentaro Takeda 1154b69a54eeSKentaro Takeda /** 1155a1f9bb6aSTetsuo Handa * tomoyo_path_number_acl - Check permission for ioctl/chmod/chown/chgrp operation. 1156a1f9bb6aSTetsuo Handa * 1157a1f9bb6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 1158a1f9bb6aSTetsuo Handa * @type: Operation. 1159a1f9bb6aSTetsuo Handa * @filename: Filename to check. 1160a1f9bb6aSTetsuo Handa * @number: Number. 1161a1f9bb6aSTetsuo Handa * 1162a1f9bb6aSTetsuo Handa * Returns 0 on success, -EPERM otherwise. 1163a1f9bb6aSTetsuo Handa * 1164a1f9bb6aSTetsuo Handa * Caller holds tomoyo_read_lock(). 1165a1f9bb6aSTetsuo Handa */ 1166a1f9bb6aSTetsuo Handa static int tomoyo_path_number_acl(struct tomoyo_request_info *r, const u8 type, 1167a1f9bb6aSTetsuo Handa const struct tomoyo_path_info *filename, 1168a1f9bb6aSTetsuo Handa const unsigned long number) 1169a1f9bb6aSTetsuo Handa { 1170a1f9bb6aSTetsuo Handa struct tomoyo_domain_info *domain = r->domain; 1171a1f9bb6aSTetsuo Handa struct tomoyo_acl_info *ptr; 1172a1f9bb6aSTetsuo Handa const u8 perm = 1 << type; 1173a1f9bb6aSTetsuo Handa int error = -EPERM; 1174a1f9bb6aSTetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 1175a1f9bb6aSTetsuo Handa struct tomoyo_path_number_acl *acl; 1176a1f9bb6aSTetsuo Handa if (ptr->type != TOMOYO_TYPE_PATH_NUMBER_ACL) 1177a1f9bb6aSTetsuo Handa continue; 1178a1f9bb6aSTetsuo Handa acl = container_of(ptr, struct tomoyo_path_number_acl, 1179a1f9bb6aSTetsuo Handa head); 1180a1f9bb6aSTetsuo Handa if (!(acl->perm & perm) || 1181a1f9bb6aSTetsuo Handa !tomoyo_compare_number_union(number, &acl->number) || 1182a1f9bb6aSTetsuo Handa !tomoyo_compare_name_union(filename, &acl->name)) 1183a1f9bb6aSTetsuo Handa continue; 1184a1f9bb6aSTetsuo Handa error = 0; 1185a1f9bb6aSTetsuo Handa break; 1186a1f9bb6aSTetsuo Handa } 1187a1f9bb6aSTetsuo Handa return error; 1188a1f9bb6aSTetsuo Handa } 1189a1f9bb6aSTetsuo Handa 1190a1f9bb6aSTetsuo Handa /** 1191a1f9bb6aSTetsuo Handa * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL. 1192a1f9bb6aSTetsuo Handa * 1193a1f9bb6aSTetsuo Handa * @type: Type of operation. 1194a1f9bb6aSTetsuo Handa * @filename: Filename. 1195a1f9bb6aSTetsuo Handa * @number: Number. 1196a1f9bb6aSTetsuo Handa * @domain: Pointer to "struct tomoyo_domain_info". 1197a1f9bb6aSTetsuo Handa * @is_delete: True if it is a delete request. 1198a1f9bb6aSTetsuo Handa * 1199a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1200a1f9bb6aSTetsuo Handa */ 1201a1f9bb6aSTetsuo Handa static inline int tomoyo_update_path_number_acl(const u8 type, 1202a1f9bb6aSTetsuo Handa const char *filename, 1203a1f9bb6aSTetsuo Handa char *number, 1204a1f9bb6aSTetsuo Handa struct tomoyo_domain_info * 1205a1f9bb6aSTetsuo Handa const domain, 1206a1f9bb6aSTetsuo Handa const bool is_delete) 1207a1f9bb6aSTetsuo Handa { 1208a1f9bb6aSTetsuo Handa const u8 perm = 1 << type; 1209a1f9bb6aSTetsuo Handa struct tomoyo_acl_info *ptr; 1210a1f9bb6aSTetsuo Handa struct tomoyo_path_number_acl e = { 1211a1f9bb6aSTetsuo Handa .head.type = TOMOYO_TYPE_PATH_NUMBER_ACL, 1212a1f9bb6aSTetsuo Handa .perm = perm 1213a1f9bb6aSTetsuo Handa }; 1214a1f9bb6aSTetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 1215a1f9bb6aSTetsuo Handa if (!domain) 1216a1f9bb6aSTetsuo Handa return -EINVAL; 1217a1f9bb6aSTetsuo Handa if (!tomoyo_parse_name_union(filename, &e.name)) 1218a1f9bb6aSTetsuo Handa return -EINVAL; 1219a1f9bb6aSTetsuo Handa if (!tomoyo_parse_number_union(number, &e.number)) 1220a1f9bb6aSTetsuo Handa goto out; 1221a1f9bb6aSTetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 1222a1f9bb6aSTetsuo Handa goto out; 1223a1f9bb6aSTetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 1224a1f9bb6aSTetsuo Handa struct tomoyo_path_number_acl *acl = 1225a1f9bb6aSTetsuo Handa container_of(ptr, struct tomoyo_path_number_acl, head); 1226a1f9bb6aSTetsuo Handa if (!tomoyo_is_same_path_number_acl(acl, &e)) 1227a1f9bb6aSTetsuo Handa continue; 1228a1f9bb6aSTetsuo Handa if (is_delete) 1229a1f9bb6aSTetsuo Handa acl->perm &= ~perm; 1230a1f9bb6aSTetsuo Handa else 1231a1f9bb6aSTetsuo Handa acl->perm |= perm; 1232a1f9bb6aSTetsuo Handa error = 0; 1233a1f9bb6aSTetsuo Handa break; 1234a1f9bb6aSTetsuo Handa } 1235a1f9bb6aSTetsuo Handa if (!is_delete && error) { 1236a1f9bb6aSTetsuo Handa struct tomoyo_path_number_acl *entry = 1237a1f9bb6aSTetsuo Handa tomoyo_commit_ok(&e, sizeof(e)); 1238a1f9bb6aSTetsuo Handa if (entry) { 1239a1f9bb6aSTetsuo Handa list_add_tail_rcu(&entry->head.list, 1240a1f9bb6aSTetsuo Handa &domain->acl_info_list); 1241a1f9bb6aSTetsuo Handa error = 0; 1242a1f9bb6aSTetsuo Handa } 1243a1f9bb6aSTetsuo Handa } 1244a1f9bb6aSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 1245a1f9bb6aSTetsuo Handa out: 1246a1f9bb6aSTetsuo Handa tomoyo_put_name_union(&e.name); 1247a1f9bb6aSTetsuo Handa tomoyo_put_number_union(&e.number); 1248a1f9bb6aSTetsuo Handa return error; 1249a1f9bb6aSTetsuo Handa } 1250a1f9bb6aSTetsuo Handa 1251a1f9bb6aSTetsuo Handa /** 1252a1f9bb6aSTetsuo Handa * tomoyo_path_number_perm2 - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp". 1253a1f9bb6aSTetsuo Handa * 1254a1f9bb6aSTetsuo Handa * @r: Pointer to "strct tomoyo_request_info". 1255a1f9bb6aSTetsuo Handa * @filename: Filename to check. 1256a1f9bb6aSTetsuo Handa * @number: Number. 1257a1f9bb6aSTetsuo Handa * 1258a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1259a1f9bb6aSTetsuo Handa * 1260a1f9bb6aSTetsuo Handa * Caller holds tomoyo_read_lock(). 1261a1f9bb6aSTetsuo Handa */ 1262a1f9bb6aSTetsuo Handa static int tomoyo_path_number_perm2(struct tomoyo_request_info *r, 1263a1f9bb6aSTetsuo Handa const u8 type, 1264a1f9bb6aSTetsuo Handa const struct tomoyo_path_info *filename, 1265a1f9bb6aSTetsuo Handa const unsigned long number) 1266a1f9bb6aSTetsuo Handa { 1267a1f9bb6aSTetsuo Handa char buffer[64]; 1268a1f9bb6aSTetsuo Handa int error; 1269a1f9bb6aSTetsuo Handa u8 radix; 1270a1f9bb6aSTetsuo Handa 1271a1f9bb6aSTetsuo Handa if (!filename) 1272a1f9bb6aSTetsuo Handa return 0; 1273a1f9bb6aSTetsuo Handa switch (type) { 1274a1f9bb6aSTetsuo Handa case TOMOYO_TYPE_CREATE: 1275a1f9bb6aSTetsuo Handa case TOMOYO_TYPE_MKDIR: 1276a1f9bb6aSTetsuo Handa case TOMOYO_TYPE_MKFIFO: 1277a1f9bb6aSTetsuo Handa case TOMOYO_TYPE_MKSOCK: 1278a1f9bb6aSTetsuo Handa case TOMOYO_TYPE_CHMOD: 1279a1f9bb6aSTetsuo Handa radix = TOMOYO_VALUE_TYPE_OCTAL; 1280a1f9bb6aSTetsuo Handa break; 1281a1f9bb6aSTetsuo Handa case TOMOYO_TYPE_IOCTL: 1282a1f9bb6aSTetsuo Handa radix = TOMOYO_VALUE_TYPE_HEXADECIMAL; 1283a1f9bb6aSTetsuo Handa break; 1284a1f9bb6aSTetsuo Handa default: 1285a1f9bb6aSTetsuo Handa radix = TOMOYO_VALUE_TYPE_DECIMAL; 1286a1f9bb6aSTetsuo Handa break; 1287a1f9bb6aSTetsuo Handa } 1288a1f9bb6aSTetsuo Handa tomoyo_print_ulong(buffer, sizeof(buffer), number, radix); 1289a1f9bb6aSTetsuo Handa error = tomoyo_path_number_acl(r, type, filename, number); 1290a1f9bb6aSTetsuo Handa if (!error) 1291a1f9bb6aSTetsuo Handa return 0; 1292a1f9bb6aSTetsuo Handa tomoyo_warn_log(r, "%s %s %s", tomoyo_path_number2keyword(type), 1293a1f9bb6aSTetsuo Handa filename->name, buffer); 1294a1f9bb6aSTetsuo Handa if (tomoyo_domain_quota_is_ok(r)) 1295a1f9bb6aSTetsuo Handa tomoyo_update_path_number_acl(type, 1296a1f9bb6aSTetsuo Handa tomoyo_get_file_pattern(filename) 1297a1f9bb6aSTetsuo Handa ->name, buffer, r->domain, false); 1298a1f9bb6aSTetsuo Handa if (r->mode != TOMOYO_CONFIG_ENFORCING) 1299a1f9bb6aSTetsuo Handa error = 0; 1300a1f9bb6aSTetsuo Handa return error; 1301a1f9bb6aSTetsuo Handa } 1302a1f9bb6aSTetsuo Handa 1303a1f9bb6aSTetsuo Handa /** 1304a1f9bb6aSTetsuo Handa * tomoyo_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp". 1305a1f9bb6aSTetsuo Handa * 1306a1f9bb6aSTetsuo Handa * @type: Type of operation. 1307a1f9bb6aSTetsuo Handa * @path: Pointer to "struct path". 1308a1f9bb6aSTetsuo Handa * @number: Number. 1309a1f9bb6aSTetsuo Handa * 1310a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1311a1f9bb6aSTetsuo Handa */ 1312a1f9bb6aSTetsuo Handa int tomoyo_path_number_perm(const u8 type, struct path *path, 1313a1f9bb6aSTetsuo Handa unsigned long number) 1314a1f9bb6aSTetsuo Handa { 1315a1f9bb6aSTetsuo Handa struct tomoyo_request_info r; 1316a1f9bb6aSTetsuo Handa int error = -ENOMEM; 1317a1f9bb6aSTetsuo Handa struct tomoyo_path_info *buf; 1318a1f9bb6aSTetsuo Handa int idx; 1319a1f9bb6aSTetsuo Handa 1320a1f9bb6aSTetsuo Handa if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED || 1321a1f9bb6aSTetsuo Handa !path->mnt || !path->dentry) 1322a1f9bb6aSTetsuo Handa return 0; 1323a1f9bb6aSTetsuo Handa idx = tomoyo_read_lock(); 1324a1f9bb6aSTetsuo Handa buf = tomoyo_get_path(path); 1325a1f9bb6aSTetsuo Handa if (!buf) 1326a1f9bb6aSTetsuo Handa goto out; 1327a1f9bb6aSTetsuo Handa if (type == TOMOYO_TYPE_MKDIR && !buf->is_dir) { 1328a1f9bb6aSTetsuo Handa /* 1329a1f9bb6aSTetsuo Handa * tomoyo_get_path() reserves space for appending "/." 1330a1f9bb6aSTetsuo Handa */ 1331a1f9bb6aSTetsuo Handa strcat((char *) buf->name, "/"); 1332a1f9bb6aSTetsuo Handa tomoyo_fill_path_info(buf); 1333a1f9bb6aSTetsuo Handa } 1334a1f9bb6aSTetsuo Handa error = tomoyo_path_number_perm2(&r, type, buf, number); 1335a1f9bb6aSTetsuo Handa out: 1336a1f9bb6aSTetsuo Handa kfree(buf); 1337a1f9bb6aSTetsuo Handa tomoyo_read_unlock(idx); 1338a1f9bb6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 1339a1f9bb6aSTetsuo Handa error = 0; 1340a1f9bb6aSTetsuo Handa return error; 1341a1f9bb6aSTetsuo Handa } 1342a1f9bb6aSTetsuo Handa 1343a1f9bb6aSTetsuo Handa /** 1344b69a54eeSKentaro Takeda * tomoyo_check_exec_perm - Check permission for "execute". 1345b69a54eeSKentaro Takeda * 1346b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 1347b69a54eeSKentaro Takeda * @filename: Check permission for "execute". 1348b69a54eeSKentaro Takeda * 1349b69a54eeSKentaro Takeda * Returns 0 on success, negativevalue otherwise. 1350fdb8ebb7STetsuo Handa * 1351fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 1352b69a54eeSKentaro Takeda */ 1353b69a54eeSKentaro Takeda int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, 1354bcb86975STetsuo Handa const struct tomoyo_path_info *filename) 1355b69a54eeSKentaro Takeda { 1356cb0abe6aSTetsuo Handa struct tomoyo_request_info r; 1357b69a54eeSKentaro Takeda 1358cb0abe6aSTetsuo Handa if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED) 1359b69a54eeSKentaro Takeda return 0; 1360cb0abe6aSTetsuo Handa return tomoyo_file_perm(&r, filename, 1); 1361b69a54eeSKentaro Takeda } 1362b69a54eeSKentaro Takeda 1363b69a54eeSKentaro Takeda /** 1364b69a54eeSKentaro Takeda * tomoyo_check_open_permission - Check permission for "read" and "write". 1365b69a54eeSKentaro Takeda * 1366b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 1367b69a54eeSKentaro Takeda * @path: Pointer to "struct path". 1368b69a54eeSKentaro Takeda * @flag: Flags for open(). 1369b69a54eeSKentaro Takeda * 1370b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1371b69a54eeSKentaro Takeda */ 1372b69a54eeSKentaro Takeda int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, 1373b69a54eeSKentaro Takeda struct path *path, const int flag) 1374b69a54eeSKentaro Takeda { 1375b69a54eeSKentaro Takeda const u8 acc_mode = ACC_MODE(flag); 1376b69a54eeSKentaro Takeda int error = -ENOMEM; 1377b69a54eeSKentaro Takeda struct tomoyo_path_info *buf; 1378cb0abe6aSTetsuo Handa struct tomoyo_request_info r; 1379fdb8ebb7STetsuo Handa int idx; 1380b69a54eeSKentaro Takeda 1381cb0abe6aSTetsuo Handa if (tomoyo_init_request_info(&r, domain) == TOMOYO_CONFIG_DISABLED || 1382cb0abe6aSTetsuo Handa !path->mnt) 1383b69a54eeSKentaro Takeda return 0; 1384b69a54eeSKentaro Takeda if (acc_mode == 0) 1385b69a54eeSKentaro Takeda return 0; 1386b69a54eeSKentaro Takeda if (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode)) 1387b69a54eeSKentaro Takeda /* 1388b69a54eeSKentaro Takeda * I don't check directories here because mkdir() and rmdir() 1389b69a54eeSKentaro Takeda * don't call me. 1390b69a54eeSKentaro Takeda */ 1391b69a54eeSKentaro Takeda return 0; 1392fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 1393b69a54eeSKentaro Takeda buf = tomoyo_get_path(path); 1394b69a54eeSKentaro Takeda if (!buf) 1395b69a54eeSKentaro Takeda goto out; 1396b69a54eeSKentaro Takeda error = 0; 1397b69a54eeSKentaro Takeda /* 1398b69a54eeSKentaro Takeda * If the filename is specified by "deny_rewrite" keyword, 1399b69a54eeSKentaro Takeda * we need to check "allow_rewrite" permission when the filename is not 1400b69a54eeSKentaro Takeda * opened for append mode or the filename is truncated at open time. 1401b69a54eeSKentaro Takeda */ 1402b69a54eeSKentaro Takeda if ((acc_mode & MAY_WRITE) && 1403b69a54eeSKentaro Takeda ((flag & O_TRUNC) || !(flag & O_APPEND)) && 1404b69a54eeSKentaro Takeda (tomoyo_is_no_rewrite_file(buf))) { 1405cb0abe6aSTetsuo Handa error = tomoyo_path_permission(&r, TOMOYO_TYPE_REWRITE, buf); 1406b69a54eeSKentaro Takeda } 1407b69a54eeSKentaro Takeda if (!error) 1408cb0abe6aSTetsuo Handa error = tomoyo_file_perm(&r, buf, acc_mode); 1409b69a54eeSKentaro Takeda if (!error && (flag & O_TRUNC)) 1410cb0abe6aSTetsuo Handa error = tomoyo_path_permission(&r, TOMOYO_TYPE_TRUNCATE, buf); 1411b69a54eeSKentaro Takeda out: 14128e2d39a1STetsuo Handa kfree(buf); 1413fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 1414cb0abe6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 1415b69a54eeSKentaro Takeda error = 0; 1416b69a54eeSKentaro Takeda return error; 1417b69a54eeSKentaro Takeda } 1418b69a54eeSKentaro Takeda 1419b69a54eeSKentaro Takeda /** 14202106ccd9STetsuo Handa * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "rewrite", "chroot" and "unmount". 1421b69a54eeSKentaro Takeda * 1422b69a54eeSKentaro Takeda * @operation: Type of operation. 1423b69a54eeSKentaro Takeda * @path: Pointer to "struct path". 1424b69a54eeSKentaro Takeda * 1425b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1426b69a54eeSKentaro Takeda */ 142797d6931eSTetsuo Handa int tomoyo_path_perm(const u8 operation, struct path *path) 1428b69a54eeSKentaro Takeda { 1429b69a54eeSKentaro Takeda int error = -ENOMEM; 1430b69a54eeSKentaro Takeda struct tomoyo_path_info *buf; 1431cb0abe6aSTetsuo Handa struct tomoyo_request_info r; 1432fdb8ebb7STetsuo Handa int idx; 1433b69a54eeSKentaro Takeda 1434cb0abe6aSTetsuo Handa if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED || 1435cb0abe6aSTetsuo Handa !path->mnt) 1436b69a54eeSKentaro Takeda return 0; 1437fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 1438b69a54eeSKentaro Takeda buf = tomoyo_get_path(path); 1439b69a54eeSKentaro Takeda if (!buf) 1440b69a54eeSKentaro Takeda goto out; 1441b69a54eeSKentaro Takeda switch (operation) { 1442cb0abe6aSTetsuo Handa case TOMOYO_TYPE_REWRITE: 1443cb0abe6aSTetsuo Handa if (!tomoyo_is_no_rewrite_file(buf)) { 1444cb0abe6aSTetsuo Handa error = 0; 1445cb0abe6aSTetsuo Handa goto out; 1446cb0abe6aSTetsuo Handa } 1447cb0abe6aSTetsuo Handa break; 14487ef61233STetsuo Handa case TOMOYO_TYPE_RMDIR: 14497ef61233STetsuo Handa case TOMOYO_TYPE_CHROOT: 1450b69a54eeSKentaro Takeda if (!buf->is_dir) { 1451b69a54eeSKentaro Takeda /* 1452b69a54eeSKentaro Takeda * tomoyo_get_path() reserves space for appending "/." 1453b69a54eeSKentaro Takeda */ 1454b69a54eeSKentaro Takeda strcat((char *) buf->name, "/"); 1455b69a54eeSKentaro Takeda tomoyo_fill_path_info(buf); 1456b69a54eeSKentaro Takeda } 1457b69a54eeSKentaro Takeda } 1458cb0abe6aSTetsuo Handa error = tomoyo_path_permission(&r, operation, buf); 1459b69a54eeSKentaro Takeda out: 14608e2d39a1STetsuo Handa kfree(buf); 1461fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 1462cb0abe6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 1463b69a54eeSKentaro Takeda error = 0; 1464b69a54eeSKentaro Takeda return error; 1465b69a54eeSKentaro Takeda } 1466b69a54eeSKentaro Takeda 1467b69a54eeSKentaro Takeda /** 1468a1f9bb6aSTetsuo Handa * tomoyo_path_number3_perm2 - Check permission for path/number/number/number operation. 1469a1f9bb6aSTetsuo Handa * 1470a1f9bb6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 1471a1f9bb6aSTetsuo Handa * @operation: Type of operation. 1472a1f9bb6aSTetsuo Handa * @filename: Filename to check. 1473a1f9bb6aSTetsuo Handa * @mode: Create mode. 1474a1f9bb6aSTetsuo Handa * @dev: Device number. 1475a1f9bb6aSTetsuo Handa * 1476a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1477a1f9bb6aSTetsuo Handa * 1478a1f9bb6aSTetsuo Handa * Caller holds tomoyo_read_lock(). 1479a1f9bb6aSTetsuo Handa */ 1480a1f9bb6aSTetsuo Handa static int tomoyo_path_number3_perm2(struct tomoyo_request_info *r, 1481a1f9bb6aSTetsuo Handa const u8 operation, 1482a1f9bb6aSTetsuo Handa const struct tomoyo_path_info *filename, 1483a1f9bb6aSTetsuo Handa const unsigned int mode, 1484a1f9bb6aSTetsuo Handa const unsigned int dev) 1485a1f9bb6aSTetsuo Handa { 1486a1f9bb6aSTetsuo Handa int error; 1487a1f9bb6aSTetsuo Handa const unsigned int major = MAJOR(dev); 1488a1f9bb6aSTetsuo Handa const unsigned int minor = MINOR(dev); 1489a1f9bb6aSTetsuo Handa 1490a1f9bb6aSTetsuo Handa error = tomoyo_path_number3_acl(r, filename, 1 << operation, mode, 1491a1f9bb6aSTetsuo Handa major, minor); 1492a1f9bb6aSTetsuo Handa if (!error) 1493a1f9bb6aSTetsuo Handa return 0; 1494a1f9bb6aSTetsuo Handa tomoyo_warn_log(r, "%s %s 0%o %u %u", 1495a1f9bb6aSTetsuo Handa tomoyo_path_number32keyword(operation), 1496a1f9bb6aSTetsuo Handa filename->name, mode, major, minor); 1497a1f9bb6aSTetsuo Handa if (tomoyo_domain_quota_is_ok(r)) { 1498a1f9bb6aSTetsuo Handa char mode_buf[64]; 1499a1f9bb6aSTetsuo Handa char major_buf[64]; 1500a1f9bb6aSTetsuo Handa char minor_buf[64]; 1501a1f9bb6aSTetsuo Handa memset(mode_buf, 0, sizeof(mode_buf)); 1502a1f9bb6aSTetsuo Handa memset(major_buf, 0, sizeof(major_buf)); 1503a1f9bb6aSTetsuo Handa memset(minor_buf, 0, sizeof(minor_buf)); 1504a1f9bb6aSTetsuo Handa snprintf(mode_buf, sizeof(mode_buf) - 1, "0%o", mode); 1505a1f9bb6aSTetsuo Handa snprintf(major_buf, sizeof(major_buf) - 1, "%u", major); 1506a1f9bb6aSTetsuo Handa snprintf(minor_buf, sizeof(minor_buf) - 1, "%u", minor); 1507a1f9bb6aSTetsuo Handa tomoyo_update_path_number3_acl(operation, 1508a1f9bb6aSTetsuo Handa tomoyo_get_file_pattern(filename) 1509a1f9bb6aSTetsuo Handa ->name, mode_buf, major_buf, 1510a1f9bb6aSTetsuo Handa minor_buf, r->domain, false); 1511a1f9bb6aSTetsuo Handa } 1512a1f9bb6aSTetsuo Handa if (r->mode != TOMOYO_CONFIG_ENFORCING) 1513a1f9bb6aSTetsuo Handa error = 0; 1514a1f9bb6aSTetsuo Handa return error; 1515a1f9bb6aSTetsuo Handa } 1516a1f9bb6aSTetsuo Handa 1517a1f9bb6aSTetsuo Handa /** 1518a1f9bb6aSTetsuo Handa * tomoyo_path_number3_perm - Check permission for "mkblock" and "mkchar". 1519a1f9bb6aSTetsuo Handa * 1520a1f9bb6aSTetsuo Handa * @operation: Type of operation. (TOMOYO_TYPE_MKCHAR or TOMOYO_TYPE_MKBLOCK) 1521a1f9bb6aSTetsuo Handa * @path: Pointer to "struct path". 1522a1f9bb6aSTetsuo Handa * @mode: Create mode. 1523a1f9bb6aSTetsuo Handa * @dev: Device number. 1524a1f9bb6aSTetsuo Handa * 1525a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1526a1f9bb6aSTetsuo Handa */ 1527a1f9bb6aSTetsuo Handa int tomoyo_path_number3_perm(const u8 operation, struct path *path, 1528a1f9bb6aSTetsuo Handa const unsigned int mode, unsigned int dev) 1529a1f9bb6aSTetsuo Handa { 1530a1f9bb6aSTetsuo Handa struct tomoyo_request_info r; 1531a1f9bb6aSTetsuo Handa int error = -ENOMEM; 1532a1f9bb6aSTetsuo Handa struct tomoyo_path_info *buf; 1533a1f9bb6aSTetsuo Handa int idx; 1534a1f9bb6aSTetsuo Handa 1535a1f9bb6aSTetsuo Handa if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED || 1536a1f9bb6aSTetsuo Handa !path->mnt) 1537a1f9bb6aSTetsuo Handa return 0; 1538a1f9bb6aSTetsuo Handa idx = tomoyo_read_lock(); 1539a1f9bb6aSTetsuo Handa error = -ENOMEM; 1540a1f9bb6aSTetsuo Handa buf = tomoyo_get_path(path); 1541a1f9bb6aSTetsuo Handa if (buf) { 1542a1f9bb6aSTetsuo Handa error = tomoyo_path_number3_perm2(&r, operation, buf, mode, 1543a1f9bb6aSTetsuo Handa new_decode_dev(dev)); 1544a1f9bb6aSTetsuo Handa kfree(buf); 1545a1f9bb6aSTetsuo Handa } 1546a1f9bb6aSTetsuo Handa tomoyo_read_unlock(idx); 1547a1f9bb6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 1548a1f9bb6aSTetsuo Handa error = 0; 1549a1f9bb6aSTetsuo Handa return error; 1550a1f9bb6aSTetsuo Handa } 1551a1f9bb6aSTetsuo Handa 1552a1f9bb6aSTetsuo Handa /** 15537ef61233STetsuo Handa * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root". 1554b69a54eeSKentaro Takeda * 1555b69a54eeSKentaro Takeda * @operation: Type of operation. 1556b69a54eeSKentaro Takeda * @path1: Pointer to "struct path". 1557b69a54eeSKentaro Takeda * @path2: Pointer to "struct path". 1558b69a54eeSKentaro Takeda * 1559b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1560b69a54eeSKentaro Takeda */ 156197d6931eSTetsuo Handa int tomoyo_path2_perm(const u8 operation, struct path *path1, 1562b69a54eeSKentaro Takeda struct path *path2) 1563b69a54eeSKentaro Takeda { 1564b69a54eeSKentaro Takeda int error = -ENOMEM; 1565cb0abe6aSTetsuo Handa struct tomoyo_path_info *buf1; 1566cb0abe6aSTetsuo Handa struct tomoyo_path_info *buf2; 1567cb0abe6aSTetsuo Handa struct tomoyo_request_info r; 1568fdb8ebb7STetsuo Handa int idx; 1569b69a54eeSKentaro Takeda 1570cb0abe6aSTetsuo Handa if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED || 1571cb0abe6aSTetsuo Handa !path1->mnt || !path2->mnt) 1572b69a54eeSKentaro Takeda return 0; 1573fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 1574b69a54eeSKentaro Takeda buf1 = tomoyo_get_path(path1); 1575b69a54eeSKentaro Takeda buf2 = tomoyo_get_path(path2); 1576b69a54eeSKentaro Takeda if (!buf1 || !buf2) 1577b69a54eeSKentaro Takeda goto out; 1578b69a54eeSKentaro Takeda { 1579b69a54eeSKentaro Takeda struct dentry *dentry = path1->dentry; 1580b69a54eeSKentaro Takeda if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) { 1581b69a54eeSKentaro Takeda /* 1582b69a54eeSKentaro Takeda * tomoyo_get_path() reserves space for appending "/." 1583b69a54eeSKentaro Takeda */ 1584b69a54eeSKentaro Takeda if (!buf1->is_dir) { 1585b69a54eeSKentaro Takeda strcat((char *) buf1->name, "/"); 1586b69a54eeSKentaro Takeda tomoyo_fill_path_info(buf1); 1587b69a54eeSKentaro Takeda } 1588b69a54eeSKentaro Takeda if (!buf2->is_dir) { 1589b69a54eeSKentaro Takeda strcat((char *) buf2->name, "/"); 1590b69a54eeSKentaro Takeda tomoyo_fill_path_info(buf2); 1591b69a54eeSKentaro Takeda } 1592b69a54eeSKentaro Takeda } 1593b69a54eeSKentaro Takeda } 1594cb0abe6aSTetsuo Handa error = tomoyo_path2_acl(&r, operation, buf1, buf2); 1595b69a54eeSKentaro Takeda if (!error) 1596b69a54eeSKentaro Takeda goto out; 1597cb0abe6aSTetsuo Handa tomoyo_warn_log(&r, "%s %s %s", tomoyo_path22keyword(operation), 1598cb0abe6aSTetsuo Handa buf1->name, buf2->name); 1599cb0abe6aSTetsuo Handa if (tomoyo_domain_quota_is_ok(&r)) { 1600b69a54eeSKentaro Takeda const char *name1 = tomoyo_get_file_pattern(buf1)->name; 1601b69a54eeSKentaro Takeda const char *name2 = tomoyo_get_file_pattern(buf2)->name; 1602cb0abe6aSTetsuo Handa tomoyo_update_path2_acl(operation, name1, name2, r.domain, 1603b69a54eeSKentaro Takeda false); 1604b69a54eeSKentaro Takeda } 1605b69a54eeSKentaro Takeda out: 16068e2d39a1STetsuo Handa kfree(buf1); 16078e2d39a1STetsuo Handa kfree(buf2); 1608fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 1609cb0abe6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 1610b69a54eeSKentaro Takeda error = 0; 1611b69a54eeSKentaro Takeda return error; 1612b69a54eeSKentaro Takeda } 1613a1f9bb6aSTetsuo Handa 1614a1f9bb6aSTetsuo Handa /** 1615a1f9bb6aSTetsuo Handa * tomoyo_write_file_policy - Update file related list. 1616a1f9bb6aSTetsuo Handa * 1617a1f9bb6aSTetsuo Handa * @data: String to parse. 1618a1f9bb6aSTetsuo Handa * @domain: Pointer to "struct tomoyo_domain_info". 1619a1f9bb6aSTetsuo Handa * @is_delete: True if it is a delete request. 1620a1f9bb6aSTetsuo Handa * 1621a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1622a1f9bb6aSTetsuo Handa * 1623a1f9bb6aSTetsuo Handa * Caller holds tomoyo_read_lock(). 1624a1f9bb6aSTetsuo Handa */ 1625a1f9bb6aSTetsuo Handa int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, 1626a1f9bb6aSTetsuo Handa const bool is_delete) 1627a1f9bb6aSTetsuo Handa { 1628a1f9bb6aSTetsuo Handa char *w[5]; 1629a1f9bb6aSTetsuo Handa u8 type; 1630a1f9bb6aSTetsuo Handa if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0]) 1631a1f9bb6aSTetsuo Handa return -EINVAL; 1632a1f9bb6aSTetsuo Handa if (strncmp(w[0], "allow_", 6)) { 1633a1f9bb6aSTetsuo Handa unsigned int perm; 1634a1f9bb6aSTetsuo Handa if (sscanf(w[0], "%u", &perm) == 1) 1635a1f9bb6aSTetsuo Handa return tomoyo_update_file_acl((u8) perm, w[1], domain, 1636a1f9bb6aSTetsuo Handa is_delete); 1637a1f9bb6aSTetsuo Handa goto out; 1638a1f9bb6aSTetsuo Handa } 1639a1f9bb6aSTetsuo Handa w[0] += 6; 1640a1f9bb6aSTetsuo Handa for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) { 1641a1f9bb6aSTetsuo Handa if (strcmp(w[0], tomoyo_path_keyword[type])) 1642a1f9bb6aSTetsuo Handa continue; 1643a1f9bb6aSTetsuo Handa return tomoyo_update_path_acl(type, w[1], domain, is_delete); 1644a1f9bb6aSTetsuo Handa } 1645a1f9bb6aSTetsuo Handa if (!w[2][0]) 1646a1f9bb6aSTetsuo Handa goto out; 1647a1f9bb6aSTetsuo Handa for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) { 1648a1f9bb6aSTetsuo Handa if (strcmp(w[0], tomoyo_path2_keyword[type])) 1649a1f9bb6aSTetsuo Handa continue; 1650a1f9bb6aSTetsuo Handa return tomoyo_update_path2_acl(type, w[1], w[2], domain, 1651a1f9bb6aSTetsuo Handa is_delete); 1652a1f9bb6aSTetsuo Handa } 1653a1f9bb6aSTetsuo Handa for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) { 1654a1f9bb6aSTetsuo Handa if (strcmp(w[0], tomoyo_path_number_keyword[type])) 1655a1f9bb6aSTetsuo Handa continue; 1656a1f9bb6aSTetsuo Handa return tomoyo_update_path_number_acl(type, w[1], w[2], domain, 1657a1f9bb6aSTetsuo Handa is_delete); 1658a1f9bb6aSTetsuo Handa } 1659a1f9bb6aSTetsuo Handa if (!w[3][0] || !w[4][0]) 1660a1f9bb6aSTetsuo Handa goto out; 1661a1f9bb6aSTetsuo Handa for (type = 0; type < TOMOYO_MAX_PATH_NUMBER3_OPERATION; type++) { 1662a1f9bb6aSTetsuo Handa if (strcmp(w[0], tomoyo_path_number3_keyword[type])) 1663a1f9bb6aSTetsuo Handa continue; 1664a1f9bb6aSTetsuo Handa return tomoyo_update_path_number3_acl(type, w[1], w[2], w[3], 1665a1f9bb6aSTetsuo Handa w[4], domain, is_delete); 1666a1f9bb6aSTetsuo Handa } 1667a1f9bb6aSTetsuo Handa out: 1668a1f9bb6aSTetsuo Handa return -EINVAL; 1669a1f9bb6aSTetsuo Handa } 1670