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 48b69a54eeSKentaro Takeda /** 497ef61233STetsuo Handa * tomoyo_path2keyword - Get the name of single path operation. 50b69a54eeSKentaro Takeda * 51b69a54eeSKentaro Takeda * @operation: Type of operation. 52b69a54eeSKentaro Takeda * 53b69a54eeSKentaro Takeda * Returns the name of single path operation. 54b69a54eeSKentaro Takeda */ 557ef61233STetsuo Handa const char *tomoyo_path2keyword(const u8 operation) 56b69a54eeSKentaro Takeda { 577ef61233STetsuo Handa return (operation < TOMOYO_MAX_PATH_OPERATION) 587ef61233STetsuo Handa ? tomoyo_path_keyword[operation] : NULL; 59b69a54eeSKentaro Takeda } 60b69a54eeSKentaro Takeda 61b69a54eeSKentaro Takeda /** 627ef61233STetsuo Handa * tomoyo_path22keyword - Get the name of double path operation. 63b69a54eeSKentaro Takeda * 64b69a54eeSKentaro Takeda * @operation: Type of operation. 65b69a54eeSKentaro Takeda * 66b69a54eeSKentaro Takeda * Returns the name of double path operation. 67b69a54eeSKentaro Takeda */ 687ef61233STetsuo Handa const char *tomoyo_path22keyword(const u8 operation) 69b69a54eeSKentaro Takeda { 707ef61233STetsuo Handa return (operation < TOMOYO_MAX_PATH2_OPERATION) 717ef61233STetsuo Handa ? tomoyo_path2_keyword[operation] : NULL; 72b69a54eeSKentaro Takeda } 73b69a54eeSKentaro Takeda 74b69a54eeSKentaro Takeda /** 75b69a54eeSKentaro Takeda * tomoyo_strendswith - Check whether the token ends with the given token. 76b69a54eeSKentaro Takeda * 77b69a54eeSKentaro Takeda * @name: The token to check. 78b69a54eeSKentaro Takeda * @tail: The token to find. 79b69a54eeSKentaro Takeda * 80b69a54eeSKentaro Takeda * Returns true if @name ends with @tail, false otherwise. 81b69a54eeSKentaro Takeda */ 82b69a54eeSKentaro Takeda static bool tomoyo_strendswith(const char *name, const char *tail) 83b69a54eeSKentaro Takeda { 84b69a54eeSKentaro Takeda int len; 85b69a54eeSKentaro Takeda 86b69a54eeSKentaro Takeda if (!name || !tail) 87b69a54eeSKentaro Takeda return false; 88b69a54eeSKentaro Takeda len = strlen(name) - strlen(tail); 89b69a54eeSKentaro Takeda return len >= 0 && !strcmp(name + len, tail); 90b69a54eeSKentaro Takeda } 91b69a54eeSKentaro Takeda 92b69a54eeSKentaro Takeda /** 93b69a54eeSKentaro Takeda * tomoyo_get_path - Get realpath. 94b69a54eeSKentaro Takeda * 95b69a54eeSKentaro Takeda * @path: Pointer to "struct path". 96b69a54eeSKentaro Takeda * 97b69a54eeSKentaro Takeda * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. 98b69a54eeSKentaro Takeda */ 99b69a54eeSKentaro Takeda static struct tomoyo_path_info *tomoyo_get_path(struct path *path) 100b69a54eeSKentaro Takeda { 101b69a54eeSKentaro Takeda int error; 1028e2d39a1STetsuo Handa struct tomoyo_path_info_with_data *buf = kzalloc(sizeof(*buf), 1034e5d6f7eSTetsuo Handa GFP_NOFS); 104b69a54eeSKentaro Takeda 105b69a54eeSKentaro Takeda if (!buf) 106b69a54eeSKentaro Takeda return NULL; 107b69a54eeSKentaro Takeda /* Reserve one byte for appending "/". */ 108b69a54eeSKentaro Takeda error = tomoyo_realpath_from_path2(path, buf->body, 109b69a54eeSKentaro Takeda sizeof(buf->body) - 2); 110b69a54eeSKentaro Takeda if (!error) { 111b69a54eeSKentaro Takeda buf->head.name = buf->body; 112b69a54eeSKentaro Takeda tomoyo_fill_path_info(&buf->head); 113b69a54eeSKentaro Takeda return &buf->head; 114b69a54eeSKentaro Takeda } 1158e2d39a1STetsuo Handa kfree(buf); 116b69a54eeSKentaro Takeda return NULL; 117b69a54eeSKentaro Takeda } 118b69a54eeSKentaro Takeda 1197ef61233STetsuo Handa static int tomoyo_update_path2_acl(const u8 type, const char *filename1, 120b69a54eeSKentaro Takeda const char *filename2, 1217ef61233STetsuo Handa struct tomoyo_domain_info *const domain, 1227ef61233STetsuo Handa const bool is_delete); 1237ef61233STetsuo Handa static int tomoyo_update_path_acl(const u8 type, const char *filename, 1247ef61233STetsuo Handa struct tomoyo_domain_info *const domain, 1257ef61233STetsuo Handa const bool is_delete); 126b69a54eeSKentaro Takeda 127c3fa109aSTetsuo Handa /* 128c3fa109aSTetsuo Handa * tomoyo_globally_readable_list is used for holding list of pathnames which 129c3fa109aSTetsuo Handa * are by default allowed to be open()ed for reading by any process. 130c3fa109aSTetsuo Handa * 131c3fa109aSTetsuo Handa * An entry is added by 132c3fa109aSTetsuo Handa * 133c3fa109aSTetsuo Handa * # echo 'allow_read /lib/libc-2.5.so' > \ 134c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 135c3fa109aSTetsuo Handa * 136c3fa109aSTetsuo Handa * and is deleted by 137c3fa109aSTetsuo Handa * 138c3fa109aSTetsuo Handa * # echo 'delete allow_read /lib/libc-2.5.so' > \ 139c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 140c3fa109aSTetsuo Handa * 141c3fa109aSTetsuo Handa * and all entries are retrieved by 142c3fa109aSTetsuo Handa * 143c3fa109aSTetsuo Handa * # grep ^allow_read /sys/kernel/security/tomoyo/exception_policy 144c3fa109aSTetsuo Handa * 145c3fa109aSTetsuo Handa * In the example above, any process is allowed to 146c3fa109aSTetsuo Handa * open("/lib/libc-2.5.so", O_RDONLY). 147c3fa109aSTetsuo Handa * One exception is, if the domain which current process belongs to is marked 148c3fa109aSTetsuo Handa * as "ignore_global_allow_read", current process can't do so unless explicitly 149c3fa109aSTetsuo Handa * given "allow_read /lib/libc-2.5.so" to the domain which current process 150c3fa109aSTetsuo Handa * belongs to. 151c3fa109aSTetsuo Handa */ 152847b173eSTetsuo Handa LIST_HEAD(tomoyo_globally_readable_list); 153b69a54eeSKentaro Takeda 154b69a54eeSKentaro Takeda /** 155b69a54eeSKentaro Takeda * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list. 156b69a54eeSKentaro Takeda * 157b69a54eeSKentaro Takeda * @filename: Filename unconditionally permitted to open() for reading. 158b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 159b69a54eeSKentaro Takeda * 160b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 161fdb8ebb7STetsuo Handa * 162fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 163b69a54eeSKentaro Takeda */ 164b69a54eeSKentaro Takeda static int tomoyo_update_globally_readable_entry(const char *filename, 165b69a54eeSKentaro Takeda const bool is_delete) 166b69a54eeSKentaro Takeda { 167ca0b7df3STetsuo Handa struct tomoyo_globally_readable_file_entry *entry = NULL; 168b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry *ptr; 169b69a54eeSKentaro Takeda const struct tomoyo_path_info *saved_filename; 170ca0b7df3STetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 171b69a54eeSKentaro Takeda 17217080008STetsuo Handa if (!tomoyo_is_correct_path(filename, 1, 0, -1)) 173b69a54eeSKentaro Takeda return -EINVAL; 174bf24fb01STetsuo Handa saved_filename = tomoyo_get_name(filename); 175b69a54eeSKentaro Takeda if (!saved_filename) 176b69a54eeSKentaro Takeda return -ENOMEM; 177ca0b7df3STetsuo Handa if (!is_delete) 1784e5d6f7eSTetsuo Handa entry = kmalloc(sizeof(*entry), GFP_NOFS); 17929282381STetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 18029282381STetsuo Handa goto out; 181fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) { 182b69a54eeSKentaro Takeda if (ptr->filename != saved_filename) 183b69a54eeSKentaro Takeda continue; 184b69a54eeSKentaro Takeda ptr->is_deleted = is_delete; 185b69a54eeSKentaro Takeda error = 0; 186ca0b7df3STetsuo Handa break; 187b69a54eeSKentaro Takeda } 188ca0b7df3STetsuo Handa if (!is_delete && error && tomoyo_memory_ok(entry)) { 189ca0b7df3STetsuo Handa entry->filename = saved_filename; 190bf24fb01STetsuo Handa saved_filename = NULL; 191ca0b7df3STetsuo Handa list_add_tail_rcu(&entry->list, &tomoyo_globally_readable_list); 192ca0b7df3STetsuo Handa entry = NULL; 193b69a54eeSKentaro Takeda error = 0; 194ca0b7df3STetsuo Handa } 195f737d95dSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 19629282381STetsuo Handa out: 197bf24fb01STetsuo Handa tomoyo_put_name(saved_filename); 198ca0b7df3STetsuo Handa kfree(entry); 199b69a54eeSKentaro Takeda return error; 200b69a54eeSKentaro Takeda } 201b69a54eeSKentaro Takeda 202b69a54eeSKentaro Takeda /** 203b69a54eeSKentaro Takeda * tomoyo_is_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading. 204b69a54eeSKentaro Takeda * 205b69a54eeSKentaro Takeda * @filename: The filename to check. 206b69a54eeSKentaro Takeda * 207b69a54eeSKentaro Takeda * Returns true if any domain can open @filename for reading, false otherwise. 208fdb8ebb7STetsuo Handa * 209fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 210b69a54eeSKentaro Takeda */ 211b69a54eeSKentaro Takeda static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info * 212b69a54eeSKentaro Takeda filename) 213b69a54eeSKentaro Takeda { 214b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry *ptr; 215b69a54eeSKentaro Takeda bool found = false; 216fdb8ebb7STetsuo Handa 217fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) { 218b69a54eeSKentaro Takeda if (!ptr->is_deleted && 219b69a54eeSKentaro Takeda tomoyo_path_matches_pattern(filename, ptr->filename)) { 220b69a54eeSKentaro Takeda found = true; 221b69a54eeSKentaro Takeda break; 222b69a54eeSKentaro Takeda } 223b69a54eeSKentaro Takeda } 224b69a54eeSKentaro Takeda return found; 225b69a54eeSKentaro Takeda } 226b69a54eeSKentaro Takeda 227b69a54eeSKentaro Takeda /** 228b69a54eeSKentaro Takeda * tomoyo_write_globally_readable_policy - Write "struct tomoyo_globally_readable_file_entry" list. 229b69a54eeSKentaro Takeda * 230b69a54eeSKentaro Takeda * @data: String to parse. 231b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 232b69a54eeSKentaro Takeda * 233b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 234fdb8ebb7STetsuo Handa * 235fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 236b69a54eeSKentaro Takeda */ 237b69a54eeSKentaro Takeda int tomoyo_write_globally_readable_policy(char *data, const bool is_delete) 238b69a54eeSKentaro Takeda { 239b69a54eeSKentaro Takeda return tomoyo_update_globally_readable_entry(data, is_delete); 240b69a54eeSKentaro Takeda } 241b69a54eeSKentaro Takeda 242b69a54eeSKentaro Takeda /** 243b69a54eeSKentaro Takeda * tomoyo_read_globally_readable_policy - Read "struct tomoyo_globally_readable_file_entry" list. 244b69a54eeSKentaro Takeda * 245b69a54eeSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 246b69a54eeSKentaro Takeda * 247b69a54eeSKentaro Takeda * Returns true on success, false otherwise. 248fdb8ebb7STetsuo Handa * 249fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 250b69a54eeSKentaro Takeda */ 251b69a54eeSKentaro Takeda bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) 252b69a54eeSKentaro Takeda { 253b69a54eeSKentaro Takeda struct list_head *pos; 254b69a54eeSKentaro Takeda bool done = true; 255b69a54eeSKentaro Takeda 256b69a54eeSKentaro Takeda list_for_each_cookie(pos, head->read_var2, 257b69a54eeSKentaro Takeda &tomoyo_globally_readable_list) { 258b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry *ptr; 259b69a54eeSKentaro Takeda ptr = list_entry(pos, 260b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry, 261b69a54eeSKentaro Takeda list); 262b69a54eeSKentaro Takeda if (ptr->is_deleted) 263b69a54eeSKentaro Takeda continue; 2647d2948b1STetsuo Handa done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n", 2657d2948b1STetsuo Handa ptr->filename->name); 2667d2948b1STetsuo Handa if (!done) 267b69a54eeSKentaro Takeda break; 268b69a54eeSKentaro Takeda } 269b69a54eeSKentaro Takeda return done; 270b69a54eeSKentaro Takeda } 271b69a54eeSKentaro Takeda 272c3fa109aSTetsuo Handa /* tomoyo_pattern_list is used for holding list of pathnames which are used for 273c3fa109aSTetsuo Handa * converting pathnames to pathname patterns during learning mode. 274c3fa109aSTetsuo Handa * 275c3fa109aSTetsuo Handa * An entry is added by 276c3fa109aSTetsuo Handa * 277c3fa109aSTetsuo Handa * # echo 'file_pattern /proc/\$/mounts' > \ 278c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 279c3fa109aSTetsuo Handa * 280c3fa109aSTetsuo Handa * and is deleted by 281c3fa109aSTetsuo Handa * 282c3fa109aSTetsuo Handa * # echo 'delete file_pattern /proc/\$/mounts' > \ 283c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 284c3fa109aSTetsuo Handa * 285c3fa109aSTetsuo Handa * and all entries are retrieved by 286c3fa109aSTetsuo Handa * 287c3fa109aSTetsuo Handa * # grep ^file_pattern /sys/kernel/security/tomoyo/exception_policy 288c3fa109aSTetsuo Handa * 289c3fa109aSTetsuo Handa * In the example above, if a process which belongs to a domain which is in 290c3fa109aSTetsuo Handa * learning mode requested open("/proc/1/mounts", O_RDONLY), 291c3fa109aSTetsuo Handa * "allow_read /proc/\$/mounts" is automatically added to the domain which that 292c3fa109aSTetsuo Handa * process belongs to. 293c3fa109aSTetsuo Handa * 294c3fa109aSTetsuo Handa * It is not a desirable behavior that we have to use /proc/\$/ instead of 295c3fa109aSTetsuo Handa * /proc/self/ when current process needs to access only current process's 296c3fa109aSTetsuo Handa * information. As of now, LSM version of TOMOYO is using __d_path() for 297c3fa109aSTetsuo Handa * calculating pathname. Non LSM version of TOMOYO is using its own function 298c3fa109aSTetsuo Handa * which pretends as if /proc/self/ is not a symlink; so that we can forbid 299c3fa109aSTetsuo Handa * current process from accessing other process's information. 300c3fa109aSTetsuo Handa */ 301847b173eSTetsuo Handa LIST_HEAD(tomoyo_pattern_list); 302b69a54eeSKentaro Takeda 303b69a54eeSKentaro Takeda /** 304b69a54eeSKentaro Takeda * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list. 305b69a54eeSKentaro Takeda * 306b69a54eeSKentaro Takeda * @pattern: Pathname pattern. 307b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 308b69a54eeSKentaro Takeda * 309b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 310fdb8ebb7STetsuo Handa * 311fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 312b69a54eeSKentaro Takeda */ 313b69a54eeSKentaro Takeda static int tomoyo_update_file_pattern_entry(const char *pattern, 314b69a54eeSKentaro Takeda const bool is_delete) 315b69a54eeSKentaro Takeda { 316ca0b7df3STetsuo Handa struct tomoyo_pattern_entry *entry = NULL; 317b69a54eeSKentaro Takeda struct tomoyo_pattern_entry *ptr; 318b69a54eeSKentaro Takeda const struct tomoyo_path_info *saved_pattern; 319ca0b7df3STetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 320b69a54eeSKentaro Takeda 321bf24fb01STetsuo Handa saved_pattern = tomoyo_get_name(pattern); 322b69a54eeSKentaro Takeda if (!saved_pattern) 323ca0b7df3STetsuo Handa return error; 324ca0b7df3STetsuo Handa if (!saved_pattern->is_patterned) 325ca0b7df3STetsuo Handa goto out; 326ca0b7df3STetsuo Handa if (!is_delete) 3274e5d6f7eSTetsuo Handa entry = kmalloc(sizeof(*entry), GFP_NOFS); 32829282381STetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 32929282381STetsuo Handa goto out; 330fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { 331b69a54eeSKentaro Takeda if (saved_pattern != ptr->pattern) 332b69a54eeSKentaro Takeda continue; 333b69a54eeSKentaro Takeda ptr->is_deleted = is_delete; 334b69a54eeSKentaro Takeda error = 0; 335ca0b7df3STetsuo Handa break; 336b69a54eeSKentaro Takeda } 337ca0b7df3STetsuo Handa if (!is_delete && error && tomoyo_memory_ok(entry)) { 338ca0b7df3STetsuo Handa entry->pattern = saved_pattern; 339bf24fb01STetsuo Handa saved_pattern = NULL; 340ca0b7df3STetsuo Handa list_add_tail_rcu(&entry->list, &tomoyo_pattern_list); 341ca0b7df3STetsuo Handa entry = NULL; 342b69a54eeSKentaro Takeda error = 0; 343ca0b7df3STetsuo Handa } 344f737d95dSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 345ca0b7df3STetsuo Handa out: 346ca0b7df3STetsuo Handa kfree(entry); 347bf24fb01STetsuo Handa tomoyo_put_name(saved_pattern); 348b69a54eeSKentaro Takeda return error; 349b69a54eeSKentaro Takeda } 350b69a54eeSKentaro Takeda 351b69a54eeSKentaro Takeda /** 352b69a54eeSKentaro Takeda * tomoyo_get_file_pattern - Get patterned pathname. 353b69a54eeSKentaro Takeda * 354b69a54eeSKentaro Takeda * @filename: The filename to find patterned pathname. 355b69a54eeSKentaro Takeda * 356b69a54eeSKentaro Takeda * Returns pointer to pathname pattern if matched, @filename otherwise. 357fdb8ebb7STetsuo Handa * 358fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 359b69a54eeSKentaro Takeda */ 360b69a54eeSKentaro Takeda static const struct tomoyo_path_info * 361b69a54eeSKentaro Takeda tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) 362b69a54eeSKentaro Takeda { 363b69a54eeSKentaro Takeda struct tomoyo_pattern_entry *ptr; 364b69a54eeSKentaro Takeda const struct tomoyo_path_info *pattern = NULL; 365b69a54eeSKentaro Takeda 366fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { 367b69a54eeSKentaro Takeda if (ptr->is_deleted) 368b69a54eeSKentaro Takeda continue; 369b69a54eeSKentaro Takeda if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) 370b69a54eeSKentaro Takeda continue; 371b69a54eeSKentaro Takeda pattern = ptr->pattern; 372b69a54eeSKentaro Takeda if (tomoyo_strendswith(pattern->name, "/\\*")) { 373b69a54eeSKentaro Takeda /* Do nothing. Try to find the better match. */ 374b69a54eeSKentaro Takeda } else { 375b69a54eeSKentaro Takeda /* This would be the better match. Use this. */ 376b69a54eeSKentaro Takeda break; 377b69a54eeSKentaro Takeda } 378b69a54eeSKentaro Takeda } 379b69a54eeSKentaro Takeda if (pattern) 380b69a54eeSKentaro Takeda filename = pattern; 381b69a54eeSKentaro Takeda return filename; 382b69a54eeSKentaro Takeda } 383b69a54eeSKentaro Takeda 384b69a54eeSKentaro Takeda /** 385b69a54eeSKentaro Takeda * tomoyo_write_pattern_policy - Write "struct tomoyo_pattern_entry" list. 386b69a54eeSKentaro Takeda * 387b69a54eeSKentaro Takeda * @data: String to parse. 388b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 389b69a54eeSKentaro Takeda * 390b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 391fdb8ebb7STetsuo Handa * 392fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 393b69a54eeSKentaro Takeda */ 394b69a54eeSKentaro Takeda int tomoyo_write_pattern_policy(char *data, const bool is_delete) 395b69a54eeSKentaro Takeda { 396b69a54eeSKentaro Takeda return tomoyo_update_file_pattern_entry(data, is_delete); 397b69a54eeSKentaro Takeda } 398b69a54eeSKentaro Takeda 399b69a54eeSKentaro Takeda /** 400b69a54eeSKentaro Takeda * tomoyo_read_file_pattern - Read "struct tomoyo_pattern_entry" list. 401b69a54eeSKentaro Takeda * 402b69a54eeSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 403b69a54eeSKentaro Takeda * 404b69a54eeSKentaro Takeda * Returns true on success, false otherwise. 405fdb8ebb7STetsuo Handa * 406fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 407b69a54eeSKentaro Takeda */ 408b69a54eeSKentaro Takeda bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) 409b69a54eeSKentaro Takeda { 410b69a54eeSKentaro Takeda struct list_head *pos; 411b69a54eeSKentaro Takeda bool done = true; 412b69a54eeSKentaro Takeda 413b69a54eeSKentaro Takeda list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) { 414b69a54eeSKentaro Takeda struct tomoyo_pattern_entry *ptr; 415b69a54eeSKentaro Takeda ptr = list_entry(pos, struct tomoyo_pattern_entry, list); 416b69a54eeSKentaro Takeda if (ptr->is_deleted) 417b69a54eeSKentaro Takeda continue; 4187d2948b1STetsuo Handa done = tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN 4197d2948b1STetsuo Handa "%s\n", ptr->pattern->name); 4207d2948b1STetsuo Handa if (!done) 421b69a54eeSKentaro Takeda break; 422b69a54eeSKentaro Takeda } 423b69a54eeSKentaro Takeda return done; 424b69a54eeSKentaro Takeda } 425b69a54eeSKentaro Takeda 426c3fa109aSTetsuo Handa /* 427c3fa109aSTetsuo Handa * tomoyo_no_rewrite_list is used for holding list of pathnames which are by 428c3fa109aSTetsuo Handa * default forbidden to modify already written content of a file. 429c3fa109aSTetsuo Handa * 430c3fa109aSTetsuo Handa * An entry is added by 431c3fa109aSTetsuo Handa * 432c3fa109aSTetsuo Handa * # echo 'deny_rewrite /var/log/messages' > \ 433c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 434c3fa109aSTetsuo Handa * 435c3fa109aSTetsuo Handa * and is deleted by 436c3fa109aSTetsuo Handa * 437c3fa109aSTetsuo Handa * # echo 'delete deny_rewrite /var/log/messages' > \ 438c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 439c3fa109aSTetsuo Handa * 440c3fa109aSTetsuo Handa * and all entries are retrieved by 441c3fa109aSTetsuo Handa * 442c3fa109aSTetsuo Handa * # grep ^deny_rewrite /sys/kernel/security/tomoyo/exception_policy 443c3fa109aSTetsuo Handa * 444c3fa109aSTetsuo Handa * In the example above, if a process requested to rewrite /var/log/messages , 445c3fa109aSTetsuo Handa * the process can't rewrite unless the domain which that process belongs to 446c3fa109aSTetsuo Handa * has "allow_rewrite /var/log/messages" entry. 447c3fa109aSTetsuo Handa * 448c3fa109aSTetsuo Handa * It is not a desirable behavior that we have to add "\040(deleted)" suffix 449c3fa109aSTetsuo Handa * when we want to allow rewriting already unlink()ed file. As of now, 450c3fa109aSTetsuo Handa * LSM version of TOMOYO is using __d_path() for calculating pathname. 451c3fa109aSTetsuo Handa * Non LSM version of TOMOYO is using its own function which doesn't append 452c3fa109aSTetsuo Handa * " (deleted)" suffix if the file is already unlink()ed; so that we don't 453c3fa109aSTetsuo Handa * need to worry whether the file is already unlink()ed or not. 454c3fa109aSTetsuo Handa */ 455847b173eSTetsuo Handa LIST_HEAD(tomoyo_no_rewrite_list); 456b69a54eeSKentaro Takeda 457b69a54eeSKentaro Takeda /** 458b69a54eeSKentaro Takeda * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list. 459b69a54eeSKentaro Takeda * 460b69a54eeSKentaro Takeda * @pattern: Pathname pattern that are not rewritable by default. 461b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 462b69a54eeSKentaro Takeda * 463b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 464fdb8ebb7STetsuo Handa * 465fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 466b69a54eeSKentaro Takeda */ 467b69a54eeSKentaro Takeda static int tomoyo_update_no_rewrite_entry(const char *pattern, 468b69a54eeSKentaro Takeda const bool is_delete) 469b69a54eeSKentaro Takeda { 470ca0b7df3STetsuo Handa struct tomoyo_no_rewrite_entry *entry = NULL; 471ca0b7df3STetsuo Handa struct tomoyo_no_rewrite_entry *ptr; 472b69a54eeSKentaro Takeda const struct tomoyo_path_info *saved_pattern; 473ca0b7df3STetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 474b69a54eeSKentaro Takeda 47517080008STetsuo Handa if (!tomoyo_is_correct_path(pattern, 0, 0, 0)) 476b69a54eeSKentaro Takeda return -EINVAL; 477bf24fb01STetsuo Handa saved_pattern = tomoyo_get_name(pattern); 478b69a54eeSKentaro Takeda if (!saved_pattern) 479ca0b7df3STetsuo Handa return error; 480ca0b7df3STetsuo Handa if (!is_delete) 4814e5d6f7eSTetsuo Handa entry = kmalloc(sizeof(*entry), GFP_NOFS); 48229282381STetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 48329282381STetsuo Handa goto out; 484fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { 485b69a54eeSKentaro Takeda if (ptr->pattern != saved_pattern) 486b69a54eeSKentaro Takeda continue; 487b69a54eeSKentaro Takeda ptr->is_deleted = is_delete; 488b69a54eeSKentaro Takeda error = 0; 489ca0b7df3STetsuo Handa break; 490b69a54eeSKentaro Takeda } 491ca0b7df3STetsuo Handa if (!is_delete && error && tomoyo_memory_ok(entry)) { 492ca0b7df3STetsuo Handa entry->pattern = saved_pattern; 493bf24fb01STetsuo Handa saved_pattern = NULL; 494ca0b7df3STetsuo Handa list_add_tail_rcu(&entry->list, &tomoyo_no_rewrite_list); 495ca0b7df3STetsuo Handa entry = NULL; 496b69a54eeSKentaro Takeda error = 0; 497ca0b7df3STetsuo Handa } 498f737d95dSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 49929282381STetsuo Handa out: 500bf24fb01STetsuo Handa tomoyo_put_name(saved_pattern); 501ca0b7df3STetsuo Handa kfree(entry); 502b69a54eeSKentaro Takeda return error; 503b69a54eeSKentaro Takeda } 504b69a54eeSKentaro Takeda 505b69a54eeSKentaro Takeda /** 506b69a54eeSKentaro Takeda * tomoyo_is_no_rewrite_file - Check if the given pathname is not permitted to be rewrited. 507b69a54eeSKentaro Takeda * 508b69a54eeSKentaro Takeda * @filename: Filename to check. 509b69a54eeSKentaro Takeda * 510b69a54eeSKentaro Takeda * Returns true if @filename is specified by "deny_rewrite" directive, 511b69a54eeSKentaro Takeda * false otherwise. 512fdb8ebb7STetsuo Handa * 513fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 514b69a54eeSKentaro Takeda */ 515b69a54eeSKentaro Takeda static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) 516b69a54eeSKentaro Takeda { 517b69a54eeSKentaro Takeda struct tomoyo_no_rewrite_entry *ptr; 518b69a54eeSKentaro Takeda bool found = false; 519b69a54eeSKentaro Takeda 520fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { 521b69a54eeSKentaro Takeda if (ptr->is_deleted) 522b69a54eeSKentaro Takeda continue; 523b69a54eeSKentaro Takeda if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) 524b69a54eeSKentaro Takeda continue; 525b69a54eeSKentaro Takeda found = true; 526b69a54eeSKentaro Takeda break; 527b69a54eeSKentaro Takeda } 528b69a54eeSKentaro Takeda return found; 529b69a54eeSKentaro Takeda } 530b69a54eeSKentaro Takeda 531b69a54eeSKentaro Takeda /** 532b69a54eeSKentaro Takeda * tomoyo_write_no_rewrite_policy - Write "struct tomoyo_no_rewrite_entry" list. 533b69a54eeSKentaro Takeda * 534b69a54eeSKentaro Takeda * @data: String to parse. 535b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 536b69a54eeSKentaro Takeda * 537b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 538fdb8ebb7STetsuo Handa * 539fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 540b69a54eeSKentaro Takeda */ 541b69a54eeSKentaro Takeda int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete) 542b69a54eeSKentaro Takeda { 543b69a54eeSKentaro Takeda return tomoyo_update_no_rewrite_entry(data, is_delete); 544b69a54eeSKentaro Takeda } 545b69a54eeSKentaro Takeda 546b69a54eeSKentaro Takeda /** 547b69a54eeSKentaro Takeda * tomoyo_read_no_rewrite_policy - Read "struct tomoyo_no_rewrite_entry" list. 548b69a54eeSKentaro Takeda * 549b69a54eeSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 550b69a54eeSKentaro Takeda * 551b69a54eeSKentaro Takeda * Returns true on success, false otherwise. 552fdb8ebb7STetsuo Handa * 553fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 554b69a54eeSKentaro Takeda */ 555b69a54eeSKentaro Takeda bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) 556b69a54eeSKentaro Takeda { 557b69a54eeSKentaro Takeda struct list_head *pos; 558b69a54eeSKentaro Takeda bool done = true; 559b69a54eeSKentaro Takeda 560b69a54eeSKentaro Takeda list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) { 561b69a54eeSKentaro Takeda struct tomoyo_no_rewrite_entry *ptr; 562b69a54eeSKentaro Takeda ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list); 563b69a54eeSKentaro Takeda if (ptr->is_deleted) 564b69a54eeSKentaro Takeda continue; 5657d2948b1STetsuo Handa done = tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE 5667d2948b1STetsuo Handa "%s\n", ptr->pattern->name); 5677d2948b1STetsuo Handa if (!done) 568b69a54eeSKentaro Takeda break; 569b69a54eeSKentaro Takeda } 570b69a54eeSKentaro Takeda return done; 571b69a54eeSKentaro Takeda } 572b69a54eeSKentaro Takeda 573b69a54eeSKentaro Takeda /** 574b69a54eeSKentaro Takeda * tomoyo_update_file_acl - Update file's read/write/execute ACL. 575b69a54eeSKentaro Takeda * 576b69a54eeSKentaro Takeda * @filename: Filename. 577b69a54eeSKentaro Takeda * @perm: Permission (between 1 to 7). 578b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 579b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 580b69a54eeSKentaro Takeda * 581b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 582b69a54eeSKentaro Takeda * 583b69a54eeSKentaro Takeda * This is legacy support interface for older policy syntax. 584b69a54eeSKentaro Takeda * Current policy syntax uses "allow_read/write" instead of "6", 585b69a54eeSKentaro Takeda * "allow_read" instead of "4", "allow_write" instead of "2", 586b69a54eeSKentaro Takeda * "allow_execute" instead of "1". 587fdb8ebb7STetsuo Handa * 588fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 589b69a54eeSKentaro Takeda */ 590b69a54eeSKentaro Takeda static int tomoyo_update_file_acl(const char *filename, u8 perm, 591b69a54eeSKentaro Takeda struct tomoyo_domain_info * const domain, 592b69a54eeSKentaro Takeda const bool is_delete) 593b69a54eeSKentaro Takeda { 594b69a54eeSKentaro Takeda if (perm > 7 || !perm) { 595b69a54eeSKentaro Takeda printk(KERN_DEBUG "%s: Invalid permission '%d %s'\n", 596b69a54eeSKentaro Takeda __func__, perm, filename); 597b69a54eeSKentaro Takeda return -EINVAL; 598b69a54eeSKentaro Takeda } 599b69a54eeSKentaro Takeda if (filename[0] != '@' && tomoyo_strendswith(filename, "/")) 600b69a54eeSKentaro Takeda /* 601b69a54eeSKentaro Takeda * Only 'allow_mkdir' and 'allow_rmdir' are valid for 602b69a54eeSKentaro Takeda * directory permissions. 603b69a54eeSKentaro Takeda */ 604b69a54eeSKentaro Takeda return 0; 605b69a54eeSKentaro Takeda if (perm & 4) 6067ef61233STetsuo Handa tomoyo_update_path_acl(TOMOYO_TYPE_READ, filename, domain, 6077ef61233STetsuo Handa is_delete); 608b69a54eeSKentaro Takeda if (perm & 2) 6097ef61233STetsuo Handa tomoyo_update_path_acl(TOMOYO_TYPE_WRITE, filename, domain, 6107ef61233STetsuo Handa is_delete); 611b69a54eeSKentaro Takeda if (perm & 1) 6127ef61233STetsuo Handa tomoyo_update_path_acl(TOMOYO_TYPE_EXECUTE, filename, domain, 6137ef61233STetsuo Handa is_delete); 614b69a54eeSKentaro Takeda return 0; 615b69a54eeSKentaro Takeda } 616b69a54eeSKentaro Takeda 617b69a54eeSKentaro Takeda /** 6187ef61233STetsuo Handa * tomoyo_path_acl2 - Check permission for single path operation. 619b69a54eeSKentaro Takeda * 620b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 621b69a54eeSKentaro Takeda * @filename: Filename to check. 622b69a54eeSKentaro Takeda * @perm: Permission. 623b69a54eeSKentaro Takeda * @may_use_pattern: True if patterned ACL is permitted. 624b69a54eeSKentaro Takeda * 625b69a54eeSKentaro Takeda * Returns 0 on success, -EPERM otherwise. 626fdb8ebb7STetsuo Handa * 627fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 628b69a54eeSKentaro Takeda */ 6297ef61233STetsuo Handa static int tomoyo_path_acl2(const struct tomoyo_domain_info *domain, 6307ef61233STetsuo Handa const struct tomoyo_path_info *filename, 6317ef61233STetsuo Handa const u32 perm, const bool may_use_pattern) 632b69a54eeSKentaro Takeda { 633b69a54eeSKentaro Takeda struct tomoyo_acl_info *ptr; 634b69a54eeSKentaro Takeda int error = -EPERM; 635b69a54eeSKentaro Takeda 636fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 6377ef61233STetsuo Handa struct tomoyo_path_acl *acl; 6387ef61233STetsuo Handa if (ptr->type != TOMOYO_TYPE_PATH_ACL) 639b69a54eeSKentaro Takeda continue; 6407ef61233STetsuo Handa acl = container_of(ptr, struct tomoyo_path_acl, head); 641937bf613STetsuo Handa if (perm <= 0xFFFF) { 642b69a54eeSKentaro Takeda if (!(acl->perm & perm)) 643b69a54eeSKentaro Takeda continue; 644937bf613STetsuo Handa } else { 645937bf613STetsuo Handa if (!(acl->perm_high & (perm >> 16))) 646937bf613STetsuo Handa continue; 647937bf613STetsuo Handa } 648b69a54eeSKentaro Takeda if (may_use_pattern || !acl->filename->is_patterned) { 649b69a54eeSKentaro Takeda if (!tomoyo_path_matches_pattern(filename, 650b69a54eeSKentaro Takeda acl->filename)) 651b69a54eeSKentaro Takeda continue; 652b69a54eeSKentaro Takeda } else { 653b69a54eeSKentaro Takeda continue; 654b69a54eeSKentaro Takeda } 655b69a54eeSKentaro Takeda error = 0; 656b69a54eeSKentaro Takeda break; 657b69a54eeSKentaro Takeda } 658b69a54eeSKentaro Takeda return error; 659b69a54eeSKentaro Takeda } 660b69a54eeSKentaro Takeda 661b69a54eeSKentaro Takeda /** 662b69a54eeSKentaro Takeda * tomoyo_check_file_acl - Check permission for opening files. 663b69a54eeSKentaro Takeda * 664b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 665b69a54eeSKentaro Takeda * @filename: Filename to check. 666b69a54eeSKentaro Takeda * @operation: Mode ("read" or "write" or "read/write" or "execute"). 667b69a54eeSKentaro Takeda * 668b69a54eeSKentaro Takeda * Returns 0 on success, -EPERM otherwise. 669fdb8ebb7STetsuo Handa * 670fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 671b69a54eeSKentaro Takeda */ 672b69a54eeSKentaro Takeda static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain, 673b69a54eeSKentaro Takeda const struct tomoyo_path_info *filename, 674b69a54eeSKentaro Takeda const u8 operation) 675b69a54eeSKentaro Takeda { 676937bf613STetsuo Handa u32 perm = 0; 677b69a54eeSKentaro Takeda 678b69a54eeSKentaro Takeda if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) 679b69a54eeSKentaro Takeda return 0; 680b69a54eeSKentaro Takeda if (operation == 6) 6817ef61233STetsuo Handa perm = 1 << TOMOYO_TYPE_READ_WRITE; 682b69a54eeSKentaro Takeda else if (operation == 4) 6837ef61233STetsuo Handa perm = 1 << TOMOYO_TYPE_READ; 684b69a54eeSKentaro Takeda else if (operation == 2) 6857ef61233STetsuo Handa perm = 1 << TOMOYO_TYPE_WRITE; 686b69a54eeSKentaro Takeda else if (operation == 1) 6877ef61233STetsuo Handa perm = 1 << TOMOYO_TYPE_EXECUTE; 688b69a54eeSKentaro Takeda else 689b69a54eeSKentaro Takeda BUG(); 6907ef61233STetsuo Handa return tomoyo_path_acl2(domain, filename, perm, operation != 1); 691b69a54eeSKentaro Takeda } 692b69a54eeSKentaro Takeda 693b69a54eeSKentaro Takeda /** 694b69a54eeSKentaro Takeda * tomoyo_check_file_perm2 - Check permission for opening files. 695b69a54eeSKentaro Takeda * 696b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 697b69a54eeSKentaro Takeda * @filename: Filename to check. 698b69a54eeSKentaro Takeda * @perm: Mode ("read" or "write" or "read/write" or "execute"). 699b69a54eeSKentaro Takeda * @operation: Operation name passed used for verbose mode. 700b69a54eeSKentaro Takeda * @mode: Access control mode. 701b69a54eeSKentaro Takeda * 702b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 703fdb8ebb7STetsuo Handa * 704fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 705b69a54eeSKentaro Takeda */ 706b69a54eeSKentaro Takeda static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain, 707b69a54eeSKentaro Takeda const struct tomoyo_path_info *filename, 708b69a54eeSKentaro Takeda const u8 perm, const char *operation, 709b69a54eeSKentaro Takeda const u8 mode) 710b69a54eeSKentaro Takeda { 711b69a54eeSKentaro Takeda const bool is_enforce = (mode == 3); 712b69a54eeSKentaro Takeda const char *msg = "<unknown>"; 713b69a54eeSKentaro Takeda int error = 0; 714b69a54eeSKentaro Takeda 715b69a54eeSKentaro Takeda if (!filename) 716b69a54eeSKentaro Takeda return 0; 717b69a54eeSKentaro Takeda error = tomoyo_check_file_acl(domain, filename, perm); 718ea13ddbaSTetsuo Handa if (error && perm == 4 && !domain->ignore_global_allow_read 719b69a54eeSKentaro Takeda && tomoyo_is_globally_readable_file(filename)) 720b69a54eeSKentaro Takeda error = 0; 721b69a54eeSKentaro Takeda if (perm == 6) 7227ef61233STetsuo Handa msg = tomoyo_path2keyword(TOMOYO_TYPE_READ_WRITE); 723b69a54eeSKentaro Takeda else if (perm == 4) 7247ef61233STetsuo Handa msg = tomoyo_path2keyword(TOMOYO_TYPE_READ); 725b69a54eeSKentaro Takeda else if (perm == 2) 7267ef61233STetsuo Handa msg = tomoyo_path2keyword(TOMOYO_TYPE_WRITE); 727b69a54eeSKentaro Takeda else if (perm == 1) 7287ef61233STetsuo Handa msg = tomoyo_path2keyword(TOMOYO_TYPE_EXECUTE); 729b69a54eeSKentaro Takeda else 730b69a54eeSKentaro Takeda BUG(); 731b69a54eeSKentaro Takeda if (!error) 732b69a54eeSKentaro Takeda return 0; 733b69a54eeSKentaro Takeda if (tomoyo_verbose_mode(domain)) 734b69a54eeSKentaro Takeda printk(KERN_WARNING "TOMOYO-%s: Access '%s(%s) %s' denied " 735b69a54eeSKentaro Takeda "for %s\n", tomoyo_get_msg(is_enforce), msg, operation, 736b69a54eeSKentaro Takeda filename->name, tomoyo_get_last_name(domain)); 737b69a54eeSKentaro Takeda if (is_enforce) 738b69a54eeSKentaro Takeda return error; 739b69a54eeSKentaro Takeda if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { 740b69a54eeSKentaro Takeda /* Don't use patterns for execute permission. */ 741b69a54eeSKentaro Takeda const struct tomoyo_path_info *patterned_file = (perm != 1) ? 742b69a54eeSKentaro Takeda tomoyo_get_file_pattern(filename) : filename; 743b69a54eeSKentaro Takeda tomoyo_update_file_acl(patterned_file->name, perm, 744b69a54eeSKentaro Takeda domain, false); 745b69a54eeSKentaro Takeda } 746b69a54eeSKentaro Takeda return 0; 747b69a54eeSKentaro Takeda } 748b69a54eeSKentaro Takeda 749b69a54eeSKentaro Takeda /** 750b69a54eeSKentaro Takeda * tomoyo_write_file_policy - Update file related list. 751b69a54eeSKentaro Takeda * 752b69a54eeSKentaro Takeda * @data: String to parse. 753b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 754b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 755b69a54eeSKentaro Takeda * 756b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 757fdb8ebb7STetsuo Handa * 758fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 759b69a54eeSKentaro Takeda */ 760b69a54eeSKentaro Takeda int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, 761b69a54eeSKentaro Takeda const bool is_delete) 762b69a54eeSKentaro Takeda { 763b69a54eeSKentaro Takeda char *filename = strchr(data, ' '); 764b69a54eeSKentaro Takeda char *filename2; 765b69a54eeSKentaro Takeda unsigned int perm; 766b69a54eeSKentaro Takeda u8 type; 767b69a54eeSKentaro Takeda 768b69a54eeSKentaro Takeda if (!filename) 769b69a54eeSKentaro Takeda return -EINVAL; 770b69a54eeSKentaro Takeda *filename++ = '\0'; 771b69a54eeSKentaro Takeda if (sscanf(data, "%u", &perm) == 1) 772b69a54eeSKentaro Takeda return tomoyo_update_file_acl(filename, (u8) perm, domain, 773b69a54eeSKentaro Takeda is_delete); 774b69a54eeSKentaro Takeda if (strncmp(data, "allow_", 6)) 775b69a54eeSKentaro Takeda goto out; 776b69a54eeSKentaro Takeda data += 6; 7777ef61233STetsuo Handa for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) { 7787ef61233STetsuo Handa if (strcmp(data, tomoyo_path_keyword[type])) 779b69a54eeSKentaro Takeda continue; 7807ef61233STetsuo Handa return tomoyo_update_path_acl(type, filename, domain, 7817ef61233STetsuo Handa is_delete); 782b69a54eeSKentaro Takeda } 783b69a54eeSKentaro Takeda filename2 = strchr(filename, ' '); 784b69a54eeSKentaro Takeda if (!filename2) 785b69a54eeSKentaro Takeda goto out; 786b69a54eeSKentaro Takeda *filename2++ = '\0'; 7877ef61233STetsuo Handa for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) { 7887ef61233STetsuo Handa if (strcmp(data, tomoyo_path2_keyword[type])) 789b69a54eeSKentaro Takeda continue; 7907ef61233STetsuo Handa return tomoyo_update_path2_acl(type, filename, filename2, 791b69a54eeSKentaro Takeda domain, is_delete); 792b69a54eeSKentaro Takeda } 793b69a54eeSKentaro Takeda out: 794b69a54eeSKentaro Takeda return -EINVAL; 795b69a54eeSKentaro Takeda } 796b69a54eeSKentaro Takeda 797b69a54eeSKentaro Takeda /** 7987ef61233STetsuo Handa * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list. 799b69a54eeSKentaro Takeda * 800b69a54eeSKentaro Takeda * @type: Type of operation. 801b69a54eeSKentaro Takeda * @filename: Filename. 802b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 803b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 804b69a54eeSKentaro Takeda * 805b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 806fdb8ebb7STetsuo Handa * 807fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 808b69a54eeSKentaro Takeda */ 8097ef61233STetsuo Handa static int tomoyo_update_path_acl(const u8 type, const char *filename, 8107ef61233STetsuo Handa struct tomoyo_domain_info *const domain, 8117ef61233STetsuo Handa const bool is_delete) 812b69a54eeSKentaro Takeda { 813937bf613STetsuo Handa static const u32 rw_mask = 8147ef61233STetsuo Handa (1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE); 815b69a54eeSKentaro Takeda const struct tomoyo_path_info *saved_filename; 816b69a54eeSKentaro Takeda struct tomoyo_acl_info *ptr; 8177ef61233STetsuo Handa struct tomoyo_path_acl *entry = NULL; 818ca0b7df3STetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 819937bf613STetsuo Handa const u32 perm = 1 << type; 820b69a54eeSKentaro Takeda 821b69a54eeSKentaro Takeda if (!domain) 822b69a54eeSKentaro Takeda return -EINVAL; 82317080008STetsuo Handa if (!tomoyo_is_correct_path(filename, 0, 0, 0)) 824b69a54eeSKentaro Takeda return -EINVAL; 825bf24fb01STetsuo Handa saved_filename = tomoyo_get_name(filename); 826b69a54eeSKentaro Takeda if (!saved_filename) 827b69a54eeSKentaro Takeda return -ENOMEM; 828ca0b7df3STetsuo Handa if (!is_delete) 8294e5d6f7eSTetsuo Handa entry = kmalloc(sizeof(*entry), GFP_NOFS); 83029282381STetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 83129282381STetsuo Handa goto out; 832fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 8337ef61233STetsuo Handa struct tomoyo_path_acl *acl = 8347ef61233STetsuo Handa container_of(ptr, struct tomoyo_path_acl, head); 8357ef61233STetsuo Handa if (ptr->type != TOMOYO_TYPE_PATH_ACL) 836b69a54eeSKentaro Takeda continue; 837b69a54eeSKentaro Takeda if (acl->filename != saved_filename) 838b69a54eeSKentaro Takeda continue; 839ca0b7df3STetsuo Handa if (is_delete) { 840ca0b7df3STetsuo Handa if (perm <= 0xFFFF) 841ca0b7df3STetsuo Handa acl->perm &= ~perm; 842ca0b7df3STetsuo Handa else 843ca0b7df3STetsuo Handa acl->perm_high &= ~(perm >> 16); 844ca0b7df3STetsuo Handa if ((acl->perm & rw_mask) != rw_mask) 8457ef61233STetsuo Handa acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE); 8467ef61233STetsuo Handa else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE))) 847ca0b7df3STetsuo Handa acl->perm &= ~rw_mask; 848ca0b7df3STetsuo Handa } else { 849937bf613STetsuo Handa if (perm <= 0xFFFF) 850b69a54eeSKentaro Takeda acl->perm |= perm; 851937bf613STetsuo Handa else 852937bf613STetsuo Handa acl->perm_high |= (perm >> 16); 853b69a54eeSKentaro Takeda if ((acl->perm & rw_mask) == rw_mask) 8547ef61233STetsuo Handa acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE; 8557ef61233STetsuo Handa else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE)) 856b69a54eeSKentaro Takeda acl->perm |= rw_mask; 857b69a54eeSKentaro Takeda } 858b69a54eeSKentaro Takeda error = 0; 859b69a54eeSKentaro Takeda break; 860b69a54eeSKentaro Takeda } 861ca0b7df3STetsuo Handa if (!is_delete && error && tomoyo_memory_ok(entry)) { 8627ef61233STetsuo Handa entry->head.type = TOMOYO_TYPE_PATH_ACL; 863ca0b7df3STetsuo Handa if (perm <= 0xFFFF) 864ca0b7df3STetsuo Handa entry->perm = perm; 865ca0b7df3STetsuo Handa else 866ca0b7df3STetsuo Handa entry->perm_high = (perm >> 16); 8677ef61233STetsuo Handa if (perm == (1 << TOMOYO_TYPE_READ_WRITE)) 868ca0b7df3STetsuo Handa entry->perm |= rw_mask; 869ca0b7df3STetsuo Handa entry->filename = saved_filename; 870bf24fb01STetsuo Handa saved_filename = NULL; 871ca0b7df3STetsuo Handa list_add_tail_rcu(&entry->head.list, &domain->acl_info_list); 872ca0b7df3STetsuo Handa entry = NULL; 873ca0b7df3STetsuo Handa error = 0; 874ca0b7df3STetsuo Handa } 875f737d95dSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 87629282381STetsuo Handa out: 877ca0b7df3STetsuo Handa kfree(entry); 878bf24fb01STetsuo Handa tomoyo_put_name(saved_filename); 879b69a54eeSKentaro Takeda return error; 880b69a54eeSKentaro Takeda } 881b69a54eeSKentaro Takeda 882b69a54eeSKentaro Takeda /** 8837ef61233STetsuo Handa * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list. 884b69a54eeSKentaro Takeda * 885b69a54eeSKentaro Takeda * @type: Type of operation. 886b69a54eeSKentaro Takeda * @filename1: First filename. 887b69a54eeSKentaro Takeda * @filename2: Second filename. 888b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 889b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 890b69a54eeSKentaro Takeda * 891b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 892fdb8ebb7STetsuo Handa * 893fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 894b69a54eeSKentaro Takeda */ 8957ef61233STetsuo Handa static int tomoyo_update_path2_acl(const u8 type, const char *filename1, 896b69a54eeSKentaro Takeda const char *filename2, 8977ef61233STetsuo Handa struct tomoyo_domain_info *const domain, 8987ef61233STetsuo Handa const bool is_delete) 899b69a54eeSKentaro Takeda { 900b69a54eeSKentaro Takeda const struct tomoyo_path_info *saved_filename1; 901b69a54eeSKentaro Takeda const struct tomoyo_path_info *saved_filename2; 902b69a54eeSKentaro Takeda struct tomoyo_acl_info *ptr; 9037ef61233STetsuo Handa struct tomoyo_path2_acl *entry = NULL; 904ca0b7df3STetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 905b69a54eeSKentaro Takeda const u8 perm = 1 << type; 906b69a54eeSKentaro Takeda 907b69a54eeSKentaro Takeda if (!domain) 908b69a54eeSKentaro Takeda return -EINVAL; 90917080008STetsuo Handa if (!tomoyo_is_correct_path(filename1, 0, 0, 0) || 91017080008STetsuo Handa !tomoyo_is_correct_path(filename2, 0, 0, 0)) 911b69a54eeSKentaro Takeda return -EINVAL; 912bf24fb01STetsuo Handa saved_filename1 = tomoyo_get_name(filename1); 913bf24fb01STetsuo Handa saved_filename2 = tomoyo_get_name(filename2); 914b69a54eeSKentaro Takeda if (!saved_filename1 || !saved_filename2) 915ca0b7df3STetsuo Handa goto out; 916ca0b7df3STetsuo Handa if (!is_delete) 9174e5d6f7eSTetsuo Handa entry = kmalloc(sizeof(*entry), GFP_NOFS); 91829282381STetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 91929282381STetsuo Handa goto out; 920ca0b7df3STetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 9217ef61233STetsuo Handa struct tomoyo_path2_acl *acl = 9227ef61233STetsuo Handa container_of(ptr, struct tomoyo_path2_acl, head); 9237ef61233STetsuo Handa if (ptr->type != TOMOYO_TYPE_PATH2_ACL) 924ca0b7df3STetsuo Handa continue; 925ca0b7df3STetsuo Handa if (acl->filename1 != saved_filename1 || 926ca0b7df3STetsuo Handa acl->filename2 != saved_filename2) 927ca0b7df3STetsuo Handa continue; 928b69a54eeSKentaro Takeda if (is_delete) 929b69a54eeSKentaro Takeda acl->perm &= ~perm; 930ca0b7df3STetsuo Handa else 931ca0b7df3STetsuo Handa acl->perm |= perm; 932b69a54eeSKentaro Takeda error = 0; 933b69a54eeSKentaro Takeda break; 934b69a54eeSKentaro Takeda } 935ca0b7df3STetsuo Handa if (!is_delete && error && tomoyo_memory_ok(entry)) { 9367ef61233STetsuo Handa entry->head.type = TOMOYO_TYPE_PATH2_ACL; 937ca0b7df3STetsuo Handa entry->perm = perm; 938ca0b7df3STetsuo Handa entry->filename1 = saved_filename1; 939bf24fb01STetsuo Handa saved_filename1 = NULL; 940ca0b7df3STetsuo Handa entry->filename2 = saved_filename2; 941bf24fb01STetsuo Handa saved_filename2 = NULL; 942ca0b7df3STetsuo Handa list_add_tail_rcu(&entry->head.list, &domain->acl_info_list); 943ca0b7df3STetsuo Handa entry = NULL; 944ca0b7df3STetsuo Handa error = 0; 945ca0b7df3STetsuo Handa } 946f737d95dSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 947ca0b7df3STetsuo Handa out: 948bf24fb01STetsuo Handa tomoyo_put_name(saved_filename1); 949bf24fb01STetsuo Handa tomoyo_put_name(saved_filename2); 950ca0b7df3STetsuo Handa kfree(entry); 951b69a54eeSKentaro Takeda return error; 952b69a54eeSKentaro Takeda } 953b69a54eeSKentaro Takeda 954b69a54eeSKentaro Takeda /** 9557ef61233STetsuo Handa * tomoyo_path_acl - Check permission for single path operation. 956b69a54eeSKentaro Takeda * 957b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 958b69a54eeSKentaro Takeda * @type: Type of operation. 959b69a54eeSKentaro Takeda * @filename: Filename to check. 960b69a54eeSKentaro Takeda * 961b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 962fdb8ebb7STetsuo Handa * 963fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 964b69a54eeSKentaro Takeda */ 9657ef61233STetsuo Handa static int tomoyo_path_acl(struct tomoyo_domain_info *domain, const u8 type, 966b69a54eeSKentaro Takeda const struct tomoyo_path_info *filename) 967b69a54eeSKentaro Takeda { 968b69a54eeSKentaro Takeda if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) 969b69a54eeSKentaro Takeda return 0; 9707ef61233STetsuo Handa return tomoyo_path_acl2(domain, filename, 1 << type, 1); 971b69a54eeSKentaro Takeda } 972b69a54eeSKentaro Takeda 973b69a54eeSKentaro Takeda /** 9747ef61233STetsuo Handa * tomoyo_path2_acl - Check permission for double path operation. 975b69a54eeSKentaro Takeda * 976b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 977b69a54eeSKentaro Takeda * @type: Type of operation. 978b69a54eeSKentaro Takeda * @filename1: First filename to check. 979b69a54eeSKentaro Takeda * @filename2: Second filename to check. 980b69a54eeSKentaro Takeda * 981b69a54eeSKentaro Takeda * Returns 0 on success, -EPERM otherwise. 982fdb8ebb7STetsuo Handa * 983fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 984b69a54eeSKentaro Takeda */ 9857ef61233STetsuo Handa static int tomoyo_path2_acl(const struct tomoyo_domain_info *domain, 986b69a54eeSKentaro Takeda const u8 type, 9877ef61233STetsuo Handa const struct tomoyo_path_info *filename1, 9887ef61233STetsuo Handa const struct tomoyo_path_info *filename2) 989b69a54eeSKentaro Takeda { 990b69a54eeSKentaro Takeda struct tomoyo_acl_info *ptr; 991b69a54eeSKentaro Takeda const u8 perm = 1 << type; 992b69a54eeSKentaro Takeda int error = -EPERM; 993b69a54eeSKentaro Takeda 994b69a54eeSKentaro Takeda if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) 995b69a54eeSKentaro Takeda return 0; 996fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 9977ef61233STetsuo Handa struct tomoyo_path2_acl *acl; 9987ef61233STetsuo Handa if (ptr->type != TOMOYO_TYPE_PATH2_ACL) 999b69a54eeSKentaro Takeda continue; 10007ef61233STetsuo Handa acl = container_of(ptr, struct tomoyo_path2_acl, head); 1001b69a54eeSKentaro Takeda if (!(acl->perm & perm)) 1002b69a54eeSKentaro Takeda continue; 1003b69a54eeSKentaro Takeda if (!tomoyo_path_matches_pattern(filename1, acl->filename1)) 1004b69a54eeSKentaro Takeda continue; 1005b69a54eeSKentaro Takeda if (!tomoyo_path_matches_pattern(filename2, acl->filename2)) 1006b69a54eeSKentaro Takeda continue; 1007b69a54eeSKentaro Takeda error = 0; 1008b69a54eeSKentaro Takeda break; 1009b69a54eeSKentaro Takeda } 1010b69a54eeSKentaro Takeda return error; 1011b69a54eeSKentaro Takeda } 1012b69a54eeSKentaro Takeda 1013b69a54eeSKentaro Takeda /** 10147ef61233STetsuo Handa * tomoyo_path_permission2 - Check permission for single path operation. 1015b69a54eeSKentaro Takeda * 1016b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 1017b69a54eeSKentaro Takeda * @operation: Type of operation. 1018b69a54eeSKentaro Takeda * @filename: Filename to check. 1019b69a54eeSKentaro Takeda * @mode: Access control mode. 1020b69a54eeSKentaro Takeda * 1021b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1022fdb8ebb7STetsuo Handa * 1023fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 1024b69a54eeSKentaro Takeda */ 10257ef61233STetsuo Handa static int tomoyo_path_permission2(struct tomoyo_domain_info *const domain, 10267ef61233STetsuo Handa u8 operation, 10277ef61233STetsuo Handa const struct tomoyo_path_info *filename, 10287ef61233STetsuo Handa const u8 mode) 1029b69a54eeSKentaro Takeda { 1030b69a54eeSKentaro Takeda const char *msg; 1031b69a54eeSKentaro Takeda int error; 1032b69a54eeSKentaro Takeda const bool is_enforce = (mode == 3); 1033b69a54eeSKentaro Takeda 1034b69a54eeSKentaro Takeda if (!mode) 1035b69a54eeSKentaro Takeda return 0; 1036b69a54eeSKentaro Takeda next: 10377ef61233STetsuo Handa error = tomoyo_path_acl(domain, operation, filename); 10387ef61233STetsuo Handa msg = tomoyo_path2keyword(operation); 1039b69a54eeSKentaro Takeda if (!error) 1040b69a54eeSKentaro Takeda goto ok; 1041b69a54eeSKentaro Takeda if (tomoyo_verbose_mode(domain)) 1042b69a54eeSKentaro Takeda printk(KERN_WARNING "TOMOYO-%s: Access '%s %s' denied for %s\n", 1043b69a54eeSKentaro Takeda tomoyo_get_msg(is_enforce), msg, filename->name, 1044b69a54eeSKentaro Takeda tomoyo_get_last_name(domain)); 1045b69a54eeSKentaro Takeda if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { 1046b69a54eeSKentaro Takeda const char *name = tomoyo_get_file_pattern(filename)->name; 10477ef61233STetsuo Handa tomoyo_update_path_acl(operation, name, domain, false); 1048b69a54eeSKentaro Takeda } 1049b69a54eeSKentaro Takeda if (!is_enforce) 1050b69a54eeSKentaro Takeda error = 0; 1051b69a54eeSKentaro Takeda ok: 1052b69a54eeSKentaro Takeda /* 1053b69a54eeSKentaro Takeda * Since "allow_truncate" doesn't imply "allow_rewrite" permission, 1054b69a54eeSKentaro Takeda * we need to check "allow_rewrite" permission if the filename is 1055b69a54eeSKentaro Takeda * specified by "deny_rewrite" keyword. 1056b69a54eeSKentaro Takeda */ 10577ef61233STetsuo Handa if (!error && operation == TOMOYO_TYPE_TRUNCATE && 1058b69a54eeSKentaro Takeda tomoyo_is_no_rewrite_file(filename)) { 10597ef61233STetsuo Handa operation = TOMOYO_TYPE_REWRITE; 1060b69a54eeSKentaro Takeda goto next; 1061b69a54eeSKentaro Takeda } 1062b69a54eeSKentaro Takeda return error; 1063b69a54eeSKentaro Takeda } 1064b69a54eeSKentaro Takeda 1065b69a54eeSKentaro Takeda /** 1066b69a54eeSKentaro Takeda * tomoyo_check_exec_perm - Check permission for "execute". 1067b69a54eeSKentaro Takeda * 1068b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 1069b69a54eeSKentaro Takeda * @filename: Check permission for "execute". 1070b69a54eeSKentaro Takeda * 1071b69a54eeSKentaro Takeda * Returns 0 on success, negativevalue otherwise. 1072fdb8ebb7STetsuo Handa * 1073fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 1074b69a54eeSKentaro Takeda */ 1075b69a54eeSKentaro Takeda int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, 1076bcb86975STetsuo Handa const struct tomoyo_path_info *filename) 1077b69a54eeSKentaro Takeda { 1078b69a54eeSKentaro Takeda const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); 1079b69a54eeSKentaro Takeda 1080b69a54eeSKentaro Takeda if (!mode) 1081b69a54eeSKentaro Takeda return 0; 1082b69a54eeSKentaro Takeda return tomoyo_check_file_perm2(domain, filename, 1, "do_execve", mode); 1083b69a54eeSKentaro Takeda } 1084b69a54eeSKentaro Takeda 1085b69a54eeSKentaro Takeda /** 1086b69a54eeSKentaro Takeda * tomoyo_check_open_permission - Check permission for "read" and "write". 1087b69a54eeSKentaro Takeda * 1088b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 1089b69a54eeSKentaro Takeda * @path: Pointer to "struct path". 1090b69a54eeSKentaro Takeda * @flag: Flags for open(). 1091b69a54eeSKentaro Takeda * 1092b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1093b69a54eeSKentaro Takeda */ 1094b69a54eeSKentaro Takeda int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, 1095b69a54eeSKentaro Takeda struct path *path, const int flag) 1096b69a54eeSKentaro Takeda { 1097b69a54eeSKentaro Takeda const u8 acc_mode = ACC_MODE(flag); 1098b69a54eeSKentaro Takeda int error = -ENOMEM; 1099b69a54eeSKentaro Takeda struct tomoyo_path_info *buf; 1100b69a54eeSKentaro Takeda const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); 1101b69a54eeSKentaro Takeda const bool is_enforce = (mode == 3); 1102fdb8ebb7STetsuo Handa int idx; 1103b69a54eeSKentaro Takeda 1104b69a54eeSKentaro Takeda if (!mode || !path->mnt) 1105b69a54eeSKentaro Takeda return 0; 1106b69a54eeSKentaro Takeda if (acc_mode == 0) 1107b69a54eeSKentaro Takeda return 0; 1108b69a54eeSKentaro Takeda if (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode)) 1109b69a54eeSKentaro Takeda /* 1110b69a54eeSKentaro Takeda * I don't check directories here because mkdir() and rmdir() 1111b69a54eeSKentaro Takeda * don't call me. 1112b69a54eeSKentaro Takeda */ 1113b69a54eeSKentaro Takeda return 0; 1114fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 1115b69a54eeSKentaro Takeda buf = tomoyo_get_path(path); 1116b69a54eeSKentaro Takeda if (!buf) 1117b69a54eeSKentaro Takeda goto out; 1118b69a54eeSKentaro Takeda error = 0; 1119b69a54eeSKentaro Takeda /* 1120b69a54eeSKentaro Takeda * If the filename is specified by "deny_rewrite" keyword, 1121b69a54eeSKentaro Takeda * we need to check "allow_rewrite" permission when the filename is not 1122b69a54eeSKentaro Takeda * opened for append mode or the filename is truncated at open time. 1123b69a54eeSKentaro Takeda */ 1124b69a54eeSKentaro Takeda if ((acc_mode & MAY_WRITE) && 1125b69a54eeSKentaro Takeda ((flag & O_TRUNC) || !(flag & O_APPEND)) && 1126b69a54eeSKentaro Takeda (tomoyo_is_no_rewrite_file(buf))) { 11277ef61233STetsuo Handa error = tomoyo_path_permission2(domain, TOMOYO_TYPE_REWRITE, 1128b69a54eeSKentaro Takeda buf, mode); 1129b69a54eeSKentaro Takeda } 1130b69a54eeSKentaro Takeda if (!error) 1131b69a54eeSKentaro Takeda error = tomoyo_check_file_perm2(domain, buf, acc_mode, "open", 1132b69a54eeSKentaro Takeda mode); 1133b69a54eeSKentaro Takeda if (!error && (flag & O_TRUNC)) 11347ef61233STetsuo Handa error = tomoyo_path_permission2(domain, TOMOYO_TYPE_TRUNCATE, 1135b69a54eeSKentaro Takeda buf, mode); 1136b69a54eeSKentaro Takeda out: 11378e2d39a1STetsuo Handa kfree(buf); 1138fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 1139b69a54eeSKentaro Takeda if (!is_enforce) 1140b69a54eeSKentaro Takeda error = 0; 1141b69a54eeSKentaro Takeda return error; 1142b69a54eeSKentaro Takeda } 1143b69a54eeSKentaro Takeda 1144b69a54eeSKentaro Takeda /** 11457ef61233STetsuo 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". 1146b69a54eeSKentaro Takeda * 1147b69a54eeSKentaro Takeda * @operation: Type of operation. 1148b69a54eeSKentaro Takeda * @path: Pointer to "struct path". 1149b69a54eeSKentaro Takeda * 1150b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1151b69a54eeSKentaro Takeda */ 115297d6931eSTetsuo Handa int tomoyo_path_perm(const u8 operation, struct path *path) 1153b69a54eeSKentaro Takeda { 1154b69a54eeSKentaro Takeda int error = -ENOMEM; 1155b69a54eeSKentaro Takeda struct tomoyo_path_info *buf; 115697d6931eSTetsuo Handa struct tomoyo_domain_info *domain = tomoyo_domain(); 1157b69a54eeSKentaro Takeda const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); 1158b69a54eeSKentaro Takeda const bool is_enforce = (mode == 3); 1159fdb8ebb7STetsuo Handa int idx; 1160b69a54eeSKentaro Takeda 1161b69a54eeSKentaro Takeda if (!mode || !path->mnt) 1162b69a54eeSKentaro Takeda return 0; 1163fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 1164b69a54eeSKentaro Takeda buf = tomoyo_get_path(path); 1165b69a54eeSKentaro Takeda if (!buf) 1166b69a54eeSKentaro Takeda goto out; 1167b69a54eeSKentaro Takeda switch (operation) { 11687ef61233STetsuo Handa case TOMOYO_TYPE_MKDIR: 11697ef61233STetsuo Handa case TOMOYO_TYPE_RMDIR: 11707ef61233STetsuo Handa case TOMOYO_TYPE_CHROOT: 1171b69a54eeSKentaro Takeda if (!buf->is_dir) { 1172b69a54eeSKentaro Takeda /* 1173b69a54eeSKentaro Takeda * tomoyo_get_path() reserves space for appending "/." 1174b69a54eeSKentaro Takeda */ 1175b69a54eeSKentaro Takeda strcat((char *) buf->name, "/"); 1176b69a54eeSKentaro Takeda tomoyo_fill_path_info(buf); 1177b69a54eeSKentaro Takeda } 1178b69a54eeSKentaro Takeda } 11797ef61233STetsuo Handa error = tomoyo_path_permission2(domain, operation, buf, mode); 1180b69a54eeSKentaro Takeda out: 11818e2d39a1STetsuo Handa kfree(buf); 1182fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 1183b69a54eeSKentaro Takeda if (!is_enforce) 1184b69a54eeSKentaro Takeda error = 0; 1185b69a54eeSKentaro Takeda return error; 1186b69a54eeSKentaro Takeda } 1187b69a54eeSKentaro Takeda 1188b69a54eeSKentaro Takeda /** 1189b69a54eeSKentaro Takeda * tomoyo_check_rewrite_permission - Check permission for "rewrite". 1190b69a54eeSKentaro Takeda * 1191b69a54eeSKentaro Takeda * @filp: Pointer to "struct file". 1192b69a54eeSKentaro Takeda * 1193b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1194b69a54eeSKentaro Takeda */ 119597d6931eSTetsuo Handa int tomoyo_check_rewrite_permission(struct file *filp) 1196b69a54eeSKentaro Takeda { 1197b69a54eeSKentaro Takeda int error = -ENOMEM; 119897d6931eSTetsuo Handa struct tomoyo_domain_info *domain = tomoyo_domain(); 1199b69a54eeSKentaro Takeda const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); 1200b69a54eeSKentaro Takeda const bool is_enforce = (mode == 3); 1201b69a54eeSKentaro Takeda struct tomoyo_path_info *buf; 1202fdb8ebb7STetsuo Handa int idx; 1203b69a54eeSKentaro Takeda 1204b69a54eeSKentaro Takeda if (!mode || !filp->f_path.mnt) 1205b69a54eeSKentaro Takeda return 0; 1206fdb8ebb7STetsuo Handa 1207fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 1208b69a54eeSKentaro Takeda buf = tomoyo_get_path(&filp->f_path); 1209b69a54eeSKentaro Takeda if (!buf) 1210b69a54eeSKentaro Takeda goto out; 1211b69a54eeSKentaro Takeda if (!tomoyo_is_no_rewrite_file(buf)) { 1212b69a54eeSKentaro Takeda error = 0; 1213b69a54eeSKentaro Takeda goto out; 1214b69a54eeSKentaro Takeda } 12157ef61233STetsuo Handa error = tomoyo_path_permission2(domain, TOMOYO_TYPE_REWRITE, buf, mode); 1216b69a54eeSKentaro Takeda out: 12178e2d39a1STetsuo Handa kfree(buf); 1218fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 1219b69a54eeSKentaro Takeda if (!is_enforce) 1220b69a54eeSKentaro Takeda error = 0; 1221b69a54eeSKentaro Takeda return error; 1222b69a54eeSKentaro Takeda } 1223b69a54eeSKentaro Takeda 1224b69a54eeSKentaro Takeda /** 12257ef61233STetsuo Handa * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root". 1226b69a54eeSKentaro Takeda * 1227b69a54eeSKentaro Takeda * @operation: Type of operation. 1228b69a54eeSKentaro Takeda * @path1: Pointer to "struct path". 1229b69a54eeSKentaro Takeda * @path2: Pointer to "struct path". 1230b69a54eeSKentaro Takeda * 1231b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1232b69a54eeSKentaro Takeda */ 123397d6931eSTetsuo Handa int tomoyo_path2_perm(const u8 operation, struct path *path1, 1234b69a54eeSKentaro Takeda struct path *path2) 1235b69a54eeSKentaro Takeda { 1236b69a54eeSKentaro Takeda int error = -ENOMEM; 1237b69a54eeSKentaro Takeda struct tomoyo_path_info *buf1, *buf2; 123897d6931eSTetsuo Handa struct tomoyo_domain_info *domain = tomoyo_domain(); 1239b69a54eeSKentaro Takeda const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); 1240b69a54eeSKentaro Takeda const bool is_enforce = (mode == 3); 1241b69a54eeSKentaro Takeda const char *msg; 1242fdb8ebb7STetsuo Handa int idx; 1243b69a54eeSKentaro Takeda 1244b69a54eeSKentaro Takeda if (!mode || !path1->mnt || !path2->mnt) 1245b69a54eeSKentaro Takeda return 0; 1246fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 1247b69a54eeSKentaro Takeda buf1 = tomoyo_get_path(path1); 1248b69a54eeSKentaro Takeda buf2 = tomoyo_get_path(path2); 1249b69a54eeSKentaro Takeda if (!buf1 || !buf2) 1250b69a54eeSKentaro Takeda goto out; 1251b69a54eeSKentaro Takeda { 1252b69a54eeSKentaro Takeda struct dentry *dentry = path1->dentry; 1253b69a54eeSKentaro Takeda if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) { 1254b69a54eeSKentaro Takeda /* 1255b69a54eeSKentaro Takeda * tomoyo_get_path() reserves space for appending "/." 1256b69a54eeSKentaro Takeda */ 1257b69a54eeSKentaro Takeda if (!buf1->is_dir) { 1258b69a54eeSKentaro Takeda strcat((char *) buf1->name, "/"); 1259b69a54eeSKentaro Takeda tomoyo_fill_path_info(buf1); 1260b69a54eeSKentaro Takeda } 1261b69a54eeSKentaro Takeda if (!buf2->is_dir) { 1262b69a54eeSKentaro Takeda strcat((char *) buf2->name, "/"); 1263b69a54eeSKentaro Takeda tomoyo_fill_path_info(buf2); 1264b69a54eeSKentaro Takeda } 1265b69a54eeSKentaro Takeda } 1266b69a54eeSKentaro Takeda } 12677ef61233STetsuo Handa error = tomoyo_path2_acl(domain, operation, buf1, buf2); 12687ef61233STetsuo Handa msg = tomoyo_path22keyword(operation); 1269b69a54eeSKentaro Takeda if (!error) 1270b69a54eeSKentaro Takeda goto out; 1271b69a54eeSKentaro Takeda if (tomoyo_verbose_mode(domain)) 1272b69a54eeSKentaro Takeda printk(KERN_WARNING "TOMOYO-%s: Access '%s %s %s' " 1273b69a54eeSKentaro Takeda "denied for %s\n", tomoyo_get_msg(is_enforce), 1274b69a54eeSKentaro Takeda msg, buf1->name, buf2->name, 1275b69a54eeSKentaro Takeda tomoyo_get_last_name(domain)); 1276b69a54eeSKentaro Takeda if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { 1277b69a54eeSKentaro Takeda const char *name1 = tomoyo_get_file_pattern(buf1)->name; 1278b69a54eeSKentaro Takeda const char *name2 = tomoyo_get_file_pattern(buf2)->name; 12797ef61233STetsuo Handa tomoyo_update_path2_acl(operation, name1, name2, domain, 1280b69a54eeSKentaro Takeda false); 1281b69a54eeSKentaro Takeda } 1282b69a54eeSKentaro Takeda out: 12838e2d39a1STetsuo Handa kfree(buf1); 12848e2d39a1STetsuo Handa kfree(buf2); 1285fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 1286b69a54eeSKentaro Takeda if (!is_enforce) 1287b69a54eeSKentaro Takeda error = 0; 1288b69a54eeSKentaro Takeda return error; 1289b69a54eeSKentaro Takeda } 1290