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 * 8b69a54eeSKentaro Takeda * Version: 2.2.0-pre 2009/02/01 9b69a54eeSKentaro Takeda * 10b69a54eeSKentaro Takeda */ 11b69a54eeSKentaro Takeda 12b69a54eeSKentaro Takeda #include "common.h" 13b69a54eeSKentaro Takeda #include "tomoyo.h" 14b69a54eeSKentaro Takeda #include "realpath.h" 15b69a54eeSKentaro Takeda #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) 16b69a54eeSKentaro Takeda 17b69a54eeSKentaro Takeda /* Structure for "allow_read" keyword. */ 18b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry { 19b69a54eeSKentaro Takeda struct list_head list; 20b69a54eeSKentaro Takeda const struct tomoyo_path_info *filename; 21b69a54eeSKentaro Takeda bool is_deleted; 22b69a54eeSKentaro Takeda }; 23b69a54eeSKentaro Takeda 24b69a54eeSKentaro Takeda /* Structure for "file_pattern" keyword. */ 25b69a54eeSKentaro Takeda struct tomoyo_pattern_entry { 26b69a54eeSKentaro Takeda struct list_head list; 27b69a54eeSKentaro Takeda const struct tomoyo_path_info *pattern; 28b69a54eeSKentaro Takeda bool is_deleted; 29b69a54eeSKentaro Takeda }; 30b69a54eeSKentaro Takeda 31b69a54eeSKentaro Takeda /* Structure for "deny_rewrite" keyword. */ 32b69a54eeSKentaro Takeda struct tomoyo_no_rewrite_entry { 33b69a54eeSKentaro Takeda struct list_head list; 34b69a54eeSKentaro Takeda const struct tomoyo_path_info *pattern; 35b69a54eeSKentaro Takeda bool is_deleted; 36b69a54eeSKentaro Takeda }; 37b69a54eeSKentaro Takeda 38b69a54eeSKentaro Takeda /* Keyword array for single path operations. */ 39b69a54eeSKentaro Takeda static const char *tomoyo_sp_keyword[TOMOYO_MAX_SINGLE_PATH_OPERATION] = { 40b69a54eeSKentaro Takeda [TOMOYO_TYPE_READ_WRITE_ACL] = "read/write", 41b69a54eeSKentaro Takeda [TOMOYO_TYPE_EXECUTE_ACL] = "execute", 42b69a54eeSKentaro Takeda [TOMOYO_TYPE_READ_ACL] = "read", 43b69a54eeSKentaro Takeda [TOMOYO_TYPE_WRITE_ACL] = "write", 44b69a54eeSKentaro Takeda [TOMOYO_TYPE_CREATE_ACL] = "create", 45b69a54eeSKentaro Takeda [TOMOYO_TYPE_UNLINK_ACL] = "unlink", 46b69a54eeSKentaro Takeda [TOMOYO_TYPE_MKDIR_ACL] = "mkdir", 47b69a54eeSKentaro Takeda [TOMOYO_TYPE_RMDIR_ACL] = "rmdir", 48b69a54eeSKentaro Takeda [TOMOYO_TYPE_MKFIFO_ACL] = "mkfifo", 49b69a54eeSKentaro Takeda [TOMOYO_TYPE_MKSOCK_ACL] = "mksock", 50b69a54eeSKentaro Takeda [TOMOYO_TYPE_MKBLOCK_ACL] = "mkblock", 51b69a54eeSKentaro Takeda [TOMOYO_TYPE_MKCHAR_ACL] = "mkchar", 52b69a54eeSKentaro Takeda [TOMOYO_TYPE_TRUNCATE_ACL] = "truncate", 53b69a54eeSKentaro Takeda [TOMOYO_TYPE_SYMLINK_ACL] = "symlink", 54b69a54eeSKentaro Takeda [TOMOYO_TYPE_REWRITE_ACL] = "rewrite", 55b69a54eeSKentaro Takeda }; 56b69a54eeSKentaro Takeda 57b69a54eeSKentaro Takeda /* Keyword array for double path operations. */ 58b69a54eeSKentaro Takeda static const char *tomoyo_dp_keyword[TOMOYO_MAX_DOUBLE_PATH_OPERATION] = { 59b69a54eeSKentaro Takeda [TOMOYO_TYPE_LINK_ACL] = "link", 60b69a54eeSKentaro Takeda [TOMOYO_TYPE_RENAME_ACL] = "rename", 61b69a54eeSKentaro Takeda }; 62b69a54eeSKentaro Takeda 63b69a54eeSKentaro Takeda /** 64b69a54eeSKentaro Takeda * tomoyo_sp2keyword - Get the name of single path operation. 65b69a54eeSKentaro Takeda * 66b69a54eeSKentaro Takeda * @operation: Type of operation. 67b69a54eeSKentaro Takeda * 68b69a54eeSKentaro Takeda * Returns the name of single path operation. 69b69a54eeSKentaro Takeda */ 70b69a54eeSKentaro Takeda const char *tomoyo_sp2keyword(const u8 operation) 71b69a54eeSKentaro Takeda { 72b69a54eeSKentaro Takeda return (operation < TOMOYO_MAX_SINGLE_PATH_OPERATION) 73b69a54eeSKentaro Takeda ? tomoyo_sp_keyword[operation] : NULL; 74b69a54eeSKentaro Takeda } 75b69a54eeSKentaro Takeda 76b69a54eeSKentaro Takeda /** 77b69a54eeSKentaro Takeda * tomoyo_dp2keyword - Get the name of double path operation. 78b69a54eeSKentaro Takeda * 79b69a54eeSKentaro Takeda * @operation: Type of operation. 80b69a54eeSKentaro Takeda * 81b69a54eeSKentaro Takeda * Returns the name of double path operation. 82b69a54eeSKentaro Takeda */ 83b69a54eeSKentaro Takeda const char *tomoyo_dp2keyword(const u8 operation) 84b69a54eeSKentaro Takeda { 85b69a54eeSKentaro Takeda return (operation < TOMOYO_MAX_DOUBLE_PATH_OPERATION) 86b69a54eeSKentaro Takeda ? tomoyo_dp_keyword[operation] : NULL; 87b69a54eeSKentaro Takeda } 88b69a54eeSKentaro Takeda 89b69a54eeSKentaro Takeda /** 90b69a54eeSKentaro Takeda * tomoyo_strendswith - Check whether the token ends with the given token. 91b69a54eeSKentaro Takeda * 92b69a54eeSKentaro Takeda * @name: The token to check. 93b69a54eeSKentaro Takeda * @tail: The token to find. 94b69a54eeSKentaro Takeda * 95b69a54eeSKentaro Takeda * Returns true if @name ends with @tail, false otherwise. 96b69a54eeSKentaro Takeda */ 97b69a54eeSKentaro Takeda static bool tomoyo_strendswith(const char *name, const char *tail) 98b69a54eeSKentaro Takeda { 99b69a54eeSKentaro Takeda int len; 100b69a54eeSKentaro Takeda 101b69a54eeSKentaro Takeda if (!name || !tail) 102b69a54eeSKentaro Takeda return false; 103b69a54eeSKentaro Takeda len = strlen(name) - strlen(tail); 104b69a54eeSKentaro Takeda return len >= 0 && !strcmp(name + len, tail); 105b69a54eeSKentaro Takeda } 106b69a54eeSKentaro Takeda 107b69a54eeSKentaro Takeda /** 108b69a54eeSKentaro Takeda * tomoyo_get_path - Get realpath. 109b69a54eeSKentaro Takeda * 110b69a54eeSKentaro Takeda * @path: Pointer to "struct path". 111b69a54eeSKentaro Takeda * 112b69a54eeSKentaro Takeda * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. 113b69a54eeSKentaro Takeda */ 114b69a54eeSKentaro Takeda static struct tomoyo_path_info *tomoyo_get_path(struct path *path) 115b69a54eeSKentaro Takeda { 116b69a54eeSKentaro Takeda int error; 117b69a54eeSKentaro Takeda struct tomoyo_path_info_with_data *buf = tomoyo_alloc(sizeof(*buf)); 118b69a54eeSKentaro Takeda 119b69a54eeSKentaro Takeda if (!buf) 120b69a54eeSKentaro Takeda return NULL; 121b69a54eeSKentaro Takeda /* Reserve one byte for appending "/". */ 122b69a54eeSKentaro Takeda error = tomoyo_realpath_from_path2(path, buf->body, 123b69a54eeSKentaro Takeda sizeof(buf->body) - 2); 124b69a54eeSKentaro Takeda if (!error) { 125b69a54eeSKentaro Takeda buf->head.name = buf->body; 126b69a54eeSKentaro Takeda tomoyo_fill_path_info(&buf->head); 127b69a54eeSKentaro Takeda return &buf->head; 128b69a54eeSKentaro Takeda } 129b69a54eeSKentaro Takeda tomoyo_free(buf); 130b69a54eeSKentaro Takeda return NULL; 131b69a54eeSKentaro Takeda } 132b69a54eeSKentaro Takeda 133b69a54eeSKentaro Takeda /* Lock for domain->acl_info_list. */ 134b69a54eeSKentaro Takeda DECLARE_RWSEM(tomoyo_domain_acl_info_list_lock); 135b69a54eeSKentaro Takeda 136b69a54eeSKentaro Takeda static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, 137b69a54eeSKentaro Takeda const char *filename2, 138b69a54eeSKentaro Takeda struct tomoyo_domain_info * 139b69a54eeSKentaro Takeda const domain, const bool is_delete); 140b69a54eeSKentaro Takeda static int tomoyo_update_single_path_acl(const u8 type, const char *filename, 141b69a54eeSKentaro Takeda struct tomoyo_domain_info * 142b69a54eeSKentaro Takeda const domain, const bool is_delete); 143b69a54eeSKentaro Takeda 144b69a54eeSKentaro Takeda /* The list for "struct tomoyo_globally_readable_file_entry". */ 145b69a54eeSKentaro Takeda static LIST_HEAD(tomoyo_globally_readable_list); 146b69a54eeSKentaro Takeda static DECLARE_RWSEM(tomoyo_globally_readable_list_lock); 147b69a54eeSKentaro Takeda 148b69a54eeSKentaro Takeda /** 149b69a54eeSKentaro Takeda * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list. 150b69a54eeSKentaro Takeda * 151b69a54eeSKentaro Takeda * @filename: Filename unconditionally permitted to open() for reading. 152b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 153b69a54eeSKentaro Takeda * 154b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 155b69a54eeSKentaro Takeda */ 156b69a54eeSKentaro Takeda static int tomoyo_update_globally_readable_entry(const char *filename, 157b69a54eeSKentaro Takeda const bool is_delete) 158b69a54eeSKentaro Takeda { 159b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry *new_entry; 160b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry *ptr; 161b69a54eeSKentaro Takeda const struct tomoyo_path_info *saved_filename; 162b69a54eeSKentaro Takeda int error = -ENOMEM; 163b69a54eeSKentaro Takeda 164b69a54eeSKentaro Takeda if (!tomoyo_is_correct_path(filename, 1, 0, -1, __func__)) 165b69a54eeSKentaro Takeda return -EINVAL; 166b69a54eeSKentaro Takeda saved_filename = tomoyo_save_name(filename); 167b69a54eeSKentaro Takeda if (!saved_filename) 168b69a54eeSKentaro Takeda return -ENOMEM; 169b69a54eeSKentaro Takeda /***** EXCLUSIVE SECTION START *****/ 170b69a54eeSKentaro Takeda down_write(&tomoyo_globally_readable_list_lock); 171b69a54eeSKentaro Takeda list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) { 172b69a54eeSKentaro Takeda if (ptr->filename != saved_filename) 173b69a54eeSKentaro Takeda continue; 174b69a54eeSKentaro Takeda ptr->is_deleted = is_delete; 175b69a54eeSKentaro Takeda error = 0; 176b69a54eeSKentaro Takeda goto out; 177b69a54eeSKentaro Takeda } 178b69a54eeSKentaro Takeda if (is_delete) { 179b69a54eeSKentaro Takeda error = -ENOENT; 180b69a54eeSKentaro Takeda goto out; 181b69a54eeSKentaro Takeda } 182b69a54eeSKentaro Takeda new_entry = tomoyo_alloc_element(sizeof(*new_entry)); 183b69a54eeSKentaro Takeda if (!new_entry) 184b69a54eeSKentaro Takeda goto out; 185b69a54eeSKentaro Takeda new_entry->filename = saved_filename; 186b69a54eeSKentaro Takeda list_add_tail(&new_entry->list, &tomoyo_globally_readable_list); 187b69a54eeSKentaro Takeda error = 0; 188b69a54eeSKentaro Takeda out: 189b69a54eeSKentaro Takeda up_write(&tomoyo_globally_readable_list_lock); 190b69a54eeSKentaro Takeda /***** EXCLUSIVE SECTION END *****/ 191b69a54eeSKentaro Takeda return error; 192b69a54eeSKentaro Takeda } 193b69a54eeSKentaro Takeda 194b69a54eeSKentaro Takeda /** 195b69a54eeSKentaro Takeda * tomoyo_is_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading. 196b69a54eeSKentaro Takeda * 197b69a54eeSKentaro Takeda * @filename: The filename to check. 198b69a54eeSKentaro Takeda * 199b69a54eeSKentaro Takeda * Returns true if any domain can open @filename for reading, false otherwise. 200b69a54eeSKentaro Takeda */ 201b69a54eeSKentaro Takeda static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info * 202b69a54eeSKentaro Takeda filename) 203b69a54eeSKentaro Takeda { 204b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry *ptr; 205b69a54eeSKentaro Takeda bool found = false; 206b69a54eeSKentaro Takeda down_read(&tomoyo_globally_readable_list_lock); 207b69a54eeSKentaro Takeda list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) { 208b69a54eeSKentaro Takeda if (!ptr->is_deleted && 209b69a54eeSKentaro Takeda tomoyo_path_matches_pattern(filename, ptr->filename)) { 210b69a54eeSKentaro Takeda found = true; 211b69a54eeSKentaro Takeda break; 212b69a54eeSKentaro Takeda } 213b69a54eeSKentaro Takeda } 214b69a54eeSKentaro Takeda up_read(&tomoyo_globally_readable_list_lock); 215b69a54eeSKentaro Takeda return found; 216b69a54eeSKentaro Takeda } 217b69a54eeSKentaro Takeda 218b69a54eeSKentaro Takeda /** 219b69a54eeSKentaro Takeda * tomoyo_write_globally_readable_policy - Write "struct tomoyo_globally_readable_file_entry" list. 220b69a54eeSKentaro Takeda * 221b69a54eeSKentaro Takeda * @data: String to parse. 222b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 223b69a54eeSKentaro Takeda * 224b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 225b69a54eeSKentaro Takeda */ 226b69a54eeSKentaro Takeda int tomoyo_write_globally_readable_policy(char *data, const bool is_delete) 227b69a54eeSKentaro Takeda { 228b69a54eeSKentaro Takeda return tomoyo_update_globally_readable_entry(data, is_delete); 229b69a54eeSKentaro Takeda } 230b69a54eeSKentaro Takeda 231b69a54eeSKentaro Takeda /** 232b69a54eeSKentaro Takeda * tomoyo_read_globally_readable_policy - Read "struct tomoyo_globally_readable_file_entry" list. 233b69a54eeSKentaro Takeda * 234b69a54eeSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 235b69a54eeSKentaro Takeda * 236b69a54eeSKentaro Takeda * Returns true on success, false otherwise. 237b69a54eeSKentaro Takeda */ 238b69a54eeSKentaro Takeda bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) 239b69a54eeSKentaro Takeda { 240b69a54eeSKentaro Takeda struct list_head *pos; 241b69a54eeSKentaro Takeda bool done = true; 242b69a54eeSKentaro Takeda 243b69a54eeSKentaro Takeda down_read(&tomoyo_globally_readable_list_lock); 244b69a54eeSKentaro Takeda list_for_each_cookie(pos, head->read_var2, 245b69a54eeSKentaro Takeda &tomoyo_globally_readable_list) { 246b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry *ptr; 247b69a54eeSKentaro Takeda ptr = list_entry(pos, 248b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry, 249b69a54eeSKentaro Takeda list); 250b69a54eeSKentaro Takeda if (ptr->is_deleted) 251b69a54eeSKentaro Takeda continue; 252b69a54eeSKentaro Takeda if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n", 253b69a54eeSKentaro Takeda ptr->filename->name)) { 254b69a54eeSKentaro Takeda done = false; 255b69a54eeSKentaro Takeda break; 256b69a54eeSKentaro Takeda } 257b69a54eeSKentaro Takeda } 258b69a54eeSKentaro Takeda up_read(&tomoyo_globally_readable_list_lock); 259b69a54eeSKentaro Takeda return done; 260b69a54eeSKentaro Takeda } 261b69a54eeSKentaro Takeda 262b69a54eeSKentaro Takeda /* The list for "struct tomoyo_pattern_entry". */ 263b69a54eeSKentaro Takeda static LIST_HEAD(tomoyo_pattern_list); 264b69a54eeSKentaro Takeda static DECLARE_RWSEM(tomoyo_pattern_list_lock); 265b69a54eeSKentaro Takeda 266b69a54eeSKentaro Takeda /** 267b69a54eeSKentaro Takeda * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list. 268b69a54eeSKentaro Takeda * 269b69a54eeSKentaro Takeda * @pattern: Pathname pattern. 270b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 271b69a54eeSKentaro Takeda * 272b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 273b69a54eeSKentaro Takeda */ 274b69a54eeSKentaro Takeda static int tomoyo_update_file_pattern_entry(const char *pattern, 275b69a54eeSKentaro Takeda const bool is_delete) 276b69a54eeSKentaro Takeda { 277b69a54eeSKentaro Takeda struct tomoyo_pattern_entry *new_entry; 278b69a54eeSKentaro Takeda struct tomoyo_pattern_entry *ptr; 279b69a54eeSKentaro Takeda const struct tomoyo_path_info *saved_pattern; 280b69a54eeSKentaro Takeda int error = -ENOMEM; 281b69a54eeSKentaro Takeda 282b69a54eeSKentaro Takeda if (!tomoyo_is_correct_path(pattern, 0, 1, 0, __func__)) 283b69a54eeSKentaro Takeda return -EINVAL; 284b69a54eeSKentaro Takeda saved_pattern = tomoyo_save_name(pattern); 285b69a54eeSKentaro Takeda if (!saved_pattern) 286b69a54eeSKentaro Takeda return -ENOMEM; 287b69a54eeSKentaro Takeda /***** EXCLUSIVE SECTION START *****/ 288b69a54eeSKentaro Takeda down_write(&tomoyo_pattern_list_lock); 289b69a54eeSKentaro Takeda list_for_each_entry(ptr, &tomoyo_pattern_list, list) { 290b69a54eeSKentaro Takeda if (saved_pattern != ptr->pattern) 291b69a54eeSKentaro Takeda continue; 292b69a54eeSKentaro Takeda ptr->is_deleted = is_delete; 293b69a54eeSKentaro Takeda error = 0; 294b69a54eeSKentaro Takeda goto out; 295b69a54eeSKentaro Takeda } 296b69a54eeSKentaro Takeda if (is_delete) { 297b69a54eeSKentaro Takeda error = -ENOENT; 298b69a54eeSKentaro Takeda goto out; 299b69a54eeSKentaro Takeda } 300b69a54eeSKentaro Takeda new_entry = tomoyo_alloc_element(sizeof(*new_entry)); 301b69a54eeSKentaro Takeda if (!new_entry) 302b69a54eeSKentaro Takeda goto out; 303b69a54eeSKentaro Takeda new_entry->pattern = saved_pattern; 304b69a54eeSKentaro Takeda list_add_tail(&new_entry->list, &tomoyo_pattern_list); 305b69a54eeSKentaro Takeda error = 0; 306b69a54eeSKentaro Takeda out: 307b69a54eeSKentaro Takeda up_write(&tomoyo_pattern_list_lock); 308b69a54eeSKentaro Takeda /***** EXCLUSIVE SECTION END *****/ 309b69a54eeSKentaro Takeda return error; 310b69a54eeSKentaro Takeda } 311b69a54eeSKentaro Takeda 312b69a54eeSKentaro Takeda /** 313b69a54eeSKentaro Takeda * tomoyo_get_file_pattern - Get patterned pathname. 314b69a54eeSKentaro Takeda * 315b69a54eeSKentaro Takeda * @filename: The filename to find patterned pathname. 316b69a54eeSKentaro Takeda * 317b69a54eeSKentaro Takeda * Returns pointer to pathname pattern if matched, @filename otherwise. 318b69a54eeSKentaro Takeda */ 319b69a54eeSKentaro Takeda static const struct tomoyo_path_info * 320b69a54eeSKentaro Takeda tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) 321b69a54eeSKentaro Takeda { 322b69a54eeSKentaro Takeda struct tomoyo_pattern_entry *ptr; 323b69a54eeSKentaro Takeda const struct tomoyo_path_info *pattern = NULL; 324b69a54eeSKentaro Takeda 325b69a54eeSKentaro Takeda down_read(&tomoyo_pattern_list_lock); 326b69a54eeSKentaro Takeda list_for_each_entry(ptr, &tomoyo_pattern_list, list) { 327b69a54eeSKentaro Takeda if (ptr->is_deleted) 328b69a54eeSKentaro Takeda continue; 329b69a54eeSKentaro Takeda if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) 330b69a54eeSKentaro Takeda continue; 331b69a54eeSKentaro Takeda pattern = ptr->pattern; 332b69a54eeSKentaro Takeda if (tomoyo_strendswith(pattern->name, "/\\*")) { 333b69a54eeSKentaro Takeda /* Do nothing. Try to find the better match. */ 334b69a54eeSKentaro Takeda } else { 335b69a54eeSKentaro Takeda /* This would be the better match. Use this. */ 336b69a54eeSKentaro Takeda break; 337b69a54eeSKentaro Takeda } 338b69a54eeSKentaro Takeda } 339b69a54eeSKentaro Takeda up_read(&tomoyo_pattern_list_lock); 340b69a54eeSKentaro Takeda if (pattern) 341b69a54eeSKentaro Takeda filename = pattern; 342b69a54eeSKentaro Takeda return filename; 343b69a54eeSKentaro Takeda } 344b69a54eeSKentaro Takeda 345b69a54eeSKentaro Takeda /** 346b69a54eeSKentaro Takeda * tomoyo_write_pattern_policy - Write "struct tomoyo_pattern_entry" list. 347b69a54eeSKentaro Takeda * 348b69a54eeSKentaro Takeda * @data: String to parse. 349b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 350b69a54eeSKentaro Takeda * 351b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 352b69a54eeSKentaro Takeda */ 353b69a54eeSKentaro Takeda int tomoyo_write_pattern_policy(char *data, const bool is_delete) 354b69a54eeSKentaro Takeda { 355b69a54eeSKentaro Takeda return tomoyo_update_file_pattern_entry(data, is_delete); 356b69a54eeSKentaro Takeda } 357b69a54eeSKentaro Takeda 358b69a54eeSKentaro Takeda /** 359b69a54eeSKentaro Takeda * tomoyo_read_file_pattern - Read "struct tomoyo_pattern_entry" list. 360b69a54eeSKentaro Takeda * 361b69a54eeSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 362b69a54eeSKentaro Takeda * 363b69a54eeSKentaro Takeda * Returns true on success, false otherwise. 364b69a54eeSKentaro Takeda */ 365b69a54eeSKentaro Takeda bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) 366b69a54eeSKentaro Takeda { 367b69a54eeSKentaro Takeda struct list_head *pos; 368b69a54eeSKentaro Takeda bool done = true; 369b69a54eeSKentaro Takeda 370b69a54eeSKentaro Takeda down_read(&tomoyo_pattern_list_lock); 371b69a54eeSKentaro Takeda list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) { 372b69a54eeSKentaro Takeda struct tomoyo_pattern_entry *ptr; 373b69a54eeSKentaro Takeda ptr = list_entry(pos, struct tomoyo_pattern_entry, list); 374b69a54eeSKentaro Takeda if (ptr->is_deleted) 375b69a54eeSKentaro Takeda continue; 376b69a54eeSKentaro Takeda if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN "%s\n", 377b69a54eeSKentaro Takeda ptr->pattern->name)) { 378b69a54eeSKentaro Takeda done = false; 379b69a54eeSKentaro Takeda break; 380b69a54eeSKentaro Takeda } 381b69a54eeSKentaro Takeda } 382b69a54eeSKentaro Takeda up_read(&tomoyo_pattern_list_lock); 383b69a54eeSKentaro Takeda return done; 384b69a54eeSKentaro Takeda } 385b69a54eeSKentaro Takeda 386b69a54eeSKentaro Takeda /* The list for "struct tomoyo_no_rewrite_entry". */ 387b69a54eeSKentaro Takeda static LIST_HEAD(tomoyo_no_rewrite_list); 388b69a54eeSKentaro Takeda static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock); 389b69a54eeSKentaro Takeda 390b69a54eeSKentaro Takeda /** 391b69a54eeSKentaro Takeda * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list. 392b69a54eeSKentaro Takeda * 393b69a54eeSKentaro Takeda * @pattern: Pathname pattern that are not rewritable by default. 394b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 395b69a54eeSKentaro Takeda * 396b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 397b69a54eeSKentaro Takeda */ 398b69a54eeSKentaro Takeda static int tomoyo_update_no_rewrite_entry(const char *pattern, 399b69a54eeSKentaro Takeda const bool is_delete) 400b69a54eeSKentaro Takeda { 401b69a54eeSKentaro Takeda struct tomoyo_no_rewrite_entry *new_entry, *ptr; 402b69a54eeSKentaro Takeda const struct tomoyo_path_info *saved_pattern; 403b69a54eeSKentaro Takeda int error = -ENOMEM; 404b69a54eeSKentaro Takeda 405b69a54eeSKentaro Takeda if (!tomoyo_is_correct_path(pattern, 0, 0, 0, __func__)) 406b69a54eeSKentaro Takeda return -EINVAL; 407b69a54eeSKentaro Takeda saved_pattern = tomoyo_save_name(pattern); 408b69a54eeSKentaro Takeda if (!saved_pattern) 409b69a54eeSKentaro Takeda return -ENOMEM; 410b69a54eeSKentaro Takeda /***** EXCLUSIVE SECTION START *****/ 411b69a54eeSKentaro Takeda down_write(&tomoyo_no_rewrite_list_lock); 412b69a54eeSKentaro Takeda list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) { 413b69a54eeSKentaro Takeda if (ptr->pattern != saved_pattern) 414b69a54eeSKentaro Takeda continue; 415b69a54eeSKentaro Takeda ptr->is_deleted = is_delete; 416b69a54eeSKentaro Takeda error = 0; 417b69a54eeSKentaro Takeda goto out; 418b69a54eeSKentaro Takeda } 419b69a54eeSKentaro Takeda if (is_delete) { 420b69a54eeSKentaro Takeda error = -ENOENT; 421b69a54eeSKentaro Takeda goto out; 422b69a54eeSKentaro Takeda } 423b69a54eeSKentaro Takeda new_entry = tomoyo_alloc_element(sizeof(*new_entry)); 424b69a54eeSKentaro Takeda if (!new_entry) 425b69a54eeSKentaro Takeda goto out; 426b69a54eeSKentaro Takeda new_entry->pattern = saved_pattern; 427b69a54eeSKentaro Takeda list_add_tail(&new_entry->list, &tomoyo_no_rewrite_list); 428b69a54eeSKentaro Takeda error = 0; 429b69a54eeSKentaro Takeda out: 430b69a54eeSKentaro Takeda up_write(&tomoyo_no_rewrite_list_lock); 431b69a54eeSKentaro Takeda /***** EXCLUSIVE SECTION END *****/ 432b69a54eeSKentaro Takeda return error; 433b69a54eeSKentaro Takeda } 434b69a54eeSKentaro Takeda 435b69a54eeSKentaro Takeda /** 436b69a54eeSKentaro Takeda * tomoyo_is_no_rewrite_file - Check if the given pathname is not permitted to be rewrited. 437b69a54eeSKentaro Takeda * 438b69a54eeSKentaro Takeda * @filename: Filename to check. 439b69a54eeSKentaro Takeda * 440b69a54eeSKentaro Takeda * Returns true if @filename is specified by "deny_rewrite" directive, 441b69a54eeSKentaro Takeda * false otherwise. 442b69a54eeSKentaro Takeda */ 443b69a54eeSKentaro Takeda static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) 444b69a54eeSKentaro Takeda { 445b69a54eeSKentaro Takeda struct tomoyo_no_rewrite_entry *ptr; 446b69a54eeSKentaro Takeda bool found = false; 447b69a54eeSKentaro Takeda 448b69a54eeSKentaro Takeda down_read(&tomoyo_no_rewrite_list_lock); 449b69a54eeSKentaro Takeda list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) { 450b69a54eeSKentaro Takeda if (ptr->is_deleted) 451b69a54eeSKentaro Takeda continue; 452b69a54eeSKentaro Takeda if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) 453b69a54eeSKentaro Takeda continue; 454b69a54eeSKentaro Takeda found = true; 455b69a54eeSKentaro Takeda break; 456b69a54eeSKentaro Takeda } 457b69a54eeSKentaro Takeda up_read(&tomoyo_no_rewrite_list_lock); 458b69a54eeSKentaro Takeda return found; 459b69a54eeSKentaro Takeda } 460b69a54eeSKentaro Takeda 461b69a54eeSKentaro Takeda /** 462b69a54eeSKentaro Takeda * tomoyo_write_no_rewrite_policy - Write "struct tomoyo_no_rewrite_entry" list. 463b69a54eeSKentaro Takeda * 464b69a54eeSKentaro Takeda * @data: String to parse. 465b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 466b69a54eeSKentaro Takeda * 467b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 468b69a54eeSKentaro Takeda */ 469b69a54eeSKentaro Takeda int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete) 470b69a54eeSKentaro Takeda { 471b69a54eeSKentaro Takeda return tomoyo_update_no_rewrite_entry(data, is_delete); 472b69a54eeSKentaro Takeda } 473b69a54eeSKentaro Takeda 474b69a54eeSKentaro Takeda /** 475b69a54eeSKentaro Takeda * tomoyo_read_no_rewrite_policy - Read "struct tomoyo_no_rewrite_entry" list. 476b69a54eeSKentaro Takeda * 477b69a54eeSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 478b69a54eeSKentaro Takeda * 479b69a54eeSKentaro Takeda * Returns true on success, false otherwise. 480b69a54eeSKentaro Takeda */ 481b69a54eeSKentaro Takeda bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) 482b69a54eeSKentaro Takeda { 483b69a54eeSKentaro Takeda struct list_head *pos; 484b69a54eeSKentaro Takeda bool done = true; 485b69a54eeSKentaro Takeda 486b69a54eeSKentaro Takeda down_read(&tomoyo_no_rewrite_list_lock); 487b69a54eeSKentaro Takeda list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) { 488b69a54eeSKentaro Takeda struct tomoyo_no_rewrite_entry *ptr; 489b69a54eeSKentaro Takeda ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list); 490b69a54eeSKentaro Takeda if (ptr->is_deleted) 491b69a54eeSKentaro Takeda continue; 492b69a54eeSKentaro Takeda if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE "%s\n", 493b69a54eeSKentaro Takeda ptr->pattern->name)) { 494b69a54eeSKentaro Takeda done = false; 495b69a54eeSKentaro Takeda break; 496b69a54eeSKentaro Takeda } 497b69a54eeSKentaro Takeda } 498b69a54eeSKentaro Takeda up_read(&tomoyo_no_rewrite_list_lock); 499b69a54eeSKentaro Takeda return done; 500b69a54eeSKentaro Takeda } 501b69a54eeSKentaro Takeda 502b69a54eeSKentaro Takeda /** 503b69a54eeSKentaro Takeda * tomoyo_update_file_acl - Update file's read/write/execute ACL. 504b69a54eeSKentaro Takeda * 505b69a54eeSKentaro Takeda * @filename: Filename. 506b69a54eeSKentaro Takeda * @perm: Permission (between 1 to 7). 507b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 508b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 509b69a54eeSKentaro Takeda * 510b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 511b69a54eeSKentaro Takeda * 512b69a54eeSKentaro Takeda * This is legacy support interface for older policy syntax. 513b69a54eeSKentaro Takeda * Current policy syntax uses "allow_read/write" instead of "6", 514b69a54eeSKentaro Takeda * "allow_read" instead of "4", "allow_write" instead of "2", 515b69a54eeSKentaro Takeda * "allow_execute" instead of "1". 516b69a54eeSKentaro Takeda */ 517b69a54eeSKentaro Takeda static int tomoyo_update_file_acl(const char *filename, u8 perm, 518b69a54eeSKentaro Takeda struct tomoyo_domain_info * const domain, 519b69a54eeSKentaro Takeda const bool is_delete) 520b69a54eeSKentaro Takeda { 521b69a54eeSKentaro Takeda if (perm > 7 || !perm) { 522b69a54eeSKentaro Takeda printk(KERN_DEBUG "%s: Invalid permission '%d %s'\n", 523b69a54eeSKentaro Takeda __func__, perm, filename); 524b69a54eeSKentaro Takeda return -EINVAL; 525b69a54eeSKentaro Takeda } 526b69a54eeSKentaro Takeda if (filename[0] != '@' && tomoyo_strendswith(filename, "/")) 527b69a54eeSKentaro Takeda /* 528b69a54eeSKentaro Takeda * Only 'allow_mkdir' and 'allow_rmdir' are valid for 529b69a54eeSKentaro Takeda * directory permissions. 530b69a54eeSKentaro Takeda */ 531b69a54eeSKentaro Takeda return 0; 532b69a54eeSKentaro Takeda if (perm & 4) 533b69a54eeSKentaro Takeda tomoyo_update_single_path_acl(TOMOYO_TYPE_READ_ACL, filename, 534b69a54eeSKentaro Takeda domain, is_delete); 535b69a54eeSKentaro Takeda if (perm & 2) 536b69a54eeSKentaro Takeda tomoyo_update_single_path_acl(TOMOYO_TYPE_WRITE_ACL, filename, 537b69a54eeSKentaro Takeda domain, is_delete); 538b69a54eeSKentaro Takeda if (perm & 1) 539b69a54eeSKentaro Takeda tomoyo_update_single_path_acl(TOMOYO_TYPE_EXECUTE_ACL, 540b69a54eeSKentaro Takeda filename, domain, is_delete); 541b69a54eeSKentaro Takeda return 0; 542b69a54eeSKentaro Takeda } 543b69a54eeSKentaro Takeda 544b69a54eeSKentaro Takeda /** 545b69a54eeSKentaro Takeda * tomoyo_check_single_path_acl2 - Check permission for single path operation. 546b69a54eeSKentaro Takeda * 547b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 548b69a54eeSKentaro Takeda * @filename: Filename to check. 549b69a54eeSKentaro Takeda * @perm: Permission. 550b69a54eeSKentaro Takeda * @may_use_pattern: True if patterned ACL is permitted. 551b69a54eeSKentaro Takeda * 552b69a54eeSKentaro Takeda * Returns 0 on success, -EPERM otherwise. 553b69a54eeSKentaro Takeda */ 554b69a54eeSKentaro Takeda static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info * 555b69a54eeSKentaro Takeda domain, 556b69a54eeSKentaro Takeda const struct tomoyo_path_info * 557b69a54eeSKentaro Takeda filename, 558b69a54eeSKentaro Takeda const u16 perm, 559b69a54eeSKentaro Takeda const bool may_use_pattern) 560b69a54eeSKentaro Takeda { 561b69a54eeSKentaro Takeda struct tomoyo_acl_info *ptr; 562b69a54eeSKentaro Takeda int error = -EPERM; 563b69a54eeSKentaro Takeda 564b69a54eeSKentaro Takeda down_read(&tomoyo_domain_acl_info_list_lock); 565b69a54eeSKentaro Takeda list_for_each_entry(ptr, &domain->acl_info_list, list) { 566b69a54eeSKentaro Takeda struct tomoyo_single_path_acl_record *acl; 567b69a54eeSKentaro Takeda if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) 568b69a54eeSKentaro Takeda continue; 569b69a54eeSKentaro Takeda acl = container_of(ptr, struct tomoyo_single_path_acl_record, 570b69a54eeSKentaro Takeda head); 571b69a54eeSKentaro Takeda if (!(acl->perm & perm)) 572b69a54eeSKentaro Takeda continue; 573b69a54eeSKentaro Takeda if (may_use_pattern || !acl->filename->is_patterned) { 574b69a54eeSKentaro Takeda if (!tomoyo_path_matches_pattern(filename, 575b69a54eeSKentaro Takeda acl->filename)) 576b69a54eeSKentaro Takeda continue; 577b69a54eeSKentaro Takeda } else { 578b69a54eeSKentaro Takeda continue; 579b69a54eeSKentaro Takeda } 580b69a54eeSKentaro Takeda error = 0; 581b69a54eeSKentaro Takeda break; 582b69a54eeSKentaro Takeda } 583b69a54eeSKentaro Takeda up_read(&tomoyo_domain_acl_info_list_lock); 584b69a54eeSKentaro Takeda return error; 585b69a54eeSKentaro Takeda } 586b69a54eeSKentaro Takeda 587b69a54eeSKentaro Takeda /** 588b69a54eeSKentaro Takeda * tomoyo_check_file_acl - Check permission for opening files. 589b69a54eeSKentaro Takeda * 590b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 591b69a54eeSKentaro Takeda * @filename: Filename to check. 592b69a54eeSKentaro Takeda * @operation: Mode ("read" or "write" or "read/write" or "execute"). 593b69a54eeSKentaro Takeda * 594b69a54eeSKentaro Takeda * Returns 0 on success, -EPERM otherwise. 595b69a54eeSKentaro Takeda */ 596b69a54eeSKentaro Takeda static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain, 597b69a54eeSKentaro Takeda const struct tomoyo_path_info *filename, 598b69a54eeSKentaro Takeda const u8 operation) 599b69a54eeSKentaro Takeda { 600b69a54eeSKentaro Takeda u16 perm = 0; 601b69a54eeSKentaro Takeda 602b69a54eeSKentaro Takeda if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) 603b69a54eeSKentaro Takeda return 0; 604b69a54eeSKentaro Takeda if (operation == 6) 605b69a54eeSKentaro Takeda perm = 1 << TOMOYO_TYPE_READ_WRITE_ACL; 606b69a54eeSKentaro Takeda else if (operation == 4) 607b69a54eeSKentaro Takeda perm = 1 << TOMOYO_TYPE_READ_ACL; 608b69a54eeSKentaro Takeda else if (operation == 2) 609b69a54eeSKentaro Takeda perm = 1 << TOMOYO_TYPE_WRITE_ACL; 610b69a54eeSKentaro Takeda else if (operation == 1) 611b69a54eeSKentaro Takeda perm = 1 << TOMOYO_TYPE_EXECUTE_ACL; 612b69a54eeSKentaro Takeda else 613b69a54eeSKentaro Takeda BUG(); 614b69a54eeSKentaro Takeda return tomoyo_check_single_path_acl2(domain, filename, perm, 615b69a54eeSKentaro Takeda operation != 1); 616b69a54eeSKentaro Takeda } 617b69a54eeSKentaro Takeda 618b69a54eeSKentaro Takeda /** 619b69a54eeSKentaro Takeda * tomoyo_check_file_perm2 - Check permission for opening files. 620b69a54eeSKentaro Takeda * 621b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 622b69a54eeSKentaro Takeda * @filename: Filename to check. 623b69a54eeSKentaro Takeda * @perm: Mode ("read" or "write" or "read/write" or "execute"). 624b69a54eeSKentaro Takeda * @operation: Operation name passed used for verbose mode. 625b69a54eeSKentaro Takeda * @mode: Access control mode. 626b69a54eeSKentaro Takeda * 627b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 628b69a54eeSKentaro Takeda */ 629b69a54eeSKentaro Takeda static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain, 630b69a54eeSKentaro Takeda const struct tomoyo_path_info *filename, 631b69a54eeSKentaro Takeda const u8 perm, const char *operation, 632b69a54eeSKentaro Takeda const u8 mode) 633b69a54eeSKentaro Takeda { 634b69a54eeSKentaro Takeda const bool is_enforce = (mode == 3); 635b69a54eeSKentaro Takeda const char *msg = "<unknown>"; 636b69a54eeSKentaro Takeda int error = 0; 637b69a54eeSKentaro Takeda 638b69a54eeSKentaro Takeda if (!filename) 639b69a54eeSKentaro Takeda return 0; 640b69a54eeSKentaro Takeda error = tomoyo_check_file_acl(domain, filename, perm); 641b69a54eeSKentaro Takeda if (error && perm == 4 && 642b69a54eeSKentaro Takeda (domain->flags & TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ) == 0 643b69a54eeSKentaro Takeda && tomoyo_is_globally_readable_file(filename)) 644b69a54eeSKentaro Takeda error = 0; 645b69a54eeSKentaro Takeda if (perm == 6) 646b69a54eeSKentaro Takeda msg = tomoyo_sp2keyword(TOMOYO_TYPE_READ_WRITE_ACL); 647b69a54eeSKentaro Takeda else if (perm == 4) 648b69a54eeSKentaro Takeda msg = tomoyo_sp2keyword(TOMOYO_TYPE_READ_ACL); 649b69a54eeSKentaro Takeda else if (perm == 2) 650b69a54eeSKentaro Takeda msg = tomoyo_sp2keyword(TOMOYO_TYPE_WRITE_ACL); 651b69a54eeSKentaro Takeda else if (perm == 1) 652b69a54eeSKentaro Takeda msg = tomoyo_sp2keyword(TOMOYO_TYPE_EXECUTE_ACL); 653b69a54eeSKentaro Takeda else 654b69a54eeSKentaro Takeda BUG(); 655b69a54eeSKentaro Takeda if (!error) 656b69a54eeSKentaro Takeda return 0; 657b69a54eeSKentaro Takeda if (tomoyo_verbose_mode(domain)) 658b69a54eeSKentaro Takeda printk(KERN_WARNING "TOMOYO-%s: Access '%s(%s) %s' denied " 659b69a54eeSKentaro Takeda "for %s\n", tomoyo_get_msg(is_enforce), msg, operation, 660b69a54eeSKentaro Takeda filename->name, tomoyo_get_last_name(domain)); 661b69a54eeSKentaro Takeda if (is_enforce) 662b69a54eeSKentaro Takeda return error; 663b69a54eeSKentaro Takeda if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { 664b69a54eeSKentaro Takeda /* Don't use patterns for execute permission. */ 665b69a54eeSKentaro Takeda const struct tomoyo_path_info *patterned_file = (perm != 1) ? 666b69a54eeSKentaro Takeda tomoyo_get_file_pattern(filename) : filename; 667b69a54eeSKentaro Takeda tomoyo_update_file_acl(patterned_file->name, perm, 668b69a54eeSKentaro Takeda domain, false); 669b69a54eeSKentaro Takeda } 670b69a54eeSKentaro Takeda return 0; 671b69a54eeSKentaro Takeda } 672b69a54eeSKentaro Takeda 673b69a54eeSKentaro Takeda /** 674b69a54eeSKentaro Takeda * tomoyo_write_file_policy - Update file related list. 675b69a54eeSKentaro Takeda * 676b69a54eeSKentaro Takeda * @data: String to parse. 677b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 678b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 679b69a54eeSKentaro Takeda * 680b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 681b69a54eeSKentaro Takeda */ 682b69a54eeSKentaro Takeda int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, 683b69a54eeSKentaro Takeda const bool is_delete) 684b69a54eeSKentaro Takeda { 685b69a54eeSKentaro Takeda char *filename = strchr(data, ' '); 686b69a54eeSKentaro Takeda char *filename2; 687b69a54eeSKentaro Takeda unsigned int perm; 688b69a54eeSKentaro Takeda u8 type; 689b69a54eeSKentaro Takeda 690b69a54eeSKentaro Takeda if (!filename) 691b69a54eeSKentaro Takeda return -EINVAL; 692b69a54eeSKentaro Takeda *filename++ = '\0'; 693b69a54eeSKentaro Takeda if (sscanf(data, "%u", &perm) == 1) 694b69a54eeSKentaro Takeda return tomoyo_update_file_acl(filename, (u8) perm, domain, 695b69a54eeSKentaro Takeda is_delete); 696b69a54eeSKentaro Takeda if (strncmp(data, "allow_", 6)) 697b69a54eeSKentaro Takeda goto out; 698b69a54eeSKentaro Takeda data += 6; 699b69a54eeSKentaro Takeda for (type = 0; type < TOMOYO_MAX_SINGLE_PATH_OPERATION; type++) { 700b69a54eeSKentaro Takeda if (strcmp(data, tomoyo_sp_keyword[type])) 701b69a54eeSKentaro Takeda continue; 702b69a54eeSKentaro Takeda return tomoyo_update_single_path_acl(type, filename, 703b69a54eeSKentaro Takeda domain, is_delete); 704b69a54eeSKentaro Takeda } 705b69a54eeSKentaro Takeda filename2 = strchr(filename, ' '); 706b69a54eeSKentaro Takeda if (!filename2) 707b69a54eeSKentaro Takeda goto out; 708b69a54eeSKentaro Takeda *filename2++ = '\0'; 709b69a54eeSKentaro Takeda for (type = 0; type < TOMOYO_MAX_DOUBLE_PATH_OPERATION; type++) { 710b69a54eeSKentaro Takeda if (strcmp(data, tomoyo_dp_keyword[type])) 711b69a54eeSKentaro Takeda continue; 712b69a54eeSKentaro Takeda return tomoyo_update_double_path_acl(type, filename, filename2, 713b69a54eeSKentaro Takeda domain, is_delete); 714b69a54eeSKentaro Takeda } 715b69a54eeSKentaro Takeda out: 716b69a54eeSKentaro Takeda return -EINVAL; 717b69a54eeSKentaro Takeda } 718b69a54eeSKentaro Takeda 719b69a54eeSKentaro Takeda /** 720b69a54eeSKentaro Takeda * tomoyo_update_single_path_acl - Update "struct tomoyo_single_path_acl_record" list. 721b69a54eeSKentaro Takeda * 722b69a54eeSKentaro Takeda * @type: Type of operation. 723b69a54eeSKentaro Takeda * @filename: Filename. 724b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 725b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 726b69a54eeSKentaro Takeda * 727b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 728b69a54eeSKentaro Takeda */ 729b69a54eeSKentaro Takeda static int tomoyo_update_single_path_acl(const u8 type, const char *filename, 730b69a54eeSKentaro Takeda struct tomoyo_domain_info * 731b69a54eeSKentaro Takeda const domain, const bool is_delete) 732b69a54eeSKentaro Takeda { 733b69a54eeSKentaro Takeda static const u16 rw_mask = 734b69a54eeSKentaro Takeda (1 << TOMOYO_TYPE_READ_ACL) | (1 << TOMOYO_TYPE_WRITE_ACL); 735b69a54eeSKentaro Takeda const struct tomoyo_path_info *saved_filename; 736b69a54eeSKentaro Takeda struct tomoyo_acl_info *ptr; 737b69a54eeSKentaro Takeda struct tomoyo_single_path_acl_record *acl; 738b69a54eeSKentaro Takeda int error = -ENOMEM; 739b69a54eeSKentaro Takeda const u16 perm = 1 << type; 740b69a54eeSKentaro Takeda 741b69a54eeSKentaro Takeda if (!domain) 742b69a54eeSKentaro Takeda return -EINVAL; 743b69a54eeSKentaro Takeda if (!tomoyo_is_correct_path(filename, 0, 0, 0, __func__)) 744b69a54eeSKentaro Takeda return -EINVAL; 745b69a54eeSKentaro Takeda saved_filename = tomoyo_save_name(filename); 746b69a54eeSKentaro Takeda if (!saved_filename) 747b69a54eeSKentaro Takeda return -ENOMEM; 748b69a54eeSKentaro Takeda /***** EXCLUSIVE SECTION START *****/ 749b69a54eeSKentaro Takeda down_write(&tomoyo_domain_acl_info_list_lock); 750b69a54eeSKentaro Takeda if (is_delete) 751b69a54eeSKentaro Takeda goto delete; 752b69a54eeSKentaro Takeda list_for_each_entry(ptr, &domain->acl_info_list, list) { 753b69a54eeSKentaro Takeda if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) 754b69a54eeSKentaro Takeda continue; 755b69a54eeSKentaro Takeda acl = container_of(ptr, struct tomoyo_single_path_acl_record, 756b69a54eeSKentaro Takeda head); 757b69a54eeSKentaro Takeda if (acl->filename != saved_filename) 758b69a54eeSKentaro Takeda continue; 759b69a54eeSKentaro Takeda /* Special case. Clear all bits if marked as deleted. */ 760b69a54eeSKentaro Takeda if (ptr->type & TOMOYO_ACL_DELETED) 761b69a54eeSKentaro Takeda acl->perm = 0; 762b69a54eeSKentaro Takeda acl->perm |= perm; 763b69a54eeSKentaro Takeda if ((acl->perm & rw_mask) == rw_mask) 764b69a54eeSKentaro Takeda acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE_ACL; 765b69a54eeSKentaro Takeda else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL)) 766b69a54eeSKentaro Takeda acl->perm |= rw_mask; 767b69a54eeSKentaro Takeda ptr->type &= ~TOMOYO_ACL_DELETED; 768b69a54eeSKentaro Takeda error = 0; 769b69a54eeSKentaro Takeda goto out; 770b69a54eeSKentaro Takeda } 771b69a54eeSKentaro Takeda /* Not found. Append it to the tail. */ 772b69a54eeSKentaro Takeda acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_SINGLE_PATH_ACL); 773b69a54eeSKentaro Takeda if (!acl) 774b69a54eeSKentaro Takeda goto out; 775b69a54eeSKentaro Takeda acl->perm = perm; 776b69a54eeSKentaro Takeda if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL)) 777b69a54eeSKentaro Takeda acl->perm |= rw_mask; 778b69a54eeSKentaro Takeda acl->filename = saved_filename; 779b69a54eeSKentaro Takeda list_add_tail(&acl->head.list, &domain->acl_info_list); 780b69a54eeSKentaro Takeda error = 0; 781b69a54eeSKentaro Takeda goto out; 782b69a54eeSKentaro Takeda delete: 783b69a54eeSKentaro Takeda error = -ENOENT; 784b69a54eeSKentaro Takeda list_for_each_entry(ptr, &domain->acl_info_list, list) { 785b69a54eeSKentaro Takeda if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) 786b69a54eeSKentaro Takeda continue; 787b69a54eeSKentaro Takeda acl = container_of(ptr, struct tomoyo_single_path_acl_record, 788b69a54eeSKentaro Takeda head); 789b69a54eeSKentaro Takeda if (acl->filename != saved_filename) 790b69a54eeSKentaro Takeda continue; 791b69a54eeSKentaro Takeda acl->perm &= ~perm; 792b69a54eeSKentaro Takeda if ((acl->perm & rw_mask) != rw_mask) 793b69a54eeSKentaro Takeda acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE_ACL); 794b69a54eeSKentaro Takeda else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL))) 795b69a54eeSKentaro Takeda acl->perm &= ~rw_mask; 796b69a54eeSKentaro Takeda if (!acl->perm) 797b69a54eeSKentaro Takeda ptr->type |= TOMOYO_ACL_DELETED; 798b69a54eeSKentaro Takeda error = 0; 799b69a54eeSKentaro Takeda break; 800b69a54eeSKentaro Takeda } 801b69a54eeSKentaro Takeda out: 802b69a54eeSKentaro Takeda up_write(&tomoyo_domain_acl_info_list_lock); 803b69a54eeSKentaro Takeda /***** EXCLUSIVE SECTION END *****/ 804b69a54eeSKentaro Takeda return error; 805b69a54eeSKentaro Takeda } 806b69a54eeSKentaro Takeda 807b69a54eeSKentaro Takeda /** 808b69a54eeSKentaro Takeda * tomoyo_update_double_path_acl - Update "struct tomoyo_double_path_acl_record" list. 809b69a54eeSKentaro Takeda * 810b69a54eeSKentaro Takeda * @type: Type of operation. 811b69a54eeSKentaro Takeda * @filename1: First filename. 812b69a54eeSKentaro Takeda * @filename2: Second filename. 813b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 814b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 815b69a54eeSKentaro Takeda * 816b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 817b69a54eeSKentaro Takeda */ 818b69a54eeSKentaro Takeda static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, 819b69a54eeSKentaro Takeda const char *filename2, 820b69a54eeSKentaro Takeda struct tomoyo_domain_info * 821b69a54eeSKentaro Takeda const domain, const bool is_delete) 822b69a54eeSKentaro Takeda { 823b69a54eeSKentaro Takeda const struct tomoyo_path_info *saved_filename1; 824b69a54eeSKentaro Takeda const struct tomoyo_path_info *saved_filename2; 825b69a54eeSKentaro Takeda struct tomoyo_acl_info *ptr; 826b69a54eeSKentaro Takeda struct tomoyo_double_path_acl_record *acl; 827b69a54eeSKentaro Takeda int error = -ENOMEM; 828b69a54eeSKentaro Takeda const u8 perm = 1 << type; 829b69a54eeSKentaro Takeda 830b69a54eeSKentaro Takeda if (!domain) 831b69a54eeSKentaro Takeda return -EINVAL; 832b69a54eeSKentaro Takeda if (!tomoyo_is_correct_path(filename1, 0, 0, 0, __func__) || 833b69a54eeSKentaro Takeda !tomoyo_is_correct_path(filename2, 0, 0, 0, __func__)) 834b69a54eeSKentaro Takeda return -EINVAL; 835b69a54eeSKentaro Takeda saved_filename1 = tomoyo_save_name(filename1); 836b69a54eeSKentaro Takeda saved_filename2 = tomoyo_save_name(filename2); 837b69a54eeSKentaro Takeda if (!saved_filename1 || !saved_filename2) 838b69a54eeSKentaro Takeda return -ENOMEM; 839b69a54eeSKentaro Takeda /***** EXCLUSIVE SECTION START *****/ 840b69a54eeSKentaro Takeda down_write(&tomoyo_domain_acl_info_list_lock); 841b69a54eeSKentaro Takeda if (is_delete) 842b69a54eeSKentaro Takeda goto delete; 843b69a54eeSKentaro Takeda list_for_each_entry(ptr, &domain->acl_info_list, list) { 844b69a54eeSKentaro Takeda if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) 845b69a54eeSKentaro Takeda continue; 846b69a54eeSKentaro Takeda acl = container_of(ptr, struct tomoyo_double_path_acl_record, 847b69a54eeSKentaro Takeda head); 848b69a54eeSKentaro Takeda if (acl->filename1 != saved_filename1 || 849b69a54eeSKentaro Takeda acl->filename2 != saved_filename2) 850b69a54eeSKentaro Takeda continue; 851b69a54eeSKentaro Takeda /* Special case. Clear all bits if marked as deleted. */ 852b69a54eeSKentaro Takeda if (ptr->type & TOMOYO_ACL_DELETED) 853b69a54eeSKentaro Takeda acl->perm = 0; 854b69a54eeSKentaro Takeda acl->perm |= perm; 855b69a54eeSKentaro Takeda ptr->type &= ~TOMOYO_ACL_DELETED; 856b69a54eeSKentaro Takeda error = 0; 857b69a54eeSKentaro Takeda goto out; 858b69a54eeSKentaro Takeda } 859b69a54eeSKentaro Takeda /* Not found. Append it to the tail. */ 860b69a54eeSKentaro Takeda acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_DOUBLE_PATH_ACL); 861b69a54eeSKentaro Takeda if (!acl) 862b69a54eeSKentaro Takeda goto out; 863b69a54eeSKentaro Takeda acl->perm = perm; 864b69a54eeSKentaro Takeda acl->filename1 = saved_filename1; 865b69a54eeSKentaro Takeda acl->filename2 = saved_filename2; 866b69a54eeSKentaro Takeda list_add_tail(&acl->head.list, &domain->acl_info_list); 867b69a54eeSKentaro Takeda error = 0; 868b69a54eeSKentaro Takeda goto out; 869b69a54eeSKentaro Takeda delete: 870b69a54eeSKentaro Takeda error = -ENOENT; 871b69a54eeSKentaro Takeda list_for_each_entry(ptr, &domain->acl_info_list, list) { 872b69a54eeSKentaro Takeda if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) 873b69a54eeSKentaro Takeda continue; 874b69a54eeSKentaro Takeda acl = container_of(ptr, struct tomoyo_double_path_acl_record, 875b69a54eeSKentaro Takeda head); 876b69a54eeSKentaro Takeda if (acl->filename1 != saved_filename1 || 877b69a54eeSKentaro Takeda acl->filename2 != saved_filename2) 878b69a54eeSKentaro Takeda continue; 879b69a54eeSKentaro Takeda acl->perm &= ~perm; 880b69a54eeSKentaro Takeda if (!acl->perm) 881b69a54eeSKentaro Takeda ptr->type |= TOMOYO_ACL_DELETED; 882b69a54eeSKentaro Takeda error = 0; 883b69a54eeSKentaro Takeda break; 884b69a54eeSKentaro Takeda } 885b69a54eeSKentaro Takeda out: 886b69a54eeSKentaro Takeda up_write(&tomoyo_domain_acl_info_list_lock); 887b69a54eeSKentaro Takeda /***** EXCLUSIVE SECTION END *****/ 888b69a54eeSKentaro Takeda return error; 889b69a54eeSKentaro Takeda } 890b69a54eeSKentaro Takeda 891b69a54eeSKentaro Takeda /** 892b69a54eeSKentaro Takeda * tomoyo_check_single_path_acl - Check permission for single path operation. 893b69a54eeSKentaro Takeda * 894b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 895b69a54eeSKentaro Takeda * @type: Type of operation. 896b69a54eeSKentaro Takeda * @filename: Filename to check. 897b69a54eeSKentaro Takeda * 898b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 899b69a54eeSKentaro Takeda */ 900b69a54eeSKentaro Takeda static int tomoyo_check_single_path_acl(struct tomoyo_domain_info *domain, 901b69a54eeSKentaro Takeda const u8 type, 902b69a54eeSKentaro Takeda const struct tomoyo_path_info *filename) 903b69a54eeSKentaro Takeda { 904b69a54eeSKentaro Takeda if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) 905b69a54eeSKentaro Takeda return 0; 906b69a54eeSKentaro Takeda return tomoyo_check_single_path_acl2(domain, filename, 1 << type, 1); 907b69a54eeSKentaro Takeda } 908b69a54eeSKentaro Takeda 909b69a54eeSKentaro Takeda /** 910b69a54eeSKentaro Takeda * tomoyo_check_double_path_acl - Check permission for double path operation. 911b69a54eeSKentaro Takeda * 912b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 913b69a54eeSKentaro Takeda * @type: Type of operation. 914b69a54eeSKentaro Takeda * @filename1: First filename to check. 915b69a54eeSKentaro Takeda * @filename2: Second filename to check. 916b69a54eeSKentaro Takeda * 917b69a54eeSKentaro Takeda * Returns 0 on success, -EPERM otherwise. 918b69a54eeSKentaro Takeda */ 919b69a54eeSKentaro Takeda static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, 920b69a54eeSKentaro Takeda const u8 type, 921b69a54eeSKentaro Takeda const struct tomoyo_path_info * 922b69a54eeSKentaro Takeda filename1, 923b69a54eeSKentaro Takeda const struct tomoyo_path_info * 924b69a54eeSKentaro Takeda filename2) 925b69a54eeSKentaro Takeda { 926b69a54eeSKentaro Takeda struct tomoyo_acl_info *ptr; 927b69a54eeSKentaro Takeda const u8 perm = 1 << type; 928b69a54eeSKentaro Takeda int error = -EPERM; 929b69a54eeSKentaro Takeda 930b69a54eeSKentaro Takeda if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) 931b69a54eeSKentaro Takeda return 0; 932b69a54eeSKentaro Takeda down_read(&tomoyo_domain_acl_info_list_lock); 933b69a54eeSKentaro Takeda list_for_each_entry(ptr, &domain->acl_info_list, list) { 934b69a54eeSKentaro Takeda struct tomoyo_double_path_acl_record *acl; 935b69a54eeSKentaro Takeda if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) 936b69a54eeSKentaro Takeda continue; 937b69a54eeSKentaro Takeda acl = container_of(ptr, struct tomoyo_double_path_acl_record, 938b69a54eeSKentaro Takeda head); 939b69a54eeSKentaro Takeda if (!(acl->perm & perm)) 940b69a54eeSKentaro Takeda continue; 941b69a54eeSKentaro Takeda if (!tomoyo_path_matches_pattern(filename1, acl->filename1)) 942b69a54eeSKentaro Takeda continue; 943b69a54eeSKentaro Takeda if (!tomoyo_path_matches_pattern(filename2, acl->filename2)) 944b69a54eeSKentaro Takeda continue; 945b69a54eeSKentaro Takeda error = 0; 946b69a54eeSKentaro Takeda break; 947b69a54eeSKentaro Takeda } 948b69a54eeSKentaro Takeda up_read(&tomoyo_domain_acl_info_list_lock); 949b69a54eeSKentaro Takeda return error; 950b69a54eeSKentaro Takeda } 951b69a54eeSKentaro Takeda 952b69a54eeSKentaro Takeda /** 953b69a54eeSKentaro Takeda * tomoyo_check_single_path_permission2 - Check permission for single path operation. 954b69a54eeSKentaro Takeda * 955b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 956b69a54eeSKentaro Takeda * @operation: Type of operation. 957b69a54eeSKentaro Takeda * @filename: Filename to check. 958b69a54eeSKentaro Takeda * @mode: Access control mode. 959b69a54eeSKentaro Takeda * 960b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 961b69a54eeSKentaro Takeda */ 962b69a54eeSKentaro Takeda static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * 963b69a54eeSKentaro Takeda const domain, u8 operation, 964b69a54eeSKentaro Takeda const struct tomoyo_path_info * 965b69a54eeSKentaro Takeda filename, const u8 mode) 966b69a54eeSKentaro Takeda { 967b69a54eeSKentaro Takeda const char *msg; 968b69a54eeSKentaro Takeda int error; 969b69a54eeSKentaro Takeda const bool is_enforce = (mode == 3); 970b69a54eeSKentaro Takeda 971b69a54eeSKentaro Takeda if (!mode) 972b69a54eeSKentaro Takeda return 0; 973b69a54eeSKentaro Takeda next: 974b69a54eeSKentaro Takeda error = tomoyo_check_single_path_acl(domain, operation, filename); 975b69a54eeSKentaro Takeda msg = tomoyo_sp2keyword(operation); 976b69a54eeSKentaro Takeda if (!error) 977b69a54eeSKentaro Takeda goto ok; 978b69a54eeSKentaro Takeda if (tomoyo_verbose_mode(domain)) 979b69a54eeSKentaro Takeda printk(KERN_WARNING "TOMOYO-%s: Access '%s %s' denied for %s\n", 980b69a54eeSKentaro Takeda tomoyo_get_msg(is_enforce), msg, filename->name, 981b69a54eeSKentaro Takeda tomoyo_get_last_name(domain)); 982b69a54eeSKentaro Takeda if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { 983b69a54eeSKentaro Takeda const char *name = tomoyo_get_file_pattern(filename)->name; 984b69a54eeSKentaro Takeda tomoyo_update_single_path_acl(operation, name, domain, false); 985b69a54eeSKentaro Takeda } 986b69a54eeSKentaro Takeda if (!is_enforce) 987b69a54eeSKentaro Takeda error = 0; 988b69a54eeSKentaro Takeda ok: 989b69a54eeSKentaro Takeda /* 990b69a54eeSKentaro Takeda * Since "allow_truncate" doesn't imply "allow_rewrite" permission, 991b69a54eeSKentaro Takeda * we need to check "allow_rewrite" permission if the filename is 992b69a54eeSKentaro Takeda * specified by "deny_rewrite" keyword. 993b69a54eeSKentaro Takeda */ 994b69a54eeSKentaro Takeda if (!error && operation == TOMOYO_TYPE_TRUNCATE_ACL && 995b69a54eeSKentaro Takeda tomoyo_is_no_rewrite_file(filename)) { 996b69a54eeSKentaro Takeda operation = TOMOYO_TYPE_REWRITE_ACL; 997b69a54eeSKentaro Takeda goto next; 998b69a54eeSKentaro Takeda } 999b69a54eeSKentaro Takeda return error; 1000b69a54eeSKentaro Takeda } 1001b69a54eeSKentaro Takeda 1002b69a54eeSKentaro Takeda /** 1003b69a54eeSKentaro Takeda * tomoyo_check_file_perm - Check permission for sysctl()'s "read" and "write". 1004b69a54eeSKentaro Takeda * 1005b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 1006b69a54eeSKentaro Takeda * @filename: Filename to check. 1007b69a54eeSKentaro Takeda * @perm: Mode ("read" or "write" or "read/write"). 1008b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1009b69a54eeSKentaro Takeda */ 1010b69a54eeSKentaro Takeda int tomoyo_check_file_perm(struct tomoyo_domain_info *domain, 1011b69a54eeSKentaro Takeda const char *filename, const u8 perm) 1012b69a54eeSKentaro Takeda { 1013b69a54eeSKentaro Takeda struct tomoyo_path_info name; 1014b69a54eeSKentaro Takeda const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); 1015b69a54eeSKentaro Takeda 1016b69a54eeSKentaro Takeda if (!mode) 1017b69a54eeSKentaro Takeda return 0; 1018b69a54eeSKentaro Takeda name.name = filename; 1019b69a54eeSKentaro Takeda tomoyo_fill_path_info(&name); 1020b69a54eeSKentaro Takeda return tomoyo_check_file_perm2(domain, &name, perm, "sysctl", mode); 1021b69a54eeSKentaro Takeda } 1022b69a54eeSKentaro Takeda 1023b69a54eeSKentaro Takeda /** 1024b69a54eeSKentaro Takeda * tomoyo_check_exec_perm - Check permission for "execute". 1025b69a54eeSKentaro Takeda * 1026b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 1027b69a54eeSKentaro Takeda * @filename: Check permission for "execute". 1028b69a54eeSKentaro Takeda * @tmp: Buffer for temporary use. 1029b69a54eeSKentaro Takeda * 1030b69a54eeSKentaro Takeda * Returns 0 on success, negativevalue otherwise. 1031b69a54eeSKentaro Takeda */ 1032b69a54eeSKentaro Takeda int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, 1033b69a54eeSKentaro Takeda const struct tomoyo_path_info *filename, 1034b69a54eeSKentaro Takeda struct tomoyo_page_buffer *tmp) 1035b69a54eeSKentaro Takeda { 1036b69a54eeSKentaro Takeda const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); 1037b69a54eeSKentaro Takeda 1038b69a54eeSKentaro Takeda if (!mode) 1039b69a54eeSKentaro Takeda return 0; 1040b69a54eeSKentaro Takeda return tomoyo_check_file_perm2(domain, filename, 1, "do_execve", mode); 1041b69a54eeSKentaro Takeda } 1042b69a54eeSKentaro Takeda 1043b69a54eeSKentaro Takeda /** 1044b69a54eeSKentaro Takeda * tomoyo_check_open_permission - Check permission for "read" and "write". 1045b69a54eeSKentaro Takeda * 1046b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 1047b69a54eeSKentaro Takeda * @path: Pointer to "struct path". 1048b69a54eeSKentaro Takeda * @flag: Flags for open(). 1049b69a54eeSKentaro Takeda * 1050b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1051b69a54eeSKentaro Takeda */ 1052b69a54eeSKentaro Takeda int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, 1053b69a54eeSKentaro Takeda struct path *path, const int flag) 1054b69a54eeSKentaro Takeda { 1055b69a54eeSKentaro Takeda const u8 acc_mode = ACC_MODE(flag); 1056b69a54eeSKentaro Takeda int error = -ENOMEM; 1057b69a54eeSKentaro Takeda struct tomoyo_path_info *buf; 1058b69a54eeSKentaro Takeda const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); 1059b69a54eeSKentaro Takeda const bool is_enforce = (mode == 3); 1060b69a54eeSKentaro Takeda 1061b69a54eeSKentaro Takeda if (!mode || !path->mnt) 1062b69a54eeSKentaro Takeda return 0; 1063b69a54eeSKentaro Takeda if (acc_mode == 0) 1064b69a54eeSKentaro Takeda return 0; 1065b69a54eeSKentaro Takeda if (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode)) 1066b69a54eeSKentaro Takeda /* 1067b69a54eeSKentaro Takeda * I don't check directories here because mkdir() and rmdir() 1068b69a54eeSKentaro Takeda * don't call me. 1069b69a54eeSKentaro Takeda */ 1070b69a54eeSKentaro Takeda return 0; 1071b69a54eeSKentaro Takeda buf = tomoyo_get_path(path); 1072b69a54eeSKentaro Takeda if (!buf) 1073b69a54eeSKentaro Takeda goto out; 1074b69a54eeSKentaro Takeda error = 0; 1075b69a54eeSKentaro Takeda /* 1076b69a54eeSKentaro Takeda * If the filename is specified by "deny_rewrite" keyword, 1077b69a54eeSKentaro Takeda * we need to check "allow_rewrite" permission when the filename is not 1078b69a54eeSKentaro Takeda * opened for append mode or the filename is truncated at open time. 1079b69a54eeSKentaro Takeda */ 1080b69a54eeSKentaro Takeda if ((acc_mode & MAY_WRITE) && 1081b69a54eeSKentaro Takeda ((flag & O_TRUNC) || !(flag & O_APPEND)) && 1082b69a54eeSKentaro Takeda (tomoyo_is_no_rewrite_file(buf))) { 1083b69a54eeSKentaro Takeda error = tomoyo_check_single_path_permission2(domain, 1084b69a54eeSKentaro Takeda TOMOYO_TYPE_REWRITE_ACL, 1085b69a54eeSKentaro Takeda buf, mode); 1086b69a54eeSKentaro Takeda } 1087b69a54eeSKentaro Takeda if (!error) 1088b69a54eeSKentaro Takeda error = tomoyo_check_file_perm2(domain, buf, acc_mode, "open", 1089b69a54eeSKentaro Takeda mode); 1090b69a54eeSKentaro Takeda if (!error && (flag & O_TRUNC)) 1091b69a54eeSKentaro Takeda error = tomoyo_check_single_path_permission2(domain, 1092b69a54eeSKentaro Takeda TOMOYO_TYPE_TRUNCATE_ACL, 1093b69a54eeSKentaro Takeda buf, mode); 1094b69a54eeSKentaro Takeda out: 1095b69a54eeSKentaro Takeda tomoyo_free(buf); 1096b69a54eeSKentaro Takeda if (!is_enforce) 1097b69a54eeSKentaro Takeda error = 0; 1098b69a54eeSKentaro Takeda return error; 1099b69a54eeSKentaro Takeda } 1100b69a54eeSKentaro Takeda 1101b69a54eeSKentaro Takeda /** 1102b69a54eeSKentaro Takeda * tomoyo_check_1path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate" and "symlink". 1103b69a54eeSKentaro Takeda * 1104b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 1105b69a54eeSKentaro Takeda * @operation: Type of operation. 1106b69a54eeSKentaro Takeda * @path: Pointer to "struct path". 1107b69a54eeSKentaro Takeda * 1108b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1109b69a54eeSKentaro Takeda */ 1110b69a54eeSKentaro Takeda int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, 1111b69a54eeSKentaro Takeda const u8 operation, struct path *path) 1112b69a54eeSKentaro Takeda { 1113b69a54eeSKentaro Takeda int error = -ENOMEM; 1114b69a54eeSKentaro Takeda struct tomoyo_path_info *buf; 1115b69a54eeSKentaro Takeda const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); 1116b69a54eeSKentaro Takeda const bool is_enforce = (mode == 3); 1117b69a54eeSKentaro Takeda 1118b69a54eeSKentaro Takeda if (!mode || !path->mnt) 1119b69a54eeSKentaro Takeda return 0; 1120b69a54eeSKentaro Takeda buf = tomoyo_get_path(path); 1121b69a54eeSKentaro Takeda if (!buf) 1122b69a54eeSKentaro Takeda goto out; 1123b69a54eeSKentaro Takeda switch (operation) { 1124b69a54eeSKentaro Takeda case TOMOYO_TYPE_MKDIR_ACL: 1125b69a54eeSKentaro Takeda case TOMOYO_TYPE_RMDIR_ACL: 1126b69a54eeSKentaro Takeda if (!buf->is_dir) { 1127b69a54eeSKentaro Takeda /* 1128b69a54eeSKentaro Takeda * tomoyo_get_path() reserves space for appending "/." 1129b69a54eeSKentaro Takeda */ 1130b69a54eeSKentaro Takeda strcat((char *) buf->name, "/"); 1131b69a54eeSKentaro Takeda tomoyo_fill_path_info(buf); 1132b69a54eeSKentaro Takeda } 1133b69a54eeSKentaro Takeda } 1134b69a54eeSKentaro Takeda error = tomoyo_check_single_path_permission2(domain, operation, buf, 1135b69a54eeSKentaro Takeda mode); 1136b69a54eeSKentaro Takeda out: 1137b69a54eeSKentaro Takeda tomoyo_free(buf); 1138b69a54eeSKentaro Takeda if (!is_enforce) 1139b69a54eeSKentaro Takeda error = 0; 1140b69a54eeSKentaro Takeda return error; 1141b69a54eeSKentaro Takeda } 1142b69a54eeSKentaro Takeda 1143b69a54eeSKentaro Takeda /** 1144b69a54eeSKentaro Takeda * tomoyo_check_rewrite_permission - Check permission for "rewrite". 1145b69a54eeSKentaro Takeda * 1146b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 1147b69a54eeSKentaro Takeda * @filp: Pointer to "struct file". 1148b69a54eeSKentaro Takeda * 1149b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1150b69a54eeSKentaro Takeda */ 1151b69a54eeSKentaro Takeda int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, 1152b69a54eeSKentaro Takeda struct file *filp) 1153b69a54eeSKentaro Takeda { 1154b69a54eeSKentaro Takeda int error = -ENOMEM; 1155b69a54eeSKentaro Takeda const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); 1156b69a54eeSKentaro Takeda const bool is_enforce = (mode == 3); 1157b69a54eeSKentaro Takeda struct tomoyo_path_info *buf; 1158b69a54eeSKentaro Takeda 1159b69a54eeSKentaro Takeda if (!mode || !filp->f_path.mnt) 1160b69a54eeSKentaro Takeda return 0; 1161b69a54eeSKentaro Takeda buf = tomoyo_get_path(&filp->f_path); 1162b69a54eeSKentaro Takeda if (!buf) 1163b69a54eeSKentaro Takeda goto out; 1164b69a54eeSKentaro Takeda if (!tomoyo_is_no_rewrite_file(buf)) { 1165b69a54eeSKentaro Takeda error = 0; 1166b69a54eeSKentaro Takeda goto out; 1167b69a54eeSKentaro Takeda } 1168b69a54eeSKentaro Takeda error = tomoyo_check_single_path_permission2(domain, 1169b69a54eeSKentaro Takeda TOMOYO_TYPE_REWRITE_ACL, 1170b69a54eeSKentaro Takeda buf, mode); 1171b69a54eeSKentaro Takeda out: 1172b69a54eeSKentaro Takeda tomoyo_free(buf); 1173b69a54eeSKentaro Takeda if (!is_enforce) 1174b69a54eeSKentaro Takeda error = 0; 1175b69a54eeSKentaro Takeda return error; 1176b69a54eeSKentaro Takeda } 1177b69a54eeSKentaro Takeda 1178b69a54eeSKentaro Takeda /** 1179b69a54eeSKentaro Takeda * tomoyo_check_2path_perm - Check permission for "rename" and "link". 1180b69a54eeSKentaro Takeda * 1181b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 1182b69a54eeSKentaro Takeda * @operation: Type of operation. 1183b69a54eeSKentaro Takeda * @path1: Pointer to "struct path". 1184b69a54eeSKentaro Takeda * @path2: Pointer to "struct path". 1185b69a54eeSKentaro Takeda * 1186b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1187b69a54eeSKentaro Takeda */ 1188b69a54eeSKentaro Takeda int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain, 1189b69a54eeSKentaro Takeda const u8 operation, struct path *path1, 1190b69a54eeSKentaro Takeda struct path *path2) 1191b69a54eeSKentaro Takeda { 1192b69a54eeSKentaro Takeda int error = -ENOMEM; 1193b69a54eeSKentaro Takeda struct tomoyo_path_info *buf1, *buf2; 1194b69a54eeSKentaro Takeda const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); 1195b69a54eeSKentaro Takeda const bool is_enforce = (mode == 3); 1196b69a54eeSKentaro Takeda const char *msg; 1197b69a54eeSKentaro Takeda 1198b69a54eeSKentaro Takeda if (!mode || !path1->mnt || !path2->mnt) 1199b69a54eeSKentaro Takeda return 0; 1200b69a54eeSKentaro Takeda buf1 = tomoyo_get_path(path1); 1201b69a54eeSKentaro Takeda buf2 = tomoyo_get_path(path2); 1202b69a54eeSKentaro Takeda if (!buf1 || !buf2) 1203b69a54eeSKentaro Takeda goto out; 1204b69a54eeSKentaro Takeda { 1205b69a54eeSKentaro Takeda struct dentry *dentry = path1->dentry; 1206b69a54eeSKentaro Takeda if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) { 1207b69a54eeSKentaro Takeda /* 1208b69a54eeSKentaro Takeda * tomoyo_get_path() reserves space for appending "/." 1209b69a54eeSKentaro Takeda */ 1210b69a54eeSKentaro Takeda if (!buf1->is_dir) { 1211b69a54eeSKentaro Takeda strcat((char *) buf1->name, "/"); 1212b69a54eeSKentaro Takeda tomoyo_fill_path_info(buf1); 1213b69a54eeSKentaro Takeda } 1214b69a54eeSKentaro Takeda if (!buf2->is_dir) { 1215b69a54eeSKentaro Takeda strcat((char *) buf2->name, "/"); 1216b69a54eeSKentaro Takeda tomoyo_fill_path_info(buf2); 1217b69a54eeSKentaro Takeda } 1218b69a54eeSKentaro Takeda } 1219b69a54eeSKentaro Takeda } 1220b69a54eeSKentaro Takeda error = tomoyo_check_double_path_acl(domain, operation, buf1, buf2); 1221b69a54eeSKentaro Takeda msg = tomoyo_dp2keyword(operation); 1222b69a54eeSKentaro Takeda if (!error) 1223b69a54eeSKentaro Takeda goto out; 1224b69a54eeSKentaro Takeda if (tomoyo_verbose_mode(domain)) 1225b69a54eeSKentaro Takeda printk(KERN_WARNING "TOMOYO-%s: Access '%s %s %s' " 1226b69a54eeSKentaro Takeda "denied for %s\n", tomoyo_get_msg(is_enforce), 1227b69a54eeSKentaro Takeda msg, buf1->name, buf2->name, 1228b69a54eeSKentaro Takeda tomoyo_get_last_name(domain)); 1229b69a54eeSKentaro Takeda if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { 1230b69a54eeSKentaro Takeda const char *name1 = tomoyo_get_file_pattern(buf1)->name; 1231b69a54eeSKentaro Takeda const char *name2 = tomoyo_get_file_pattern(buf2)->name; 1232b69a54eeSKentaro Takeda tomoyo_update_double_path_acl(operation, name1, name2, domain, 1233b69a54eeSKentaro Takeda false); 1234b69a54eeSKentaro Takeda } 1235b69a54eeSKentaro Takeda out: 1236b69a54eeSKentaro Takeda tomoyo_free(buf1); 1237b69a54eeSKentaro Takeda tomoyo_free(buf2); 1238b69a54eeSKentaro Takeda if (!is_enforce) 1239b69a54eeSKentaro Takeda error = 0; 1240b69a54eeSKentaro Takeda return error; 1241b69a54eeSKentaro Takeda } 1242