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" 13b69a54eeSKentaro Takeda #include "tomoyo.h" 14b69a54eeSKentaro Takeda #include "realpath.h" 15b69a54eeSKentaro Takeda 16c3fa109aSTetsuo Handa /* 17c3fa109aSTetsuo Handa * tomoyo_globally_readable_file_entry is a structure which is used for holding 18c3fa109aSTetsuo Handa * "allow_read" entries. 19c3fa109aSTetsuo Handa * It has following fields. 20c3fa109aSTetsuo Handa * 21c3fa109aSTetsuo Handa * (1) "list" which is linked to tomoyo_globally_readable_list . 22c3fa109aSTetsuo Handa * (2) "filename" is a pathname which is allowed to open(O_RDONLY). 23c3fa109aSTetsuo Handa * (3) "is_deleted" is a bool which is true if marked as deleted, false 24c3fa109aSTetsuo Handa * otherwise. 25c3fa109aSTetsuo Handa */ 26b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry { 27b69a54eeSKentaro Takeda struct list_head list; 28b69a54eeSKentaro Takeda const struct tomoyo_path_info *filename; 29b69a54eeSKentaro Takeda bool is_deleted; 30b69a54eeSKentaro Takeda }; 31b69a54eeSKentaro Takeda 32c3fa109aSTetsuo Handa /* 33c3fa109aSTetsuo Handa * tomoyo_pattern_entry is a structure which is used for holding 34c3fa109aSTetsuo Handa * "tomoyo_pattern_list" entries. 35c3fa109aSTetsuo Handa * It has following fields. 36c3fa109aSTetsuo Handa * 37c3fa109aSTetsuo Handa * (1) "list" which is linked to tomoyo_pattern_list . 38c3fa109aSTetsuo Handa * (2) "pattern" is a pathname pattern which is used for converting pathnames 39c3fa109aSTetsuo Handa * to pathname patterns during learning mode. 40c3fa109aSTetsuo Handa * (3) "is_deleted" is a bool which is true if marked as deleted, false 41c3fa109aSTetsuo Handa * otherwise. 42c3fa109aSTetsuo Handa */ 43b69a54eeSKentaro Takeda struct tomoyo_pattern_entry { 44b69a54eeSKentaro Takeda struct list_head list; 45b69a54eeSKentaro Takeda const struct tomoyo_path_info *pattern; 46b69a54eeSKentaro Takeda bool is_deleted; 47b69a54eeSKentaro Takeda }; 48b69a54eeSKentaro Takeda 49c3fa109aSTetsuo Handa /* 50c3fa109aSTetsuo Handa * tomoyo_no_rewrite_entry is a structure which is used for holding 51c3fa109aSTetsuo Handa * "deny_rewrite" entries. 52c3fa109aSTetsuo Handa * It has following fields. 53c3fa109aSTetsuo Handa * 54c3fa109aSTetsuo Handa * (1) "list" which is linked to tomoyo_no_rewrite_list . 55c3fa109aSTetsuo Handa * (2) "pattern" is a pathname which is by default not permitted to modify 56c3fa109aSTetsuo Handa * already existing content. 57c3fa109aSTetsuo Handa * (3) "is_deleted" is a bool which is true if marked as deleted, false 58c3fa109aSTetsuo Handa * otherwise. 59c3fa109aSTetsuo Handa */ 60b69a54eeSKentaro Takeda struct tomoyo_no_rewrite_entry { 61b69a54eeSKentaro Takeda struct list_head list; 62b69a54eeSKentaro Takeda const struct tomoyo_path_info *pattern; 63b69a54eeSKentaro Takeda bool is_deleted; 64b69a54eeSKentaro Takeda }; 65b69a54eeSKentaro Takeda 66b69a54eeSKentaro Takeda /* Keyword array for single path operations. */ 67b69a54eeSKentaro Takeda static const char *tomoyo_sp_keyword[TOMOYO_MAX_SINGLE_PATH_OPERATION] = { 68b69a54eeSKentaro Takeda [TOMOYO_TYPE_READ_WRITE_ACL] = "read/write", 69b69a54eeSKentaro Takeda [TOMOYO_TYPE_EXECUTE_ACL] = "execute", 70b69a54eeSKentaro Takeda [TOMOYO_TYPE_READ_ACL] = "read", 71b69a54eeSKentaro Takeda [TOMOYO_TYPE_WRITE_ACL] = "write", 72b69a54eeSKentaro Takeda [TOMOYO_TYPE_CREATE_ACL] = "create", 73b69a54eeSKentaro Takeda [TOMOYO_TYPE_UNLINK_ACL] = "unlink", 74b69a54eeSKentaro Takeda [TOMOYO_TYPE_MKDIR_ACL] = "mkdir", 75b69a54eeSKentaro Takeda [TOMOYO_TYPE_RMDIR_ACL] = "rmdir", 76b69a54eeSKentaro Takeda [TOMOYO_TYPE_MKFIFO_ACL] = "mkfifo", 77b69a54eeSKentaro Takeda [TOMOYO_TYPE_MKSOCK_ACL] = "mksock", 78b69a54eeSKentaro Takeda [TOMOYO_TYPE_MKBLOCK_ACL] = "mkblock", 79b69a54eeSKentaro Takeda [TOMOYO_TYPE_MKCHAR_ACL] = "mkchar", 80b69a54eeSKentaro Takeda [TOMOYO_TYPE_TRUNCATE_ACL] = "truncate", 81b69a54eeSKentaro Takeda [TOMOYO_TYPE_SYMLINK_ACL] = "symlink", 82b69a54eeSKentaro Takeda [TOMOYO_TYPE_REWRITE_ACL] = "rewrite", 83937bf613STetsuo Handa [TOMOYO_TYPE_IOCTL_ACL] = "ioctl", 84937bf613STetsuo Handa [TOMOYO_TYPE_CHMOD_ACL] = "chmod", 85937bf613STetsuo Handa [TOMOYO_TYPE_CHOWN_ACL] = "chown", 86937bf613STetsuo Handa [TOMOYO_TYPE_CHGRP_ACL] = "chgrp", 87937bf613STetsuo Handa [TOMOYO_TYPE_CHROOT_ACL] = "chroot", 88937bf613STetsuo Handa [TOMOYO_TYPE_MOUNT_ACL] = "mount", 89937bf613STetsuo Handa [TOMOYO_TYPE_UMOUNT_ACL] = "unmount", 90b69a54eeSKentaro Takeda }; 91b69a54eeSKentaro Takeda 92b69a54eeSKentaro Takeda /* Keyword array for double path operations. */ 93b69a54eeSKentaro Takeda static const char *tomoyo_dp_keyword[TOMOYO_MAX_DOUBLE_PATH_OPERATION] = { 94b69a54eeSKentaro Takeda [TOMOYO_TYPE_LINK_ACL] = "link", 95b69a54eeSKentaro Takeda [TOMOYO_TYPE_RENAME_ACL] = "rename", 96937bf613STetsuo Handa [TOMOYO_TYPE_PIVOT_ROOT_ACL] = "pivot_root", 97b69a54eeSKentaro Takeda }; 98b69a54eeSKentaro Takeda 99b69a54eeSKentaro Takeda /** 100b69a54eeSKentaro Takeda * tomoyo_sp2keyword - 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 */ 106b69a54eeSKentaro Takeda const char *tomoyo_sp2keyword(const u8 operation) 107b69a54eeSKentaro Takeda { 108b69a54eeSKentaro Takeda return (operation < TOMOYO_MAX_SINGLE_PATH_OPERATION) 109b69a54eeSKentaro Takeda ? tomoyo_sp_keyword[operation] : NULL; 110b69a54eeSKentaro Takeda } 111b69a54eeSKentaro Takeda 112b69a54eeSKentaro Takeda /** 113b69a54eeSKentaro Takeda * tomoyo_dp2keyword - Get the name of double path operation. 114b69a54eeSKentaro Takeda * 115b69a54eeSKentaro Takeda * @operation: Type of operation. 116b69a54eeSKentaro Takeda * 117b69a54eeSKentaro Takeda * Returns the name of double path operation. 118b69a54eeSKentaro Takeda */ 119b69a54eeSKentaro Takeda const char *tomoyo_dp2keyword(const u8 operation) 120b69a54eeSKentaro Takeda { 121b69a54eeSKentaro Takeda return (operation < TOMOYO_MAX_DOUBLE_PATH_OPERATION) 122b69a54eeSKentaro Takeda ? tomoyo_dp_keyword[operation] : NULL; 123b69a54eeSKentaro Takeda } 124b69a54eeSKentaro Takeda 125b69a54eeSKentaro Takeda /** 126b69a54eeSKentaro Takeda * tomoyo_strendswith - Check whether the token ends with the given token. 127b69a54eeSKentaro Takeda * 128b69a54eeSKentaro Takeda * @name: The token to check. 129b69a54eeSKentaro Takeda * @tail: The token to find. 130b69a54eeSKentaro Takeda * 131b69a54eeSKentaro Takeda * Returns true if @name ends with @tail, false otherwise. 132b69a54eeSKentaro Takeda */ 133b69a54eeSKentaro Takeda static bool tomoyo_strendswith(const char *name, const char *tail) 134b69a54eeSKentaro Takeda { 135b69a54eeSKentaro Takeda int len; 136b69a54eeSKentaro Takeda 137b69a54eeSKentaro Takeda if (!name || !tail) 138b69a54eeSKentaro Takeda return false; 139b69a54eeSKentaro Takeda len = strlen(name) - strlen(tail); 140b69a54eeSKentaro Takeda return len >= 0 && !strcmp(name + len, tail); 141b69a54eeSKentaro Takeda } 142b69a54eeSKentaro Takeda 143b69a54eeSKentaro Takeda /** 144b69a54eeSKentaro Takeda * tomoyo_get_path - Get realpath. 145b69a54eeSKentaro Takeda * 146b69a54eeSKentaro Takeda * @path: Pointer to "struct path". 147b69a54eeSKentaro Takeda * 148b69a54eeSKentaro Takeda * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. 149b69a54eeSKentaro Takeda */ 150b69a54eeSKentaro Takeda static struct tomoyo_path_info *tomoyo_get_path(struct path *path) 151b69a54eeSKentaro Takeda { 152b69a54eeSKentaro Takeda int error; 1538e2d39a1STetsuo Handa struct tomoyo_path_info_with_data *buf = kzalloc(sizeof(*buf), 1548e2d39a1STetsuo Handa GFP_KERNEL); 155b69a54eeSKentaro Takeda 156b69a54eeSKentaro Takeda if (!buf) 157b69a54eeSKentaro Takeda return NULL; 158b69a54eeSKentaro Takeda /* Reserve one byte for appending "/". */ 159b69a54eeSKentaro Takeda error = tomoyo_realpath_from_path2(path, buf->body, 160b69a54eeSKentaro Takeda sizeof(buf->body) - 2); 161b69a54eeSKentaro Takeda if (!error) { 162b69a54eeSKentaro Takeda buf->head.name = buf->body; 163b69a54eeSKentaro Takeda tomoyo_fill_path_info(&buf->head); 164b69a54eeSKentaro Takeda return &buf->head; 165b69a54eeSKentaro Takeda } 1668e2d39a1STetsuo Handa kfree(buf); 167b69a54eeSKentaro Takeda return NULL; 168b69a54eeSKentaro Takeda } 169b69a54eeSKentaro Takeda 170b69a54eeSKentaro Takeda static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, 171b69a54eeSKentaro Takeda const char *filename2, 172b69a54eeSKentaro Takeda struct tomoyo_domain_info * 173b69a54eeSKentaro Takeda const domain, const bool is_delete); 174b69a54eeSKentaro Takeda static int tomoyo_update_single_path_acl(const u8 type, const char *filename, 175b69a54eeSKentaro Takeda struct tomoyo_domain_info * 176b69a54eeSKentaro Takeda const domain, const bool is_delete); 177b69a54eeSKentaro Takeda 178c3fa109aSTetsuo Handa /* 179c3fa109aSTetsuo Handa * tomoyo_globally_readable_list is used for holding list of pathnames which 180c3fa109aSTetsuo Handa * are by default allowed to be open()ed for reading by any process. 181c3fa109aSTetsuo Handa * 182c3fa109aSTetsuo Handa * An entry is added by 183c3fa109aSTetsuo Handa * 184c3fa109aSTetsuo Handa * # echo 'allow_read /lib/libc-2.5.so' > \ 185c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 186c3fa109aSTetsuo Handa * 187c3fa109aSTetsuo Handa * and is deleted by 188c3fa109aSTetsuo Handa * 189c3fa109aSTetsuo Handa * # echo 'delete allow_read /lib/libc-2.5.so' > \ 190c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 191c3fa109aSTetsuo Handa * 192c3fa109aSTetsuo Handa * and all entries are retrieved by 193c3fa109aSTetsuo Handa * 194c3fa109aSTetsuo Handa * # grep ^allow_read /sys/kernel/security/tomoyo/exception_policy 195c3fa109aSTetsuo Handa * 196c3fa109aSTetsuo Handa * In the example above, any process is allowed to 197c3fa109aSTetsuo Handa * open("/lib/libc-2.5.so", O_RDONLY). 198c3fa109aSTetsuo Handa * One exception is, if the domain which current process belongs to is marked 199c3fa109aSTetsuo Handa * as "ignore_global_allow_read", current process can't do so unless explicitly 200c3fa109aSTetsuo Handa * given "allow_read /lib/libc-2.5.so" to the domain which current process 201c3fa109aSTetsuo Handa * belongs to. 202c3fa109aSTetsuo Handa */ 203b69a54eeSKentaro Takeda static LIST_HEAD(tomoyo_globally_readable_list); 204b69a54eeSKentaro Takeda 205b69a54eeSKentaro Takeda /** 206b69a54eeSKentaro Takeda * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list. 207b69a54eeSKentaro Takeda * 208b69a54eeSKentaro Takeda * @filename: Filename unconditionally permitted to open() for reading. 209b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 210b69a54eeSKentaro Takeda * 211b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 212fdb8ebb7STetsuo Handa * 213fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 214b69a54eeSKentaro Takeda */ 215b69a54eeSKentaro Takeda static int tomoyo_update_globally_readable_entry(const char *filename, 216b69a54eeSKentaro Takeda const bool is_delete) 217b69a54eeSKentaro Takeda { 218b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry *new_entry; 219b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry *ptr; 220b69a54eeSKentaro Takeda const struct tomoyo_path_info *saved_filename; 221b69a54eeSKentaro Takeda int error = -ENOMEM; 222b69a54eeSKentaro Takeda 223b69a54eeSKentaro Takeda if (!tomoyo_is_correct_path(filename, 1, 0, -1, __func__)) 224b69a54eeSKentaro Takeda return -EINVAL; 225b69a54eeSKentaro Takeda saved_filename = tomoyo_save_name(filename); 226b69a54eeSKentaro Takeda if (!saved_filename) 227b69a54eeSKentaro Takeda return -ENOMEM; 228cd7bec6aSTetsuo Handa new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL); 229f737d95dSTetsuo Handa mutex_lock(&tomoyo_policy_lock); 230fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) { 231b69a54eeSKentaro Takeda if (ptr->filename != saved_filename) 232b69a54eeSKentaro Takeda continue; 233b69a54eeSKentaro Takeda ptr->is_deleted = is_delete; 234b69a54eeSKentaro Takeda error = 0; 235b69a54eeSKentaro Takeda goto out; 236b69a54eeSKentaro Takeda } 237b69a54eeSKentaro Takeda if (is_delete) { 238b69a54eeSKentaro Takeda error = -ENOENT; 239b69a54eeSKentaro Takeda goto out; 240b69a54eeSKentaro Takeda } 241cd7bec6aSTetsuo Handa if (!tomoyo_memory_ok(new_entry)) 242b69a54eeSKentaro Takeda goto out; 243b69a54eeSKentaro Takeda new_entry->filename = saved_filename; 244fdb8ebb7STetsuo Handa list_add_tail_rcu(&new_entry->list, &tomoyo_globally_readable_list); 245cd7bec6aSTetsuo Handa new_entry = NULL; 246b69a54eeSKentaro Takeda error = 0; 247b69a54eeSKentaro Takeda out: 248f737d95dSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 249cd7bec6aSTetsuo Handa kfree(new_entry); 250b69a54eeSKentaro Takeda return error; 251b69a54eeSKentaro Takeda } 252b69a54eeSKentaro Takeda 253b69a54eeSKentaro Takeda /** 254b69a54eeSKentaro Takeda * tomoyo_is_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading. 255b69a54eeSKentaro Takeda * 256b69a54eeSKentaro Takeda * @filename: The filename to check. 257b69a54eeSKentaro Takeda * 258b69a54eeSKentaro Takeda * Returns true if any domain can open @filename for reading, false otherwise. 259fdb8ebb7STetsuo Handa * 260fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 261b69a54eeSKentaro Takeda */ 262b69a54eeSKentaro Takeda static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info * 263b69a54eeSKentaro Takeda filename) 264b69a54eeSKentaro Takeda { 265b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry *ptr; 266b69a54eeSKentaro Takeda bool found = false; 267fdb8ebb7STetsuo Handa 268fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) { 269b69a54eeSKentaro Takeda if (!ptr->is_deleted && 270b69a54eeSKentaro Takeda tomoyo_path_matches_pattern(filename, ptr->filename)) { 271b69a54eeSKentaro Takeda found = true; 272b69a54eeSKentaro Takeda break; 273b69a54eeSKentaro Takeda } 274b69a54eeSKentaro Takeda } 275b69a54eeSKentaro Takeda return found; 276b69a54eeSKentaro Takeda } 277b69a54eeSKentaro Takeda 278b69a54eeSKentaro Takeda /** 279b69a54eeSKentaro Takeda * tomoyo_write_globally_readable_policy - Write "struct tomoyo_globally_readable_file_entry" list. 280b69a54eeSKentaro Takeda * 281b69a54eeSKentaro Takeda * @data: String to parse. 282b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 283b69a54eeSKentaro Takeda * 284b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 285fdb8ebb7STetsuo Handa * 286fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 287b69a54eeSKentaro Takeda */ 288b69a54eeSKentaro Takeda int tomoyo_write_globally_readable_policy(char *data, const bool is_delete) 289b69a54eeSKentaro Takeda { 290b69a54eeSKentaro Takeda return tomoyo_update_globally_readable_entry(data, is_delete); 291b69a54eeSKentaro Takeda } 292b69a54eeSKentaro Takeda 293b69a54eeSKentaro Takeda /** 294b69a54eeSKentaro Takeda * tomoyo_read_globally_readable_policy - Read "struct tomoyo_globally_readable_file_entry" list. 295b69a54eeSKentaro Takeda * 296b69a54eeSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 297b69a54eeSKentaro Takeda * 298b69a54eeSKentaro Takeda * Returns true on success, false otherwise. 299fdb8ebb7STetsuo Handa * 300fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 301b69a54eeSKentaro Takeda */ 302b69a54eeSKentaro Takeda bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) 303b69a54eeSKentaro Takeda { 304b69a54eeSKentaro Takeda struct list_head *pos; 305b69a54eeSKentaro Takeda bool done = true; 306b69a54eeSKentaro Takeda 307b69a54eeSKentaro Takeda list_for_each_cookie(pos, head->read_var2, 308b69a54eeSKentaro Takeda &tomoyo_globally_readable_list) { 309b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry *ptr; 310b69a54eeSKentaro Takeda ptr = list_entry(pos, 311b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry, 312b69a54eeSKentaro Takeda list); 313b69a54eeSKentaro Takeda if (ptr->is_deleted) 314b69a54eeSKentaro Takeda continue; 3157d2948b1STetsuo Handa done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n", 3167d2948b1STetsuo Handa ptr->filename->name); 3177d2948b1STetsuo Handa if (!done) 318b69a54eeSKentaro Takeda break; 319b69a54eeSKentaro Takeda } 320b69a54eeSKentaro Takeda return done; 321b69a54eeSKentaro Takeda } 322b69a54eeSKentaro Takeda 323c3fa109aSTetsuo Handa /* tomoyo_pattern_list is used for holding list of pathnames which are used for 324c3fa109aSTetsuo Handa * converting pathnames to pathname patterns during learning mode. 325c3fa109aSTetsuo Handa * 326c3fa109aSTetsuo Handa * An entry is added by 327c3fa109aSTetsuo Handa * 328c3fa109aSTetsuo Handa * # echo 'file_pattern /proc/\$/mounts' > \ 329c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 330c3fa109aSTetsuo Handa * 331c3fa109aSTetsuo Handa * and is deleted by 332c3fa109aSTetsuo Handa * 333c3fa109aSTetsuo Handa * # echo 'delete file_pattern /proc/\$/mounts' > \ 334c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 335c3fa109aSTetsuo Handa * 336c3fa109aSTetsuo Handa * and all entries are retrieved by 337c3fa109aSTetsuo Handa * 338c3fa109aSTetsuo Handa * # grep ^file_pattern /sys/kernel/security/tomoyo/exception_policy 339c3fa109aSTetsuo Handa * 340c3fa109aSTetsuo Handa * In the example above, if a process which belongs to a domain which is in 341c3fa109aSTetsuo Handa * learning mode requested open("/proc/1/mounts", O_RDONLY), 342c3fa109aSTetsuo Handa * "allow_read /proc/\$/mounts" is automatically added to the domain which that 343c3fa109aSTetsuo Handa * process belongs to. 344c3fa109aSTetsuo Handa * 345c3fa109aSTetsuo Handa * It is not a desirable behavior that we have to use /proc/\$/ instead of 346c3fa109aSTetsuo Handa * /proc/self/ when current process needs to access only current process's 347c3fa109aSTetsuo Handa * information. As of now, LSM version of TOMOYO is using __d_path() for 348c3fa109aSTetsuo Handa * calculating pathname. Non LSM version of TOMOYO is using its own function 349c3fa109aSTetsuo Handa * which pretends as if /proc/self/ is not a symlink; so that we can forbid 350c3fa109aSTetsuo Handa * current process from accessing other process's information. 351c3fa109aSTetsuo Handa */ 352b69a54eeSKentaro Takeda static LIST_HEAD(tomoyo_pattern_list); 353b69a54eeSKentaro Takeda 354b69a54eeSKentaro Takeda /** 355b69a54eeSKentaro Takeda * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list. 356b69a54eeSKentaro Takeda * 357b69a54eeSKentaro Takeda * @pattern: Pathname pattern. 358b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 359b69a54eeSKentaro Takeda * 360b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 361fdb8ebb7STetsuo Handa * 362fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 363b69a54eeSKentaro Takeda */ 364b69a54eeSKentaro Takeda static int tomoyo_update_file_pattern_entry(const char *pattern, 365b69a54eeSKentaro Takeda const bool is_delete) 366b69a54eeSKentaro Takeda { 367b69a54eeSKentaro Takeda struct tomoyo_pattern_entry *new_entry; 368b69a54eeSKentaro Takeda struct tomoyo_pattern_entry *ptr; 369b69a54eeSKentaro Takeda const struct tomoyo_path_info *saved_pattern; 370b69a54eeSKentaro Takeda int error = -ENOMEM; 371b69a54eeSKentaro Takeda 372b69a54eeSKentaro Takeda if (!tomoyo_is_correct_path(pattern, 0, 1, 0, __func__)) 373b69a54eeSKentaro Takeda return -EINVAL; 374b69a54eeSKentaro Takeda saved_pattern = tomoyo_save_name(pattern); 375b69a54eeSKentaro Takeda if (!saved_pattern) 376b69a54eeSKentaro Takeda return -ENOMEM; 377cd7bec6aSTetsuo Handa new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL); 378f737d95dSTetsuo Handa mutex_lock(&tomoyo_policy_lock); 379fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { 380b69a54eeSKentaro Takeda if (saved_pattern != ptr->pattern) 381b69a54eeSKentaro Takeda continue; 382b69a54eeSKentaro Takeda ptr->is_deleted = is_delete; 383b69a54eeSKentaro Takeda error = 0; 384b69a54eeSKentaro Takeda goto out; 385b69a54eeSKentaro Takeda } 386b69a54eeSKentaro Takeda if (is_delete) { 387b69a54eeSKentaro Takeda error = -ENOENT; 388b69a54eeSKentaro Takeda goto out; 389b69a54eeSKentaro Takeda } 390cd7bec6aSTetsuo Handa if (!tomoyo_memory_ok(new_entry)) 391b69a54eeSKentaro Takeda goto out; 392b69a54eeSKentaro Takeda new_entry->pattern = saved_pattern; 393fdb8ebb7STetsuo Handa list_add_tail_rcu(&new_entry->list, &tomoyo_pattern_list); 394cd7bec6aSTetsuo Handa new_entry = NULL; 395b69a54eeSKentaro Takeda error = 0; 396b69a54eeSKentaro Takeda out: 397f737d95dSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 398cd7bec6aSTetsuo Handa kfree(new_entry); 399b69a54eeSKentaro Takeda return error; 400b69a54eeSKentaro Takeda } 401b69a54eeSKentaro Takeda 402b69a54eeSKentaro Takeda /** 403b69a54eeSKentaro Takeda * tomoyo_get_file_pattern - Get patterned pathname. 404b69a54eeSKentaro Takeda * 405b69a54eeSKentaro Takeda * @filename: The filename to find patterned pathname. 406b69a54eeSKentaro Takeda * 407b69a54eeSKentaro Takeda * Returns pointer to pathname pattern if matched, @filename otherwise. 408fdb8ebb7STetsuo Handa * 409fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 410b69a54eeSKentaro Takeda */ 411b69a54eeSKentaro Takeda static const struct tomoyo_path_info * 412b69a54eeSKentaro Takeda tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) 413b69a54eeSKentaro Takeda { 414b69a54eeSKentaro Takeda struct tomoyo_pattern_entry *ptr; 415b69a54eeSKentaro Takeda const struct tomoyo_path_info *pattern = NULL; 416b69a54eeSKentaro Takeda 417fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { 418b69a54eeSKentaro Takeda if (ptr->is_deleted) 419b69a54eeSKentaro Takeda continue; 420b69a54eeSKentaro Takeda if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) 421b69a54eeSKentaro Takeda continue; 422b69a54eeSKentaro Takeda pattern = ptr->pattern; 423b69a54eeSKentaro Takeda if (tomoyo_strendswith(pattern->name, "/\\*")) { 424b69a54eeSKentaro Takeda /* Do nothing. Try to find the better match. */ 425b69a54eeSKentaro Takeda } else { 426b69a54eeSKentaro Takeda /* This would be the better match. Use this. */ 427b69a54eeSKentaro Takeda break; 428b69a54eeSKentaro Takeda } 429b69a54eeSKentaro Takeda } 430b69a54eeSKentaro Takeda if (pattern) 431b69a54eeSKentaro Takeda filename = pattern; 432b69a54eeSKentaro Takeda return filename; 433b69a54eeSKentaro Takeda } 434b69a54eeSKentaro Takeda 435b69a54eeSKentaro Takeda /** 436b69a54eeSKentaro Takeda * tomoyo_write_pattern_policy - Write "struct tomoyo_pattern_entry" list. 437b69a54eeSKentaro Takeda * 438b69a54eeSKentaro Takeda * @data: String to parse. 439b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 440b69a54eeSKentaro Takeda * 441b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 442fdb8ebb7STetsuo Handa * 443fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 444b69a54eeSKentaro Takeda */ 445b69a54eeSKentaro Takeda int tomoyo_write_pattern_policy(char *data, const bool is_delete) 446b69a54eeSKentaro Takeda { 447b69a54eeSKentaro Takeda return tomoyo_update_file_pattern_entry(data, is_delete); 448b69a54eeSKentaro Takeda } 449b69a54eeSKentaro Takeda 450b69a54eeSKentaro Takeda /** 451b69a54eeSKentaro Takeda * tomoyo_read_file_pattern - Read "struct tomoyo_pattern_entry" list. 452b69a54eeSKentaro Takeda * 453b69a54eeSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 454b69a54eeSKentaro Takeda * 455b69a54eeSKentaro Takeda * Returns true on success, false otherwise. 456fdb8ebb7STetsuo Handa * 457fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 458b69a54eeSKentaro Takeda */ 459b69a54eeSKentaro Takeda bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) 460b69a54eeSKentaro Takeda { 461b69a54eeSKentaro Takeda struct list_head *pos; 462b69a54eeSKentaro Takeda bool done = true; 463b69a54eeSKentaro Takeda 464b69a54eeSKentaro Takeda list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) { 465b69a54eeSKentaro Takeda struct tomoyo_pattern_entry *ptr; 466b69a54eeSKentaro Takeda ptr = list_entry(pos, struct tomoyo_pattern_entry, list); 467b69a54eeSKentaro Takeda if (ptr->is_deleted) 468b69a54eeSKentaro Takeda continue; 4697d2948b1STetsuo Handa done = tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN 4707d2948b1STetsuo Handa "%s\n", ptr->pattern->name); 4717d2948b1STetsuo Handa if (!done) 472b69a54eeSKentaro Takeda break; 473b69a54eeSKentaro Takeda } 474b69a54eeSKentaro Takeda return done; 475b69a54eeSKentaro Takeda } 476b69a54eeSKentaro Takeda 477c3fa109aSTetsuo Handa /* 478c3fa109aSTetsuo Handa * tomoyo_no_rewrite_list is used for holding list of pathnames which are by 479c3fa109aSTetsuo Handa * default forbidden to modify already written content of a file. 480c3fa109aSTetsuo Handa * 481c3fa109aSTetsuo Handa * An entry is added by 482c3fa109aSTetsuo Handa * 483c3fa109aSTetsuo Handa * # echo 'deny_rewrite /var/log/messages' > \ 484c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 485c3fa109aSTetsuo Handa * 486c3fa109aSTetsuo Handa * and is deleted by 487c3fa109aSTetsuo Handa * 488c3fa109aSTetsuo Handa * # echo 'delete deny_rewrite /var/log/messages' > \ 489c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 490c3fa109aSTetsuo Handa * 491c3fa109aSTetsuo Handa * and all entries are retrieved by 492c3fa109aSTetsuo Handa * 493c3fa109aSTetsuo Handa * # grep ^deny_rewrite /sys/kernel/security/tomoyo/exception_policy 494c3fa109aSTetsuo Handa * 495c3fa109aSTetsuo Handa * In the example above, if a process requested to rewrite /var/log/messages , 496c3fa109aSTetsuo Handa * the process can't rewrite unless the domain which that process belongs to 497c3fa109aSTetsuo Handa * has "allow_rewrite /var/log/messages" entry. 498c3fa109aSTetsuo Handa * 499c3fa109aSTetsuo Handa * It is not a desirable behavior that we have to add "\040(deleted)" suffix 500c3fa109aSTetsuo Handa * when we want to allow rewriting already unlink()ed file. As of now, 501c3fa109aSTetsuo Handa * LSM version of TOMOYO is using __d_path() for calculating pathname. 502c3fa109aSTetsuo Handa * Non LSM version of TOMOYO is using its own function which doesn't append 503c3fa109aSTetsuo Handa * " (deleted)" suffix if the file is already unlink()ed; so that we don't 504c3fa109aSTetsuo Handa * need to worry whether the file is already unlink()ed or not. 505c3fa109aSTetsuo Handa */ 506b69a54eeSKentaro Takeda static LIST_HEAD(tomoyo_no_rewrite_list); 507b69a54eeSKentaro Takeda 508b69a54eeSKentaro Takeda /** 509b69a54eeSKentaro Takeda * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list. 510b69a54eeSKentaro Takeda * 511b69a54eeSKentaro Takeda * @pattern: Pathname pattern that are not rewritable by default. 512b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 513b69a54eeSKentaro Takeda * 514b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 515fdb8ebb7STetsuo Handa * 516fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 517b69a54eeSKentaro Takeda */ 518b69a54eeSKentaro Takeda static int tomoyo_update_no_rewrite_entry(const char *pattern, 519b69a54eeSKentaro Takeda const bool is_delete) 520b69a54eeSKentaro Takeda { 521b69a54eeSKentaro Takeda struct tomoyo_no_rewrite_entry *new_entry, *ptr; 522b69a54eeSKentaro Takeda const struct tomoyo_path_info *saved_pattern; 523b69a54eeSKentaro Takeda int error = -ENOMEM; 524b69a54eeSKentaro Takeda 525b69a54eeSKentaro Takeda if (!tomoyo_is_correct_path(pattern, 0, 0, 0, __func__)) 526b69a54eeSKentaro Takeda return -EINVAL; 527b69a54eeSKentaro Takeda saved_pattern = tomoyo_save_name(pattern); 528b69a54eeSKentaro Takeda if (!saved_pattern) 529b69a54eeSKentaro Takeda return -ENOMEM; 530cd7bec6aSTetsuo Handa new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL); 531f737d95dSTetsuo Handa mutex_lock(&tomoyo_policy_lock); 532fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { 533b69a54eeSKentaro Takeda if (ptr->pattern != saved_pattern) 534b69a54eeSKentaro Takeda continue; 535b69a54eeSKentaro Takeda ptr->is_deleted = is_delete; 536b69a54eeSKentaro Takeda error = 0; 537b69a54eeSKentaro Takeda goto out; 538b69a54eeSKentaro Takeda } 539b69a54eeSKentaro Takeda if (is_delete) { 540b69a54eeSKentaro Takeda error = -ENOENT; 541b69a54eeSKentaro Takeda goto out; 542b69a54eeSKentaro Takeda } 543cd7bec6aSTetsuo Handa if (!tomoyo_memory_ok(new_entry)) 544b69a54eeSKentaro Takeda goto out; 545b69a54eeSKentaro Takeda new_entry->pattern = saved_pattern; 546fdb8ebb7STetsuo Handa list_add_tail_rcu(&new_entry->list, &tomoyo_no_rewrite_list); 547cd7bec6aSTetsuo Handa new_entry = NULL; 548b69a54eeSKentaro Takeda error = 0; 549b69a54eeSKentaro Takeda out: 550f737d95dSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 551cd7bec6aSTetsuo Handa kfree(new_entry); 552b69a54eeSKentaro Takeda return error; 553b69a54eeSKentaro Takeda } 554b69a54eeSKentaro Takeda 555b69a54eeSKentaro Takeda /** 556b69a54eeSKentaro Takeda * tomoyo_is_no_rewrite_file - Check if the given pathname is not permitted to be rewrited. 557b69a54eeSKentaro Takeda * 558b69a54eeSKentaro Takeda * @filename: Filename to check. 559b69a54eeSKentaro Takeda * 560b69a54eeSKentaro Takeda * Returns true if @filename is specified by "deny_rewrite" directive, 561b69a54eeSKentaro Takeda * false otherwise. 562fdb8ebb7STetsuo Handa * 563fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 564b69a54eeSKentaro Takeda */ 565b69a54eeSKentaro Takeda static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) 566b69a54eeSKentaro Takeda { 567b69a54eeSKentaro Takeda struct tomoyo_no_rewrite_entry *ptr; 568b69a54eeSKentaro Takeda bool found = false; 569b69a54eeSKentaro Takeda 570fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { 571b69a54eeSKentaro Takeda if (ptr->is_deleted) 572b69a54eeSKentaro Takeda continue; 573b69a54eeSKentaro Takeda if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) 574b69a54eeSKentaro Takeda continue; 575b69a54eeSKentaro Takeda found = true; 576b69a54eeSKentaro Takeda break; 577b69a54eeSKentaro Takeda } 578b69a54eeSKentaro Takeda return found; 579b69a54eeSKentaro Takeda } 580b69a54eeSKentaro Takeda 581b69a54eeSKentaro Takeda /** 582b69a54eeSKentaro Takeda * tomoyo_write_no_rewrite_policy - Write "struct tomoyo_no_rewrite_entry" list. 583b69a54eeSKentaro Takeda * 584b69a54eeSKentaro Takeda * @data: String to parse. 585b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 586b69a54eeSKentaro Takeda * 587b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 588fdb8ebb7STetsuo Handa * 589fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 590b69a54eeSKentaro Takeda */ 591b69a54eeSKentaro Takeda int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete) 592b69a54eeSKentaro Takeda { 593b69a54eeSKentaro Takeda return tomoyo_update_no_rewrite_entry(data, is_delete); 594b69a54eeSKentaro Takeda } 595b69a54eeSKentaro Takeda 596b69a54eeSKentaro Takeda /** 597b69a54eeSKentaro Takeda * tomoyo_read_no_rewrite_policy - Read "struct tomoyo_no_rewrite_entry" list. 598b69a54eeSKentaro Takeda * 599b69a54eeSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 600b69a54eeSKentaro Takeda * 601b69a54eeSKentaro Takeda * Returns true on success, false otherwise. 602fdb8ebb7STetsuo Handa * 603fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 604b69a54eeSKentaro Takeda */ 605b69a54eeSKentaro Takeda bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) 606b69a54eeSKentaro Takeda { 607b69a54eeSKentaro Takeda struct list_head *pos; 608b69a54eeSKentaro Takeda bool done = true; 609b69a54eeSKentaro Takeda 610b69a54eeSKentaro Takeda list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) { 611b69a54eeSKentaro Takeda struct tomoyo_no_rewrite_entry *ptr; 612b69a54eeSKentaro Takeda ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list); 613b69a54eeSKentaro Takeda if (ptr->is_deleted) 614b69a54eeSKentaro Takeda continue; 6157d2948b1STetsuo Handa done = tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE 6167d2948b1STetsuo Handa "%s\n", ptr->pattern->name); 6177d2948b1STetsuo Handa if (!done) 618b69a54eeSKentaro Takeda break; 619b69a54eeSKentaro Takeda } 620b69a54eeSKentaro Takeda return done; 621b69a54eeSKentaro Takeda } 622b69a54eeSKentaro Takeda 623b69a54eeSKentaro Takeda /** 624b69a54eeSKentaro Takeda * tomoyo_update_file_acl - Update file's read/write/execute ACL. 625b69a54eeSKentaro Takeda * 626b69a54eeSKentaro Takeda * @filename: Filename. 627b69a54eeSKentaro Takeda * @perm: Permission (between 1 to 7). 628b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 629b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 630b69a54eeSKentaro Takeda * 631b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 632b69a54eeSKentaro Takeda * 633b69a54eeSKentaro Takeda * This is legacy support interface for older policy syntax. 634b69a54eeSKentaro Takeda * Current policy syntax uses "allow_read/write" instead of "6", 635b69a54eeSKentaro Takeda * "allow_read" instead of "4", "allow_write" instead of "2", 636b69a54eeSKentaro Takeda * "allow_execute" instead of "1". 637fdb8ebb7STetsuo Handa * 638fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 639b69a54eeSKentaro Takeda */ 640b69a54eeSKentaro Takeda static int tomoyo_update_file_acl(const char *filename, u8 perm, 641b69a54eeSKentaro Takeda struct tomoyo_domain_info * const domain, 642b69a54eeSKentaro Takeda const bool is_delete) 643b69a54eeSKentaro Takeda { 644b69a54eeSKentaro Takeda if (perm > 7 || !perm) { 645b69a54eeSKentaro Takeda printk(KERN_DEBUG "%s: Invalid permission '%d %s'\n", 646b69a54eeSKentaro Takeda __func__, perm, filename); 647b69a54eeSKentaro Takeda return -EINVAL; 648b69a54eeSKentaro Takeda } 649b69a54eeSKentaro Takeda if (filename[0] != '@' && tomoyo_strendswith(filename, "/")) 650b69a54eeSKentaro Takeda /* 651b69a54eeSKentaro Takeda * Only 'allow_mkdir' and 'allow_rmdir' are valid for 652b69a54eeSKentaro Takeda * directory permissions. 653b69a54eeSKentaro Takeda */ 654b69a54eeSKentaro Takeda return 0; 655b69a54eeSKentaro Takeda if (perm & 4) 656b69a54eeSKentaro Takeda tomoyo_update_single_path_acl(TOMOYO_TYPE_READ_ACL, filename, 657b69a54eeSKentaro Takeda domain, is_delete); 658b69a54eeSKentaro Takeda if (perm & 2) 659b69a54eeSKentaro Takeda tomoyo_update_single_path_acl(TOMOYO_TYPE_WRITE_ACL, filename, 660b69a54eeSKentaro Takeda domain, is_delete); 661b69a54eeSKentaro Takeda if (perm & 1) 662b69a54eeSKentaro Takeda tomoyo_update_single_path_acl(TOMOYO_TYPE_EXECUTE_ACL, 663b69a54eeSKentaro Takeda filename, domain, is_delete); 664b69a54eeSKentaro Takeda return 0; 665b69a54eeSKentaro Takeda } 666b69a54eeSKentaro Takeda 667b69a54eeSKentaro Takeda /** 668b69a54eeSKentaro Takeda * tomoyo_check_single_path_acl2 - Check permission for single path operation. 669b69a54eeSKentaro Takeda * 670b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 671b69a54eeSKentaro Takeda * @filename: Filename to check. 672b69a54eeSKentaro Takeda * @perm: Permission. 673b69a54eeSKentaro Takeda * @may_use_pattern: True if patterned ACL is permitted. 674b69a54eeSKentaro Takeda * 675b69a54eeSKentaro Takeda * Returns 0 on success, -EPERM otherwise. 676fdb8ebb7STetsuo Handa * 677fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 678b69a54eeSKentaro Takeda */ 679b69a54eeSKentaro Takeda static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info * 680b69a54eeSKentaro Takeda domain, 681b69a54eeSKentaro Takeda const struct tomoyo_path_info * 682b69a54eeSKentaro Takeda filename, 683937bf613STetsuo Handa const u32 perm, 684b69a54eeSKentaro Takeda const bool may_use_pattern) 685b69a54eeSKentaro Takeda { 686b69a54eeSKentaro Takeda struct tomoyo_acl_info *ptr; 687b69a54eeSKentaro Takeda int error = -EPERM; 688b69a54eeSKentaro Takeda 689fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 690b69a54eeSKentaro Takeda struct tomoyo_single_path_acl_record *acl; 691b69a54eeSKentaro Takeda if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) 692b69a54eeSKentaro Takeda continue; 693b69a54eeSKentaro Takeda acl = container_of(ptr, struct tomoyo_single_path_acl_record, 694b69a54eeSKentaro Takeda head); 695937bf613STetsuo Handa if (perm <= 0xFFFF) { 696b69a54eeSKentaro Takeda if (!(acl->perm & perm)) 697b69a54eeSKentaro Takeda continue; 698937bf613STetsuo Handa } else { 699937bf613STetsuo Handa if (!(acl->perm_high & (perm >> 16))) 700937bf613STetsuo Handa continue; 701937bf613STetsuo Handa } 702b69a54eeSKentaro Takeda if (may_use_pattern || !acl->filename->is_patterned) { 703b69a54eeSKentaro Takeda if (!tomoyo_path_matches_pattern(filename, 704b69a54eeSKentaro Takeda acl->filename)) 705b69a54eeSKentaro Takeda continue; 706b69a54eeSKentaro Takeda } else { 707b69a54eeSKentaro Takeda continue; 708b69a54eeSKentaro Takeda } 709b69a54eeSKentaro Takeda error = 0; 710b69a54eeSKentaro Takeda break; 711b69a54eeSKentaro Takeda } 712b69a54eeSKentaro Takeda return error; 713b69a54eeSKentaro Takeda } 714b69a54eeSKentaro Takeda 715b69a54eeSKentaro Takeda /** 716b69a54eeSKentaro Takeda * tomoyo_check_file_acl - Check permission for opening files. 717b69a54eeSKentaro Takeda * 718b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 719b69a54eeSKentaro Takeda * @filename: Filename to check. 720b69a54eeSKentaro Takeda * @operation: Mode ("read" or "write" or "read/write" or "execute"). 721b69a54eeSKentaro Takeda * 722b69a54eeSKentaro Takeda * Returns 0 on success, -EPERM otherwise. 723fdb8ebb7STetsuo Handa * 724fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 725b69a54eeSKentaro Takeda */ 726b69a54eeSKentaro Takeda static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain, 727b69a54eeSKentaro Takeda const struct tomoyo_path_info *filename, 728b69a54eeSKentaro Takeda const u8 operation) 729b69a54eeSKentaro Takeda { 730937bf613STetsuo Handa u32 perm = 0; 731b69a54eeSKentaro Takeda 732b69a54eeSKentaro Takeda if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) 733b69a54eeSKentaro Takeda return 0; 734b69a54eeSKentaro Takeda if (operation == 6) 735b69a54eeSKentaro Takeda perm = 1 << TOMOYO_TYPE_READ_WRITE_ACL; 736b69a54eeSKentaro Takeda else if (operation == 4) 737b69a54eeSKentaro Takeda perm = 1 << TOMOYO_TYPE_READ_ACL; 738b69a54eeSKentaro Takeda else if (operation == 2) 739b69a54eeSKentaro Takeda perm = 1 << TOMOYO_TYPE_WRITE_ACL; 740b69a54eeSKentaro Takeda else if (operation == 1) 741b69a54eeSKentaro Takeda perm = 1 << TOMOYO_TYPE_EXECUTE_ACL; 742b69a54eeSKentaro Takeda else 743b69a54eeSKentaro Takeda BUG(); 744b69a54eeSKentaro Takeda return tomoyo_check_single_path_acl2(domain, filename, perm, 745b69a54eeSKentaro Takeda operation != 1); 746b69a54eeSKentaro Takeda } 747b69a54eeSKentaro Takeda 748b69a54eeSKentaro Takeda /** 749b69a54eeSKentaro Takeda * tomoyo_check_file_perm2 - Check permission for opening files. 750b69a54eeSKentaro Takeda * 751b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 752b69a54eeSKentaro Takeda * @filename: Filename to check. 753b69a54eeSKentaro Takeda * @perm: Mode ("read" or "write" or "read/write" or "execute"). 754b69a54eeSKentaro Takeda * @operation: Operation name passed used for verbose mode. 755b69a54eeSKentaro Takeda * @mode: Access control mode. 756b69a54eeSKentaro Takeda * 757b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 758fdb8ebb7STetsuo Handa * 759fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 760b69a54eeSKentaro Takeda */ 761b69a54eeSKentaro Takeda static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain, 762b69a54eeSKentaro Takeda const struct tomoyo_path_info *filename, 763b69a54eeSKentaro Takeda const u8 perm, const char *operation, 764b69a54eeSKentaro Takeda const u8 mode) 765b69a54eeSKentaro Takeda { 766b69a54eeSKentaro Takeda const bool is_enforce = (mode == 3); 767b69a54eeSKentaro Takeda const char *msg = "<unknown>"; 768b69a54eeSKentaro Takeda int error = 0; 769b69a54eeSKentaro Takeda 770b69a54eeSKentaro Takeda if (!filename) 771b69a54eeSKentaro Takeda return 0; 772b69a54eeSKentaro Takeda error = tomoyo_check_file_acl(domain, filename, perm); 773b69a54eeSKentaro Takeda if (error && perm == 4 && 774b69a54eeSKentaro Takeda (domain->flags & TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ) == 0 775b69a54eeSKentaro Takeda && tomoyo_is_globally_readable_file(filename)) 776b69a54eeSKentaro Takeda error = 0; 777b69a54eeSKentaro Takeda if (perm == 6) 778b69a54eeSKentaro Takeda msg = tomoyo_sp2keyword(TOMOYO_TYPE_READ_WRITE_ACL); 779b69a54eeSKentaro Takeda else if (perm == 4) 780b69a54eeSKentaro Takeda msg = tomoyo_sp2keyword(TOMOYO_TYPE_READ_ACL); 781b69a54eeSKentaro Takeda else if (perm == 2) 782b69a54eeSKentaro Takeda msg = tomoyo_sp2keyword(TOMOYO_TYPE_WRITE_ACL); 783b69a54eeSKentaro Takeda else if (perm == 1) 784b69a54eeSKentaro Takeda msg = tomoyo_sp2keyword(TOMOYO_TYPE_EXECUTE_ACL); 785b69a54eeSKentaro Takeda else 786b69a54eeSKentaro Takeda BUG(); 787b69a54eeSKentaro Takeda if (!error) 788b69a54eeSKentaro Takeda return 0; 789b69a54eeSKentaro Takeda if (tomoyo_verbose_mode(domain)) 790b69a54eeSKentaro Takeda printk(KERN_WARNING "TOMOYO-%s: Access '%s(%s) %s' denied " 791b69a54eeSKentaro Takeda "for %s\n", tomoyo_get_msg(is_enforce), msg, operation, 792b69a54eeSKentaro Takeda filename->name, tomoyo_get_last_name(domain)); 793b69a54eeSKentaro Takeda if (is_enforce) 794b69a54eeSKentaro Takeda return error; 795b69a54eeSKentaro Takeda if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { 796b69a54eeSKentaro Takeda /* Don't use patterns for execute permission. */ 797b69a54eeSKentaro Takeda const struct tomoyo_path_info *patterned_file = (perm != 1) ? 798b69a54eeSKentaro Takeda tomoyo_get_file_pattern(filename) : filename; 799b69a54eeSKentaro Takeda tomoyo_update_file_acl(patterned_file->name, perm, 800b69a54eeSKentaro Takeda domain, false); 801b69a54eeSKentaro Takeda } 802b69a54eeSKentaro Takeda return 0; 803b69a54eeSKentaro Takeda } 804b69a54eeSKentaro Takeda 805b69a54eeSKentaro Takeda /** 806b69a54eeSKentaro Takeda * tomoyo_write_file_policy - Update file related list. 807b69a54eeSKentaro Takeda * 808b69a54eeSKentaro Takeda * @data: String to parse. 809b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 810b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 811b69a54eeSKentaro Takeda * 812b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 813fdb8ebb7STetsuo Handa * 814fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 815b69a54eeSKentaro Takeda */ 816b69a54eeSKentaro Takeda int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, 817b69a54eeSKentaro Takeda const bool is_delete) 818b69a54eeSKentaro Takeda { 819b69a54eeSKentaro Takeda char *filename = strchr(data, ' '); 820b69a54eeSKentaro Takeda char *filename2; 821b69a54eeSKentaro Takeda unsigned int perm; 822b69a54eeSKentaro Takeda u8 type; 823b69a54eeSKentaro Takeda 824b69a54eeSKentaro Takeda if (!filename) 825b69a54eeSKentaro Takeda return -EINVAL; 826b69a54eeSKentaro Takeda *filename++ = '\0'; 827b69a54eeSKentaro Takeda if (sscanf(data, "%u", &perm) == 1) 828b69a54eeSKentaro Takeda return tomoyo_update_file_acl(filename, (u8) perm, domain, 829b69a54eeSKentaro Takeda is_delete); 830b69a54eeSKentaro Takeda if (strncmp(data, "allow_", 6)) 831b69a54eeSKentaro Takeda goto out; 832b69a54eeSKentaro Takeda data += 6; 833b69a54eeSKentaro Takeda for (type = 0; type < TOMOYO_MAX_SINGLE_PATH_OPERATION; type++) { 834b69a54eeSKentaro Takeda if (strcmp(data, tomoyo_sp_keyword[type])) 835b69a54eeSKentaro Takeda continue; 836b69a54eeSKentaro Takeda return tomoyo_update_single_path_acl(type, filename, 837b69a54eeSKentaro Takeda domain, is_delete); 838b69a54eeSKentaro Takeda } 839b69a54eeSKentaro Takeda filename2 = strchr(filename, ' '); 840b69a54eeSKentaro Takeda if (!filename2) 841b69a54eeSKentaro Takeda goto out; 842b69a54eeSKentaro Takeda *filename2++ = '\0'; 843b69a54eeSKentaro Takeda for (type = 0; type < TOMOYO_MAX_DOUBLE_PATH_OPERATION; type++) { 844b69a54eeSKentaro Takeda if (strcmp(data, tomoyo_dp_keyword[type])) 845b69a54eeSKentaro Takeda continue; 846b69a54eeSKentaro Takeda return tomoyo_update_double_path_acl(type, filename, filename2, 847b69a54eeSKentaro Takeda domain, is_delete); 848b69a54eeSKentaro Takeda } 849b69a54eeSKentaro Takeda out: 850b69a54eeSKentaro Takeda return -EINVAL; 851b69a54eeSKentaro Takeda } 852b69a54eeSKentaro Takeda 853b69a54eeSKentaro Takeda /** 854b69a54eeSKentaro Takeda * tomoyo_update_single_path_acl - Update "struct tomoyo_single_path_acl_record" list. 855b69a54eeSKentaro Takeda * 856b69a54eeSKentaro Takeda * @type: Type of operation. 857b69a54eeSKentaro Takeda * @filename: Filename. 858b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 859b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 860b69a54eeSKentaro Takeda * 861b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 862fdb8ebb7STetsuo Handa * 863fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 864b69a54eeSKentaro Takeda */ 865b69a54eeSKentaro Takeda static int tomoyo_update_single_path_acl(const u8 type, const char *filename, 866b69a54eeSKentaro Takeda struct tomoyo_domain_info * 867b69a54eeSKentaro Takeda const domain, const bool is_delete) 868b69a54eeSKentaro Takeda { 869937bf613STetsuo Handa static const u32 rw_mask = 870b69a54eeSKentaro Takeda (1 << TOMOYO_TYPE_READ_ACL) | (1 << TOMOYO_TYPE_WRITE_ACL); 871b69a54eeSKentaro Takeda const struct tomoyo_path_info *saved_filename; 872b69a54eeSKentaro Takeda struct tomoyo_acl_info *ptr; 873b69a54eeSKentaro Takeda struct tomoyo_single_path_acl_record *acl; 874b69a54eeSKentaro Takeda int error = -ENOMEM; 875937bf613STetsuo Handa const u32 perm = 1 << type; 876b69a54eeSKentaro Takeda 877b69a54eeSKentaro Takeda if (!domain) 878b69a54eeSKentaro Takeda return -EINVAL; 879b69a54eeSKentaro Takeda if (!tomoyo_is_correct_path(filename, 0, 0, 0, __func__)) 880b69a54eeSKentaro Takeda return -EINVAL; 881b69a54eeSKentaro Takeda saved_filename = tomoyo_save_name(filename); 882b69a54eeSKentaro Takeda if (!saved_filename) 883b69a54eeSKentaro Takeda return -ENOMEM; 884f737d95dSTetsuo Handa mutex_lock(&tomoyo_policy_lock); 885b69a54eeSKentaro Takeda if (is_delete) 886b69a54eeSKentaro Takeda goto delete; 887fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 888b69a54eeSKentaro Takeda if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) 889b69a54eeSKentaro Takeda continue; 890b69a54eeSKentaro Takeda acl = container_of(ptr, struct tomoyo_single_path_acl_record, 891b69a54eeSKentaro Takeda head); 892b69a54eeSKentaro Takeda if (acl->filename != saved_filename) 893b69a54eeSKentaro Takeda continue; 894b69a54eeSKentaro Takeda /* Special case. Clear all bits if marked as deleted. */ 895b69a54eeSKentaro Takeda if (ptr->type & TOMOYO_ACL_DELETED) 896b69a54eeSKentaro Takeda acl->perm = 0; 897937bf613STetsuo Handa if (perm <= 0xFFFF) 898b69a54eeSKentaro Takeda acl->perm |= perm; 899937bf613STetsuo Handa else 900937bf613STetsuo Handa acl->perm_high |= (perm >> 16); 901b69a54eeSKentaro Takeda if ((acl->perm & rw_mask) == rw_mask) 902b69a54eeSKentaro Takeda acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE_ACL; 903b69a54eeSKentaro Takeda else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL)) 904b69a54eeSKentaro Takeda acl->perm |= rw_mask; 905b69a54eeSKentaro Takeda ptr->type &= ~TOMOYO_ACL_DELETED; 906b69a54eeSKentaro Takeda error = 0; 907b69a54eeSKentaro Takeda goto out; 908b69a54eeSKentaro Takeda } 909b69a54eeSKentaro Takeda /* Not found. Append it to the tail. */ 910cd7bec6aSTetsuo Handa acl = kmalloc(sizeof(*acl), GFP_KERNEL); 911cd7bec6aSTetsuo Handa if (!tomoyo_memory_ok(acl)) { 912cd7bec6aSTetsuo Handa kfree(acl); 913cd7bec6aSTetsuo Handa acl = NULL; 914b69a54eeSKentaro Takeda goto out; 915cd7bec6aSTetsuo Handa } 916cd7bec6aSTetsuo Handa acl->head.type = TOMOYO_TYPE_SINGLE_PATH_ACL; 917937bf613STetsuo Handa if (perm <= 0xFFFF) 918b69a54eeSKentaro Takeda acl->perm = perm; 919937bf613STetsuo Handa else 920937bf613STetsuo Handa acl->perm_high = (perm >> 16); 921b69a54eeSKentaro Takeda if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL)) 922b69a54eeSKentaro Takeda acl->perm |= rw_mask; 923b69a54eeSKentaro Takeda acl->filename = saved_filename; 924fdb8ebb7STetsuo Handa list_add_tail_rcu(&acl->head.list, &domain->acl_info_list); 925b69a54eeSKentaro Takeda error = 0; 926b69a54eeSKentaro Takeda goto out; 927b69a54eeSKentaro Takeda delete: 928b69a54eeSKentaro Takeda error = -ENOENT; 929fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 930b69a54eeSKentaro Takeda if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) 931b69a54eeSKentaro Takeda continue; 932b69a54eeSKentaro Takeda acl = container_of(ptr, struct tomoyo_single_path_acl_record, 933b69a54eeSKentaro Takeda head); 934b69a54eeSKentaro Takeda if (acl->filename != saved_filename) 935b69a54eeSKentaro Takeda continue; 936937bf613STetsuo Handa if (perm <= 0xFFFF) 937b69a54eeSKentaro Takeda acl->perm &= ~perm; 938937bf613STetsuo Handa else 939937bf613STetsuo Handa acl->perm_high &= ~(perm >> 16); 940b69a54eeSKentaro Takeda if ((acl->perm & rw_mask) != rw_mask) 941b69a54eeSKentaro Takeda acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE_ACL); 942b69a54eeSKentaro Takeda else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL))) 943b69a54eeSKentaro Takeda acl->perm &= ~rw_mask; 944937bf613STetsuo Handa if (!acl->perm && !acl->perm_high) 945b69a54eeSKentaro Takeda ptr->type |= TOMOYO_ACL_DELETED; 946b69a54eeSKentaro Takeda error = 0; 947b69a54eeSKentaro Takeda break; 948b69a54eeSKentaro Takeda } 949b69a54eeSKentaro Takeda out: 950f737d95dSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 951b69a54eeSKentaro Takeda return error; 952b69a54eeSKentaro Takeda } 953b69a54eeSKentaro Takeda 954b69a54eeSKentaro Takeda /** 955b69a54eeSKentaro Takeda * tomoyo_update_double_path_acl - Update "struct tomoyo_double_path_acl_record" list. 956b69a54eeSKentaro Takeda * 957b69a54eeSKentaro Takeda * @type: Type of operation. 958b69a54eeSKentaro Takeda * @filename1: First filename. 959b69a54eeSKentaro Takeda * @filename2: Second filename. 960b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 961b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 962b69a54eeSKentaro Takeda * 963b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 964fdb8ebb7STetsuo Handa * 965fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 966b69a54eeSKentaro Takeda */ 967b69a54eeSKentaro Takeda static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, 968b69a54eeSKentaro Takeda const char *filename2, 969b69a54eeSKentaro Takeda struct tomoyo_domain_info * 970b69a54eeSKentaro Takeda const domain, const bool is_delete) 971b69a54eeSKentaro Takeda { 972b69a54eeSKentaro Takeda const struct tomoyo_path_info *saved_filename1; 973b69a54eeSKentaro Takeda const struct tomoyo_path_info *saved_filename2; 974b69a54eeSKentaro Takeda struct tomoyo_acl_info *ptr; 975b69a54eeSKentaro Takeda struct tomoyo_double_path_acl_record *acl; 976b69a54eeSKentaro Takeda int error = -ENOMEM; 977b69a54eeSKentaro Takeda const u8 perm = 1 << type; 978b69a54eeSKentaro Takeda 979b69a54eeSKentaro Takeda if (!domain) 980b69a54eeSKentaro Takeda return -EINVAL; 981b69a54eeSKentaro Takeda if (!tomoyo_is_correct_path(filename1, 0, 0, 0, __func__) || 982b69a54eeSKentaro Takeda !tomoyo_is_correct_path(filename2, 0, 0, 0, __func__)) 983b69a54eeSKentaro Takeda return -EINVAL; 984b69a54eeSKentaro Takeda saved_filename1 = tomoyo_save_name(filename1); 985b69a54eeSKentaro Takeda saved_filename2 = tomoyo_save_name(filename2); 986b69a54eeSKentaro Takeda if (!saved_filename1 || !saved_filename2) 987b69a54eeSKentaro Takeda return -ENOMEM; 988f737d95dSTetsuo Handa mutex_lock(&tomoyo_policy_lock); 989b69a54eeSKentaro Takeda if (is_delete) 990b69a54eeSKentaro Takeda goto delete; 991fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 992b69a54eeSKentaro Takeda if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) 993b69a54eeSKentaro Takeda continue; 994b69a54eeSKentaro Takeda acl = container_of(ptr, struct tomoyo_double_path_acl_record, 995b69a54eeSKentaro Takeda head); 996b69a54eeSKentaro Takeda if (acl->filename1 != saved_filename1 || 997b69a54eeSKentaro Takeda acl->filename2 != saved_filename2) 998b69a54eeSKentaro Takeda continue; 999b69a54eeSKentaro Takeda /* Special case. Clear all bits if marked as deleted. */ 1000b69a54eeSKentaro Takeda if (ptr->type & TOMOYO_ACL_DELETED) 1001b69a54eeSKentaro Takeda acl->perm = 0; 1002b69a54eeSKentaro Takeda acl->perm |= perm; 1003b69a54eeSKentaro Takeda ptr->type &= ~TOMOYO_ACL_DELETED; 1004b69a54eeSKentaro Takeda error = 0; 1005b69a54eeSKentaro Takeda goto out; 1006b69a54eeSKentaro Takeda } 1007b69a54eeSKentaro Takeda /* Not found. Append it to the tail. */ 1008cd7bec6aSTetsuo Handa acl = kmalloc(sizeof(*acl), GFP_KERNEL); 1009cd7bec6aSTetsuo Handa if (!tomoyo_memory_ok(acl)) { 1010cd7bec6aSTetsuo Handa kfree(acl); 1011cd7bec6aSTetsuo Handa acl = NULL; 1012b69a54eeSKentaro Takeda goto out; 1013cd7bec6aSTetsuo Handa } 1014cd7bec6aSTetsuo Handa acl->head.type = TOMOYO_TYPE_DOUBLE_PATH_ACL; 1015b69a54eeSKentaro Takeda acl->perm = perm; 1016b69a54eeSKentaro Takeda acl->filename1 = saved_filename1; 1017b69a54eeSKentaro Takeda acl->filename2 = saved_filename2; 1018fdb8ebb7STetsuo Handa list_add_tail_rcu(&acl->head.list, &domain->acl_info_list); 1019b69a54eeSKentaro Takeda error = 0; 1020b69a54eeSKentaro Takeda goto out; 1021b69a54eeSKentaro Takeda delete: 1022b69a54eeSKentaro Takeda error = -ENOENT; 1023fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 1024b69a54eeSKentaro Takeda if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) 1025b69a54eeSKentaro Takeda continue; 1026b69a54eeSKentaro Takeda acl = container_of(ptr, struct tomoyo_double_path_acl_record, 1027b69a54eeSKentaro Takeda head); 1028b69a54eeSKentaro Takeda if (acl->filename1 != saved_filename1 || 1029b69a54eeSKentaro Takeda acl->filename2 != saved_filename2) 1030b69a54eeSKentaro Takeda continue; 1031b69a54eeSKentaro Takeda acl->perm &= ~perm; 1032b69a54eeSKentaro Takeda if (!acl->perm) 1033b69a54eeSKentaro Takeda ptr->type |= TOMOYO_ACL_DELETED; 1034b69a54eeSKentaro Takeda error = 0; 1035b69a54eeSKentaro Takeda break; 1036b69a54eeSKentaro Takeda } 1037b69a54eeSKentaro Takeda out: 1038f737d95dSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 1039b69a54eeSKentaro Takeda return error; 1040b69a54eeSKentaro Takeda } 1041b69a54eeSKentaro Takeda 1042b69a54eeSKentaro Takeda /** 1043b69a54eeSKentaro Takeda * tomoyo_check_single_path_acl - Check permission for single path operation. 1044b69a54eeSKentaro Takeda * 1045b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 1046b69a54eeSKentaro Takeda * @type: Type of operation. 1047b69a54eeSKentaro Takeda * @filename: Filename to check. 1048b69a54eeSKentaro Takeda * 1049b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1050fdb8ebb7STetsuo Handa * 1051fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 1052b69a54eeSKentaro Takeda */ 1053b69a54eeSKentaro Takeda static int tomoyo_check_single_path_acl(struct tomoyo_domain_info *domain, 1054b69a54eeSKentaro Takeda const u8 type, 1055b69a54eeSKentaro Takeda const struct tomoyo_path_info *filename) 1056b69a54eeSKentaro Takeda { 1057b69a54eeSKentaro Takeda if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) 1058b69a54eeSKentaro Takeda return 0; 1059b69a54eeSKentaro Takeda return tomoyo_check_single_path_acl2(domain, filename, 1 << type, 1); 1060b69a54eeSKentaro Takeda } 1061b69a54eeSKentaro Takeda 1062b69a54eeSKentaro Takeda /** 1063b69a54eeSKentaro Takeda * tomoyo_check_double_path_acl - Check permission for double path operation. 1064b69a54eeSKentaro Takeda * 1065b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 1066b69a54eeSKentaro Takeda * @type: Type of operation. 1067b69a54eeSKentaro Takeda * @filename1: First filename to check. 1068b69a54eeSKentaro Takeda * @filename2: Second filename to check. 1069b69a54eeSKentaro Takeda * 1070b69a54eeSKentaro Takeda * Returns 0 on success, -EPERM otherwise. 1071fdb8ebb7STetsuo Handa * 1072fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 1073b69a54eeSKentaro Takeda */ 1074b69a54eeSKentaro Takeda static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, 1075b69a54eeSKentaro Takeda const u8 type, 1076b69a54eeSKentaro Takeda const struct tomoyo_path_info * 1077b69a54eeSKentaro Takeda filename1, 1078b69a54eeSKentaro Takeda const struct tomoyo_path_info * 1079b69a54eeSKentaro Takeda filename2) 1080b69a54eeSKentaro Takeda { 1081b69a54eeSKentaro Takeda struct tomoyo_acl_info *ptr; 1082b69a54eeSKentaro Takeda const u8 perm = 1 << type; 1083b69a54eeSKentaro Takeda int error = -EPERM; 1084b69a54eeSKentaro Takeda 1085b69a54eeSKentaro Takeda if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) 1086b69a54eeSKentaro Takeda return 0; 1087fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 1088b69a54eeSKentaro Takeda struct tomoyo_double_path_acl_record *acl; 1089b69a54eeSKentaro Takeda if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) 1090b69a54eeSKentaro Takeda continue; 1091b69a54eeSKentaro Takeda acl = container_of(ptr, struct tomoyo_double_path_acl_record, 1092b69a54eeSKentaro Takeda head); 1093b69a54eeSKentaro Takeda if (!(acl->perm & perm)) 1094b69a54eeSKentaro Takeda continue; 1095b69a54eeSKentaro Takeda if (!tomoyo_path_matches_pattern(filename1, acl->filename1)) 1096b69a54eeSKentaro Takeda continue; 1097b69a54eeSKentaro Takeda if (!tomoyo_path_matches_pattern(filename2, acl->filename2)) 1098b69a54eeSKentaro Takeda continue; 1099b69a54eeSKentaro Takeda error = 0; 1100b69a54eeSKentaro Takeda break; 1101b69a54eeSKentaro Takeda } 1102b69a54eeSKentaro Takeda return error; 1103b69a54eeSKentaro Takeda } 1104b69a54eeSKentaro Takeda 1105b69a54eeSKentaro Takeda /** 1106b69a54eeSKentaro Takeda * tomoyo_check_single_path_permission2 - Check permission for single path operation. 1107b69a54eeSKentaro Takeda * 1108b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 1109b69a54eeSKentaro Takeda * @operation: Type of operation. 1110b69a54eeSKentaro Takeda * @filename: Filename to check. 1111b69a54eeSKentaro Takeda * @mode: Access control mode. 1112b69a54eeSKentaro Takeda * 1113b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1114fdb8ebb7STetsuo Handa * 1115fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 1116b69a54eeSKentaro Takeda */ 1117b69a54eeSKentaro Takeda static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * 1118b69a54eeSKentaro Takeda const domain, u8 operation, 1119b69a54eeSKentaro Takeda const struct tomoyo_path_info * 1120b69a54eeSKentaro Takeda filename, const u8 mode) 1121b69a54eeSKentaro Takeda { 1122b69a54eeSKentaro Takeda const char *msg; 1123b69a54eeSKentaro Takeda int error; 1124b69a54eeSKentaro Takeda const bool is_enforce = (mode == 3); 1125b69a54eeSKentaro Takeda 1126b69a54eeSKentaro Takeda if (!mode) 1127b69a54eeSKentaro Takeda return 0; 1128b69a54eeSKentaro Takeda next: 1129b69a54eeSKentaro Takeda error = tomoyo_check_single_path_acl(domain, operation, filename); 1130b69a54eeSKentaro Takeda msg = tomoyo_sp2keyword(operation); 1131b69a54eeSKentaro Takeda if (!error) 1132b69a54eeSKentaro Takeda goto ok; 1133b69a54eeSKentaro Takeda if (tomoyo_verbose_mode(domain)) 1134b69a54eeSKentaro Takeda printk(KERN_WARNING "TOMOYO-%s: Access '%s %s' denied for %s\n", 1135b69a54eeSKentaro Takeda tomoyo_get_msg(is_enforce), msg, filename->name, 1136b69a54eeSKentaro Takeda tomoyo_get_last_name(domain)); 1137b69a54eeSKentaro Takeda if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { 1138b69a54eeSKentaro Takeda const char *name = tomoyo_get_file_pattern(filename)->name; 1139b69a54eeSKentaro Takeda tomoyo_update_single_path_acl(operation, name, domain, false); 1140b69a54eeSKentaro Takeda } 1141b69a54eeSKentaro Takeda if (!is_enforce) 1142b69a54eeSKentaro Takeda error = 0; 1143b69a54eeSKentaro Takeda ok: 1144b69a54eeSKentaro Takeda /* 1145b69a54eeSKentaro Takeda * Since "allow_truncate" doesn't imply "allow_rewrite" permission, 1146b69a54eeSKentaro Takeda * we need to check "allow_rewrite" permission if the filename is 1147b69a54eeSKentaro Takeda * specified by "deny_rewrite" keyword. 1148b69a54eeSKentaro Takeda */ 1149b69a54eeSKentaro Takeda if (!error && operation == TOMOYO_TYPE_TRUNCATE_ACL && 1150b69a54eeSKentaro Takeda tomoyo_is_no_rewrite_file(filename)) { 1151b69a54eeSKentaro Takeda operation = TOMOYO_TYPE_REWRITE_ACL; 1152b69a54eeSKentaro Takeda goto next; 1153b69a54eeSKentaro Takeda } 1154b69a54eeSKentaro Takeda return error; 1155b69a54eeSKentaro Takeda } 1156b69a54eeSKentaro Takeda 1157b69a54eeSKentaro Takeda /** 1158b69a54eeSKentaro Takeda * tomoyo_check_exec_perm - Check permission for "execute". 1159b69a54eeSKentaro Takeda * 1160b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 1161b69a54eeSKentaro Takeda * @filename: Check permission for "execute". 1162b69a54eeSKentaro Takeda * 1163b69a54eeSKentaro Takeda * Returns 0 on success, negativevalue otherwise. 1164fdb8ebb7STetsuo Handa * 1165fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 1166b69a54eeSKentaro Takeda */ 1167b69a54eeSKentaro Takeda int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, 1168bcb86975STetsuo Handa const struct tomoyo_path_info *filename) 1169b69a54eeSKentaro Takeda { 1170b69a54eeSKentaro Takeda const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); 1171b69a54eeSKentaro Takeda 1172b69a54eeSKentaro Takeda if (!mode) 1173b69a54eeSKentaro Takeda return 0; 1174b69a54eeSKentaro Takeda return tomoyo_check_file_perm2(domain, filename, 1, "do_execve", mode); 1175b69a54eeSKentaro Takeda } 1176b69a54eeSKentaro Takeda 1177b69a54eeSKentaro Takeda /** 1178b69a54eeSKentaro Takeda * tomoyo_check_open_permission - Check permission for "read" and "write". 1179b69a54eeSKentaro Takeda * 1180b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 1181b69a54eeSKentaro Takeda * @path: Pointer to "struct path". 1182b69a54eeSKentaro Takeda * @flag: Flags for open(). 1183b69a54eeSKentaro Takeda * 1184b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1185b69a54eeSKentaro Takeda */ 1186b69a54eeSKentaro Takeda int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, 1187b69a54eeSKentaro Takeda struct path *path, const int flag) 1188b69a54eeSKentaro Takeda { 1189b69a54eeSKentaro Takeda const u8 acc_mode = ACC_MODE(flag); 1190b69a54eeSKentaro Takeda int error = -ENOMEM; 1191b69a54eeSKentaro Takeda struct tomoyo_path_info *buf; 1192b69a54eeSKentaro Takeda const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); 1193b69a54eeSKentaro Takeda const bool is_enforce = (mode == 3); 1194fdb8ebb7STetsuo Handa int idx; 1195b69a54eeSKentaro Takeda 1196b69a54eeSKentaro Takeda if (!mode || !path->mnt) 1197b69a54eeSKentaro Takeda return 0; 1198b69a54eeSKentaro Takeda if (acc_mode == 0) 1199b69a54eeSKentaro Takeda return 0; 1200b69a54eeSKentaro Takeda if (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode)) 1201b69a54eeSKentaro Takeda /* 1202b69a54eeSKentaro Takeda * I don't check directories here because mkdir() and rmdir() 1203b69a54eeSKentaro Takeda * don't call me. 1204b69a54eeSKentaro Takeda */ 1205b69a54eeSKentaro Takeda return 0; 1206fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 1207b69a54eeSKentaro Takeda buf = tomoyo_get_path(path); 1208b69a54eeSKentaro Takeda if (!buf) 1209b69a54eeSKentaro Takeda goto out; 1210b69a54eeSKentaro Takeda error = 0; 1211b69a54eeSKentaro Takeda /* 1212b69a54eeSKentaro Takeda * If the filename is specified by "deny_rewrite" keyword, 1213b69a54eeSKentaro Takeda * we need to check "allow_rewrite" permission when the filename is not 1214b69a54eeSKentaro Takeda * opened for append mode or the filename is truncated at open time. 1215b69a54eeSKentaro Takeda */ 1216b69a54eeSKentaro Takeda if ((acc_mode & MAY_WRITE) && 1217b69a54eeSKentaro Takeda ((flag & O_TRUNC) || !(flag & O_APPEND)) && 1218b69a54eeSKentaro Takeda (tomoyo_is_no_rewrite_file(buf))) { 1219b69a54eeSKentaro Takeda error = tomoyo_check_single_path_permission2(domain, 1220b69a54eeSKentaro Takeda TOMOYO_TYPE_REWRITE_ACL, 1221b69a54eeSKentaro Takeda buf, mode); 1222b69a54eeSKentaro Takeda } 1223b69a54eeSKentaro Takeda if (!error) 1224b69a54eeSKentaro Takeda error = tomoyo_check_file_perm2(domain, buf, acc_mode, "open", 1225b69a54eeSKentaro Takeda mode); 1226b69a54eeSKentaro Takeda if (!error && (flag & O_TRUNC)) 1227b69a54eeSKentaro Takeda error = tomoyo_check_single_path_permission2(domain, 1228b69a54eeSKentaro Takeda TOMOYO_TYPE_TRUNCATE_ACL, 1229b69a54eeSKentaro Takeda buf, mode); 1230b69a54eeSKentaro Takeda out: 12318e2d39a1STetsuo Handa kfree(buf); 1232fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 1233b69a54eeSKentaro Takeda if (!is_enforce) 1234b69a54eeSKentaro Takeda error = 0; 1235b69a54eeSKentaro Takeda return error; 1236b69a54eeSKentaro Takeda } 1237b69a54eeSKentaro Takeda 1238b69a54eeSKentaro Takeda /** 1239937bf613STetsuo Handa * tomoyo_check_1path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate", "symlink", "ioctl", "chmod", "chown", "chgrp", "chroot", "mount" and "unmount". 1240b69a54eeSKentaro Takeda * 1241b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 1242b69a54eeSKentaro Takeda * @operation: Type of operation. 1243b69a54eeSKentaro Takeda * @path: Pointer to "struct path". 1244b69a54eeSKentaro Takeda * 1245b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1246b69a54eeSKentaro Takeda */ 1247b69a54eeSKentaro Takeda int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, 1248b69a54eeSKentaro Takeda const u8 operation, struct path *path) 1249b69a54eeSKentaro Takeda { 1250b69a54eeSKentaro Takeda int error = -ENOMEM; 1251b69a54eeSKentaro Takeda struct tomoyo_path_info *buf; 1252b69a54eeSKentaro Takeda const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); 1253b69a54eeSKentaro Takeda const bool is_enforce = (mode == 3); 1254fdb8ebb7STetsuo Handa int idx; 1255b69a54eeSKentaro Takeda 1256b69a54eeSKentaro Takeda if (!mode || !path->mnt) 1257b69a54eeSKentaro Takeda return 0; 1258fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 1259b69a54eeSKentaro Takeda buf = tomoyo_get_path(path); 1260b69a54eeSKentaro Takeda if (!buf) 1261b69a54eeSKentaro Takeda goto out; 1262b69a54eeSKentaro Takeda switch (operation) { 1263b69a54eeSKentaro Takeda case TOMOYO_TYPE_MKDIR_ACL: 1264b69a54eeSKentaro Takeda case TOMOYO_TYPE_RMDIR_ACL: 1265937bf613STetsuo Handa case TOMOYO_TYPE_CHROOT_ACL: 1266b69a54eeSKentaro Takeda if (!buf->is_dir) { 1267b69a54eeSKentaro Takeda /* 1268b69a54eeSKentaro Takeda * tomoyo_get_path() reserves space for appending "/." 1269b69a54eeSKentaro Takeda */ 1270b69a54eeSKentaro Takeda strcat((char *) buf->name, "/"); 1271b69a54eeSKentaro Takeda tomoyo_fill_path_info(buf); 1272b69a54eeSKentaro Takeda } 1273b69a54eeSKentaro Takeda } 1274b69a54eeSKentaro Takeda error = tomoyo_check_single_path_permission2(domain, operation, buf, 1275b69a54eeSKentaro Takeda mode); 1276b69a54eeSKentaro Takeda out: 12778e2d39a1STetsuo Handa kfree(buf); 1278fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 1279b69a54eeSKentaro Takeda if (!is_enforce) 1280b69a54eeSKentaro Takeda error = 0; 1281b69a54eeSKentaro Takeda return error; 1282b69a54eeSKentaro Takeda } 1283b69a54eeSKentaro Takeda 1284b69a54eeSKentaro Takeda /** 1285b69a54eeSKentaro Takeda * tomoyo_check_rewrite_permission - Check permission for "rewrite". 1286b69a54eeSKentaro Takeda * 1287b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 1288b69a54eeSKentaro Takeda * @filp: Pointer to "struct file". 1289b69a54eeSKentaro Takeda * 1290b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1291b69a54eeSKentaro Takeda */ 1292b69a54eeSKentaro Takeda int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, 1293b69a54eeSKentaro Takeda struct file *filp) 1294b69a54eeSKentaro Takeda { 1295b69a54eeSKentaro Takeda int error = -ENOMEM; 1296b69a54eeSKentaro Takeda const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); 1297b69a54eeSKentaro Takeda const bool is_enforce = (mode == 3); 1298b69a54eeSKentaro Takeda struct tomoyo_path_info *buf; 1299fdb8ebb7STetsuo Handa int idx; 1300b69a54eeSKentaro Takeda 1301b69a54eeSKentaro Takeda if (!mode || !filp->f_path.mnt) 1302b69a54eeSKentaro Takeda return 0; 1303fdb8ebb7STetsuo Handa 1304fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 1305b69a54eeSKentaro Takeda buf = tomoyo_get_path(&filp->f_path); 1306b69a54eeSKentaro Takeda if (!buf) 1307b69a54eeSKentaro Takeda goto out; 1308b69a54eeSKentaro Takeda if (!tomoyo_is_no_rewrite_file(buf)) { 1309b69a54eeSKentaro Takeda error = 0; 1310b69a54eeSKentaro Takeda goto out; 1311b69a54eeSKentaro Takeda } 1312b69a54eeSKentaro Takeda error = tomoyo_check_single_path_permission2(domain, 1313b69a54eeSKentaro Takeda TOMOYO_TYPE_REWRITE_ACL, 1314b69a54eeSKentaro Takeda buf, mode); 1315b69a54eeSKentaro Takeda out: 13168e2d39a1STetsuo Handa kfree(buf); 1317fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 1318b69a54eeSKentaro Takeda if (!is_enforce) 1319b69a54eeSKentaro Takeda error = 0; 1320b69a54eeSKentaro Takeda return error; 1321b69a54eeSKentaro Takeda } 1322b69a54eeSKentaro Takeda 1323b69a54eeSKentaro Takeda /** 1324937bf613STetsuo Handa * tomoyo_check_2path_perm - Check permission for "rename", "link" and "pivot_root". 1325b69a54eeSKentaro Takeda * 1326b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 1327b69a54eeSKentaro Takeda * @operation: Type of operation. 1328b69a54eeSKentaro Takeda * @path1: Pointer to "struct path". 1329b69a54eeSKentaro Takeda * @path2: Pointer to "struct path". 1330b69a54eeSKentaro Takeda * 1331b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1332b69a54eeSKentaro Takeda */ 1333b69a54eeSKentaro Takeda int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain, 1334b69a54eeSKentaro Takeda const u8 operation, struct path *path1, 1335b69a54eeSKentaro Takeda struct path *path2) 1336b69a54eeSKentaro Takeda { 1337b69a54eeSKentaro Takeda int error = -ENOMEM; 1338b69a54eeSKentaro Takeda struct tomoyo_path_info *buf1, *buf2; 1339b69a54eeSKentaro Takeda const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); 1340b69a54eeSKentaro Takeda const bool is_enforce = (mode == 3); 1341b69a54eeSKentaro Takeda const char *msg; 1342fdb8ebb7STetsuo Handa int idx; 1343b69a54eeSKentaro Takeda 1344b69a54eeSKentaro Takeda if (!mode || !path1->mnt || !path2->mnt) 1345b69a54eeSKentaro Takeda return 0; 1346fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 1347b69a54eeSKentaro Takeda buf1 = tomoyo_get_path(path1); 1348b69a54eeSKentaro Takeda buf2 = tomoyo_get_path(path2); 1349b69a54eeSKentaro Takeda if (!buf1 || !buf2) 1350b69a54eeSKentaro Takeda goto out; 1351b69a54eeSKentaro Takeda { 1352b69a54eeSKentaro Takeda struct dentry *dentry = path1->dentry; 1353b69a54eeSKentaro Takeda if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) { 1354b69a54eeSKentaro Takeda /* 1355b69a54eeSKentaro Takeda * tomoyo_get_path() reserves space for appending "/." 1356b69a54eeSKentaro Takeda */ 1357b69a54eeSKentaro Takeda if (!buf1->is_dir) { 1358b69a54eeSKentaro Takeda strcat((char *) buf1->name, "/"); 1359b69a54eeSKentaro Takeda tomoyo_fill_path_info(buf1); 1360b69a54eeSKentaro Takeda } 1361b69a54eeSKentaro Takeda if (!buf2->is_dir) { 1362b69a54eeSKentaro Takeda strcat((char *) buf2->name, "/"); 1363b69a54eeSKentaro Takeda tomoyo_fill_path_info(buf2); 1364b69a54eeSKentaro Takeda } 1365b69a54eeSKentaro Takeda } 1366b69a54eeSKentaro Takeda } 1367b69a54eeSKentaro Takeda error = tomoyo_check_double_path_acl(domain, operation, buf1, buf2); 1368b69a54eeSKentaro Takeda msg = tomoyo_dp2keyword(operation); 1369b69a54eeSKentaro Takeda if (!error) 1370b69a54eeSKentaro Takeda goto out; 1371b69a54eeSKentaro Takeda if (tomoyo_verbose_mode(domain)) 1372b69a54eeSKentaro Takeda printk(KERN_WARNING "TOMOYO-%s: Access '%s %s %s' " 1373b69a54eeSKentaro Takeda "denied for %s\n", tomoyo_get_msg(is_enforce), 1374b69a54eeSKentaro Takeda msg, buf1->name, buf2->name, 1375b69a54eeSKentaro Takeda tomoyo_get_last_name(domain)); 1376b69a54eeSKentaro Takeda if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { 1377b69a54eeSKentaro Takeda const char *name1 = tomoyo_get_file_pattern(buf1)->name; 1378b69a54eeSKentaro Takeda const char *name2 = tomoyo_get_file_pattern(buf2)->name; 1379b69a54eeSKentaro Takeda tomoyo_update_double_path_acl(operation, name1, name2, domain, 1380b69a54eeSKentaro Takeda false); 1381b69a54eeSKentaro Takeda } 1382b69a54eeSKentaro Takeda out: 13838e2d39a1STetsuo Handa kfree(buf1); 13848e2d39a1STetsuo Handa kfree(buf2); 1385fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 1386b69a54eeSKentaro Takeda if (!is_enforce) 1387b69a54eeSKentaro Takeda error = 0; 1388b69a54eeSKentaro Takeda return error; 1389b69a54eeSKentaro Takeda } 1390