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