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 15b69a54eeSKentaro Takeda /* Keyword array for single path operations. */ 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_CREATE] = "create", 227ef61233STetsuo Handa [TOMOYO_TYPE_UNLINK] = "unlink", 237ef61233STetsuo Handa [TOMOYO_TYPE_MKDIR] = "mkdir", 247ef61233STetsuo Handa [TOMOYO_TYPE_RMDIR] = "rmdir", 257ef61233STetsuo Handa [TOMOYO_TYPE_MKFIFO] = "mkfifo", 267ef61233STetsuo Handa [TOMOYO_TYPE_MKSOCK] = "mksock", 277ef61233STetsuo Handa [TOMOYO_TYPE_MKBLOCK] = "mkblock", 287ef61233STetsuo Handa [TOMOYO_TYPE_MKCHAR] = "mkchar", 297ef61233STetsuo Handa [TOMOYO_TYPE_TRUNCATE] = "truncate", 307ef61233STetsuo Handa [TOMOYO_TYPE_SYMLINK] = "symlink", 317ef61233STetsuo Handa [TOMOYO_TYPE_REWRITE] = "rewrite", 327ef61233STetsuo Handa [TOMOYO_TYPE_IOCTL] = "ioctl", 337ef61233STetsuo Handa [TOMOYO_TYPE_CHMOD] = "chmod", 347ef61233STetsuo Handa [TOMOYO_TYPE_CHOWN] = "chown", 357ef61233STetsuo Handa [TOMOYO_TYPE_CHGRP] = "chgrp", 367ef61233STetsuo Handa [TOMOYO_TYPE_CHROOT] = "chroot", 377ef61233STetsuo Handa [TOMOYO_TYPE_MOUNT] = "mount", 387ef61233STetsuo Handa [TOMOYO_TYPE_UMOUNT] = "unmount", 39b69a54eeSKentaro Takeda }; 40b69a54eeSKentaro Takeda 41b69a54eeSKentaro Takeda /* Keyword array for double path operations. */ 427ef61233STetsuo Handa static const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = { 437ef61233STetsuo Handa [TOMOYO_TYPE_LINK] = "link", 447ef61233STetsuo Handa [TOMOYO_TYPE_RENAME] = "rename", 457ef61233STetsuo Handa [TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root", 46b69a54eeSKentaro Takeda }; 47b69a54eeSKentaro Takeda 487762fbffSTetsuo Handa void tomoyo_put_name_union(struct tomoyo_name_union *ptr) 497762fbffSTetsuo Handa { 507762fbffSTetsuo Handa if (!ptr) 517762fbffSTetsuo Handa return; 527762fbffSTetsuo Handa if (ptr->is_group) 537762fbffSTetsuo Handa tomoyo_put_path_group(ptr->group); 547762fbffSTetsuo Handa else 557762fbffSTetsuo Handa tomoyo_put_name(ptr->filename); 567762fbffSTetsuo Handa } 577762fbffSTetsuo Handa 587762fbffSTetsuo Handa bool tomoyo_compare_name_union(const struct tomoyo_path_info *name, 597762fbffSTetsuo Handa const struct tomoyo_name_union *ptr) 607762fbffSTetsuo Handa { 617762fbffSTetsuo Handa if (ptr->is_group) 627762fbffSTetsuo Handa return tomoyo_path_matches_group(name, ptr->group, 1); 637762fbffSTetsuo Handa return tomoyo_path_matches_pattern(name, ptr->filename); 647762fbffSTetsuo Handa } 657762fbffSTetsuo Handa 667762fbffSTetsuo Handa static bool tomoyo_compare_name_union_pattern(const struct tomoyo_path_info 677762fbffSTetsuo Handa *name, 687762fbffSTetsuo Handa const struct tomoyo_name_union 697762fbffSTetsuo Handa *ptr, const bool may_use_pattern) 707762fbffSTetsuo Handa { 717762fbffSTetsuo Handa if (ptr->is_group) 727762fbffSTetsuo Handa return tomoyo_path_matches_group(name, ptr->group, 737762fbffSTetsuo Handa may_use_pattern); 747762fbffSTetsuo Handa if (may_use_pattern || !ptr->filename->is_patterned) 757762fbffSTetsuo Handa return tomoyo_path_matches_pattern(name, ptr->filename); 767762fbffSTetsuo Handa return false; 777762fbffSTetsuo Handa } 787762fbffSTetsuo Handa 794c3e9e2dSTetsuo Handa void tomoyo_put_number_union(struct tomoyo_number_union *ptr) 804c3e9e2dSTetsuo Handa { 814c3e9e2dSTetsuo Handa if (ptr && ptr->is_group) 824c3e9e2dSTetsuo Handa tomoyo_put_number_group(ptr->group); 834c3e9e2dSTetsuo Handa } 844c3e9e2dSTetsuo Handa 854c3e9e2dSTetsuo Handa bool tomoyo_compare_number_union(const unsigned long value, 864c3e9e2dSTetsuo Handa const struct tomoyo_number_union *ptr) 874c3e9e2dSTetsuo Handa { 884c3e9e2dSTetsuo Handa if (ptr->is_group) 894c3e9e2dSTetsuo Handa return tomoyo_number_matches_group(value, value, ptr->group); 904c3e9e2dSTetsuo Handa return value >= ptr->values[0] && value <= ptr->values[1]; 914c3e9e2dSTetsuo Handa } 924c3e9e2dSTetsuo Handa 93b69a54eeSKentaro Takeda /** 947ef61233STetsuo Handa * tomoyo_path2keyword - Get the name of single path operation. 95b69a54eeSKentaro Takeda * 96b69a54eeSKentaro Takeda * @operation: Type of operation. 97b69a54eeSKentaro Takeda * 98b69a54eeSKentaro Takeda * Returns the name of single path operation. 99b69a54eeSKentaro Takeda */ 1007ef61233STetsuo Handa const char *tomoyo_path2keyword(const u8 operation) 101b69a54eeSKentaro Takeda { 1027ef61233STetsuo Handa return (operation < TOMOYO_MAX_PATH_OPERATION) 1037ef61233STetsuo Handa ? tomoyo_path_keyword[operation] : NULL; 104b69a54eeSKentaro Takeda } 105b69a54eeSKentaro Takeda 106b69a54eeSKentaro Takeda /** 1077ef61233STetsuo Handa * tomoyo_path22keyword - Get the name of double path operation. 108b69a54eeSKentaro Takeda * 109b69a54eeSKentaro Takeda * @operation: Type of operation. 110b69a54eeSKentaro Takeda * 111b69a54eeSKentaro Takeda * Returns the name of double path operation. 112b69a54eeSKentaro Takeda */ 1137ef61233STetsuo Handa const char *tomoyo_path22keyword(const u8 operation) 114b69a54eeSKentaro Takeda { 1157ef61233STetsuo Handa return (operation < TOMOYO_MAX_PATH2_OPERATION) 1167ef61233STetsuo Handa ? tomoyo_path2_keyword[operation] : NULL; 117b69a54eeSKentaro Takeda } 118b69a54eeSKentaro Takeda 119b69a54eeSKentaro Takeda /** 120b69a54eeSKentaro Takeda * tomoyo_strendswith - Check whether the token ends with the given token. 121b69a54eeSKentaro Takeda * 122b69a54eeSKentaro Takeda * @name: The token to check. 123b69a54eeSKentaro Takeda * @tail: The token to find. 124b69a54eeSKentaro Takeda * 125b69a54eeSKentaro Takeda * Returns true if @name ends with @tail, false otherwise. 126b69a54eeSKentaro Takeda */ 127b69a54eeSKentaro Takeda static bool tomoyo_strendswith(const char *name, const char *tail) 128b69a54eeSKentaro Takeda { 129b69a54eeSKentaro Takeda int len; 130b69a54eeSKentaro Takeda 131b69a54eeSKentaro Takeda if (!name || !tail) 132b69a54eeSKentaro Takeda return false; 133b69a54eeSKentaro Takeda len = strlen(name) - strlen(tail); 134b69a54eeSKentaro Takeda return len >= 0 && !strcmp(name + len, tail); 135b69a54eeSKentaro Takeda } 136b69a54eeSKentaro Takeda 137b69a54eeSKentaro Takeda /** 138b69a54eeSKentaro Takeda * tomoyo_get_path - Get realpath. 139b69a54eeSKentaro Takeda * 140b69a54eeSKentaro Takeda * @path: Pointer to "struct path". 141b69a54eeSKentaro Takeda * 142b69a54eeSKentaro Takeda * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. 143b69a54eeSKentaro Takeda */ 144b69a54eeSKentaro Takeda static struct tomoyo_path_info *tomoyo_get_path(struct path *path) 145b69a54eeSKentaro Takeda { 146b69a54eeSKentaro Takeda int error; 1478e2d39a1STetsuo Handa struct tomoyo_path_info_with_data *buf = kzalloc(sizeof(*buf), 1484e5d6f7eSTetsuo Handa GFP_NOFS); 149b69a54eeSKentaro Takeda 150b69a54eeSKentaro Takeda if (!buf) 151b69a54eeSKentaro Takeda return NULL; 152b69a54eeSKentaro Takeda /* Reserve one byte for appending "/". */ 153b69a54eeSKentaro Takeda error = tomoyo_realpath_from_path2(path, buf->body, 154b69a54eeSKentaro Takeda sizeof(buf->body) - 2); 155b69a54eeSKentaro Takeda if (!error) { 156b69a54eeSKentaro Takeda buf->head.name = buf->body; 157b69a54eeSKentaro Takeda tomoyo_fill_path_info(&buf->head); 158b69a54eeSKentaro Takeda return &buf->head; 159b69a54eeSKentaro Takeda } 1608e2d39a1STetsuo Handa kfree(buf); 161b69a54eeSKentaro Takeda return NULL; 162b69a54eeSKentaro Takeda } 163b69a54eeSKentaro Takeda 1647ef61233STetsuo Handa static int tomoyo_update_path2_acl(const u8 type, const char *filename1, 165b69a54eeSKentaro Takeda const char *filename2, 1667ef61233STetsuo Handa struct tomoyo_domain_info *const domain, 1677ef61233STetsuo Handa const bool is_delete); 1687ef61233STetsuo Handa static int tomoyo_update_path_acl(const u8 type, const char *filename, 1697ef61233STetsuo Handa struct tomoyo_domain_info *const domain, 1707ef61233STetsuo Handa const bool is_delete); 171b69a54eeSKentaro Takeda 172c3fa109aSTetsuo Handa /* 173c3fa109aSTetsuo Handa * tomoyo_globally_readable_list is used for holding list of pathnames which 174c3fa109aSTetsuo Handa * are by default allowed to be open()ed for reading by any process. 175c3fa109aSTetsuo Handa * 176c3fa109aSTetsuo Handa * An entry is added by 177c3fa109aSTetsuo Handa * 178c3fa109aSTetsuo Handa * # echo 'allow_read /lib/libc-2.5.so' > \ 179c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 180c3fa109aSTetsuo Handa * 181c3fa109aSTetsuo Handa * and is deleted by 182c3fa109aSTetsuo Handa * 183c3fa109aSTetsuo Handa * # echo 'delete allow_read /lib/libc-2.5.so' > \ 184c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 185c3fa109aSTetsuo Handa * 186c3fa109aSTetsuo Handa * and all entries are retrieved by 187c3fa109aSTetsuo Handa * 188c3fa109aSTetsuo Handa * # grep ^allow_read /sys/kernel/security/tomoyo/exception_policy 189c3fa109aSTetsuo Handa * 190c3fa109aSTetsuo Handa * In the example above, any process is allowed to 191c3fa109aSTetsuo Handa * open("/lib/libc-2.5.so", O_RDONLY). 192c3fa109aSTetsuo Handa * One exception is, if the domain which current process belongs to is marked 193c3fa109aSTetsuo Handa * as "ignore_global_allow_read", current process can't do so unless explicitly 194c3fa109aSTetsuo Handa * given "allow_read /lib/libc-2.5.so" to the domain which current process 195c3fa109aSTetsuo Handa * belongs to. 196c3fa109aSTetsuo Handa */ 197847b173eSTetsuo Handa LIST_HEAD(tomoyo_globally_readable_list); 198b69a54eeSKentaro Takeda 199b69a54eeSKentaro Takeda /** 200b69a54eeSKentaro Takeda * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list. 201b69a54eeSKentaro Takeda * 202b69a54eeSKentaro Takeda * @filename: Filename unconditionally permitted to open() for reading. 203b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 204b69a54eeSKentaro Takeda * 205b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 206fdb8ebb7STetsuo Handa * 207fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 208b69a54eeSKentaro Takeda */ 209b69a54eeSKentaro Takeda static int tomoyo_update_globally_readable_entry(const char *filename, 210b69a54eeSKentaro Takeda const bool is_delete) 211b69a54eeSKentaro Takeda { 212b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry *ptr; 2139e4b50e9STetsuo Handa struct tomoyo_globally_readable_file_entry e = { }; 214ca0b7df3STetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 215b69a54eeSKentaro Takeda 21617080008STetsuo Handa if (!tomoyo_is_correct_path(filename, 1, 0, -1)) 217b69a54eeSKentaro Takeda return -EINVAL; 2189e4b50e9STetsuo Handa e.filename = tomoyo_get_name(filename); 2199e4b50e9STetsuo Handa if (!e.filename) 220b69a54eeSKentaro Takeda return -ENOMEM; 22129282381STetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 22229282381STetsuo Handa goto out; 223fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) { 2249e4b50e9STetsuo Handa if (ptr->filename != e.filename) 225b69a54eeSKentaro Takeda continue; 226b69a54eeSKentaro Takeda ptr->is_deleted = is_delete; 227b69a54eeSKentaro Takeda error = 0; 228ca0b7df3STetsuo Handa break; 229b69a54eeSKentaro Takeda } 2309e4b50e9STetsuo Handa if (!is_delete && error) { 2319e4b50e9STetsuo Handa struct tomoyo_globally_readable_file_entry *entry = 2329e4b50e9STetsuo Handa tomoyo_commit_ok(&e, sizeof(e)); 2339e4b50e9STetsuo Handa if (entry) { 2349e4b50e9STetsuo Handa list_add_tail_rcu(&entry->list, 2359e4b50e9STetsuo Handa &tomoyo_globally_readable_list); 236b69a54eeSKentaro Takeda error = 0; 237ca0b7df3STetsuo Handa } 2389e4b50e9STetsuo Handa } 239f737d95dSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 24029282381STetsuo Handa out: 2419e4b50e9STetsuo Handa tomoyo_put_name(e.filename); 242b69a54eeSKentaro Takeda return error; 243b69a54eeSKentaro Takeda } 244b69a54eeSKentaro Takeda 245b69a54eeSKentaro Takeda /** 246b69a54eeSKentaro Takeda * tomoyo_is_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading. 247b69a54eeSKentaro Takeda * 248b69a54eeSKentaro Takeda * @filename: The filename to check. 249b69a54eeSKentaro Takeda * 250b69a54eeSKentaro Takeda * Returns true if any domain can open @filename for reading, false otherwise. 251fdb8ebb7STetsuo Handa * 252fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 253b69a54eeSKentaro Takeda */ 254b69a54eeSKentaro Takeda static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info * 255b69a54eeSKentaro Takeda filename) 256b69a54eeSKentaro Takeda { 257b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry *ptr; 258b69a54eeSKentaro Takeda bool found = false; 259fdb8ebb7STetsuo Handa 260fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) { 261b69a54eeSKentaro Takeda if (!ptr->is_deleted && 262b69a54eeSKentaro Takeda tomoyo_path_matches_pattern(filename, ptr->filename)) { 263b69a54eeSKentaro Takeda found = true; 264b69a54eeSKentaro Takeda break; 265b69a54eeSKentaro Takeda } 266b69a54eeSKentaro Takeda } 267b69a54eeSKentaro Takeda return found; 268b69a54eeSKentaro Takeda } 269b69a54eeSKentaro Takeda 270b69a54eeSKentaro Takeda /** 271b69a54eeSKentaro Takeda * tomoyo_write_globally_readable_policy - Write "struct tomoyo_globally_readable_file_entry" list. 272b69a54eeSKentaro Takeda * 273b69a54eeSKentaro Takeda * @data: String to parse. 274b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 275b69a54eeSKentaro Takeda * 276b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 277fdb8ebb7STetsuo Handa * 278fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 279b69a54eeSKentaro Takeda */ 280b69a54eeSKentaro Takeda int tomoyo_write_globally_readable_policy(char *data, const bool is_delete) 281b69a54eeSKentaro Takeda { 282b69a54eeSKentaro Takeda return tomoyo_update_globally_readable_entry(data, is_delete); 283b69a54eeSKentaro Takeda } 284b69a54eeSKentaro Takeda 285b69a54eeSKentaro Takeda /** 286b69a54eeSKentaro Takeda * tomoyo_read_globally_readable_policy - Read "struct tomoyo_globally_readable_file_entry" list. 287b69a54eeSKentaro Takeda * 288b69a54eeSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 289b69a54eeSKentaro Takeda * 290b69a54eeSKentaro Takeda * Returns true on success, false otherwise. 291fdb8ebb7STetsuo Handa * 292fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 293b69a54eeSKentaro Takeda */ 294b69a54eeSKentaro Takeda bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) 295b69a54eeSKentaro Takeda { 296b69a54eeSKentaro Takeda struct list_head *pos; 297b69a54eeSKentaro Takeda bool done = true; 298b69a54eeSKentaro Takeda 299b69a54eeSKentaro Takeda list_for_each_cookie(pos, head->read_var2, 300b69a54eeSKentaro Takeda &tomoyo_globally_readable_list) { 301b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry *ptr; 302b69a54eeSKentaro Takeda ptr = list_entry(pos, 303b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry, 304b69a54eeSKentaro Takeda list); 305b69a54eeSKentaro Takeda if (ptr->is_deleted) 306b69a54eeSKentaro Takeda continue; 3077d2948b1STetsuo Handa done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n", 3087d2948b1STetsuo Handa ptr->filename->name); 3097d2948b1STetsuo Handa if (!done) 310b69a54eeSKentaro Takeda break; 311b69a54eeSKentaro Takeda } 312b69a54eeSKentaro Takeda return done; 313b69a54eeSKentaro Takeda } 314b69a54eeSKentaro Takeda 315c3fa109aSTetsuo Handa /* tomoyo_pattern_list is used for holding list of pathnames which are used for 316c3fa109aSTetsuo Handa * converting pathnames to pathname patterns during learning mode. 317c3fa109aSTetsuo Handa * 318c3fa109aSTetsuo Handa * An entry is added by 319c3fa109aSTetsuo Handa * 320c3fa109aSTetsuo Handa * # echo 'file_pattern /proc/\$/mounts' > \ 321c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 322c3fa109aSTetsuo Handa * 323c3fa109aSTetsuo Handa * and is deleted by 324c3fa109aSTetsuo Handa * 325c3fa109aSTetsuo Handa * # echo 'delete file_pattern /proc/\$/mounts' > \ 326c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 327c3fa109aSTetsuo Handa * 328c3fa109aSTetsuo Handa * and all entries are retrieved by 329c3fa109aSTetsuo Handa * 330c3fa109aSTetsuo Handa * # grep ^file_pattern /sys/kernel/security/tomoyo/exception_policy 331c3fa109aSTetsuo Handa * 332c3fa109aSTetsuo Handa * In the example above, if a process which belongs to a domain which is in 333c3fa109aSTetsuo Handa * learning mode requested open("/proc/1/mounts", O_RDONLY), 334c3fa109aSTetsuo Handa * "allow_read /proc/\$/mounts" is automatically added to the domain which that 335c3fa109aSTetsuo Handa * process belongs to. 336c3fa109aSTetsuo Handa * 337c3fa109aSTetsuo Handa * It is not a desirable behavior that we have to use /proc/\$/ instead of 338c3fa109aSTetsuo Handa * /proc/self/ when current process needs to access only current process's 339c3fa109aSTetsuo Handa * information. As of now, LSM version of TOMOYO is using __d_path() for 340c3fa109aSTetsuo Handa * calculating pathname. Non LSM version of TOMOYO is using its own function 341c3fa109aSTetsuo Handa * which pretends as if /proc/self/ is not a symlink; so that we can forbid 342c3fa109aSTetsuo Handa * current process from accessing other process's information. 343c3fa109aSTetsuo Handa */ 344847b173eSTetsuo Handa LIST_HEAD(tomoyo_pattern_list); 345b69a54eeSKentaro Takeda 346b69a54eeSKentaro Takeda /** 347b69a54eeSKentaro Takeda * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list. 348b69a54eeSKentaro Takeda * 349b69a54eeSKentaro Takeda * @pattern: Pathname pattern. 350b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 351b69a54eeSKentaro Takeda * 352b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 353fdb8ebb7STetsuo Handa * 354fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 355b69a54eeSKentaro Takeda */ 356b69a54eeSKentaro Takeda static int tomoyo_update_file_pattern_entry(const char *pattern, 357b69a54eeSKentaro Takeda const bool is_delete) 358b69a54eeSKentaro Takeda { 359b69a54eeSKentaro Takeda struct tomoyo_pattern_entry *ptr; 3609e4b50e9STetsuo Handa struct tomoyo_pattern_entry e = { .pattern = tomoyo_get_name(pattern) }; 361ca0b7df3STetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 362b69a54eeSKentaro Takeda 3639e4b50e9STetsuo Handa if (!e.pattern) 364ca0b7df3STetsuo Handa return error; 3659e4b50e9STetsuo Handa if (!e.pattern->is_patterned) 366ca0b7df3STetsuo Handa goto out; 36729282381STetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 36829282381STetsuo Handa goto out; 369fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { 3709e4b50e9STetsuo Handa if (e.pattern != ptr->pattern) 371b69a54eeSKentaro Takeda continue; 372b69a54eeSKentaro Takeda ptr->is_deleted = is_delete; 373b69a54eeSKentaro Takeda error = 0; 374ca0b7df3STetsuo Handa break; 375b69a54eeSKentaro Takeda } 3769e4b50e9STetsuo Handa if (!is_delete && error) { 3779e4b50e9STetsuo Handa struct tomoyo_pattern_entry *entry = 3789e4b50e9STetsuo Handa tomoyo_commit_ok(&e, sizeof(e)); 3799e4b50e9STetsuo Handa if (entry) { 380ca0b7df3STetsuo Handa list_add_tail_rcu(&entry->list, &tomoyo_pattern_list); 381b69a54eeSKentaro Takeda error = 0; 382ca0b7df3STetsuo Handa } 3839e4b50e9STetsuo Handa } 384f737d95dSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 385ca0b7df3STetsuo Handa out: 3869e4b50e9STetsuo Handa tomoyo_put_name(e.pattern); 387b69a54eeSKentaro Takeda return error; 388b69a54eeSKentaro Takeda } 389b69a54eeSKentaro Takeda 390b69a54eeSKentaro Takeda /** 391b69a54eeSKentaro Takeda * tomoyo_get_file_pattern - Get patterned pathname. 392b69a54eeSKentaro Takeda * 393b69a54eeSKentaro Takeda * @filename: The filename to find patterned pathname. 394b69a54eeSKentaro Takeda * 395b69a54eeSKentaro Takeda * Returns pointer to pathname pattern if matched, @filename otherwise. 396fdb8ebb7STetsuo Handa * 397fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 398b69a54eeSKentaro Takeda */ 399b69a54eeSKentaro Takeda static const struct tomoyo_path_info * 400b69a54eeSKentaro Takeda tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) 401b69a54eeSKentaro Takeda { 402b69a54eeSKentaro Takeda struct tomoyo_pattern_entry *ptr; 403b69a54eeSKentaro Takeda const struct tomoyo_path_info *pattern = NULL; 404b69a54eeSKentaro Takeda 405fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { 406b69a54eeSKentaro Takeda if (ptr->is_deleted) 407b69a54eeSKentaro Takeda continue; 408b69a54eeSKentaro Takeda if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) 409b69a54eeSKentaro Takeda continue; 410b69a54eeSKentaro Takeda pattern = ptr->pattern; 411b69a54eeSKentaro Takeda if (tomoyo_strendswith(pattern->name, "/\\*")) { 412b69a54eeSKentaro Takeda /* Do nothing. Try to find the better match. */ 413b69a54eeSKentaro Takeda } else { 414b69a54eeSKentaro Takeda /* This would be the better match. Use this. */ 415b69a54eeSKentaro Takeda break; 416b69a54eeSKentaro Takeda } 417b69a54eeSKentaro Takeda } 418b69a54eeSKentaro Takeda if (pattern) 419b69a54eeSKentaro Takeda filename = pattern; 420b69a54eeSKentaro Takeda return filename; 421b69a54eeSKentaro Takeda } 422b69a54eeSKentaro Takeda 423b69a54eeSKentaro Takeda /** 424b69a54eeSKentaro Takeda * tomoyo_write_pattern_policy - Write "struct tomoyo_pattern_entry" list. 425b69a54eeSKentaro Takeda * 426b69a54eeSKentaro Takeda * @data: String to parse. 427b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 428b69a54eeSKentaro Takeda * 429b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 430fdb8ebb7STetsuo Handa * 431fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 432b69a54eeSKentaro Takeda */ 433b69a54eeSKentaro Takeda int tomoyo_write_pattern_policy(char *data, const bool is_delete) 434b69a54eeSKentaro Takeda { 435b69a54eeSKentaro Takeda return tomoyo_update_file_pattern_entry(data, is_delete); 436b69a54eeSKentaro Takeda } 437b69a54eeSKentaro Takeda 438b69a54eeSKentaro Takeda /** 439b69a54eeSKentaro Takeda * tomoyo_read_file_pattern - Read "struct tomoyo_pattern_entry" list. 440b69a54eeSKentaro Takeda * 441b69a54eeSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 442b69a54eeSKentaro Takeda * 443b69a54eeSKentaro Takeda * Returns true on success, false otherwise. 444fdb8ebb7STetsuo Handa * 445fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 446b69a54eeSKentaro Takeda */ 447b69a54eeSKentaro Takeda bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) 448b69a54eeSKentaro Takeda { 449b69a54eeSKentaro Takeda struct list_head *pos; 450b69a54eeSKentaro Takeda bool done = true; 451b69a54eeSKentaro Takeda 452b69a54eeSKentaro Takeda list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) { 453b69a54eeSKentaro Takeda struct tomoyo_pattern_entry *ptr; 454b69a54eeSKentaro Takeda ptr = list_entry(pos, struct tomoyo_pattern_entry, list); 455b69a54eeSKentaro Takeda if (ptr->is_deleted) 456b69a54eeSKentaro Takeda continue; 4577d2948b1STetsuo Handa done = tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN 4587d2948b1STetsuo Handa "%s\n", ptr->pattern->name); 4597d2948b1STetsuo Handa if (!done) 460b69a54eeSKentaro Takeda break; 461b69a54eeSKentaro Takeda } 462b69a54eeSKentaro Takeda return done; 463b69a54eeSKentaro Takeda } 464b69a54eeSKentaro Takeda 465c3fa109aSTetsuo Handa /* 466c3fa109aSTetsuo Handa * tomoyo_no_rewrite_list is used for holding list of pathnames which are by 467c3fa109aSTetsuo Handa * default forbidden to modify already written content of a file. 468c3fa109aSTetsuo Handa * 469c3fa109aSTetsuo Handa * An entry is added by 470c3fa109aSTetsuo Handa * 471c3fa109aSTetsuo Handa * # echo 'deny_rewrite /var/log/messages' > \ 472c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 473c3fa109aSTetsuo Handa * 474c3fa109aSTetsuo Handa * and is deleted by 475c3fa109aSTetsuo Handa * 476c3fa109aSTetsuo Handa * # echo 'delete deny_rewrite /var/log/messages' > \ 477c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 478c3fa109aSTetsuo Handa * 479c3fa109aSTetsuo Handa * and all entries are retrieved by 480c3fa109aSTetsuo Handa * 481c3fa109aSTetsuo Handa * # grep ^deny_rewrite /sys/kernel/security/tomoyo/exception_policy 482c3fa109aSTetsuo Handa * 483c3fa109aSTetsuo Handa * In the example above, if a process requested to rewrite /var/log/messages , 484c3fa109aSTetsuo Handa * the process can't rewrite unless the domain which that process belongs to 485c3fa109aSTetsuo Handa * has "allow_rewrite /var/log/messages" entry. 486c3fa109aSTetsuo Handa * 487c3fa109aSTetsuo Handa * It is not a desirable behavior that we have to add "\040(deleted)" suffix 488c3fa109aSTetsuo Handa * when we want to allow rewriting already unlink()ed file. As of now, 489c3fa109aSTetsuo Handa * LSM version of TOMOYO is using __d_path() for calculating pathname. 490c3fa109aSTetsuo Handa * Non LSM version of TOMOYO is using its own function which doesn't append 491c3fa109aSTetsuo Handa * " (deleted)" suffix if the file is already unlink()ed; so that we don't 492c3fa109aSTetsuo Handa * need to worry whether the file is already unlink()ed or not. 493c3fa109aSTetsuo Handa */ 494847b173eSTetsuo Handa LIST_HEAD(tomoyo_no_rewrite_list); 495b69a54eeSKentaro Takeda 496b69a54eeSKentaro Takeda /** 497b69a54eeSKentaro Takeda * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list. 498b69a54eeSKentaro Takeda * 499b69a54eeSKentaro Takeda * @pattern: Pathname pattern that are not rewritable by default. 500b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 501b69a54eeSKentaro Takeda * 502b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 503fdb8ebb7STetsuo Handa * 504fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 505b69a54eeSKentaro Takeda */ 506b69a54eeSKentaro Takeda static int tomoyo_update_no_rewrite_entry(const char *pattern, 507b69a54eeSKentaro Takeda const bool is_delete) 508b69a54eeSKentaro Takeda { 509ca0b7df3STetsuo Handa struct tomoyo_no_rewrite_entry *ptr; 5109e4b50e9STetsuo Handa struct tomoyo_no_rewrite_entry e = { }; 511ca0b7df3STetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 512b69a54eeSKentaro Takeda 51317080008STetsuo Handa if (!tomoyo_is_correct_path(pattern, 0, 0, 0)) 514b69a54eeSKentaro Takeda return -EINVAL; 5159e4b50e9STetsuo Handa e.pattern = tomoyo_get_name(pattern); 5169e4b50e9STetsuo Handa if (!e.pattern) 517ca0b7df3STetsuo Handa return error; 51829282381STetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 51929282381STetsuo Handa goto out; 520fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { 5219e4b50e9STetsuo Handa if (ptr->pattern != e.pattern) 522b69a54eeSKentaro Takeda continue; 523b69a54eeSKentaro Takeda ptr->is_deleted = is_delete; 524b69a54eeSKentaro Takeda error = 0; 525ca0b7df3STetsuo Handa break; 526b69a54eeSKentaro Takeda } 5279e4b50e9STetsuo Handa if (!is_delete && error) { 5289e4b50e9STetsuo Handa struct tomoyo_no_rewrite_entry *entry = 5299e4b50e9STetsuo Handa tomoyo_commit_ok(&e, sizeof(e)); 5309e4b50e9STetsuo Handa if (entry) { 5319e4b50e9STetsuo Handa list_add_tail_rcu(&entry->list, 5329e4b50e9STetsuo Handa &tomoyo_no_rewrite_list); 533b69a54eeSKentaro Takeda error = 0; 534ca0b7df3STetsuo Handa } 5359e4b50e9STetsuo Handa } 536f737d95dSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 53729282381STetsuo Handa out: 5389e4b50e9STetsuo Handa tomoyo_put_name(e.pattern); 539b69a54eeSKentaro Takeda return error; 540b69a54eeSKentaro Takeda } 541b69a54eeSKentaro Takeda 542b69a54eeSKentaro Takeda /** 543b69a54eeSKentaro Takeda * tomoyo_is_no_rewrite_file - Check if the given pathname is not permitted to be rewrited. 544b69a54eeSKentaro Takeda * 545b69a54eeSKentaro Takeda * @filename: Filename to check. 546b69a54eeSKentaro Takeda * 547b69a54eeSKentaro Takeda * Returns true if @filename is specified by "deny_rewrite" directive, 548b69a54eeSKentaro Takeda * false otherwise. 549fdb8ebb7STetsuo Handa * 550fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 551b69a54eeSKentaro Takeda */ 552b69a54eeSKentaro Takeda static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) 553b69a54eeSKentaro Takeda { 554b69a54eeSKentaro Takeda struct tomoyo_no_rewrite_entry *ptr; 555b69a54eeSKentaro Takeda bool found = false; 556b69a54eeSKentaro Takeda 557fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { 558b69a54eeSKentaro Takeda if (ptr->is_deleted) 559b69a54eeSKentaro Takeda continue; 560b69a54eeSKentaro Takeda if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) 561b69a54eeSKentaro Takeda continue; 562b69a54eeSKentaro Takeda found = true; 563b69a54eeSKentaro Takeda break; 564b69a54eeSKentaro Takeda } 565b69a54eeSKentaro Takeda return found; 566b69a54eeSKentaro Takeda } 567b69a54eeSKentaro Takeda 568b69a54eeSKentaro Takeda /** 569b69a54eeSKentaro Takeda * tomoyo_write_no_rewrite_policy - Write "struct tomoyo_no_rewrite_entry" list. 570b69a54eeSKentaro Takeda * 571b69a54eeSKentaro Takeda * @data: String to parse. 572b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 573b69a54eeSKentaro Takeda * 574b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 575fdb8ebb7STetsuo Handa * 576fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 577b69a54eeSKentaro Takeda */ 578b69a54eeSKentaro Takeda int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete) 579b69a54eeSKentaro Takeda { 580b69a54eeSKentaro Takeda return tomoyo_update_no_rewrite_entry(data, is_delete); 581b69a54eeSKentaro Takeda } 582b69a54eeSKentaro Takeda 583b69a54eeSKentaro Takeda /** 584b69a54eeSKentaro Takeda * tomoyo_read_no_rewrite_policy - Read "struct tomoyo_no_rewrite_entry" list. 585b69a54eeSKentaro Takeda * 586b69a54eeSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 587b69a54eeSKentaro Takeda * 588b69a54eeSKentaro Takeda * Returns true on success, false otherwise. 589fdb8ebb7STetsuo Handa * 590fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 591b69a54eeSKentaro Takeda */ 592b69a54eeSKentaro Takeda bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) 593b69a54eeSKentaro Takeda { 594b69a54eeSKentaro Takeda struct list_head *pos; 595b69a54eeSKentaro Takeda bool done = true; 596b69a54eeSKentaro Takeda 597b69a54eeSKentaro Takeda list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) { 598b69a54eeSKentaro Takeda struct tomoyo_no_rewrite_entry *ptr; 599b69a54eeSKentaro Takeda ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list); 600b69a54eeSKentaro Takeda if (ptr->is_deleted) 601b69a54eeSKentaro Takeda continue; 6027d2948b1STetsuo Handa done = tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE 6037d2948b1STetsuo Handa "%s\n", ptr->pattern->name); 6047d2948b1STetsuo Handa if (!done) 605b69a54eeSKentaro Takeda break; 606b69a54eeSKentaro Takeda } 607b69a54eeSKentaro Takeda return done; 608b69a54eeSKentaro Takeda } 609b69a54eeSKentaro Takeda 610b69a54eeSKentaro Takeda /** 611b69a54eeSKentaro Takeda * tomoyo_update_file_acl - Update file's read/write/execute ACL. 612b69a54eeSKentaro Takeda * 613b69a54eeSKentaro Takeda * @filename: Filename. 614b69a54eeSKentaro Takeda * @perm: Permission (between 1 to 7). 615b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 616b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 617b69a54eeSKentaro Takeda * 618b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 619b69a54eeSKentaro Takeda * 620b69a54eeSKentaro Takeda * This is legacy support interface for older policy syntax. 621b69a54eeSKentaro Takeda * Current policy syntax uses "allow_read/write" instead of "6", 622b69a54eeSKentaro Takeda * "allow_read" instead of "4", "allow_write" instead of "2", 623b69a54eeSKentaro Takeda * "allow_execute" instead of "1". 624fdb8ebb7STetsuo Handa * 625fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 626b69a54eeSKentaro Takeda */ 627b69a54eeSKentaro Takeda static int tomoyo_update_file_acl(const char *filename, u8 perm, 628b69a54eeSKentaro Takeda struct tomoyo_domain_info * const domain, 629b69a54eeSKentaro Takeda const bool is_delete) 630b69a54eeSKentaro Takeda { 631b69a54eeSKentaro Takeda if (perm > 7 || !perm) { 632b69a54eeSKentaro Takeda printk(KERN_DEBUG "%s: Invalid permission '%d %s'\n", 633b69a54eeSKentaro Takeda __func__, perm, filename); 634b69a54eeSKentaro Takeda return -EINVAL; 635b69a54eeSKentaro Takeda } 636b69a54eeSKentaro Takeda if (filename[0] != '@' && tomoyo_strendswith(filename, "/")) 637b69a54eeSKentaro Takeda /* 638b69a54eeSKentaro Takeda * Only 'allow_mkdir' and 'allow_rmdir' are valid for 639b69a54eeSKentaro Takeda * directory permissions. 640b69a54eeSKentaro Takeda */ 641b69a54eeSKentaro Takeda return 0; 642b69a54eeSKentaro Takeda if (perm & 4) 6437ef61233STetsuo Handa tomoyo_update_path_acl(TOMOYO_TYPE_READ, filename, domain, 6447ef61233STetsuo Handa is_delete); 645b69a54eeSKentaro Takeda if (perm & 2) 6467ef61233STetsuo Handa tomoyo_update_path_acl(TOMOYO_TYPE_WRITE, filename, domain, 6477ef61233STetsuo Handa is_delete); 648b69a54eeSKentaro Takeda if (perm & 1) 6497ef61233STetsuo Handa tomoyo_update_path_acl(TOMOYO_TYPE_EXECUTE, filename, domain, 6507ef61233STetsuo Handa is_delete); 651b69a54eeSKentaro Takeda return 0; 652b69a54eeSKentaro Takeda } 653b69a54eeSKentaro Takeda 654b69a54eeSKentaro Takeda /** 6557ef61233STetsuo Handa * tomoyo_path_acl2 - Check permission for single path operation. 656b69a54eeSKentaro Takeda * 657b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 658b69a54eeSKentaro Takeda * @filename: Filename to check. 659b69a54eeSKentaro Takeda * @perm: Permission. 660b69a54eeSKentaro Takeda * @may_use_pattern: True if patterned ACL is permitted. 661b69a54eeSKentaro Takeda * 662b69a54eeSKentaro Takeda * Returns 0 on success, -EPERM otherwise. 663fdb8ebb7STetsuo Handa * 664fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 665b69a54eeSKentaro Takeda */ 6667ef61233STetsuo Handa static int tomoyo_path_acl2(const struct tomoyo_domain_info *domain, 6677ef61233STetsuo Handa const struct tomoyo_path_info *filename, 6687ef61233STetsuo Handa const u32 perm, const bool may_use_pattern) 669b69a54eeSKentaro Takeda { 670b69a54eeSKentaro Takeda struct tomoyo_acl_info *ptr; 671b69a54eeSKentaro Takeda int error = -EPERM; 672b69a54eeSKentaro Takeda 673fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 6747ef61233STetsuo Handa struct tomoyo_path_acl *acl; 6757ef61233STetsuo Handa if (ptr->type != TOMOYO_TYPE_PATH_ACL) 676b69a54eeSKentaro Takeda continue; 6777ef61233STetsuo Handa acl = container_of(ptr, struct tomoyo_path_acl, head); 678937bf613STetsuo Handa if (perm <= 0xFFFF) { 679b69a54eeSKentaro Takeda if (!(acl->perm & perm)) 680b69a54eeSKentaro Takeda continue; 681937bf613STetsuo Handa } else { 682937bf613STetsuo Handa if (!(acl->perm_high & (perm >> 16))) 683937bf613STetsuo Handa continue; 684937bf613STetsuo Handa } 6857762fbffSTetsuo Handa if (!tomoyo_compare_name_union_pattern(filename, &acl->name, 6867762fbffSTetsuo Handa may_use_pattern)) 687b69a54eeSKentaro Takeda continue; 688b69a54eeSKentaro Takeda error = 0; 689b69a54eeSKentaro Takeda break; 690b69a54eeSKentaro Takeda } 691b69a54eeSKentaro Takeda return error; 692b69a54eeSKentaro Takeda } 693b69a54eeSKentaro Takeda 694b69a54eeSKentaro Takeda /** 695b69a54eeSKentaro Takeda * tomoyo_check_file_acl - Check permission for opening files. 696b69a54eeSKentaro Takeda * 697b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 698b69a54eeSKentaro Takeda * @filename: Filename to check. 699b69a54eeSKentaro Takeda * @operation: Mode ("read" or "write" or "read/write" or "execute"). 700b69a54eeSKentaro Takeda * 701b69a54eeSKentaro Takeda * Returns 0 on success, -EPERM otherwise. 702fdb8ebb7STetsuo Handa * 703fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 704b69a54eeSKentaro Takeda */ 705b69a54eeSKentaro Takeda static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain, 706b69a54eeSKentaro Takeda const struct tomoyo_path_info *filename, 707b69a54eeSKentaro Takeda const u8 operation) 708b69a54eeSKentaro Takeda { 709937bf613STetsuo Handa u32 perm = 0; 710b69a54eeSKentaro Takeda 711b69a54eeSKentaro Takeda if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) 712b69a54eeSKentaro Takeda return 0; 713b69a54eeSKentaro Takeda if (operation == 6) 7147ef61233STetsuo Handa perm = 1 << TOMOYO_TYPE_READ_WRITE; 715b69a54eeSKentaro Takeda else if (operation == 4) 7167ef61233STetsuo Handa perm = 1 << TOMOYO_TYPE_READ; 717b69a54eeSKentaro Takeda else if (operation == 2) 7187ef61233STetsuo Handa perm = 1 << TOMOYO_TYPE_WRITE; 719b69a54eeSKentaro Takeda else if (operation == 1) 7207ef61233STetsuo Handa perm = 1 << TOMOYO_TYPE_EXECUTE; 721b69a54eeSKentaro Takeda else 722b69a54eeSKentaro Takeda BUG(); 7237ef61233STetsuo Handa return tomoyo_path_acl2(domain, filename, perm, operation != 1); 724b69a54eeSKentaro Takeda } 725b69a54eeSKentaro Takeda 726b69a54eeSKentaro Takeda /** 727b69a54eeSKentaro Takeda * tomoyo_check_file_perm2 - Check permission for opening files. 728b69a54eeSKentaro Takeda * 729b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 730b69a54eeSKentaro Takeda * @filename: Filename to check. 731b69a54eeSKentaro Takeda * @perm: Mode ("read" or "write" or "read/write" or "execute"). 732b69a54eeSKentaro Takeda * @operation: Operation name passed used for verbose mode. 733b69a54eeSKentaro Takeda * @mode: Access control mode. 734b69a54eeSKentaro Takeda * 735b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 736fdb8ebb7STetsuo Handa * 737fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 738b69a54eeSKentaro Takeda */ 739b69a54eeSKentaro Takeda static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain, 740b69a54eeSKentaro Takeda const struct tomoyo_path_info *filename, 741b69a54eeSKentaro Takeda const u8 perm, const char *operation, 742b69a54eeSKentaro Takeda const u8 mode) 743b69a54eeSKentaro Takeda { 744b69a54eeSKentaro Takeda const bool is_enforce = (mode == 3); 745b69a54eeSKentaro Takeda const char *msg = "<unknown>"; 746b69a54eeSKentaro Takeda int error = 0; 747b69a54eeSKentaro Takeda 748b69a54eeSKentaro Takeda if (!filename) 749b69a54eeSKentaro Takeda return 0; 750b69a54eeSKentaro Takeda error = tomoyo_check_file_acl(domain, filename, perm); 751ea13ddbaSTetsuo Handa if (error && perm == 4 && !domain->ignore_global_allow_read 752b69a54eeSKentaro Takeda && tomoyo_is_globally_readable_file(filename)) 753b69a54eeSKentaro Takeda error = 0; 754b69a54eeSKentaro Takeda if (perm == 6) 7557ef61233STetsuo Handa msg = tomoyo_path2keyword(TOMOYO_TYPE_READ_WRITE); 756b69a54eeSKentaro Takeda else if (perm == 4) 7577ef61233STetsuo Handa msg = tomoyo_path2keyword(TOMOYO_TYPE_READ); 758b69a54eeSKentaro Takeda else if (perm == 2) 7597ef61233STetsuo Handa msg = tomoyo_path2keyword(TOMOYO_TYPE_WRITE); 760b69a54eeSKentaro Takeda else if (perm == 1) 7617ef61233STetsuo Handa msg = tomoyo_path2keyword(TOMOYO_TYPE_EXECUTE); 762b69a54eeSKentaro Takeda else 763b69a54eeSKentaro Takeda BUG(); 764b69a54eeSKentaro Takeda if (!error) 765b69a54eeSKentaro Takeda return 0; 766b69a54eeSKentaro Takeda if (tomoyo_verbose_mode(domain)) 767b69a54eeSKentaro Takeda printk(KERN_WARNING "TOMOYO-%s: Access '%s(%s) %s' denied " 768b69a54eeSKentaro Takeda "for %s\n", tomoyo_get_msg(is_enforce), msg, operation, 769b69a54eeSKentaro Takeda filename->name, tomoyo_get_last_name(domain)); 770b69a54eeSKentaro Takeda if (is_enforce) 771b69a54eeSKentaro Takeda return error; 772b69a54eeSKentaro Takeda if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { 773b69a54eeSKentaro Takeda /* Don't use patterns for execute permission. */ 774b69a54eeSKentaro Takeda const struct tomoyo_path_info *patterned_file = (perm != 1) ? 775b69a54eeSKentaro Takeda tomoyo_get_file_pattern(filename) : filename; 776b69a54eeSKentaro Takeda tomoyo_update_file_acl(patterned_file->name, perm, 777b69a54eeSKentaro Takeda domain, false); 778b69a54eeSKentaro Takeda } 779b69a54eeSKentaro Takeda return 0; 780b69a54eeSKentaro Takeda } 781b69a54eeSKentaro Takeda 782b69a54eeSKentaro Takeda /** 783b69a54eeSKentaro Takeda * tomoyo_write_file_policy - Update file related list. 784b69a54eeSKentaro Takeda * 785b69a54eeSKentaro Takeda * @data: String to parse. 786b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 787b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 788b69a54eeSKentaro Takeda * 789b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 790fdb8ebb7STetsuo Handa * 791fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 792b69a54eeSKentaro Takeda */ 793b69a54eeSKentaro Takeda int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, 794b69a54eeSKentaro Takeda const bool is_delete) 795b69a54eeSKentaro Takeda { 796b69a54eeSKentaro Takeda char *filename = strchr(data, ' '); 797b69a54eeSKentaro Takeda char *filename2; 798b69a54eeSKentaro Takeda unsigned int perm; 799b69a54eeSKentaro Takeda u8 type; 800b69a54eeSKentaro Takeda 801b69a54eeSKentaro Takeda if (!filename) 802b69a54eeSKentaro Takeda return -EINVAL; 803b69a54eeSKentaro Takeda *filename++ = '\0'; 804b69a54eeSKentaro Takeda if (sscanf(data, "%u", &perm) == 1) 805b69a54eeSKentaro Takeda return tomoyo_update_file_acl(filename, (u8) perm, domain, 806b69a54eeSKentaro Takeda is_delete); 807b69a54eeSKentaro Takeda if (strncmp(data, "allow_", 6)) 808b69a54eeSKentaro Takeda goto out; 809b69a54eeSKentaro Takeda data += 6; 8107ef61233STetsuo Handa for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) { 8117ef61233STetsuo Handa if (strcmp(data, tomoyo_path_keyword[type])) 812b69a54eeSKentaro Takeda continue; 8137ef61233STetsuo Handa return tomoyo_update_path_acl(type, filename, domain, 8147ef61233STetsuo Handa is_delete); 815b69a54eeSKentaro Takeda } 816b69a54eeSKentaro Takeda filename2 = strchr(filename, ' '); 817b69a54eeSKentaro Takeda if (!filename2) 818b69a54eeSKentaro Takeda goto out; 819b69a54eeSKentaro Takeda *filename2++ = '\0'; 8207ef61233STetsuo Handa for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) { 8217ef61233STetsuo Handa if (strcmp(data, tomoyo_path2_keyword[type])) 822b69a54eeSKentaro Takeda continue; 8237ef61233STetsuo Handa return tomoyo_update_path2_acl(type, filename, filename2, 824b69a54eeSKentaro Takeda domain, is_delete); 825b69a54eeSKentaro Takeda } 826b69a54eeSKentaro Takeda out: 827b69a54eeSKentaro Takeda return -EINVAL; 828b69a54eeSKentaro Takeda } 829b69a54eeSKentaro Takeda 830b69a54eeSKentaro Takeda /** 8317ef61233STetsuo Handa * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list. 832b69a54eeSKentaro Takeda * 833b69a54eeSKentaro Takeda * @type: Type of operation. 834b69a54eeSKentaro Takeda * @filename: Filename. 835b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 836b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 837b69a54eeSKentaro Takeda * 838b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 839fdb8ebb7STetsuo Handa * 840fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 841b69a54eeSKentaro Takeda */ 8427ef61233STetsuo Handa static int tomoyo_update_path_acl(const u8 type, const char *filename, 8437ef61233STetsuo Handa struct tomoyo_domain_info *const domain, 8447ef61233STetsuo Handa const bool is_delete) 845b69a54eeSKentaro Takeda { 8469e4b50e9STetsuo Handa static const u32 tomoyo_rw_mask = 8477ef61233STetsuo Handa (1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE); 848937bf613STetsuo Handa const u32 perm = 1 << type; 8499e4b50e9STetsuo Handa struct tomoyo_acl_info *ptr; 8509e4b50e9STetsuo Handa struct tomoyo_path_acl e = { 8519e4b50e9STetsuo Handa .head.type = TOMOYO_TYPE_PATH_ACL, 8529e4b50e9STetsuo Handa .perm_high = perm >> 16, 8539e4b50e9STetsuo Handa .perm = perm 8549e4b50e9STetsuo Handa }; 8559e4b50e9STetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 856b69a54eeSKentaro Takeda 8579e4b50e9STetsuo Handa if (type == TOMOYO_TYPE_READ_WRITE) 8589e4b50e9STetsuo Handa e.perm |= tomoyo_rw_mask; 859b69a54eeSKentaro Takeda if (!domain) 860b69a54eeSKentaro Takeda return -EINVAL; 8617762fbffSTetsuo Handa if (!tomoyo_parse_name_union(filename, &e.name)) 862b69a54eeSKentaro Takeda return -EINVAL; 86329282381STetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 86429282381STetsuo Handa goto out; 865fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 8667ef61233STetsuo Handa struct tomoyo_path_acl *acl = 8677ef61233STetsuo Handa container_of(ptr, struct tomoyo_path_acl, head); 8687762fbffSTetsuo Handa if (!tomoyo_is_same_path_acl(acl, &e)) 869b69a54eeSKentaro Takeda continue; 870ca0b7df3STetsuo Handa if (is_delete) { 871ca0b7df3STetsuo Handa if (perm <= 0xFFFF) 872ca0b7df3STetsuo Handa acl->perm &= ~perm; 873ca0b7df3STetsuo Handa else 874ca0b7df3STetsuo Handa acl->perm_high &= ~(perm >> 16); 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 { 880937bf613STetsuo Handa if (perm <= 0xFFFF) 881b69a54eeSKentaro Takeda acl->perm |= perm; 882937bf613STetsuo Handa else 883937bf613STetsuo Handa acl->perm_high |= (perm >> 16); 8849e4b50e9STetsuo Handa if ((acl->perm & tomoyo_rw_mask) == tomoyo_rw_mask) 8857ef61233STetsuo Handa acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE; 8867ef61233STetsuo Handa else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE)) 8879e4b50e9STetsuo Handa acl->perm |= tomoyo_rw_mask; 888b69a54eeSKentaro Takeda } 889b69a54eeSKentaro Takeda error = 0; 890b69a54eeSKentaro Takeda break; 891b69a54eeSKentaro Takeda } 8929e4b50e9STetsuo Handa if (!is_delete && error) { 8939e4b50e9STetsuo Handa struct tomoyo_path_acl *entry = 8949e4b50e9STetsuo Handa tomoyo_commit_ok(&e, sizeof(e)); 8959e4b50e9STetsuo Handa if (entry) { 8969e4b50e9STetsuo Handa list_add_tail_rcu(&entry->head.list, 8979e4b50e9STetsuo Handa &domain->acl_info_list); 898ca0b7df3STetsuo Handa error = 0; 899ca0b7df3STetsuo Handa } 9009e4b50e9STetsuo Handa } 901f737d95dSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 90229282381STetsuo Handa out: 9037762fbffSTetsuo Handa tomoyo_put_name_union(&e.name); 904b69a54eeSKentaro Takeda return error; 905b69a54eeSKentaro Takeda } 906b69a54eeSKentaro Takeda 907b69a54eeSKentaro Takeda /** 9087ef61233STetsuo Handa * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list. 909b69a54eeSKentaro Takeda * 910b69a54eeSKentaro Takeda * @type: Type of operation. 911b69a54eeSKentaro Takeda * @filename1: First filename. 912b69a54eeSKentaro Takeda * @filename2: Second filename. 913b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 914b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 915b69a54eeSKentaro Takeda * 916b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 917fdb8ebb7STetsuo Handa * 918fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 919b69a54eeSKentaro Takeda */ 9207ef61233STetsuo Handa static int tomoyo_update_path2_acl(const u8 type, const char *filename1, 921b69a54eeSKentaro Takeda const char *filename2, 9227ef61233STetsuo Handa struct tomoyo_domain_info *const domain, 9237ef61233STetsuo Handa const bool is_delete) 924b69a54eeSKentaro Takeda { 925b69a54eeSKentaro Takeda const u8 perm = 1 << type; 9269e4b50e9STetsuo Handa struct tomoyo_path2_acl e = { 9279e4b50e9STetsuo Handa .head.type = TOMOYO_TYPE_PATH2_ACL, 9289e4b50e9STetsuo Handa .perm = perm 9299e4b50e9STetsuo Handa }; 9309e4b50e9STetsuo Handa struct tomoyo_acl_info *ptr; 9319e4b50e9STetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 932b69a54eeSKentaro Takeda 933b69a54eeSKentaro Takeda if (!domain) 934b69a54eeSKentaro Takeda return -EINVAL; 9357762fbffSTetsuo Handa if (!tomoyo_parse_name_union(filename1, &e.name1) || 9367762fbffSTetsuo Handa !tomoyo_parse_name_union(filename2, &e.name2)) 937ca0b7df3STetsuo Handa goto out; 93829282381STetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 93929282381STetsuo Handa goto out; 940ca0b7df3STetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 9417ef61233STetsuo Handa struct tomoyo_path2_acl *acl = 9427ef61233STetsuo Handa container_of(ptr, struct tomoyo_path2_acl, head); 9437762fbffSTetsuo Handa if (!tomoyo_is_same_path2_acl(acl, &e)) 944ca0b7df3STetsuo Handa continue; 945b69a54eeSKentaro Takeda if (is_delete) 946b69a54eeSKentaro Takeda acl->perm &= ~perm; 947ca0b7df3STetsuo Handa else 948ca0b7df3STetsuo Handa acl->perm |= perm; 949b69a54eeSKentaro Takeda error = 0; 950b69a54eeSKentaro Takeda break; 951b69a54eeSKentaro Takeda } 9529e4b50e9STetsuo Handa if (!is_delete && error) { 9539e4b50e9STetsuo Handa struct tomoyo_path2_acl *entry = 9549e4b50e9STetsuo Handa tomoyo_commit_ok(&e, sizeof(e)); 9559e4b50e9STetsuo Handa if (entry) { 9569e4b50e9STetsuo Handa list_add_tail_rcu(&entry->head.list, 9579e4b50e9STetsuo Handa &domain->acl_info_list); 958ca0b7df3STetsuo Handa error = 0; 959ca0b7df3STetsuo Handa } 9609e4b50e9STetsuo Handa } 961f737d95dSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 962ca0b7df3STetsuo Handa out: 9637762fbffSTetsuo Handa tomoyo_put_name_union(&e.name1); 9647762fbffSTetsuo Handa tomoyo_put_name_union(&e.name2); 965b69a54eeSKentaro Takeda return error; 966b69a54eeSKentaro Takeda } 967b69a54eeSKentaro Takeda 968b69a54eeSKentaro Takeda /** 9697ef61233STetsuo Handa * tomoyo_path_acl - Check permission for single path operation. 970b69a54eeSKentaro Takeda * 971b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 972b69a54eeSKentaro Takeda * @type: Type of operation. 973b69a54eeSKentaro Takeda * @filename: Filename to check. 974b69a54eeSKentaro Takeda * 975b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 976fdb8ebb7STetsuo Handa * 977fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 978b69a54eeSKentaro Takeda */ 9797ef61233STetsuo Handa static int tomoyo_path_acl(struct tomoyo_domain_info *domain, const u8 type, 980b69a54eeSKentaro Takeda const struct tomoyo_path_info *filename) 981b69a54eeSKentaro Takeda { 982b69a54eeSKentaro Takeda if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) 983b69a54eeSKentaro Takeda return 0; 9847ef61233STetsuo Handa return tomoyo_path_acl2(domain, filename, 1 << type, 1); 985b69a54eeSKentaro Takeda } 986b69a54eeSKentaro Takeda 987b69a54eeSKentaro Takeda /** 9887ef61233STetsuo Handa * tomoyo_path2_acl - Check permission for double path operation. 989b69a54eeSKentaro Takeda * 990b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 991b69a54eeSKentaro Takeda * @type: Type of operation. 992b69a54eeSKentaro Takeda * @filename1: First filename to check. 993b69a54eeSKentaro Takeda * @filename2: Second filename to check. 994b69a54eeSKentaro Takeda * 995b69a54eeSKentaro Takeda * Returns 0 on success, -EPERM otherwise. 996fdb8ebb7STetsuo Handa * 997fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 998b69a54eeSKentaro Takeda */ 9997ef61233STetsuo Handa static int tomoyo_path2_acl(const struct tomoyo_domain_info *domain, 1000b69a54eeSKentaro Takeda const u8 type, 10017ef61233STetsuo Handa const struct tomoyo_path_info *filename1, 10027ef61233STetsuo Handa const struct tomoyo_path_info *filename2) 1003b69a54eeSKentaro Takeda { 1004b69a54eeSKentaro Takeda struct tomoyo_acl_info *ptr; 1005b69a54eeSKentaro Takeda const u8 perm = 1 << type; 1006b69a54eeSKentaro Takeda int error = -EPERM; 1007b69a54eeSKentaro Takeda 1008b69a54eeSKentaro Takeda if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) 1009b69a54eeSKentaro Takeda return 0; 1010fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 10117ef61233STetsuo Handa struct tomoyo_path2_acl *acl; 10127ef61233STetsuo Handa if (ptr->type != TOMOYO_TYPE_PATH2_ACL) 1013b69a54eeSKentaro Takeda continue; 10147ef61233STetsuo Handa acl = container_of(ptr, struct tomoyo_path2_acl, head); 1015b69a54eeSKentaro Takeda if (!(acl->perm & perm)) 1016b69a54eeSKentaro Takeda continue; 10177762fbffSTetsuo Handa if (!tomoyo_compare_name_union(filename1, &acl->name1)) 1018b69a54eeSKentaro Takeda continue; 10197762fbffSTetsuo Handa if (!tomoyo_compare_name_union(filename2, &acl->name2)) 1020b69a54eeSKentaro Takeda continue; 1021b69a54eeSKentaro Takeda error = 0; 1022b69a54eeSKentaro Takeda break; 1023b69a54eeSKentaro Takeda } 1024b69a54eeSKentaro Takeda return error; 1025b69a54eeSKentaro Takeda } 1026b69a54eeSKentaro Takeda 1027b69a54eeSKentaro Takeda /** 10287ef61233STetsuo Handa * tomoyo_path_permission2 - Check permission for single path operation. 1029b69a54eeSKentaro Takeda * 1030b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 1031b69a54eeSKentaro Takeda * @operation: Type of operation. 1032b69a54eeSKentaro Takeda * @filename: Filename to check. 1033b69a54eeSKentaro Takeda * @mode: Access control mode. 1034b69a54eeSKentaro Takeda * 1035b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1036fdb8ebb7STetsuo Handa * 1037fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 1038b69a54eeSKentaro Takeda */ 10397ef61233STetsuo Handa static int tomoyo_path_permission2(struct tomoyo_domain_info *const domain, 10407ef61233STetsuo Handa u8 operation, 10417ef61233STetsuo Handa const struct tomoyo_path_info *filename, 10427ef61233STetsuo Handa const u8 mode) 1043b69a54eeSKentaro Takeda { 1044b69a54eeSKentaro Takeda const char *msg; 1045b69a54eeSKentaro Takeda int error; 1046b69a54eeSKentaro Takeda const bool is_enforce = (mode == 3); 1047b69a54eeSKentaro Takeda 1048b69a54eeSKentaro Takeda if (!mode) 1049b69a54eeSKentaro Takeda return 0; 1050b69a54eeSKentaro Takeda next: 10517ef61233STetsuo Handa error = tomoyo_path_acl(domain, operation, filename); 10527ef61233STetsuo Handa msg = tomoyo_path2keyword(operation); 1053b69a54eeSKentaro Takeda if (!error) 1054b69a54eeSKentaro Takeda goto ok; 1055b69a54eeSKentaro Takeda if (tomoyo_verbose_mode(domain)) 1056b69a54eeSKentaro Takeda printk(KERN_WARNING "TOMOYO-%s: Access '%s %s' denied for %s\n", 1057b69a54eeSKentaro Takeda tomoyo_get_msg(is_enforce), msg, filename->name, 1058b69a54eeSKentaro Takeda tomoyo_get_last_name(domain)); 1059b69a54eeSKentaro Takeda if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { 1060b69a54eeSKentaro Takeda const char *name = tomoyo_get_file_pattern(filename)->name; 10617ef61233STetsuo Handa tomoyo_update_path_acl(operation, name, domain, false); 1062b69a54eeSKentaro Takeda } 1063b69a54eeSKentaro Takeda if (!is_enforce) 1064b69a54eeSKentaro Takeda error = 0; 1065b69a54eeSKentaro Takeda ok: 1066b69a54eeSKentaro Takeda /* 1067b69a54eeSKentaro Takeda * Since "allow_truncate" doesn't imply "allow_rewrite" permission, 1068b69a54eeSKentaro Takeda * we need to check "allow_rewrite" permission if the filename is 1069b69a54eeSKentaro Takeda * specified by "deny_rewrite" keyword. 1070b69a54eeSKentaro Takeda */ 10717ef61233STetsuo Handa if (!error && operation == TOMOYO_TYPE_TRUNCATE && 1072b69a54eeSKentaro Takeda tomoyo_is_no_rewrite_file(filename)) { 10737ef61233STetsuo Handa operation = TOMOYO_TYPE_REWRITE; 1074b69a54eeSKentaro Takeda goto next; 1075b69a54eeSKentaro Takeda } 1076b69a54eeSKentaro Takeda return error; 1077b69a54eeSKentaro Takeda } 1078b69a54eeSKentaro Takeda 1079b69a54eeSKentaro Takeda /** 1080b69a54eeSKentaro Takeda * tomoyo_check_exec_perm - Check permission for "execute". 1081b69a54eeSKentaro Takeda * 1082b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 1083b69a54eeSKentaro Takeda * @filename: Check permission for "execute". 1084b69a54eeSKentaro Takeda * 1085b69a54eeSKentaro Takeda * Returns 0 on success, negativevalue otherwise. 1086fdb8ebb7STetsuo Handa * 1087fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 1088b69a54eeSKentaro Takeda */ 1089b69a54eeSKentaro Takeda int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, 1090bcb86975STetsuo Handa const struct tomoyo_path_info *filename) 1091b69a54eeSKentaro Takeda { 1092b69a54eeSKentaro Takeda const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); 1093b69a54eeSKentaro Takeda 1094b69a54eeSKentaro Takeda if (!mode) 1095b69a54eeSKentaro Takeda return 0; 1096b69a54eeSKentaro Takeda return tomoyo_check_file_perm2(domain, filename, 1, "do_execve", mode); 1097b69a54eeSKentaro Takeda } 1098b69a54eeSKentaro Takeda 1099b69a54eeSKentaro Takeda /** 1100b69a54eeSKentaro Takeda * tomoyo_check_open_permission - Check permission for "read" and "write". 1101b69a54eeSKentaro Takeda * 1102b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 1103b69a54eeSKentaro Takeda * @path: Pointer to "struct path". 1104b69a54eeSKentaro Takeda * @flag: Flags for open(). 1105b69a54eeSKentaro Takeda * 1106b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1107b69a54eeSKentaro Takeda */ 1108b69a54eeSKentaro Takeda int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, 1109b69a54eeSKentaro Takeda struct path *path, const int flag) 1110b69a54eeSKentaro Takeda { 1111b69a54eeSKentaro Takeda const u8 acc_mode = ACC_MODE(flag); 1112b69a54eeSKentaro Takeda int error = -ENOMEM; 1113b69a54eeSKentaro Takeda struct tomoyo_path_info *buf; 1114b69a54eeSKentaro Takeda const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); 1115b69a54eeSKentaro Takeda const bool is_enforce = (mode == 3); 1116fdb8ebb7STetsuo Handa int idx; 1117b69a54eeSKentaro Takeda 1118b69a54eeSKentaro Takeda if (!mode || !path->mnt) 1119b69a54eeSKentaro Takeda return 0; 1120b69a54eeSKentaro Takeda if (acc_mode == 0) 1121b69a54eeSKentaro Takeda return 0; 1122b69a54eeSKentaro Takeda if (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode)) 1123b69a54eeSKentaro Takeda /* 1124b69a54eeSKentaro Takeda * I don't check directories here because mkdir() and rmdir() 1125b69a54eeSKentaro Takeda * don't call me. 1126b69a54eeSKentaro Takeda */ 1127b69a54eeSKentaro Takeda return 0; 1128fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 1129b69a54eeSKentaro Takeda buf = tomoyo_get_path(path); 1130b69a54eeSKentaro Takeda if (!buf) 1131b69a54eeSKentaro Takeda goto out; 1132b69a54eeSKentaro Takeda error = 0; 1133b69a54eeSKentaro Takeda /* 1134b69a54eeSKentaro Takeda * If the filename is specified by "deny_rewrite" keyword, 1135b69a54eeSKentaro Takeda * we need to check "allow_rewrite" permission when the filename is not 1136b69a54eeSKentaro Takeda * opened for append mode or the filename is truncated at open time. 1137b69a54eeSKentaro Takeda */ 1138b69a54eeSKentaro Takeda if ((acc_mode & MAY_WRITE) && 1139b69a54eeSKentaro Takeda ((flag & O_TRUNC) || !(flag & O_APPEND)) && 1140b69a54eeSKentaro Takeda (tomoyo_is_no_rewrite_file(buf))) { 11417ef61233STetsuo Handa error = tomoyo_path_permission2(domain, TOMOYO_TYPE_REWRITE, 1142b69a54eeSKentaro Takeda buf, mode); 1143b69a54eeSKentaro Takeda } 1144b69a54eeSKentaro Takeda if (!error) 1145b69a54eeSKentaro Takeda error = tomoyo_check_file_perm2(domain, buf, acc_mode, "open", 1146b69a54eeSKentaro Takeda mode); 1147b69a54eeSKentaro Takeda if (!error && (flag & O_TRUNC)) 11487ef61233STetsuo Handa error = tomoyo_path_permission2(domain, TOMOYO_TYPE_TRUNCATE, 1149b69a54eeSKentaro Takeda buf, mode); 1150b69a54eeSKentaro Takeda out: 11518e2d39a1STetsuo Handa kfree(buf); 1152fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 1153b69a54eeSKentaro Takeda if (!is_enforce) 1154b69a54eeSKentaro Takeda error = 0; 1155b69a54eeSKentaro Takeda return error; 1156b69a54eeSKentaro Takeda } 1157b69a54eeSKentaro Takeda 1158b69a54eeSKentaro Takeda /** 11597ef61233STetsuo Handa * tomoyo_path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate", "symlink", "ioctl", "chmod", "chown", "chgrp", "chroot", "mount" and "unmount". 1160b69a54eeSKentaro Takeda * 1161b69a54eeSKentaro Takeda * @operation: Type of operation. 1162b69a54eeSKentaro Takeda * @path: Pointer to "struct path". 1163b69a54eeSKentaro Takeda * 1164b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1165b69a54eeSKentaro Takeda */ 116697d6931eSTetsuo Handa int tomoyo_path_perm(const u8 operation, struct path *path) 1167b69a54eeSKentaro Takeda { 1168b69a54eeSKentaro Takeda int error = -ENOMEM; 1169b69a54eeSKentaro Takeda struct tomoyo_path_info *buf; 117097d6931eSTetsuo Handa struct tomoyo_domain_info *domain = tomoyo_domain(); 1171b69a54eeSKentaro Takeda const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); 1172b69a54eeSKentaro Takeda const bool is_enforce = (mode == 3); 1173fdb8ebb7STetsuo Handa int idx; 1174b69a54eeSKentaro Takeda 1175b69a54eeSKentaro Takeda if (!mode || !path->mnt) 1176b69a54eeSKentaro Takeda return 0; 1177fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 1178b69a54eeSKentaro Takeda buf = tomoyo_get_path(path); 1179b69a54eeSKentaro Takeda if (!buf) 1180b69a54eeSKentaro Takeda goto out; 1181b69a54eeSKentaro Takeda switch (operation) { 11827ef61233STetsuo Handa case TOMOYO_TYPE_MKDIR: 11837ef61233STetsuo Handa case TOMOYO_TYPE_RMDIR: 11847ef61233STetsuo Handa case TOMOYO_TYPE_CHROOT: 1185b69a54eeSKentaro Takeda if (!buf->is_dir) { 1186b69a54eeSKentaro Takeda /* 1187b69a54eeSKentaro Takeda * tomoyo_get_path() reserves space for appending "/." 1188b69a54eeSKentaro Takeda */ 1189b69a54eeSKentaro Takeda strcat((char *) buf->name, "/"); 1190b69a54eeSKentaro Takeda tomoyo_fill_path_info(buf); 1191b69a54eeSKentaro Takeda } 1192b69a54eeSKentaro Takeda } 11937ef61233STetsuo Handa error = tomoyo_path_permission2(domain, operation, buf, mode); 1194b69a54eeSKentaro Takeda out: 11958e2d39a1STetsuo Handa kfree(buf); 1196fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 1197b69a54eeSKentaro Takeda if (!is_enforce) 1198b69a54eeSKentaro Takeda error = 0; 1199b69a54eeSKentaro Takeda return error; 1200b69a54eeSKentaro Takeda } 1201b69a54eeSKentaro Takeda 1202b69a54eeSKentaro Takeda /** 1203b69a54eeSKentaro Takeda * tomoyo_check_rewrite_permission - Check permission for "rewrite". 1204b69a54eeSKentaro Takeda * 1205b69a54eeSKentaro Takeda * @filp: Pointer to "struct file". 1206b69a54eeSKentaro Takeda * 1207b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1208b69a54eeSKentaro Takeda */ 120997d6931eSTetsuo Handa int tomoyo_check_rewrite_permission(struct file *filp) 1210b69a54eeSKentaro Takeda { 1211b69a54eeSKentaro Takeda int error = -ENOMEM; 121297d6931eSTetsuo Handa struct tomoyo_domain_info *domain = tomoyo_domain(); 1213b69a54eeSKentaro Takeda const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); 1214b69a54eeSKentaro Takeda const bool is_enforce = (mode == 3); 1215b69a54eeSKentaro Takeda struct tomoyo_path_info *buf; 1216fdb8ebb7STetsuo Handa int idx; 1217b69a54eeSKentaro Takeda 1218b69a54eeSKentaro Takeda if (!mode || !filp->f_path.mnt) 1219b69a54eeSKentaro Takeda return 0; 1220fdb8ebb7STetsuo Handa 1221fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 1222b69a54eeSKentaro Takeda buf = tomoyo_get_path(&filp->f_path); 1223b69a54eeSKentaro Takeda if (!buf) 1224b69a54eeSKentaro Takeda goto out; 1225b69a54eeSKentaro Takeda if (!tomoyo_is_no_rewrite_file(buf)) { 1226b69a54eeSKentaro Takeda error = 0; 1227b69a54eeSKentaro Takeda goto out; 1228b69a54eeSKentaro Takeda } 12297ef61233STetsuo Handa error = tomoyo_path_permission2(domain, TOMOYO_TYPE_REWRITE, buf, mode); 1230b69a54eeSKentaro Takeda out: 12318e2d39a1STetsuo Handa kfree(buf); 1232fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 1233b69a54eeSKentaro Takeda if (!is_enforce) 1234b69a54eeSKentaro Takeda error = 0; 1235b69a54eeSKentaro Takeda return error; 1236b69a54eeSKentaro Takeda } 1237b69a54eeSKentaro Takeda 1238b69a54eeSKentaro Takeda /** 12397ef61233STetsuo Handa * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root". 1240b69a54eeSKentaro Takeda * 1241b69a54eeSKentaro Takeda * @operation: Type of operation. 1242b69a54eeSKentaro Takeda * @path1: Pointer to "struct path". 1243b69a54eeSKentaro Takeda * @path2: Pointer to "struct path". 1244b69a54eeSKentaro Takeda * 1245b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1246b69a54eeSKentaro Takeda */ 124797d6931eSTetsuo Handa int tomoyo_path2_perm(const u8 operation, struct path *path1, 1248b69a54eeSKentaro Takeda struct path *path2) 1249b69a54eeSKentaro Takeda { 1250b69a54eeSKentaro Takeda int error = -ENOMEM; 1251b69a54eeSKentaro Takeda struct tomoyo_path_info *buf1, *buf2; 125297d6931eSTetsuo Handa struct tomoyo_domain_info *domain = tomoyo_domain(); 1253b69a54eeSKentaro Takeda const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); 1254b69a54eeSKentaro Takeda const bool is_enforce = (mode == 3); 1255b69a54eeSKentaro Takeda const char *msg; 1256fdb8ebb7STetsuo Handa int idx; 1257b69a54eeSKentaro Takeda 1258b69a54eeSKentaro Takeda if (!mode || !path1->mnt || !path2->mnt) 1259b69a54eeSKentaro Takeda return 0; 1260fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 1261b69a54eeSKentaro Takeda buf1 = tomoyo_get_path(path1); 1262b69a54eeSKentaro Takeda buf2 = tomoyo_get_path(path2); 1263b69a54eeSKentaro Takeda if (!buf1 || !buf2) 1264b69a54eeSKentaro Takeda goto out; 1265b69a54eeSKentaro Takeda { 1266b69a54eeSKentaro Takeda struct dentry *dentry = path1->dentry; 1267b69a54eeSKentaro Takeda if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) { 1268b69a54eeSKentaro Takeda /* 1269b69a54eeSKentaro Takeda * tomoyo_get_path() reserves space for appending "/." 1270b69a54eeSKentaro Takeda */ 1271b69a54eeSKentaro Takeda if (!buf1->is_dir) { 1272b69a54eeSKentaro Takeda strcat((char *) buf1->name, "/"); 1273b69a54eeSKentaro Takeda tomoyo_fill_path_info(buf1); 1274b69a54eeSKentaro Takeda } 1275b69a54eeSKentaro Takeda if (!buf2->is_dir) { 1276b69a54eeSKentaro Takeda strcat((char *) buf2->name, "/"); 1277b69a54eeSKentaro Takeda tomoyo_fill_path_info(buf2); 1278b69a54eeSKentaro Takeda } 1279b69a54eeSKentaro Takeda } 1280b69a54eeSKentaro Takeda } 12817ef61233STetsuo Handa error = tomoyo_path2_acl(domain, operation, buf1, buf2); 12827ef61233STetsuo Handa msg = tomoyo_path22keyword(operation); 1283b69a54eeSKentaro Takeda if (!error) 1284b69a54eeSKentaro Takeda goto out; 1285b69a54eeSKentaro Takeda if (tomoyo_verbose_mode(domain)) 1286b69a54eeSKentaro Takeda printk(KERN_WARNING "TOMOYO-%s: Access '%s %s %s' " 1287b69a54eeSKentaro Takeda "denied for %s\n", tomoyo_get_msg(is_enforce), 1288b69a54eeSKentaro Takeda msg, buf1->name, buf2->name, 1289b69a54eeSKentaro Takeda tomoyo_get_last_name(domain)); 1290b69a54eeSKentaro Takeda if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { 1291b69a54eeSKentaro Takeda const char *name1 = tomoyo_get_file_pattern(buf1)->name; 1292b69a54eeSKentaro Takeda const char *name2 = tomoyo_get_file_pattern(buf2)->name; 12937ef61233STetsuo Handa tomoyo_update_path2_acl(operation, name1, name2, domain, 1294b69a54eeSKentaro Takeda false); 1295b69a54eeSKentaro Takeda } 1296b69a54eeSKentaro Takeda out: 12978e2d39a1STetsuo Handa kfree(buf1); 12988e2d39a1STetsuo Handa kfree(buf2); 1299fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 1300b69a54eeSKentaro Takeda if (!is_enforce) 1301b69a54eeSKentaro Takeda error = 0; 1302b69a54eeSKentaro Takeda return error; 1303b69a54eeSKentaro Takeda } 1304