1b69a54eeSKentaro Takeda /* 2b69a54eeSKentaro Takeda * security/tomoyo/file.c 3b69a54eeSKentaro Takeda * 4c3ef1500STetsuo Handa * Pathname restriction functions. 5b69a54eeSKentaro Takeda * 6c3ef1500STetsuo Handa * Copyright (C) 2005-2010 NTT DATA CORPORATION 7b69a54eeSKentaro Takeda */ 8b69a54eeSKentaro Takeda 9b69a54eeSKentaro Takeda #include "common.h" 105a0e3ad6STejun Heo #include <linux/slab.h> 11b69a54eeSKentaro Takeda 12a1f9bb6aSTetsuo Handa /* Keyword array for operations with one pathname. */ 137ef61233STetsuo Handa static const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = { 147ef61233STetsuo Handa [TOMOYO_TYPE_READ_WRITE] = "read/write", 157ef61233STetsuo Handa [TOMOYO_TYPE_EXECUTE] = "execute", 167ef61233STetsuo Handa [TOMOYO_TYPE_READ] = "read", 177ef61233STetsuo Handa [TOMOYO_TYPE_WRITE] = "write", 187ef61233STetsuo Handa [TOMOYO_TYPE_UNLINK] = "unlink", 197ef61233STetsuo Handa [TOMOYO_TYPE_RMDIR] = "rmdir", 207ef61233STetsuo Handa [TOMOYO_TYPE_TRUNCATE] = "truncate", 217ef61233STetsuo Handa [TOMOYO_TYPE_SYMLINK] = "symlink", 227ef61233STetsuo Handa [TOMOYO_TYPE_REWRITE] = "rewrite", 237ef61233STetsuo Handa [TOMOYO_TYPE_CHROOT] = "chroot", 247ef61233STetsuo Handa [TOMOYO_TYPE_UMOUNT] = "unmount", 25b69a54eeSKentaro Takeda }; 26b69a54eeSKentaro Takeda 27a1f9bb6aSTetsuo Handa /* Keyword array for operations with one pathname and three numbers. */ 28a1f9bb6aSTetsuo Handa static const char *tomoyo_path_number3_keyword 29a1f9bb6aSTetsuo Handa [TOMOYO_MAX_PATH_NUMBER3_OPERATION] = { 30a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_MKBLOCK] = "mkblock", 31a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_MKCHAR] = "mkchar", 32a1f9bb6aSTetsuo Handa }; 33a1f9bb6aSTetsuo Handa 34a1f9bb6aSTetsuo Handa /* Keyword array for operations with two pathnames. */ 357ef61233STetsuo Handa static const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = { 367ef61233STetsuo Handa [TOMOYO_TYPE_LINK] = "link", 377ef61233STetsuo Handa [TOMOYO_TYPE_RENAME] = "rename", 387ef61233STetsuo Handa [TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root", 39b69a54eeSKentaro Takeda }; 40b69a54eeSKentaro Takeda 41a1f9bb6aSTetsuo Handa /* Keyword array for operations with one pathname and one number. */ 42a1f9bb6aSTetsuo Handa static const char *tomoyo_path_number_keyword 43a1f9bb6aSTetsuo Handa [TOMOYO_MAX_PATH_NUMBER_OPERATION] = { 44a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_CREATE] = "create", 45a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_MKDIR] = "mkdir", 46a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_MKFIFO] = "mkfifo", 47a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_MKSOCK] = "mksock", 48a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_IOCTL] = "ioctl", 49a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_CHMOD] = "chmod", 50a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_CHOWN] = "chown", 51a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_CHGRP] = "chgrp", 52a1f9bb6aSTetsuo Handa }; 53a1f9bb6aSTetsuo Handa 547762fbffSTetsuo Handa void tomoyo_put_name_union(struct tomoyo_name_union *ptr) 557762fbffSTetsuo Handa { 567762fbffSTetsuo Handa if (!ptr) 577762fbffSTetsuo Handa return; 587762fbffSTetsuo Handa if (ptr->is_group) 597762fbffSTetsuo Handa tomoyo_put_path_group(ptr->group); 607762fbffSTetsuo Handa else 617762fbffSTetsuo Handa tomoyo_put_name(ptr->filename); 627762fbffSTetsuo Handa } 637762fbffSTetsuo Handa 647762fbffSTetsuo Handa bool tomoyo_compare_name_union(const struct tomoyo_path_info *name, 657762fbffSTetsuo Handa const struct tomoyo_name_union *ptr) 667762fbffSTetsuo Handa { 677762fbffSTetsuo Handa if (ptr->is_group) 687762fbffSTetsuo Handa return tomoyo_path_matches_group(name, ptr->group, 1); 697762fbffSTetsuo Handa return tomoyo_path_matches_pattern(name, ptr->filename); 707762fbffSTetsuo Handa } 717762fbffSTetsuo Handa 727762fbffSTetsuo Handa static bool tomoyo_compare_name_union_pattern(const struct tomoyo_path_info 737762fbffSTetsuo Handa *name, 747762fbffSTetsuo Handa const struct tomoyo_name_union 757762fbffSTetsuo Handa *ptr, const bool may_use_pattern) 767762fbffSTetsuo Handa { 777762fbffSTetsuo Handa if (ptr->is_group) 787762fbffSTetsuo Handa return tomoyo_path_matches_group(name, ptr->group, 797762fbffSTetsuo Handa may_use_pattern); 807762fbffSTetsuo Handa if (may_use_pattern || !ptr->filename->is_patterned) 817762fbffSTetsuo Handa return tomoyo_path_matches_pattern(name, ptr->filename); 827762fbffSTetsuo Handa return false; 837762fbffSTetsuo Handa } 847762fbffSTetsuo Handa 854c3e9e2dSTetsuo Handa void tomoyo_put_number_union(struct tomoyo_number_union *ptr) 864c3e9e2dSTetsuo Handa { 874c3e9e2dSTetsuo Handa if (ptr && ptr->is_group) 884c3e9e2dSTetsuo Handa tomoyo_put_number_group(ptr->group); 894c3e9e2dSTetsuo Handa } 904c3e9e2dSTetsuo Handa 914c3e9e2dSTetsuo Handa bool tomoyo_compare_number_union(const unsigned long value, 924c3e9e2dSTetsuo Handa const struct tomoyo_number_union *ptr) 934c3e9e2dSTetsuo Handa { 944c3e9e2dSTetsuo Handa if (ptr->is_group) 954c3e9e2dSTetsuo Handa return tomoyo_number_matches_group(value, value, ptr->group); 964c3e9e2dSTetsuo Handa return value >= ptr->values[0] && value <= ptr->values[1]; 974c3e9e2dSTetsuo Handa } 984c3e9e2dSTetsuo Handa 99b69a54eeSKentaro Takeda /** 1007ef61233STetsuo Handa * tomoyo_path2keyword - Get the name of single path operation. 101b69a54eeSKentaro Takeda * 102b69a54eeSKentaro Takeda * @operation: Type of operation. 103b69a54eeSKentaro Takeda * 104b69a54eeSKentaro Takeda * Returns the name of single path operation. 105b69a54eeSKentaro Takeda */ 1067ef61233STetsuo Handa const char *tomoyo_path2keyword(const u8 operation) 107b69a54eeSKentaro Takeda { 1087ef61233STetsuo Handa return (operation < TOMOYO_MAX_PATH_OPERATION) 1097ef61233STetsuo Handa ? tomoyo_path_keyword[operation] : NULL; 110b69a54eeSKentaro Takeda } 111b69a54eeSKentaro Takeda 112b69a54eeSKentaro Takeda /** 113a1f9bb6aSTetsuo Handa * tomoyo_path_number32keyword - Get the name of path/number/number/number operations. 114a1f9bb6aSTetsuo Handa * 115a1f9bb6aSTetsuo Handa * @operation: Type of operation. 116a1f9bb6aSTetsuo Handa * 117a1f9bb6aSTetsuo Handa * Returns the name of path/number/number/number operation. 118a1f9bb6aSTetsuo Handa */ 119a1f9bb6aSTetsuo Handa const char *tomoyo_path_number32keyword(const u8 operation) 120a1f9bb6aSTetsuo Handa { 121a1f9bb6aSTetsuo Handa return (operation < TOMOYO_MAX_PATH_NUMBER3_OPERATION) 122a1f9bb6aSTetsuo Handa ? tomoyo_path_number3_keyword[operation] : NULL; 123a1f9bb6aSTetsuo Handa } 124a1f9bb6aSTetsuo Handa 125a1f9bb6aSTetsuo Handa /** 1267ef61233STetsuo Handa * tomoyo_path22keyword - Get the name of double path operation. 127b69a54eeSKentaro Takeda * 128b69a54eeSKentaro Takeda * @operation: Type of operation. 129b69a54eeSKentaro Takeda * 130b69a54eeSKentaro Takeda * Returns the name of double path operation. 131b69a54eeSKentaro Takeda */ 1327ef61233STetsuo Handa const char *tomoyo_path22keyword(const u8 operation) 133b69a54eeSKentaro Takeda { 1347ef61233STetsuo Handa return (operation < TOMOYO_MAX_PATH2_OPERATION) 1357ef61233STetsuo Handa ? tomoyo_path2_keyword[operation] : NULL; 136b69a54eeSKentaro Takeda } 137b69a54eeSKentaro Takeda 138b69a54eeSKentaro Takeda /** 139a1f9bb6aSTetsuo Handa * tomoyo_path_number2keyword - Get the name of path/number operations. 140a1f9bb6aSTetsuo Handa * 141a1f9bb6aSTetsuo Handa * @operation: Type of operation. 142a1f9bb6aSTetsuo Handa * 143a1f9bb6aSTetsuo Handa * Returns the name of path/number operation. 144a1f9bb6aSTetsuo Handa */ 145a1f9bb6aSTetsuo Handa const char *tomoyo_path_number2keyword(const u8 operation) 146a1f9bb6aSTetsuo Handa { 147a1f9bb6aSTetsuo Handa return (operation < TOMOYO_MAX_PATH_NUMBER_OPERATION) 148a1f9bb6aSTetsuo Handa ? tomoyo_path_number_keyword[operation] : NULL; 149a1f9bb6aSTetsuo Handa } 150a1f9bb6aSTetsuo Handa 151c8c57e84STetsuo Handa static void tomoyo_add_slash(struct tomoyo_path_info *buf) 152c8c57e84STetsuo Handa { 153c8c57e84STetsuo Handa if (buf->is_dir) 154c8c57e84STetsuo Handa return; 155c8c57e84STetsuo Handa /* 156c8c57e84STetsuo Handa * This is OK because tomoyo_encode() reserves space for appending "/". 157c8c57e84STetsuo Handa */ 158c8c57e84STetsuo Handa strcat((char *) buf->name, "/"); 159c8c57e84STetsuo Handa tomoyo_fill_path_info(buf); 160c8c57e84STetsuo Handa } 161c8c57e84STetsuo Handa 162a1f9bb6aSTetsuo Handa /** 163b69a54eeSKentaro Takeda * tomoyo_strendswith - Check whether the token ends with the given token. 164b69a54eeSKentaro Takeda * 165b69a54eeSKentaro Takeda * @name: The token to check. 166b69a54eeSKentaro Takeda * @tail: The token to find. 167b69a54eeSKentaro Takeda * 168b69a54eeSKentaro Takeda * Returns true if @name ends with @tail, false otherwise. 169b69a54eeSKentaro Takeda */ 170b69a54eeSKentaro Takeda static bool tomoyo_strendswith(const char *name, const char *tail) 171b69a54eeSKentaro Takeda { 172b69a54eeSKentaro Takeda int len; 173b69a54eeSKentaro Takeda 174b69a54eeSKentaro Takeda if (!name || !tail) 175b69a54eeSKentaro Takeda return false; 176b69a54eeSKentaro Takeda len = strlen(name) - strlen(tail); 177b69a54eeSKentaro Takeda return len >= 0 && !strcmp(name + len, tail); 178b69a54eeSKentaro Takeda } 179b69a54eeSKentaro Takeda 180b69a54eeSKentaro Takeda /** 181c8c57e84STetsuo Handa * tomoyo_get_realpath - Get realpath. 182b69a54eeSKentaro Takeda * 183c8c57e84STetsuo Handa * @buf: Pointer to "struct tomoyo_path_info". 184b69a54eeSKentaro Takeda * @path: Pointer to "struct path". 185b69a54eeSKentaro Takeda * 186c8c57e84STetsuo Handa * Returns true on success, false otherwise. 187b69a54eeSKentaro Takeda */ 188c8c57e84STetsuo Handa static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path) 189b69a54eeSKentaro Takeda { 190c8c57e84STetsuo Handa buf->name = tomoyo_realpath_from_path(path); 191c8c57e84STetsuo Handa if (buf->name) { 192c8c57e84STetsuo Handa tomoyo_fill_path_info(buf); 193c8c57e84STetsuo Handa return true; 194b69a54eeSKentaro Takeda } 195c8c57e84STetsuo Handa return false; 196b69a54eeSKentaro Takeda } 197b69a54eeSKentaro Takeda 1987ef61233STetsuo Handa static int tomoyo_update_path2_acl(const u8 type, const char *filename1, 199b69a54eeSKentaro Takeda const char *filename2, 2007ef61233STetsuo Handa struct tomoyo_domain_info *const domain, 2017ef61233STetsuo Handa const bool is_delete); 2027ef61233STetsuo Handa static int tomoyo_update_path_acl(const u8 type, const char *filename, 2037ef61233STetsuo Handa struct tomoyo_domain_info *const domain, 2047ef61233STetsuo Handa const bool is_delete); 205b69a54eeSKentaro Takeda 206c3fa109aSTetsuo Handa /* 207c3fa109aSTetsuo Handa * tomoyo_globally_readable_list is used for holding list of pathnames which 208c3fa109aSTetsuo Handa * are by default allowed to be open()ed for reading by any process. 209c3fa109aSTetsuo Handa * 210c3fa109aSTetsuo Handa * An entry is added by 211c3fa109aSTetsuo Handa * 212c3fa109aSTetsuo Handa * # echo 'allow_read /lib/libc-2.5.so' > \ 213c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 214c3fa109aSTetsuo Handa * 215c3fa109aSTetsuo Handa * and is deleted by 216c3fa109aSTetsuo Handa * 217c3fa109aSTetsuo Handa * # echo 'delete allow_read /lib/libc-2.5.so' > \ 218c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 219c3fa109aSTetsuo Handa * 220c3fa109aSTetsuo Handa * and all entries are retrieved by 221c3fa109aSTetsuo Handa * 222c3fa109aSTetsuo Handa * # grep ^allow_read /sys/kernel/security/tomoyo/exception_policy 223c3fa109aSTetsuo Handa * 224c3fa109aSTetsuo Handa * In the example above, any process is allowed to 225c3fa109aSTetsuo Handa * open("/lib/libc-2.5.so", O_RDONLY). 226c3fa109aSTetsuo Handa * One exception is, if the domain which current process belongs to is marked 227c3fa109aSTetsuo Handa * as "ignore_global_allow_read", current process can't do so unless explicitly 228c3fa109aSTetsuo Handa * given "allow_read /lib/libc-2.5.so" to the domain which current process 229c3fa109aSTetsuo Handa * belongs to. 230c3fa109aSTetsuo Handa */ 231847b173eSTetsuo Handa LIST_HEAD(tomoyo_globally_readable_list); 232b69a54eeSKentaro Takeda 233b69a54eeSKentaro Takeda /** 234b69a54eeSKentaro Takeda * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list. 235b69a54eeSKentaro Takeda * 236b69a54eeSKentaro Takeda * @filename: Filename unconditionally permitted to open() for reading. 237b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 238b69a54eeSKentaro Takeda * 239b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 240fdb8ebb7STetsuo Handa * 241fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 242b69a54eeSKentaro Takeda */ 243b69a54eeSKentaro Takeda static int tomoyo_update_globally_readable_entry(const char *filename, 244b69a54eeSKentaro Takeda const bool is_delete) 245b69a54eeSKentaro Takeda { 246b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry *ptr; 2479e4b50e9STetsuo Handa struct tomoyo_globally_readable_file_entry e = { }; 248ca0b7df3STetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 249b69a54eeSKentaro Takeda 25017080008STetsuo Handa if (!tomoyo_is_correct_path(filename, 1, 0, -1)) 251b69a54eeSKentaro Takeda return -EINVAL; 2529e4b50e9STetsuo Handa e.filename = tomoyo_get_name(filename); 2539e4b50e9STetsuo Handa if (!e.filename) 254b69a54eeSKentaro Takeda return -ENOMEM; 25529282381STetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 25629282381STetsuo Handa goto out; 257fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) { 2589e4b50e9STetsuo Handa if (ptr->filename != e.filename) 259b69a54eeSKentaro Takeda continue; 260b69a54eeSKentaro Takeda ptr->is_deleted = is_delete; 261b69a54eeSKentaro Takeda error = 0; 262ca0b7df3STetsuo Handa break; 263b69a54eeSKentaro Takeda } 2649e4b50e9STetsuo Handa if (!is_delete && error) { 2659e4b50e9STetsuo Handa struct tomoyo_globally_readable_file_entry *entry = 2669e4b50e9STetsuo Handa tomoyo_commit_ok(&e, sizeof(e)); 2679e4b50e9STetsuo Handa if (entry) { 2689e4b50e9STetsuo Handa list_add_tail_rcu(&entry->list, 2699e4b50e9STetsuo Handa &tomoyo_globally_readable_list); 270b69a54eeSKentaro Takeda error = 0; 271ca0b7df3STetsuo Handa } 2729e4b50e9STetsuo Handa } 273f737d95dSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 27429282381STetsuo Handa out: 2759e4b50e9STetsuo Handa tomoyo_put_name(e.filename); 276b69a54eeSKentaro Takeda return error; 277b69a54eeSKentaro Takeda } 278b69a54eeSKentaro Takeda 279b69a54eeSKentaro Takeda /** 280b69a54eeSKentaro Takeda * tomoyo_is_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading. 281b69a54eeSKentaro Takeda * 282b69a54eeSKentaro Takeda * @filename: The filename to check. 283b69a54eeSKentaro Takeda * 284b69a54eeSKentaro Takeda * Returns true if any domain can open @filename for reading, false otherwise. 285fdb8ebb7STetsuo Handa * 286fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 287b69a54eeSKentaro Takeda */ 288b69a54eeSKentaro Takeda static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info * 289b69a54eeSKentaro Takeda filename) 290b69a54eeSKentaro Takeda { 291b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry *ptr; 292b69a54eeSKentaro Takeda bool found = false; 293fdb8ebb7STetsuo Handa 294fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) { 295b69a54eeSKentaro Takeda if (!ptr->is_deleted && 296b69a54eeSKentaro Takeda tomoyo_path_matches_pattern(filename, ptr->filename)) { 297b69a54eeSKentaro Takeda found = true; 298b69a54eeSKentaro Takeda break; 299b69a54eeSKentaro Takeda } 300b69a54eeSKentaro Takeda } 301b69a54eeSKentaro Takeda return found; 302b69a54eeSKentaro Takeda } 303b69a54eeSKentaro Takeda 304b69a54eeSKentaro Takeda /** 305b69a54eeSKentaro Takeda * tomoyo_write_globally_readable_policy - Write "struct tomoyo_globally_readable_file_entry" list. 306b69a54eeSKentaro Takeda * 307b69a54eeSKentaro Takeda * @data: String to parse. 308b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 309b69a54eeSKentaro Takeda * 310b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 311fdb8ebb7STetsuo Handa * 312fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 313b69a54eeSKentaro Takeda */ 314b69a54eeSKentaro Takeda int tomoyo_write_globally_readable_policy(char *data, const bool is_delete) 315b69a54eeSKentaro Takeda { 316b69a54eeSKentaro Takeda return tomoyo_update_globally_readable_entry(data, is_delete); 317b69a54eeSKentaro Takeda } 318b69a54eeSKentaro Takeda 319b69a54eeSKentaro Takeda /** 320b69a54eeSKentaro Takeda * tomoyo_read_globally_readable_policy - Read "struct tomoyo_globally_readable_file_entry" list. 321b69a54eeSKentaro Takeda * 322b69a54eeSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 323b69a54eeSKentaro Takeda * 324b69a54eeSKentaro Takeda * Returns true on success, false otherwise. 325fdb8ebb7STetsuo Handa * 326fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 327b69a54eeSKentaro Takeda */ 328b69a54eeSKentaro Takeda bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) 329b69a54eeSKentaro Takeda { 330b69a54eeSKentaro Takeda struct list_head *pos; 331b69a54eeSKentaro Takeda bool done = true; 332b69a54eeSKentaro Takeda 333b69a54eeSKentaro Takeda list_for_each_cookie(pos, head->read_var2, 334b69a54eeSKentaro Takeda &tomoyo_globally_readable_list) { 335b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry *ptr; 336b69a54eeSKentaro Takeda ptr = list_entry(pos, 337b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry, 338b69a54eeSKentaro Takeda list); 339b69a54eeSKentaro Takeda if (ptr->is_deleted) 340b69a54eeSKentaro Takeda continue; 3417d2948b1STetsuo Handa done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n", 3427d2948b1STetsuo Handa ptr->filename->name); 3437d2948b1STetsuo Handa if (!done) 344b69a54eeSKentaro Takeda break; 345b69a54eeSKentaro Takeda } 346b69a54eeSKentaro Takeda return done; 347b69a54eeSKentaro Takeda } 348b69a54eeSKentaro Takeda 349c3fa109aSTetsuo Handa /* tomoyo_pattern_list is used for holding list of pathnames which are used for 350c3fa109aSTetsuo Handa * converting pathnames to pathname patterns during learning mode. 351c3fa109aSTetsuo Handa * 352c3fa109aSTetsuo Handa * An entry is added by 353c3fa109aSTetsuo Handa * 354c3fa109aSTetsuo Handa * # echo 'file_pattern /proc/\$/mounts' > \ 355c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 356c3fa109aSTetsuo Handa * 357c3fa109aSTetsuo Handa * and is deleted by 358c3fa109aSTetsuo Handa * 359c3fa109aSTetsuo Handa * # echo 'delete file_pattern /proc/\$/mounts' > \ 360c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 361c3fa109aSTetsuo Handa * 362c3fa109aSTetsuo Handa * and all entries are retrieved by 363c3fa109aSTetsuo Handa * 364c3fa109aSTetsuo Handa * # grep ^file_pattern /sys/kernel/security/tomoyo/exception_policy 365c3fa109aSTetsuo Handa * 366c3fa109aSTetsuo Handa * In the example above, if a process which belongs to a domain which is in 367c3fa109aSTetsuo Handa * learning mode requested open("/proc/1/mounts", O_RDONLY), 368c3fa109aSTetsuo Handa * "allow_read /proc/\$/mounts" is automatically added to the domain which that 369c3fa109aSTetsuo Handa * process belongs to. 370c3fa109aSTetsuo Handa * 371c3fa109aSTetsuo Handa * It is not a desirable behavior that we have to use /proc/\$/ instead of 372c3fa109aSTetsuo Handa * /proc/self/ when current process needs to access only current process's 373c3fa109aSTetsuo Handa * information. As of now, LSM version of TOMOYO is using __d_path() for 374c3fa109aSTetsuo Handa * calculating pathname. Non LSM version of TOMOYO is using its own function 375c3fa109aSTetsuo Handa * which pretends as if /proc/self/ is not a symlink; so that we can forbid 376c3fa109aSTetsuo Handa * current process from accessing other process's information. 377c3fa109aSTetsuo Handa */ 378847b173eSTetsuo Handa LIST_HEAD(tomoyo_pattern_list); 379b69a54eeSKentaro Takeda 380b69a54eeSKentaro Takeda /** 381b69a54eeSKentaro Takeda * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list. 382b69a54eeSKentaro Takeda * 383b69a54eeSKentaro Takeda * @pattern: Pathname pattern. 384b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 385b69a54eeSKentaro Takeda * 386b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 387fdb8ebb7STetsuo Handa * 388fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 389b69a54eeSKentaro Takeda */ 390b69a54eeSKentaro Takeda static int tomoyo_update_file_pattern_entry(const char *pattern, 391b69a54eeSKentaro Takeda const bool is_delete) 392b69a54eeSKentaro Takeda { 393b69a54eeSKentaro Takeda struct tomoyo_pattern_entry *ptr; 3949e4b50e9STetsuo Handa struct tomoyo_pattern_entry e = { .pattern = tomoyo_get_name(pattern) }; 395ca0b7df3STetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 396b69a54eeSKentaro Takeda 3979e4b50e9STetsuo Handa if (!e.pattern) 398ca0b7df3STetsuo Handa return error; 3999e4b50e9STetsuo Handa if (!e.pattern->is_patterned) 400ca0b7df3STetsuo Handa goto out; 40129282381STetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 40229282381STetsuo Handa goto out; 403fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { 4049e4b50e9STetsuo Handa if (e.pattern != ptr->pattern) 405b69a54eeSKentaro Takeda continue; 406b69a54eeSKentaro Takeda ptr->is_deleted = is_delete; 407b69a54eeSKentaro Takeda error = 0; 408ca0b7df3STetsuo Handa break; 409b69a54eeSKentaro Takeda } 4109e4b50e9STetsuo Handa if (!is_delete && error) { 4119e4b50e9STetsuo Handa struct tomoyo_pattern_entry *entry = 4129e4b50e9STetsuo Handa tomoyo_commit_ok(&e, sizeof(e)); 4139e4b50e9STetsuo Handa if (entry) { 414ca0b7df3STetsuo Handa list_add_tail_rcu(&entry->list, &tomoyo_pattern_list); 415b69a54eeSKentaro Takeda error = 0; 416ca0b7df3STetsuo Handa } 4179e4b50e9STetsuo Handa } 418f737d95dSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 419ca0b7df3STetsuo Handa out: 4209e4b50e9STetsuo Handa tomoyo_put_name(e.pattern); 421b69a54eeSKentaro Takeda return error; 422b69a54eeSKentaro Takeda } 423b69a54eeSKentaro Takeda 424b69a54eeSKentaro Takeda /** 42517fcfbd9STetsuo Handa * tomoyo_file_pattern - Get patterned pathname. 426b69a54eeSKentaro Takeda * 427b69a54eeSKentaro Takeda * @filename: The filename to find patterned pathname. 428b69a54eeSKentaro Takeda * 429b69a54eeSKentaro Takeda * Returns pointer to pathname pattern if matched, @filename otherwise. 430fdb8ebb7STetsuo Handa * 431fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 432b69a54eeSKentaro Takeda */ 43317fcfbd9STetsuo Handa const char *tomoyo_file_pattern(const struct tomoyo_path_info *filename) 434b69a54eeSKentaro Takeda { 435b69a54eeSKentaro Takeda struct tomoyo_pattern_entry *ptr; 436b69a54eeSKentaro Takeda const struct tomoyo_path_info *pattern = NULL; 437b69a54eeSKentaro Takeda 438fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { 439b69a54eeSKentaro Takeda if (ptr->is_deleted) 440b69a54eeSKentaro Takeda continue; 441b69a54eeSKentaro Takeda if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) 442b69a54eeSKentaro Takeda continue; 443b69a54eeSKentaro Takeda pattern = ptr->pattern; 444b69a54eeSKentaro Takeda if (tomoyo_strendswith(pattern->name, "/\\*")) { 445b69a54eeSKentaro Takeda /* Do nothing. Try to find the better match. */ 446b69a54eeSKentaro Takeda } else { 447b69a54eeSKentaro Takeda /* This would be the better match. Use this. */ 448b69a54eeSKentaro Takeda break; 449b69a54eeSKentaro Takeda } 450b69a54eeSKentaro Takeda } 451b69a54eeSKentaro Takeda if (pattern) 452b69a54eeSKentaro Takeda filename = pattern; 45317fcfbd9STetsuo Handa return filename->name; 454b69a54eeSKentaro Takeda } 455b69a54eeSKentaro Takeda 456b69a54eeSKentaro Takeda /** 457b69a54eeSKentaro Takeda * tomoyo_write_pattern_policy - Write "struct tomoyo_pattern_entry" list. 458b69a54eeSKentaro Takeda * 459b69a54eeSKentaro Takeda * @data: String to parse. 460b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 461b69a54eeSKentaro Takeda * 462b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 463fdb8ebb7STetsuo Handa * 464fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 465b69a54eeSKentaro Takeda */ 466b69a54eeSKentaro Takeda int tomoyo_write_pattern_policy(char *data, const bool is_delete) 467b69a54eeSKentaro Takeda { 468b69a54eeSKentaro Takeda return tomoyo_update_file_pattern_entry(data, is_delete); 469b69a54eeSKentaro Takeda } 470b69a54eeSKentaro Takeda 471b69a54eeSKentaro Takeda /** 472b69a54eeSKentaro Takeda * tomoyo_read_file_pattern - Read "struct tomoyo_pattern_entry" list. 473b69a54eeSKentaro Takeda * 474b69a54eeSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 475b69a54eeSKentaro Takeda * 476b69a54eeSKentaro Takeda * Returns true on success, false otherwise. 477fdb8ebb7STetsuo Handa * 478fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 479b69a54eeSKentaro Takeda */ 480b69a54eeSKentaro Takeda bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) 481b69a54eeSKentaro Takeda { 482b69a54eeSKentaro Takeda struct list_head *pos; 483b69a54eeSKentaro Takeda bool done = true; 484b69a54eeSKentaro Takeda 485b69a54eeSKentaro Takeda list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) { 486b69a54eeSKentaro Takeda struct tomoyo_pattern_entry *ptr; 487b69a54eeSKentaro Takeda ptr = list_entry(pos, struct tomoyo_pattern_entry, list); 488b69a54eeSKentaro Takeda if (ptr->is_deleted) 489b69a54eeSKentaro Takeda continue; 4907d2948b1STetsuo Handa done = tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN 4917d2948b1STetsuo Handa "%s\n", ptr->pattern->name); 4927d2948b1STetsuo Handa if (!done) 493b69a54eeSKentaro Takeda break; 494b69a54eeSKentaro Takeda } 495b69a54eeSKentaro Takeda return done; 496b69a54eeSKentaro Takeda } 497b69a54eeSKentaro Takeda 498c3fa109aSTetsuo Handa /* 499c3fa109aSTetsuo Handa * tomoyo_no_rewrite_list is used for holding list of pathnames which are by 500c3fa109aSTetsuo Handa * default forbidden to modify already written content of a file. 501c3fa109aSTetsuo Handa * 502c3fa109aSTetsuo Handa * An entry is added by 503c3fa109aSTetsuo Handa * 504c3fa109aSTetsuo Handa * # echo 'deny_rewrite /var/log/messages' > \ 505c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 506c3fa109aSTetsuo Handa * 507c3fa109aSTetsuo Handa * and is deleted by 508c3fa109aSTetsuo Handa * 509c3fa109aSTetsuo Handa * # echo 'delete deny_rewrite /var/log/messages' > \ 510c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 511c3fa109aSTetsuo Handa * 512c3fa109aSTetsuo Handa * and all entries are retrieved by 513c3fa109aSTetsuo Handa * 514c3fa109aSTetsuo Handa * # grep ^deny_rewrite /sys/kernel/security/tomoyo/exception_policy 515c3fa109aSTetsuo Handa * 516c3fa109aSTetsuo Handa * In the example above, if a process requested to rewrite /var/log/messages , 517c3fa109aSTetsuo Handa * the process can't rewrite unless the domain which that process belongs to 518c3fa109aSTetsuo Handa * has "allow_rewrite /var/log/messages" entry. 519c3fa109aSTetsuo Handa * 520c3fa109aSTetsuo Handa * It is not a desirable behavior that we have to add "\040(deleted)" suffix 521c3fa109aSTetsuo Handa * when we want to allow rewriting already unlink()ed file. As of now, 522c3fa109aSTetsuo Handa * LSM version of TOMOYO is using __d_path() for calculating pathname. 523c3fa109aSTetsuo Handa * Non LSM version of TOMOYO is using its own function which doesn't append 524c3fa109aSTetsuo Handa * " (deleted)" suffix if the file is already unlink()ed; so that we don't 525c3fa109aSTetsuo Handa * need to worry whether the file is already unlink()ed or not. 526c3fa109aSTetsuo Handa */ 527847b173eSTetsuo Handa LIST_HEAD(tomoyo_no_rewrite_list); 528b69a54eeSKentaro Takeda 529b69a54eeSKentaro Takeda /** 530b69a54eeSKentaro Takeda * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list. 531b69a54eeSKentaro Takeda * 532b69a54eeSKentaro Takeda * @pattern: Pathname pattern that are not rewritable by default. 533b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 534b69a54eeSKentaro Takeda * 535b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 536fdb8ebb7STetsuo Handa * 537fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 538b69a54eeSKentaro Takeda */ 539b69a54eeSKentaro Takeda static int tomoyo_update_no_rewrite_entry(const char *pattern, 540b69a54eeSKentaro Takeda const bool is_delete) 541b69a54eeSKentaro Takeda { 542ca0b7df3STetsuo Handa struct tomoyo_no_rewrite_entry *ptr; 5439e4b50e9STetsuo Handa struct tomoyo_no_rewrite_entry e = { }; 544ca0b7df3STetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 545b69a54eeSKentaro Takeda 54617080008STetsuo Handa if (!tomoyo_is_correct_path(pattern, 0, 0, 0)) 547b69a54eeSKentaro Takeda return -EINVAL; 5489e4b50e9STetsuo Handa e.pattern = tomoyo_get_name(pattern); 5499e4b50e9STetsuo Handa if (!e.pattern) 550ca0b7df3STetsuo Handa return error; 55129282381STetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 55229282381STetsuo Handa goto out; 553fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { 5549e4b50e9STetsuo Handa if (ptr->pattern != e.pattern) 555b69a54eeSKentaro Takeda continue; 556b69a54eeSKentaro Takeda ptr->is_deleted = is_delete; 557b69a54eeSKentaro Takeda error = 0; 558ca0b7df3STetsuo Handa break; 559b69a54eeSKentaro Takeda } 5609e4b50e9STetsuo Handa if (!is_delete && error) { 5619e4b50e9STetsuo Handa struct tomoyo_no_rewrite_entry *entry = 5629e4b50e9STetsuo Handa tomoyo_commit_ok(&e, sizeof(e)); 5639e4b50e9STetsuo Handa if (entry) { 5649e4b50e9STetsuo Handa list_add_tail_rcu(&entry->list, 5659e4b50e9STetsuo Handa &tomoyo_no_rewrite_list); 566b69a54eeSKentaro Takeda error = 0; 567ca0b7df3STetsuo Handa } 5689e4b50e9STetsuo Handa } 569f737d95dSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 57029282381STetsuo Handa out: 5719e4b50e9STetsuo Handa tomoyo_put_name(e.pattern); 572b69a54eeSKentaro Takeda return error; 573b69a54eeSKentaro Takeda } 574b69a54eeSKentaro Takeda 575b69a54eeSKentaro Takeda /** 576b69a54eeSKentaro Takeda * tomoyo_is_no_rewrite_file - Check if the given pathname is not permitted to be rewrited. 577b69a54eeSKentaro Takeda * 578b69a54eeSKentaro Takeda * @filename: Filename to check. 579b69a54eeSKentaro Takeda * 580b69a54eeSKentaro Takeda * Returns true if @filename is specified by "deny_rewrite" directive, 581b69a54eeSKentaro Takeda * false otherwise. 582fdb8ebb7STetsuo Handa * 583fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 584b69a54eeSKentaro Takeda */ 585b69a54eeSKentaro Takeda static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) 586b69a54eeSKentaro Takeda { 587b69a54eeSKentaro Takeda struct tomoyo_no_rewrite_entry *ptr; 588b69a54eeSKentaro Takeda bool found = false; 589b69a54eeSKentaro Takeda 590fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { 591b69a54eeSKentaro Takeda if (ptr->is_deleted) 592b69a54eeSKentaro Takeda continue; 593b69a54eeSKentaro Takeda if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) 594b69a54eeSKentaro Takeda continue; 595b69a54eeSKentaro Takeda found = true; 596b69a54eeSKentaro Takeda break; 597b69a54eeSKentaro Takeda } 598b69a54eeSKentaro Takeda return found; 599b69a54eeSKentaro Takeda } 600b69a54eeSKentaro Takeda 601b69a54eeSKentaro Takeda /** 602b69a54eeSKentaro Takeda * tomoyo_write_no_rewrite_policy - Write "struct tomoyo_no_rewrite_entry" list. 603b69a54eeSKentaro Takeda * 604b69a54eeSKentaro Takeda * @data: String to parse. 605b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 606b69a54eeSKentaro Takeda * 607b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 608fdb8ebb7STetsuo Handa * 609fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 610b69a54eeSKentaro Takeda */ 611b69a54eeSKentaro Takeda int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete) 612b69a54eeSKentaro Takeda { 613b69a54eeSKentaro Takeda return tomoyo_update_no_rewrite_entry(data, is_delete); 614b69a54eeSKentaro Takeda } 615b69a54eeSKentaro Takeda 616b69a54eeSKentaro Takeda /** 617b69a54eeSKentaro Takeda * tomoyo_read_no_rewrite_policy - Read "struct tomoyo_no_rewrite_entry" list. 618b69a54eeSKentaro Takeda * 619b69a54eeSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 620b69a54eeSKentaro Takeda * 621b69a54eeSKentaro Takeda * Returns true on success, false otherwise. 622fdb8ebb7STetsuo Handa * 623fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 624b69a54eeSKentaro Takeda */ 625b69a54eeSKentaro Takeda bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) 626b69a54eeSKentaro Takeda { 627b69a54eeSKentaro Takeda struct list_head *pos; 628b69a54eeSKentaro Takeda bool done = true; 629b69a54eeSKentaro Takeda 630b69a54eeSKentaro Takeda list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) { 631b69a54eeSKentaro Takeda struct tomoyo_no_rewrite_entry *ptr; 632b69a54eeSKentaro Takeda ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list); 633b69a54eeSKentaro Takeda if (ptr->is_deleted) 634b69a54eeSKentaro Takeda continue; 6357d2948b1STetsuo Handa done = tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE 6367d2948b1STetsuo Handa "%s\n", ptr->pattern->name); 6377d2948b1STetsuo Handa if (!done) 638b69a54eeSKentaro Takeda break; 639b69a54eeSKentaro Takeda } 640b69a54eeSKentaro Takeda return done; 641b69a54eeSKentaro Takeda } 642b69a54eeSKentaro Takeda 643b69a54eeSKentaro Takeda /** 644b69a54eeSKentaro Takeda * tomoyo_update_file_acl - Update file's read/write/execute ACL. 645b69a54eeSKentaro Takeda * 646b69a54eeSKentaro Takeda * @perm: Permission (between 1 to 7). 647a1f9bb6aSTetsuo Handa * @filename: Filename. 648b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 649b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 650b69a54eeSKentaro Takeda * 651b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 652b69a54eeSKentaro Takeda * 653b69a54eeSKentaro Takeda * This is legacy support interface for older policy syntax. 654b69a54eeSKentaro Takeda * Current policy syntax uses "allow_read/write" instead of "6", 655b69a54eeSKentaro Takeda * "allow_read" instead of "4", "allow_write" instead of "2", 656b69a54eeSKentaro Takeda * "allow_execute" instead of "1". 657fdb8ebb7STetsuo Handa * 658fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 659b69a54eeSKentaro Takeda */ 660a1f9bb6aSTetsuo Handa static int tomoyo_update_file_acl(u8 perm, const char *filename, 661b69a54eeSKentaro Takeda struct tomoyo_domain_info * const domain, 662b69a54eeSKentaro Takeda const bool is_delete) 663b69a54eeSKentaro Takeda { 664b69a54eeSKentaro Takeda if (perm > 7 || !perm) { 665b69a54eeSKentaro Takeda printk(KERN_DEBUG "%s: Invalid permission '%d %s'\n", 666b69a54eeSKentaro Takeda __func__, perm, filename); 667b69a54eeSKentaro Takeda return -EINVAL; 668b69a54eeSKentaro Takeda } 669b69a54eeSKentaro Takeda if (filename[0] != '@' && tomoyo_strendswith(filename, "/")) 670b69a54eeSKentaro Takeda /* 671b69a54eeSKentaro Takeda * Only 'allow_mkdir' and 'allow_rmdir' are valid for 672b69a54eeSKentaro Takeda * directory permissions. 673b69a54eeSKentaro Takeda */ 674b69a54eeSKentaro Takeda return 0; 675b69a54eeSKentaro Takeda if (perm & 4) 6767ef61233STetsuo Handa tomoyo_update_path_acl(TOMOYO_TYPE_READ, filename, domain, 6777ef61233STetsuo Handa is_delete); 678b69a54eeSKentaro Takeda if (perm & 2) 6797ef61233STetsuo Handa tomoyo_update_path_acl(TOMOYO_TYPE_WRITE, filename, domain, 6807ef61233STetsuo Handa is_delete); 681b69a54eeSKentaro Takeda if (perm & 1) 6827ef61233STetsuo Handa tomoyo_update_path_acl(TOMOYO_TYPE_EXECUTE, filename, domain, 6837ef61233STetsuo Handa is_delete); 684b69a54eeSKentaro Takeda return 0; 685b69a54eeSKentaro Takeda } 686b69a54eeSKentaro Takeda 687b69a54eeSKentaro Takeda /** 688cb0abe6aSTetsuo Handa * tomoyo_path_acl - Check permission for single path operation. 689b69a54eeSKentaro Takeda * 690cb0abe6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 691b69a54eeSKentaro Takeda * @filename: Filename to check. 692b69a54eeSKentaro Takeda * @perm: Permission. 693b69a54eeSKentaro Takeda * @may_use_pattern: True if patterned ACL is permitted. 694b69a54eeSKentaro Takeda * 695b69a54eeSKentaro Takeda * Returns 0 on success, -EPERM otherwise. 696fdb8ebb7STetsuo Handa * 697fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 698b69a54eeSKentaro Takeda */ 699cb0abe6aSTetsuo Handa static int tomoyo_path_acl(const struct tomoyo_request_info *r, 7007ef61233STetsuo Handa const struct tomoyo_path_info *filename, 7017ef61233STetsuo Handa const u32 perm, const bool may_use_pattern) 702b69a54eeSKentaro Takeda { 703cb0abe6aSTetsuo Handa struct tomoyo_domain_info *domain = r->domain; 704b69a54eeSKentaro Takeda struct tomoyo_acl_info *ptr; 705b69a54eeSKentaro Takeda int error = -EPERM; 706b69a54eeSKentaro Takeda 707fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 7087ef61233STetsuo Handa struct tomoyo_path_acl *acl; 7097ef61233STetsuo Handa if (ptr->type != TOMOYO_TYPE_PATH_ACL) 710b69a54eeSKentaro Takeda continue; 7117ef61233STetsuo Handa acl = container_of(ptr, struct tomoyo_path_acl, head); 712a1f9bb6aSTetsuo Handa if (!(acl->perm & perm) || 713a1f9bb6aSTetsuo Handa !tomoyo_compare_name_union_pattern(filename, &acl->name, 7147762fbffSTetsuo Handa may_use_pattern)) 715b69a54eeSKentaro Takeda continue; 716b69a54eeSKentaro Takeda error = 0; 717b69a54eeSKentaro Takeda break; 718b69a54eeSKentaro Takeda } 719b69a54eeSKentaro Takeda return error; 720b69a54eeSKentaro Takeda } 721b69a54eeSKentaro Takeda 722b69a54eeSKentaro Takeda /** 723cb0abe6aSTetsuo Handa * tomoyo_file_perm - Check permission for opening files. 724b69a54eeSKentaro Takeda * 725cb0abe6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 726b69a54eeSKentaro Takeda * @filename: Filename to check. 727cb0abe6aSTetsuo Handa * @mode: Mode ("read" or "write" or "read/write" or "execute"). 728b69a54eeSKentaro Takeda * 729b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 730fdb8ebb7STetsuo Handa * 731fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 732b69a54eeSKentaro Takeda */ 733cb0abe6aSTetsuo Handa static int tomoyo_file_perm(struct tomoyo_request_info *r, 734b69a54eeSKentaro Takeda const struct tomoyo_path_info *filename, 735b69a54eeSKentaro Takeda const u8 mode) 736b69a54eeSKentaro Takeda { 737b69a54eeSKentaro Takeda const char *msg = "<unknown>"; 738b69a54eeSKentaro Takeda int error = 0; 739cb0abe6aSTetsuo Handa u32 perm = 0; 740b69a54eeSKentaro Takeda 741b69a54eeSKentaro Takeda if (!filename) 742b69a54eeSKentaro Takeda return 0; 743cb0abe6aSTetsuo Handa 744cb0abe6aSTetsuo Handa if (mode == 6) { 745cb0abe6aSTetsuo Handa msg = tomoyo_path2keyword(TOMOYO_TYPE_READ_WRITE); 746cb0abe6aSTetsuo Handa perm = 1 << TOMOYO_TYPE_READ_WRITE; 747cb0abe6aSTetsuo Handa } else if (mode == 4) { 748cb0abe6aSTetsuo Handa msg = tomoyo_path2keyword(TOMOYO_TYPE_READ); 749cb0abe6aSTetsuo Handa perm = 1 << TOMOYO_TYPE_READ; 750cb0abe6aSTetsuo Handa } else if (mode == 2) { 751cb0abe6aSTetsuo Handa msg = tomoyo_path2keyword(TOMOYO_TYPE_WRITE); 752cb0abe6aSTetsuo Handa perm = 1 << TOMOYO_TYPE_WRITE; 753cb0abe6aSTetsuo Handa } else if (mode == 1) { 754cb0abe6aSTetsuo Handa msg = tomoyo_path2keyword(TOMOYO_TYPE_EXECUTE); 755cb0abe6aSTetsuo Handa perm = 1 << TOMOYO_TYPE_EXECUTE; 756cb0abe6aSTetsuo Handa } else 757cb0abe6aSTetsuo Handa BUG(); 75817fcfbd9STetsuo Handa do { 759cb0abe6aSTetsuo Handa error = tomoyo_path_acl(r, filename, perm, mode != 1); 760cb0abe6aSTetsuo Handa if (error && mode == 4 && !r->domain->ignore_global_allow_read 761b69a54eeSKentaro Takeda && tomoyo_is_globally_readable_file(filename)) 762b69a54eeSKentaro Takeda error = 0; 763b69a54eeSKentaro Takeda if (!error) 76417fcfbd9STetsuo Handa break; 765cb0abe6aSTetsuo Handa tomoyo_warn_log(r, "%s %s", msg, filename->name); 76617fcfbd9STetsuo Handa error = tomoyo_supervisor(r, "allow_%s %s\n", msg, 76717fcfbd9STetsuo Handa mode == 1 ? filename->name : 76817fcfbd9STetsuo Handa tomoyo_file_pattern(filename)); 76917fcfbd9STetsuo Handa /* 77017fcfbd9STetsuo Handa * Do not retry for execute request, for alias may have 77117fcfbd9STetsuo Handa * changed. 77217fcfbd9STetsuo Handa */ 77317fcfbd9STetsuo Handa } while (error == TOMOYO_RETRY_REQUEST && mode != 1); 77417fcfbd9STetsuo Handa if (r->mode != TOMOYO_CONFIG_ENFORCING) 77517fcfbd9STetsuo Handa error = 0; 776b69a54eeSKentaro Takeda return error; 777b69a54eeSKentaro Takeda } 778b69a54eeSKentaro Takeda 779b69a54eeSKentaro Takeda /** 7807ef61233STetsuo Handa * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list. 781b69a54eeSKentaro Takeda * 782b69a54eeSKentaro Takeda * @type: Type of operation. 783b69a54eeSKentaro Takeda * @filename: Filename. 784b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 785b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 786b69a54eeSKentaro Takeda * 787b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 788fdb8ebb7STetsuo Handa * 789fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 790b69a54eeSKentaro Takeda */ 7917ef61233STetsuo Handa static int tomoyo_update_path_acl(const u8 type, const char *filename, 7927ef61233STetsuo Handa struct tomoyo_domain_info *const domain, 7937ef61233STetsuo Handa const bool is_delete) 794b69a54eeSKentaro Takeda { 795a1f9bb6aSTetsuo Handa static const u16 tomoyo_rw_mask = 7967ef61233STetsuo Handa (1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE); 797a1f9bb6aSTetsuo Handa const u16 perm = 1 << type; 7989e4b50e9STetsuo Handa struct tomoyo_acl_info *ptr; 7999e4b50e9STetsuo Handa struct tomoyo_path_acl e = { 8009e4b50e9STetsuo Handa .head.type = TOMOYO_TYPE_PATH_ACL, 8019e4b50e9STetsuo Handa .perm = perm 8029e4b50e9STetsuo Handa }; 8039e4b50e9STetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 804b69a54eeSKentaro Takeda 8059e4b50e9STetsuo Handa if (type == TOMOYO_TYPE_READ_WRITE) 8069e4b50e9STetsuo Handa e.perm |= tomoyo_rw_mask; 807b69a54eeSKentaro Takeda if (!domain) 808b69a54eeSKentaro Takeda return -EINVAL; 8097762fbffSTetsuo Handa if (!tomoyo_parse_name_union(filename, &e.name)) 810b69a54eeSKentaro Takeda return -EINVAL; 81129282381STetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 81229282381STetsuo Handa goto out; 813fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 8147ef61233STetsuo Handa struct tomoyo_path_acl *acl = 8157ef61233STetsuo Handa container_of(ptr, struct tomoyo_path_acl, head); 8167762fbffSTetsuo Handa if (!tomoyo_is_same_path_acl(acl, &e)) 817b69a54eeSKentaro Takeda continue; 818ca0b7df3STetsuo Handa if (is_delete) { 819ca0b7df3STetsuo Handa acl->perm &= ~perm; 8209e4b50e9STetsuo Handa if ((acl->perm & tomoyo_rw_mask) != tomoyo_rw_mask) 8217ef61233STetsuo Handa acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE); 8227ef61233STetsuo Handa else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE))) 8239e4b50e9STetsuo Handa acl->perm &= ~tomoyo_rw_mask; 824ca0b7df3STetsuo Handa } else { 825b69a54eeSKentaro Takeda acl->perm |= perm; 8269e4b50e9STetsuo Handa if ((acl->perm & tomoyo_rw_mask) == tomoyo_rw_mask) 8277ef61233STetsuo Handa acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE; 8287ef61233STetsuo Handa else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE)) 8299e4b50e9STetsuo Handa acl->perm |= tomoyo_rw_mask; 830b69a54eeSKentaro Takeda } 831b69a54eeSKentaro Takeda error = 0; 832b69a54eeSKentaro Takeda break; 833b69a54eeSKentaro Takeda } 8349e4b50e9STetsuo Handa if (!is_delete && error) { 8359e4b50e9STetsuo Handa struct tomoyo_path_acl *entry = 8369e4b50e9STetsuo Handa tomoyo_commit_ok(&e, sizeof(e)); 8379e4b50e9STetsuo Handa if (entry) { 8389e4b50e9STetsuo Handa list_add_tail_rcu(&entry->head.list, 8399e4b50e9STetsuo Handa &domain->acl_info_list); 840ca0b7df3STetsuo Handa error = 0; 841ca0b7df3STetsuo Handa } 8429e4b50e9STetsuo Handa } 843f737d95dSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 84429282381STetsuo Handa out: 8457762fbffSTetsuo Handa tomoyo_put_name_union(&e.name); 846b69a54eeSKentaro Takeda return error; 847b69a54eeSKentaro Takeda } 848b69a54eeSKentaro Takeda 849b69a54eeSKentaro Takeda /** 850a1f9bb6aSTetsuo Handa * tomoyo_update_path_number3_acl - Update "struct tomoyo_path_number3_acl" list. 851a1f9bb6aSTetsuo Handa * 852a1f9bb6aSTetsuo Handa * @type: Type of operation. 853a1f9bb6aSTetsuo Handa * @filename: Filename. 854a1f9bb6aSTetsuo Handa * @mode: Create mode. 855a1f9bb6aSTetsuo Handa * @major: Device major number. 856a1f9bb6aSTetsuo Handa * @minor: Device minor number. 857a1f9bb6aSTetsuo Handa * @domain: Pointer to "struct tomoyo_domain_info". 858a1f9bb6aSTetsuo Handa * @is_delete: True if it is a delete request. 859a1f9bb6aSTetsuo Handa * 860a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 861a1f9bb6aSTetsuo Handa */ 862a1f9bb6aSTetsuo Handa static inline int tomoyo_update_path_number3_acl(const u8 type, 863a1f9bb6aSTetsuo Handa const char *filename, 864a1f9bb6aSTetsuo Handa char *mode, 865a1f9bb6aSTetsuo Handa char *major, char *minor, 866a1f9bb6aSTetsuo Handa struct tomoyo_domain_info * 867a1f9bb6aSTetsuo Handa const domain, 868a1f9bb6aSTetsuo Handa const bool is_delete) 869a1f9bb6aSTetsuo Handa { 870a1f9bb6aSTetsuo Handa const u8 perm = 1 << type; 871a1f9bb6aSTetsuo Handa struct tomoyo_acl_info *ptr; 872a1f9bb6aSTetsuo Handa struct tomoyo_path_number3_acl e = { 873a1f9bb6aSTetsuo Handa .head.type = TOMOYO_TYPE_PATH_NUMBER3_ACL, 874a1f9bb6aSTetsuo Handa .perm = perm 875a1f9bb6aSTetsuo Handa }; 876a1f9bb6aSTetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 877a1f9bb6aSTetsuo Handa if (!tomoyo_parse_name_union(filename, &e.name) || 878a1f9bb6aSTetsuo Handa !tomoyo_parse_number_union(mode, &e.mode) || 879a1f9bb6aSTetsuo Handa !tomoyo_parse_number_union(major, &e.major) || 880a1f9bb6aSTetsuo Handa !tomoyo_parse_number_union(minor, &e.minor)) 881a1f9bb6aSTetsuo Handa goto out; 882a1f9bb6aSTetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 883a1f9bb6aSTetsuo Handa goto out; 884a1f9bb6aSTetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 885a1f9bb6aSTetsuo Handa struct tomoyo_path_number3_acl *acl = 886a1f9bb6aSTetsuo Handa container_of(ptr, struct tomoyo_path_number3_acl, head); 887a1f9bb6aSTetsuo Handa if (!tomoyo_is_same_path_number3_acl(acl, &e)) 888a1f9bb6aSTetsuo Handa continue; 889a1f9bb6aSTetsuo Handa if (is_delete) 890a1f9bb6aSTetsuo Handa acl->perm &= ~perm; 891a1f9bb6aSTetsuo Handa else 892a1f9bb6aSTetsuo Handa acl->perm |= perm; 893a1f9bb6aSTetsuo Handa error = 0; 894a1f9bb6aSTetsuo Handa break; 895a1f9bb6aSTetsuo Handa } 896a1f9bb6aSTetsuo Handa if (!is_delete && error) { 897a1f9bb6aSTetsuo Handa struct tomoyo_path_number3_acl *entry = 898a1f9bb6aSTetsuo Handa tomoyo_commit_ok(&e, sizeof(e)); 899a1f9bb6aSTetsuo Handa if (entry) { 900a1f9bb6aSTetsuo Handa list_add_tail_rcu(&entry->head.list, 901a1f9bb6aSTetsuo Handa &domain->acl_info_list); 902a1f9bb6aSTetsuo Handa error = 0; 903a1f9bb6aSTetsuo Handa } 904a1f9bb6aSTetsuo Handa } 905a1f9bb6aSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 906a1f9bb6aSTetsuo Handa out: 907a1f9bb6aSTetsuo Handa tomoyo_put_name_union(&e.name); 908a1f9bb6aSTetsuo Handa tomoyo_put_number_union(&e.mode); 909a1f9bb6aSTetsuo Handa tomoyo_put_number_union(&e.major); 910a1f9bb6aSTetsuo Handa tomoyo_put_number_union(&e.minor); 911a1f9bb6aSTetsuo Handa return error; 912a1f9bb6aSTetsuo Handa } 913a1f9bb6aSTetsuo Handa 914a1f9bb6aSTetsuo Handa /** 9157ef61233STetsuo Handa * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list. 916b69a54eeSKentaro Takeda * 917b69a54eeSKentaro Takeda * @type: Type of operation. 918b69a54eeSKentaro Takeda * @filename1: First filename. 919b69a54eeSKentaro Takeda * @filename2: Second filename. 920b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 921b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 922b69a54eeSKentaro Takeda * 923b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 924fdb8ebb7STetsuo Handa * 925fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 926b69a54eeSKentaro Takeda */ 9277ef61233STetsuo Handa static int tomoyo_update_path2_acl(const u8 type, const char *filename1, 928b69a54eeSKentaro Takeda const char *filename2, 9297ef61233STetsuo Handa struct tomoyo_domain_info *const domain, 9307ef61233STetsuo Handa const bool is_delete) 931b69a54eeSKentaro Takeda { 932b69a54eeSKentaro Takeda const u8 perm = 1 << type; 9339e4b50e9STetsuo Handa struct tomoyo_path2_acl e = { 9349e4b50e9STetsuo Handa .head.type = TOMOYO_TYPE_PATH2_ACL, 9359e4b50e9STetsuo Handa .perm = perm 9369e4b50e9STetsuo Handa }; 9379e4b50e9STetsuo Handa struct tomoyo_acl_info *ptr; 9389e4b50e9STetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 939b69a54eeSKentaro Takeda 940b69a54eeSKentaro Takeda if (!domain) 941b69a54eeSKentaro Takeda return -EINVAL; 9427762fbffSTetsuo Handa if (!tomoyo_parse_name_union(filename1, &e.name1) || 9437762fbffSTetsuo Handa !tomoyo_parse_name_union(filename2, &e.name2)) 944ca0b7df3STetsuo Handa goto out; 94529282381STetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 94629282381STetsuo Handa goto out; 947ca0b7df3STetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 9487ef61233STetsuo Handa struct tomoyo_path2_acl *acl = 9497ef61233STetsuo Handa container_of(ptr, struct tomoyo_path2_acl, head); 9507762fbffSTetsuo Handa if (!tomoyo_is_same_path2_acl(acl, &e)) 951ca0b7df3STetsuo Handa continue; 952b69a54eeSKentaro Takeda if (is_delete) 953b69a54eeSKentaro Takeda acl->perm &= ~perm; 954ca0b7df3STetsuo Handa else 955ca0b7df3STetsuo Handa acl->perm |= perm; 956b69a54eeSKentaro Takeda error = 0; 957b69a54eeSKentaro Takeda break; 958b69a54eeSKentaro Takeda } 9599e4b50e9STetsuo Handa if (!is_delete && error) { 9609e4b50e9STetsuo Handa struct tomoyo_path2_acl *entry = 9619e4b50e9STetsuo Handa tomoyo_commit_ok(&e, sizeof(e)); 9629e4b50e9STetsuo Handa if (entry) { 9639e4b50e9STetsuo Handa list_add_tail_rcu(&entry->head.list, 9649e4b50e9STetsuo Handa &domain->acl_info_list); 965ca0b7df3STetsuo Handa error = 0; 966ca0b7df3STetsuo Handa } 9679e4b50e9STetsuo Handa } 968f737d95dSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 969ca0b7df3STetsuo Handa out: 9707762fbffSTetsuo Handa tomoyo_put_name_union(&e.name1); 9717762fbffSTetsuo Handa tomoyo_put_name_union(&e.name2); 972b69a54eeSKentaro Takeda return error; 973b69a54eeSKentaro Takeda } 974b69a54eeSKentaro Takeda 975b69a54eeSKentaro Takeda /** 976a1f9bb6aSTetsuo Handa * tomoyo_path_number3_acl - Check permission for path/number/number/number operation. 977a1f9bb6aSTetsuo Handa * 978a1f9bb6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 979a1f9bb6aSTetsuo Handa * @filename: Filename to check. 980a1f9bb6aSTetsuo Handa * @perm: Permission. 981a1f9bb6aSTetsuo Handa * @mode: Create mode. 982a1f9bb6aSTetsuo Handa * @major: Device major number. 983a1f9bb6aSTetsuo Handa * @minor: Device minor number. 984a1f9bb6aSTetsuo Handa * 985a1f9bb6aSTetsuo Handa * Returns 0 on success, -EPERM otherwise. 986a1f9bb6aSTetsuo Handa * 987a1f9bb6aSTetsuo Handa * Caller holds tomoyo_read_lock(). 988a1f9bb6aSTetsuo Handa */ 989a1f9bb6aSTetsuo Handa static int tomoyo_path_number3_acl(struct tomoyo_request_info *r, 990a1f9bb6aSTetsuo Handa const struct tomoyo_path_info *filename, 991a1f9bb6aSTetsuo Handa const u16 perm, const unsigned int mode, 992a1f9bb6aSTetsuo Handa const unsigned int major, 993a1f9bb6aSTetsuo Handa const unsigned int minor) 994a1f9bb6aSTetsuo Handa { 995a1f9bb6aSTetsuo Handa struct tomoyo_domain_info *domain = r->domain; 996a1f9bb6aSTetsuo Handa struct tomoyo_acl_info *ptr; 997a1f9bb6aSTetsuo Handa int error = -EPERM; 998a1f9bb6aSTetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 999a1f9bb6aSTetsuo Handa struct tomoyo_path_number3_acl *acl; 1000a1f9bb6aSTetsuo Handa if (ptr->type != TOMOYO_TYPE_PATH_NUMBER3_ACL) 1001a1f9bb6aSTetsuo Handa continue; 1002a1f9bb6aSTetsuo Handa acl = container_of(ptr, struct tomoyo_path_number3_acl, head); 1003a1f9bb6aSTetsuo Handa if (!tomoyo_compare_number_union(mode, &acl->mode)) 1004a1f9bb6aSTetsuo Handa continue; 1005a1f9bb6aSTetsuo Handa if (!tomoyo_compare_number_union(major, &acl->major)) 1006a1f9bb6aSTetsuo Handa continue; 1007a1f9bb6aSTetsuo Handa if (!tomoyo_compare_number_union(minor, &acl->minor)) 1008a1f9bb6aSTetsuo Handa continue; 1009a1f9bb6aSTetsuo Handa if (!(acl->perm & perm)) 1010a1f9bb6aSTetsuo Handa continue; 1011a1f9bb6aSTetsuo Handa if (!tomoyo_compare_name_union(filename, &acl->name)) 1012a1f9bb6aSTetsuo Handa continue; 1013a1f9bb6aSTetsuo Handa error = 0; 1014a1f9bb6aSTetsuo Handa break; 1015a1f9bb6aSTetsuo Handa } 1016a1f9bb6aSTetsuo Handa return error; 1017a1f9bb6aSTetsuo Handa } 1018a1f9bb6aSTetsuo Handa 1019a1f9bb6aSTetsuo Handa /** 10207ef61233STetsuo Handa * tomoyo_path2_acl - Check permission for double path operation. 1021b69a54eeSKentaro Takeda * 1022cb0abe6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 1023b69a54eeSKentaro Takeda * @type: Type of operation. 1024b69a54eeSKentaro Takeda * @filename1: First filename to check. 1025b69a54eeSKentaro Takeda * @filename2: Second filename to check. 1026b69a54eeSKentaro Takeda * 1027b69a54eeSKentaro Takeda * Returns 0 on success, -EPERM otherwise. 1028fdb8ebb7STetsuo Handa * 1029fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 1030b69a54eeSKentaro Takeda */ 1031cb0abe6aSTetsuo Handa static int tomoyo_path2_acl(const struct tomoyo_request_info *r, const u8 type, 10327ef61233STetsuo Handa const struct tomoyo_path_info *filename1, 10337ef61233STetsuo Handa const struct tomoyo_path_info *filename2) 1034b69a54eeSKentaro Takeda { 1035cb0abe6aSTetsuo Handa const struct tomoyo_domain_info *domain = r->domain; 1036b69a54eeSKentaro Takeda struct tomoyo_acl_info *ptr; 1037b69a54eeSKentaro Takeda const u8 perm = 1 << type; 1038b69a54eeSKentaro Takeda int error = -EPERM; 1039b69a54eeSKentaro Takeda 1040fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 10417ef61233STetsuo Handa struct tomoyo_path2_acl *acl; 10427ef61233STetsuo Handa if (ptr->type != TOMOYO_TYPE_PATH2_ACL) 1043b69a54eeSKentaro Takeda continue; 10447ef61233STetsuo Handa acl = container_of(ptr, struct tomoyo_path2_acl, head); 1045b69a54eeSKentaro Takeda if (!(acl->perm & perm)) 1046b69a54eeSKentaro Takeda continue; 10477762fbffSTetsuo Handa if (!tomoyo_compare_name_union(filename1, &acl->name1)) 1048b69a54eeSKentaro Takeda continue; 10497762fbffSTetsuo Handa if (!tomoyo_compare_name_union(filename2, &acl->name2)) 1050b69a54eeSKentaro Takeda continue; 1051b69a54eeSKentaro Takeda error = 0; 1052b69a54eeSKentaro Takeda break; 1053b69a54eeSKentaro Takeda } 1054b69a54eeSKentaro Takeda return error; 1055b69a54eeSKentaro Takeda } 1056b69a54eeSKentaro Takeda 1057b69a54eeSKentaro Takeda /** 1058cb0abe6aSTetsuo Handa * tomoyo_path_permission - Check permission for single path operation. 1059b69a54eeSKentaro Takeda * 1060cb0abe6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 1061b69a54eeSKentaro Takeda * @operation: Type of operation. 1062b69a54eeSKentaro Takeda * @filename: Filename to check. 1063b69a54eeSKentaro Takeda * 1064b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1065fdb8ebb7STetsuo Handa * 1066fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 1067b69a54eeSKentaro Takeda */ 1068cb0abe6aSTetsuo Handa static int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, 1069cb0abe6aSTetsuo Handa const struct tomoyo_path_info *filename) 1070b69a54eeSKentaro Takeda { 107117fcfbd9STetsuo Handa const char *msg; 1072b69a54eeSKentaro Takeda int error; 1073b69a54eeSKentaro Takeda 1074b69a54eeSKentaro Takeda next: 107517fcfbd9STetsuo Handa do { 1076cb0abe6aSTetsuo Handa error = tomoyo_path_acl(r, filename, 1 << operation, 1); 1077b69a54eeSKentaro Takeda if (!error) 107817fcfbd9STetsuo Handa break; 107917fcfbd9STetsuo Handa msg = tomoyo_path2keyword(operation); 108017fcfbd9STetsuo Handa tomoyo_warn_log(r, "%s %s", msg, filename->name); 108117fcfbd9STetsuo Handa error = tomoyo_supervisor(r, "allow_%s %s\n", msg, 108217fcfbd9STetsuo Handa tomoyo_file_pattern(filename)); 108317fcfbd9STetsuo Handa } while (error == TOMOYO_RETRY_REQUEST); 1084cb0abe6aSTetsuo Handa if (r->mode != TOMOYO_CONFIG_ENFORCING) 1085b69a54eeSKentaro Takeda error = 0; 1086b69a54eeSKentaro Takeda /* 1087b69a54eeSKentaro Takeda * Since "allow_truncate" doesn't imply "allow_rewrite" permission, 1088b69a54eeSKentaro Takeda * we need to check "allow_rewrite" permission if the filename is 1089b69a54eeSKentaro Takeda * specified by "deny_rewrite" keyword. 1090b69a54eeSKentaro Takeda */ 10917ef61233STetsuo Handa if (!error && operation == TOMOYO_TYPE_TRUNCATE && 1092b69a54eeSKentaro Takeda tomoyo_is_no_rewrite_file(filename)) { 10937ef61233STetsuo Handa operation = TOMOYO_TYPE_REWRITE; 1094b69a54eeSKentaro Takeda goto next; 1095b69a54eeSKentaro Takeda } 1096b69a54eeSKentaro Takeda return error; 1097b69a54eeSKentaro Takeda } 1098b69a54eeSKentaro Takeda 1099b69a54eeSKentaro Takeda /** 1100a1f9bb6aSTetsuo Handa * tomoyo_path_number_acl - Check permission for ioctl/chmod/chown/chgrp operation. 1101a1f9bb6aSTetsuo Handa * 1102a1f9bb6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 1103a1f9bb6aSTetsuo Handa * @type: Operation. 1104a1f9bb6aSTetsuo Handa * @filename: Filename to check. 1105a1f9bb6aSTetsuo Handa * @number: Number. 1106a1f9bb6aSTetsuo Handa * 1107a1f9bb6aSTetsuo Handa * Returns 0 on success, -EPERM otherwise. 1108a1f9bb6aSTetsuo Handa * 1109a1f9bb6aSTetsuo Handa * Caller holds tomoyo_read_lock(). 1110a1f9bb6aSTetsuo Handa */ 1111a1f9bb6aSTetsuo Handa static int tomoyo_path_number_acl(struct tomoyo_request_info *r, const u8 type, 1112a1f9bb6aSTetsuo Handa const struct tomoyo_path_info *filename, 1113a1f9bb6aSTetsuo Handa const unsigned long number) 1114a1f9bb6aSTetsuo Handa { 1115a1f9bb6aSTetsuo Handa struct tomoyo_domain_info *domain = r->domain; 1116a1f9bb6aSTetsuo Handa struct tomoyo_acl_info *ptr; 1117a1f9bb6aSTetsuo Handa const u8 perm = 1 << type; 1118a1f9bb6aSTetsuo Handa int error = -EPERM; 1119a1f9bb6aSTetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 1120a1f9bb6aSTetsuo Handa struct tomoyo_path_number_acl *acl; 1121a1f9bb6aSTetsuo Handa if (ptr->type != TOMOYO_TYPE_PATH_NUMBER_ACL) 1122a1f9bb6aSTetsuo Handa continue; 1123a1f9bb6aSTetsuo Handa acl = container_of(ptr, struct tomoyo_path_number_acl, 1124a1f9bb6aSTetsuo Handa head); 1125a1f9bb6aSTetsuo Handa if (!(acl->perm & perm) || 1126a1f9bb6aSTetsuo Handa !tomoyo_compare_number_union(number, &acl->number) || 1127a1f9bb6aSTetsuo Handa !tomoyo_compare_name_union(filename, &acl->name)) 1128a1f9bb6aSTetsuo Handa continue; 1129a1f9bb6aSTetsuo Handa error = 0; 1130a1f9bb6aSTetsuo Handa break; 1131a1f9bb6aSTetsuo Handa } 1132a1f9bb6aSTetsuo Handa return error; 1133a1f9bb6aSTetsuo Handa } 1134a1f9bb6aSTetsuo Handa 1135a1f9bb6aSTetsuo Handa /** 1136a1f9bb6aSTetsuo Handa * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL. 1137a1f9bb6aSTetsuo Handa * 1138a1f9bb6aSTetsuo Handa * @type: Type of operation. 1139a1f9bb6aSTetsuo Handa * @filename: Filename. 1140a1f9bb6aSTetsuo Handa * @number: Number. 1141a1f9bb6aSTetsuo Handa * @domain: Pointer to "struct tomoyo_domain_info". 1142a1f9bb6aSTetsuo Handa * @is_delete: True if it is a delete request. 1143a1f9bb6aSTetsuo Handa * 1144a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1145a1f9bb6aSTetsuo Handa */ 1146a1f9bb6aSTetsuo Handa static inline int tomoyo_update_path_number_acl(const u8 type, 1147a1f9bb6aSTetsuo Handa const char *filename, 1148a1f9bb6aSTetsuo Handa char *number, 1149a1f9bb6aSTetsuo Handa struct tomoyo_domain_info * 1150a1f9bb6aSTetsuo Handa const domain, 1151a1f9bb6aSTetsuo Handa const bool is_delete) 1152a1f9bb6aSTetsuo Handa { 1153a1f9bb6aSTetsuo Handa const u8 perm = 1 << type; 1154a1f9bb6aSTetsuo Handa struct tomoyo_acl_info *ptr; 1155a1f9bb6aSTetsuo Handa struct tomoyo_path_number_acl e = { 1156a1f9bb6aSTetsuo Handa .head.type = TOMOYO_TYPE_PATH_NUMBER_ACL, 1157a1f9bb6aSTetsuo Handa .perm = perm 1158a1f9bb6aSTetsuo Handa }; 1159a1f9bb6aSTetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 1160a1f9bb6aSTetsuo Handa if (!domain) 1161a1f9bb6aSTetsuo Handa return -EINVAL; 1162a1f9bb6aSTetsuo Handa if (!tomoyo_parse_name_union(filename, &e.name)) 1163a1f9bb6aSTetsuo Handa return -EINVAL; 1164a1f9bb6aSTetsuo Handa if (!tomoyo_parse_number_union(number, &e.number)) 1165a1f9bb6aSTetsuo Handa goto out; 1166a1f9bb6aSTetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 1167a1f9bb6aSTetsuo Handa goto out; 1168a1f9bb6aSTetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 1169a1f9bb6aSTetsuo Handa struct tomoyo_path_number_acl *acl = 1170a1f9bb6aSTetsuo Handa container_of(ptr, struct tomoyo_path_number_acl, head); 1171a1f9bb6aSTetsuo Handa if (!tomoyo_is_same_path_number_acl(acl, &e)) 1172a1f9bb6aSTetsuo Handa continue; 1173a1f9bb6aSTetsuo Handa if (is_delete) 1174a1f9bb6aSTetsuo Handa acl->perm &= ~perm; 1175a1f9bb6aSTetsuo Handa else 1176a1f9bb6aSTetsuo Handa acl->perm |= perm; 1177a1f9bb6aSTetsuo Handa error = 0; 1178a1f9bb6aSTetsuo Handa break; 1179a1f9bb6aSTetsuo Handa } 1180a1f9bb6aSTetsuo Handa if (!is_delete && error) { 1181a1f9bb6aSTetsuo Handa struct tomoyo_path_number_acl *entry = 1182a1f9bb6aSTetsuo Handa tomoyo_commit_ok(&e, sizeof(e)); 1183a1f9bb6aSTetsuo Handa if (entry) { 1184a1f9bb6aSTetsuo Handa list_add_tail_rcu(&entry->head.list, 1185a1f9bb6aSTetsuo Handa &domain->acl_info_list); 1186a1f9bb6aSTetsuo Handa error = 0; 1187a1f9bb6aSTetsuo Handa } 1188a1f9bb6aSTetsuo Handa } 1189a1f9bb6aSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 1190a1f9bb6aSTetsuo Handa out: 1191a1f9bb6aSTetsuo Handa tomoyo_put_name_union(&e.name); 1192a1f9bb6aSTetsuo Handa tomoyo_put_number_union(&e.number); 1193a1f9bb6aSTetsuo Handa return error; 1194a1f9bb6aSTetsuo Handa } 1195a1f9bb6aSTetsuo Handa 1196a1f9bb6aSTetsuo Handa /** 1197a1f9bb6aSTetsuo Handa * tomoyo_path_number_perm2 - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp". 1198a1f9bb6aSTetsuo Handa * 1199a1f9bb6aSTetsuo Handa * @r: Pointer to "strct tomoyo_request_info". 1200a1f9bb6aSTetsuo Handa * @filename: Filename to check. 1201a1f9bb6aSTetsuo Handa * @number: Number. 1202a1f9bb6aSTetsuo Handa * 1203a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1204a1f9bb6aSTetsuo Handa * 1205a1f9bb6aSTetsuo Handa * Caller holds tomoyo_read_lock(). 1206a1f9bb6aSTetsuo Handa */ 1207a1f9bb6aSTetsuo Handa static int tomoyo_path_number_perm2(struct tomoyo_request_info *r, 1208a1f9bb6aSTetsuo Handa const u8 type, 1209a1f9bb6aSTetsuo Handa const struct tomoyo_path_info *filename, 1210a1f9bb6aSTetsuo Handa const unsigned long number) 1211a1f9bb6aSTetsuo Handa { 1212a1f9bb6aSTetsuo Handa char buffer[64]; 1213a1f9bb6aSTetsuo Handa int error; 1214a1f9bb6aSTetsuo Handa u8 radix; 121517fcfbd9STetsuo Handa const char *msg; 1216a1f9bb6aSTetsuo Handa 1217a1f9bb6aSTetsuo Handa if (!filename) 1218a1f9bb6aSTetsuo Handa return 0; 1219a1f9bb6aSTetsuo Handa switch (type) { 1220a1f9bb6aSTetsuo Handa case TOMOYO_TYPE_CREATE: 1221a1f9bb6aSTetsuo Handa case TOMOYO_TYPE_MKDIR: 1222a1f9bb6aSTetsuo Handa case TOMOYO_TYPE_MKFIFO: 1223a1f9bb6aSTetsuo Handa case TOMOYO_TYPE_MKSOCK: 1224a1f9bb6aSTetsuo Handa case TOMOYO_TYPE_CHMOD: 1225a1f9bb6aSTetsuo Handa radix = TOMOYO_VALUE_TYPE_OCTAL; 1226a1f9bb6aSTetsuo Handa break; 1227a1f9bb6aSTetsuo Handa case TOMOYO_TYPE_IOCTL: 1228a1f9bb6aSTetsuo Handa radix = TOMOYO_VALUE_TYPE_HEXADECIMAL; 1229a1f9bb6aSTetsuo Handa break; 1230a1f9bb6aSTetsuo Handa default: 1231a1f9bb6aSTetsuo Handa radix = TOMOYO_VALUE_TYPE_DECIMAL; 1232a1f9bb6aSTetsuo Handa break; 1233a1f9bb6aSTetsuo Handa } 1234a1f9bb6aSTetsuo Handa tomoyo_print_ulong(buffer, sizeof(buffer), number, radix); 123517fcfbd9STetsuo Handa do { 1236a1f9bb6aSTetsuo Handa error = tomoyo_path_number_acl(r, type, filename, number); 1237a1f9bb6aSTetsuo Handa if (!error) 123817fcfbd9STetsuo Handa break; 123917fcfbd9STetsuo Handa msg = tomoyo_path_number2keyword(type); 124017fcfbd9STetsuo Handa tomoyo_warn_log(r, "%s %s %s", msg, filename->name, buffer); 124117fcfbd9STetsuo Handa error = tomoyo_supervisor(r, "allow_%s %s %s\n", msg, 124217fcfbd9STetsuo Handa tomoyo_file_pattern(filename), 124317fcfbd9STetsuo Handa buffer); 124417fcfbd9STetsuo Handa } while (error == TOMOYO_RETRY_REQUEST); 1245a1f9bb6aSTetsuo Handa if (r->mode != TOMOYO_CONFIG_ENFORCING) 1246a1f9bb6aSTetsuo Handa error = 0; 1247a1f9bb6aSTetsuo Handa return error; 1248a1f9bb6aSTetsuo Handa } 1249a1f9bb6aSTetsuo Handa 1250a1f9bb6aSTetsuo Handa /** 1251a1f9bb6aSTetsuo Handa * tomoyo_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp". 1252a1f9bb6aSTetsuo Handa * 1253a1f9bb6aSTetsuo Handa * @type: Type of operation. 1254a1f9bb6aSTetsuo Handa * @path: Pointer to "struct path". 1255a1f9bb6aSTetsuo Handa * @number: Number. 1256a1f9bb6aSTetsuo Handa * 1257a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1258a1f9bb6aSTetsuo Handa */ 1259a1f9bb6aSTetsuo Handa int tomoyo_path_number_perm(const u8 type, struct path *path, 1260a1f9bb6aSTetsuo Handa unsigned long number) 1261a1f9bb6aSTetsuo Handa { 1262a1f9bb6aSTetsuo Handa struct tomoyo_request_info r; 1263a1f9bb6aSTetsuo Handa int error = -ENOMEM; 1264c8c57e84STetsuo Handa struct tomoyo_path_info buf; 1265a1f9bb6aSTetsuo Handa int idx; 1266a1f9bb6aSTetsuo Handa 1267a1f9bb6aSTetsuo Handa if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED || 1268a1f9bb6aSTetsuo Handa !path->mnt || !path->dentry) 1269a1f9bb6aSTetsuo Handa return 0; 1270a1f9bb6aSTetsuo Handa idx = tomoyo_read_lock(); 1271c8c57e84STetsuo Handa if (!tomoyo_get_realpath(&buf, path)) 1272a1f9bb6aSTetsuo Handa goto out; 1273c8c57e84STetsuo Handa if (type == TOMOYO_TYPE_MKDIR) 1274c8c57e84STetsuo Handa tomoyo_add_slash(&buf); 1275c8c57e84STetsuo Handa error = tomoyo_path_number_perm2(&r, type, &buf, number); 1276a1f9bb6aSTetsuo Handa out: 1277c8c57e84STetsuo Handa kfree(buf.name); 1278a1f9bb6aSTetsuo Handa tomoyo_read_unlock(idx); 1279a1f9bb6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 1280a1f9bb6aSTetsuo Handa error = 0; 1281a1f9bb6aSTetsuo Handa return error; 1282a1f9bb6aSTetsuo Handa } 1283a1f9bb6aSTetsuo Handa 1284a1f9bb6aSTetsuo Handa /** 1285b69a54eeSKentaro Takeda * tomoyo_check_exec_perm - Check permission for "execute". 1286b69a54eeSKentaro Takeda * 1287b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 1288b69a54eeSKentaro Takeda * @filename: Check permission for "execute". 1289b69a54eeSKentaro Takeda * 1290b69a54eeSKentaro Takeda * Returns 0 on success, negativevalue otherwise. 1291fdb8ebb7STetsuo Handa * 1292fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 1293b69a54eeSKentaro Takeda */ 1294b69a54eeSKentaro Takeda int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, 1295bcb86975STetsuo Handa const struct tomoyo_path_info *filename) 1296b69a54eeSKentaro Takeda { 1297cb0abe6aSTetsuo Handa struct tomoyo_request_info r; 1298b69a54eeSKentaro Takeda 1299cb0abe6aSTetsuo Handa if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED) 1300b69a54eeSKentaro Takeda return 0; 1301cb0abe6aSTetsuo Handa return tomoyo_file_perm(&r, filename, 1); 1302b69a54eeSKentaro Takeda } 1303b69a54eeSKentaro Takeda 1304b69a54eeSKentaro Takeda /** 1305b69a54eeSKentaro Takeda * tomoyo_check_open_permission - Check permission for "read" and "write". 1306b69a54eeSKentaro Takeda * 1307b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 1308b69a54eeSKentaro Takeda * @path: Pointer to "struct path". 1309b69a54eeSKentaro Takeda * @flag: Flags for open(). 1310b69a54eeSKentaro Takeda * 1311b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1312b69a54eeSKentaro Takeda */ 1313b69a54eeSKentaro Takeda int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, 1314b69a54eeSKentaro Takeda struct path *path, const int flag) 1315b69a54eeSKentaro Takeda { 1316b69a54eeSKentaro Takeda const u8 acc_mode = ACC_MODE(flag); 1317b69a54eeSKentaro Takeda int error = -ENOMEM; 1318c8c57e84STetsuo Handa struct tomoyo_path_info buf; 1319cb0abe6aSTetsuo Handa struct tomoyo_request_info r; 1320fdb8ebb7STetsuo Handa int idx; 1321b69a54eeSKentaro Takeda 1322cb0abe6aSTetsuo Handa if (tomoyo_init_request_info(&r, domain) == TOMOYO_CONFIG_DISABLED || 1323cb0abe6aSTetsuo Handa !path->mnt) 1324b69a54eeSKentaro Takeda return 0; 1325b69a54eeSKentaro Takeda if (acc_mode == 0) 1326b69a54eeSKentaro Takeda return 0; 1327b69a54eeSKentaro Takeda if (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode)) 1328b69a54eeSKentaro Takeda /* 1329b69a54eeSKentaro Takeda * I don't check directories here because mkdir() and rmdir() 1330b69a54eeSKentaro Takeda * don't call me. 1331b69a54eeSKentaro Takeda */ 1332b69a54eeSKentaro Takeda return 0; 1333fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 1334c8c57e84STetsuo Handa if (!tomoyo_get_realpath(&buf, path)) 1335b69a54eeSKentaro Takeda goto out; 1336b69a54eeSKentaro Takeda error = 0; 1337b69a54eeSKentaro Takeda /* 1338b69a54eeSKentaro Takeda * If the filename is specified by "deny_rewrite" keyword, 1339b69a54eeSKentaro Takeda * we need to check "allow_rewrite" permission when the filename is not 1340b69a54eeSKentaro Takeda * opened for append mode or the filename is truncated at open time. 1341b69a54eeSKentaro Takeda */ 1342b69a54eeSKentaro Takeda if ((acc_mode & MAY_WRITE) && 1343b69a54eeSKentaro Takeda ((flag & O_TRUNC) || !(flag & O_APPEND)) && 1344c8c57e84STetsuo Handa (tomoyo_is_no_rewrite_file(&buf))) { 1345c8c57e84STetsuo Handa error = tomoyo_path_permission(&r, TOMOYO_TYPE_REWRITE, &buf); 1346b69a54eeSKentaro Takeda } 1347b69a54eeSKentaro Takeda if (!error) 1348c8c57e84STetsuo Handa error = tomoyo_file_perm(&r, &buf, acc_mode); 1349b69a54eeSKentaro Takeda if (!error && (flag & O_TRUNC)) 1350c8c57e84STetsuo Handa error = tomoyo_path_permission(&r, TOMOYO_TYPE_TRUNCATE, &buf); 1351b69a54eeSKentaro Takeda out: 1352c8c57e84STetsuo Handa kfree(buf.name); 1353fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 1354cb0abe6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 1355b69a54eeSKentaro Takeda error = 0; 1356b69a54eeSKentaro Takeda return error; 1357b69a54eeSKentaro Takeda } 1358b69a54eeSKentaro Takeda 1359b69a54eeSKentaro Takeda /** 13602106ccd9STetsuo Handa * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "rewrite", "chroot" and "unmount". 1361b69a54eeSKentaro Takeda * 1362b69a54eeSKentaro Takeda * @operation: Type of operation. 1363b69a54eeSKentaro Takeda * @path: Pointer to "struct path". 1364b69a54eeSKentaro Takeda * 1365b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1366b69a54eeSKentaro Takeda */ 136797d6931eSTetsuo Handa int tomoyo_path_perm(const u8 operation, struct path *path) 1368b69a54eeSKentaro Takeda { 1369b69a54eeSKentaro Takeda int error = -ENOMEM; 1370c8c57e84STetsuo Handa struct tomoyo_path_info buf; 1371cb0abe6aSTetsuo Handa struct tomoyo_request_info r; 1372fdb8ebb7STetsuo Handa int idx; 1373b69a54eeSKentaro Takeda 1374cb0abe6aSTetsuo Handa if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED || 1375cb0abe6aSTetsuo Handa !path->mnt) 1376b69a54eeSKentaro Takeda return 0; 1377fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 1378c8c57e84STetsuo Handa if (!tomoyo_get_realpath(&buf, path)) 1379b69a54eeSKentaro Takeda goto out; 1380b69a54eeSKentaro Takeda switch (operation) { 1381cb0abe6aSTetsuo Handa case TOMOYO_TYPE_REWRITE: 1382c8c57e84STetsuo Handa if (!tomoyo_is_no_rewrite_file(&buf)) { 1383cb0abe6aSTetsuo Handa error = 0; 1384cb0abe6aSTetsuo Handa goto out; 1385cb0abe6aSTetsuo Handa } 1386cb0abe6aSTetsuo Handa break; 13877ef61233STetsuo Handa case TOMOYO_TYPE_RMDIR: 13887ef61233STetsuo Handa case TOMOYO_TYPE_CHROOT: 1389c8c57e84STetsuo Handa tomoyo_add_slash(&buf); 1390c8c57e84STetsuo Handa break; 1391b69a54eeSKentaro Takeda } 1392c8c57e84STetsuo Handa error = tomoyo_path_permission(&r, operation, &buf); 1393b69a54eeSKentaro Takeda out: 1394c8c57e84STetsuo Handa kfree(buf.name); 1395fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 1396cb0abe6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 1397b69a54eeSKentaro Takeda error = 0; 1398b69a54eeSKentaro Takeda return error; 1399b69a54eeSKentaro Takeda } 1400b69a54eeSKentaro Takeda 1401b69a54eeSKentaro Takeda /** 1402a1f9bb6aSTetsuo Handa * tomoyo_path_number3_perm2 - Check permission for path/number/number/number operation. 1403a1f9bb6aSTetsuo Handa * 1404a1f9bb6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 1405a1f9bb6aSTetsuo Handa * @operation: Type of operation. 1406a1f9bb6aSTetsuo Handa * @filename: Filename to check. 1407a1f9bb6aSTetsuo Handa * @mode: Create mode. 1408a1f9bb6aSTetsuo Handa * @dev: Device number. 1409a1f9bb6aSTetsuo Handa * 1410a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1411a1f9bb6aSTetsuo Handa * 1412a1f9bb6aSTetsuo Handa * Caller holds tomoyo_read_lock(). 1413a1f9bb6aSTetsuo Handa */ 1414a1f9bb6aSTetsuo Handa static int tomoyo_path_number3_perm2(struct tomoyo_request_info *r, 1415a1f9bb6aSTetsuo Handa const u8 operation, 1416a1f9bb6aSTetsuo Handa const struct tomoyo_path_info *filename, 1417a1f9bb6aSTetsuo Handa const unsigned int mode, 1418a1f9bb6aSTetsuo Handa const unsigned int dev) 1419a1f9bb6aSTetsuo Handa { 1420a1f9bb6aSTetsuo Handa int error; 142117fcfbd9STetsuo Handa const char *msg; 1422a1f9bb6aSTetsuo Handa const unsigned int major = MAJOR(dev); 1423a1f9bb6aSTetsuo Handa const unsigned int minor = MINOR(dev); 1424a1f9bb6aSTetsuo Handa 142517fcfbd9STetsuo Handa do { 142617fcfbd9STetsuo Handa error = tomoyo_path_number3_acl(r, filename, 1 << operation, 142717fcfbd9STetsuo Handa mode, major, minor); 1428a1f9bb6aSTetsuo Handa if (!error) 142917fcfbd9STetsuo Handa break; 143017fcfbd9STetsuo Handa msg = tomoyo_path_number32keyword(operation); 143117fcfbd9STetsuo Handa tomoyo_warn_log(r, "%s %s 0%o %u %u", msg, filename->name, 143217fcfbd9STetsuo Handa mode, major, minor); 143317fcfbd9STetsuo Handa error = tomoyo_supervisor(r, "allow_%s %s 0%o %u %u\n", msg, 143417fcfbd9STetsuo Handa tomoyo_file_pattern(filename), mode, 143517fcfbd9STetsuo Handa major, minor); 143617fcfbd9STetsuo Handa } while (error == TOMOYO_RETRY_REQUEST); 1437a1f9bb6aSTetsuo Handa if (r->mode != TOMOYO_CONFIG_ENFORCING) 1438a1f9bb6aSTetsuo Handa error = 0; 1439a1f9bb6aSTetsuo Handa return error; 1440a1f9bb6aSTetsuo Handa } 1441a1f9bb6aSTetsuo Handa 1442a1f9bb6aSTetsuo Handa /** 1443a1f9bb6aSTetsuo Handa * tomoyo_path_number3_perm - Check permission for "mkblock" and "mkchar". 1444a1f9bb6aSTetsuo Handa * 1445a1f9bb6aSTetsuo Handa * @operation: Type of operation. (TOMOYO_TYPE_MKCHAR or TOMOYO_TYPE_MKBLOCK) 1446a1f9bb6aSTetsuo Handa * @path: Pointer to "struct path". 1447a1f9bb6aSTetsuo Handa * @mode: Create mode. 1448a1f9bb6aSTetsuo Handa * @dev: Device number. 1449a1f9bb6aSTetsuo Handa * 1450a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1451a1f9bb6aSTetsuo Handa */ 1452a1f9bb6aSTetsuo Handa int tomoyo_path_number3_perm(const u8 operation, struct path *path, 1453a1f9bb6aSTetsuo Handa const unsigned int mode, unsigned int dev) 1454a1f9bb6aSTetsuo Handa { 1455a1f9bb6aSTetsuo Handa struct tomoyo_request_info r; 1456a1f9bb6aSTetsuo Handa int error = -ENOMEM; 1457c8c57e84STetsuo Handa struct tomoyo_path_info buf; 1458a1f9bb6aSTetsuo Handa int idx; 1459a1f9bb6aSTetsuo Handa 1460a1f9bb6aSTetsuo Handa if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED || 1461a1f9bb6aSTetsuo Handa !path->mnt) 1462a1f9bb6aSTetsuo Handa return 0; 1463a1f9bb6aSTetsuo Handa idx = tomoyo_read_lock(); 1464a1f9bb6aSTetsuo Handa error = -ENOMEM; 1465c8c57e84STetsuo Handa if (tomoyo_get_realpath(&buf, path)) { 1466c8c57e84STetsuo Handa error = tomoyo_path_number3_perm2(&r, operation, &buf, mode, 1467a1f9bb6aSTetsuo Handa new_decode_dev(dev)); 1468c8c57e84STetsuo Handa kfree(buf.name); 1469a1f9bb6aSTetsuo Handa } 1470a1f9bb6aSTetsuo Handa tomoyo_read_unlock(idx); 1471a1f9bb6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 1472a1f9bb6aSTetsuo Handa error = 0; 1473a1f9bb6aSTetsuo Handa return error; 1474a1f9bb6aSTetsuo Handa } 1475a1f9bb6aSTetsuo Handa 1476a1f9bb6aSTetsuo Handa /** 14777ef61233STetsuo Handa * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root". 1478b69a54eeSKentaro Takeda * 1479b69a54eeSKentaro Takeda * @operation: Type of operation. 1480b69a54eeSKentaro Takeda * @path1: Pointer to "struct path". 1481b69a54eeSKentaro Takeda * @path2: Pointer to "struct path". 1482b69a54eeSKentaro Takeda * 1483b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1484b69a54eeSKentaro Takeda */ 148597d6931eSTetsuo Handa int tomoyo_path2_perm(const u8 operation, struct path *path1, 1486b69a54eeSKentaro Takeda struct path *path2) 1487b69a54eeSKentaro Takeda { 1488b69a54eeSKentaro Takeda int error = -ENOMEM; 148917fcfbd9STetsuo Handa const char *msg; 1490c8c57e84STetsuo Handa struct tomoyo_path_info buf1; 1491c8c57e84STetsuo Handa struct tomoyo_path_info buf2; 1492cb0abe6aSTetsuo Handa struct tomoyo_request_info r; 1493fdb8ebb7STetsuo Handa int idx; 1494b69a54eeSKentaro Takeda 1495cb0abe6aSTetsuo Handa if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED || 1496cb0abe6aSTetsuo Handa !path1->mnt || !path2->mnt) 1497b69a54eeSKentaro Takeda return 0; 1498c8c57e84STetsuo Handa buf1.name = NULL; 1499c8c57e84STetsuo Handa buf2.name = NULL; 1500fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 1501c8c57e84STetsuo Handa if (!tomoyo_get_realpath(&buf1, path1) || 1502c8c57e84STetsuo Handa !tomoyo_get_realpath(&buf2, path2)) 1503b69a54eeSKentaro Takeda goto out; 1504b69a54eeSKentaro Takeda { 1505b69a54eeSKentaro Takeda struct dentry *dentry = path1->dentry; 1506b69a54eeSKentaro Takeda if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) { 1507c8c57e84STetsuo Handa tomoyo_add_slash(&buf1); 1508c8c57e84STetsuo Handa tomoyo_add_slash(&buf2); 1509b69a54eeSKentaro Takeda } 1510b69a54eeSKentaro Takeda } 151117fcfbd9STetsuo Handa do { 1512c8c57e84STetsuo Handa error = tomoyo_path2_acl(&r, operation, &buf1, &buf2); 1513b69a54eeSKentaro Takeda if (!error) 151417fcfbd9STetsuo Handa break; 151517fcfbd9STetsuo Handa msg = tomoyo_path22keyword(operation); 1516c8c57e84STetsuo Handa tomoyo_warn_log(&r, "%s %s %s", msg, buf1.name, buf2.name); 151717fcfbd9STetsuo Handa error = tomoyo_supervisor(&r, "allow_%s %s %s\n", msg, 1518c8c57e84STetsuo Handa tomoyo_file_pattern(&buf1), 1519c8c57e84STetsuo Handa tomoyo_file_pattern(&buf2)); 152017fcfbd9STetsuo Handa } while (error == TOMOYO_RETRY_REQUEST); 1521b69a54eeSKentaro Takeda out: 1522c8c57e84STetsuo Handa kfree(buf1.name); 1523c8c57e84STetsuo Handa kfree(buf2.name); 1524fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 1525cb0abe6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 1526b69a54eeSKentaro Takeda error = 0; 1527b69a54eeSKentaro Takeda return error; 1528b69a54eeSKentaro Takeda } 1529a1f9bb6aSTetsuo Handa 1530a1f9bb6aSTetsuo Handa /** 1531a1f9bb6aSTetsuo Handa * tomoyo_write_file_policy - Update file related list. 1532a1f9bb6aSTetsuo Handa * 1533a1f9bb6aSTetsuo Handa * @data: String to parse. 1534a1f9bb6aSTetsuo Handa * @domain: Pointer to "struct tomoyo_domain_info". 1535a1f9bb6aSTetsuo Handa * @is_delete: True if it is a delete request. 1536a1f9bb6aSTetsuo Handa * 1537a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1538a1f9bb6aSTetsuo Handa * 1539a1f9bb6aSTetsuo Handa * Caller holds tomoyo_read_lock(). 1540a1f9bb6aSTetsuo Handa */ 1541a1f9bb6aSTetsuo Handa int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, 1542a1f9bb6aSTetsuo Handa const bool is_delete) 1543a1f9bb6aSTetsuo Handa { 1544a1f9bb6aSTetsuo Handa char *w[5]; 1545a1f9bb6aSTetsuo Handa u8 type; 1546a1f9bb6aSTetsuo Handa if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0]) 1547a1f9bb6aSTetsuo Handa return -EINVAL; 1548a1f9bb6aSTetsuo Handa if (strncmp(w[0], "allow_", 6)) { 1549a1f9bb6aSTetsuo Handa unsigned int perm; 1550a1f9bb6aSTetsuo Handa if (sscanf(w[0], "%u", &perm) == 1) 1551a1f9bb6aSTetsuo Handa return tomoyo_update_file_acl((u8) perm, w[1], domain, 1552a1f9bb6aSTetsuo Handa is_delete); 1553a1f9bb6aSTetsuo Handa goto out; 1554a1f9bb6aSTetsuo Handa } 1555a1f9bb6aSTetsuo Handa w[0] += 6; 1556a1f9bb6aSTetsuo Handa for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) { 1557a1f9bb6aSTetsuo Handa if (strcmp(w[0], tomoyo_path_keyword[type])) 1558a1f9bb6aSTetsuo Handa continue; 1559a1f9bb6aSTetsuo Handa return tomoyo_update_path_acl(type, w[1], domain, is_delete); 1560a1f9bb6aSTetsuo Handa } 1561a1f9bb6aSTetsuo Handa if (!w[2][0]) 1562a1f9bb6aSTetsuo Handa goto out; 1563a1f9bb6aSTetsuo Handa for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) { 1564a1f9bb6aSTetsuo Handa if (strcmp(w[0], tomoyo_path2_keyword[type])) 1565a1f9bb6aSTetsuo Handa continue; 1566a1f9bb6aSTetsuo Handa return tomoyo_update_path2_acl(type, w[1], w[2], domain, 1567a1f9bb6aSTetsuo Handa is_delete); 1568a1f9bb6aSTetsuo Handa } 1569a1f9bb6aSTetsuo Handa for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) { 1570a1f9bb6aSTetsuo Handa if (strcmp(w[0], tomoyo_path_number_keyword[type])) 1571a1f9bb6aSTetsuo Handa continue; 1572a1f9bb6aSTetsuo Handa return tomoyo_update_path_number_acl(type, w[1], w[2], domain, 1573a1f9bb6aSTetsuo Handa is_delete); 1574a1f9bb6aSTetsuo Handa } 1575a1f9bb6aSTetsuo Handa if (!w[3][0] || !w[4][0]) 1576a1f9bb6aSTetsuo Handa goto out; 1577a1f9bb6aSTetsuo Handa for (type = 0; type < TOMOYO_MAX_PATH_NUMBER3_OPERATION; type++) { 1578a1f9bb6aSTetsuo Handa if (strcmp(w[0], tomoyo_path_number3_keyword[type])) 1579a1f9bb6aSTetsuo Handa continue; 1580a1f9bb6aSTetsuo Handa return tomoyo_update_path_number3_acl(type, w[1], w[2], w[3], 1581a1f9bb6aSTetsuo Handa w[4], domain, is_delete); 1582a1f9bb6aSTetsuo Handa } 1583a1f9bb6aSTetsuo Handa out: 1584a1f9bb6aSTetsuo Handa return -EINVAL; 1585a1f9bb6aSTetsuo Handa } 1586