1b69a54eeSKentaro Takeda /* 2b69a54eeSKentaro Takeda * security/tomoyo/file.c 3b69a54eeSKentaro Takeda * 4c3ef1500STetsuo Handa * Pathname restriction functions. 5b69a54eeSKentaro Takeda * 6c3ef1500STetsuo Handa * Copyright (C) 2005-2010 NTT DATA CORPORATION 7b69a54eeSKentaro Takeda */ 8b69a54eeSKentaro Takeda 9b69a54eeSKentaro Takeda #include "common.h" 105a0e3ad6STejun Heo #include <linux/slab.h> 11b69a54eeSKentaro Takeda 12a1f9bb6aSTetsuo Handa /* Keyword array for operations with one pathname. */ 137ef61233STetsuo Handa static const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = { 147ef61233STetsuo Handa [TOMOYO_TYPE_READ_WRITE] = "read/write", 157ef61233STetsuo Handa [TOMOYO_TYPE_EXECUTE] = "execute", 167ef61233STetsuo Handa [TOMOYO_TYPE_READ] = "read", 177ef61233STetsuo Handa [TOMOYO_TYPE_WRITE] = "write", 187ef61233STetsuo Handa [TOMOYO_TYPE_UNLINK] = "unlink", 197ef61233STetsuo Handa [TOMOYO_TYPE_RMDIR] = "rmdir", 207ef61233STetsuo Handa [TOMOYO_TYPE_TRUNCATE] = "truncate", 217ef61233STetsuo Handa [TOMOYO_TYPE_SYMLINK] = "symlink", 227ef61233STetsuo Handa [TOMOYO_TYPE_REWRITE] = "rewrite", 237ef61233STetsuo Handa [TOMOYO_TYPE_CHROOT] = "chroot", 247ef61233STetsuo Handa [TOMOYO_TYPE_UMOUNT] = "unmount", 25b69a54eeSKentaro Takeda }; 26b69a54eeSKentaro Takeda 27a1f9bb6aSTetsuo Handa /* Keyword array for operations with one pathname and three numbers. */ 28a1f9bb6aSTetsuo Handa static const char *tomoyo_path_number3_keyword 29a1f9bb6aSTetsuo Handa [TOMOYO_MAX_PATH_NUMBER3_OPERATION] = { 30a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_MKBLOCK] = "mkblock", 31a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_MKCHAR] = "mkchar", 32a1f9bb6aSTetsuo Handa }; 33a1f9bb6aSTetsuo Handa 34a1f9bb6aSTetsuo Handa /* Keyword array for operations with two pathnames. */ 357ef61233STetsuo Handa static const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = { 367ef61233STetsuo Handa [TOMOYO_TYPE_LINK] = "link", 377ef61233STetsuo Handa [TOMOYO_TYPE_RENAME] = "rename", 387ef61233STetsuo Handa [TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root", 39b69a54eeSKentaro Takeda }; 40b69a54eeSKentaro Takeda 41a1f9bb6aSTetsuo Handa /* Keyword array for operations with one pathname and one number. */ 42a1f9bb6aSTetsuo Handa static const char *tomoyo_path_number_keyword 43a1f9bb6aSTetsuo Handa [TOMOYO_MAX_PATH_NUMBER_OPERATION] = { 44a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_CREATE] = "create", 45a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_MKDIR] = "mkdir", 46a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_MKFIFO] = "mkfifo", 47a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_MKSOCK] = "mksock", 48a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_IOCTL] = "ioctl", 49a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_CHMOD] = "chmod", 50a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_CHOWN] = "chown", 51a1f9bb6aSTetsuo Handa [TOMOYO_TYPE_CHGRP] = "chgrp", 52a1f9bb6aSTetsuo Handa }; 53a1f9bb6aSTetsuo Handa 5457c2590fSTetsuo Handa static const u8 tomoyo_p2mac[TOMOYO_MAX_PATH_OPERATION] = { 5557c2590fSTetsuo Handa [TOMOYO_TYPE_READ_WRITE] = TOMOYO_MAC_FILE_OPEN, 5657c2590fSTetsuo Handa [TOMOYO_TYPE_EXECUTE] = TOMOYO_MAC_FILE_EXECUTE, 5757c2590fSTetsuo Handa [TOMOYO_TYPE_READ] = TOMOYO_MAC_FILE_OPEN, 5857c2590fSTetsuo Handa [TOMOYO_TYPE_WRITE] = TOMOYO_MAC_FILE_OPEN, 5957c2590fSTetsuo Handa [TOMOYO_TYPE_UNLINK] = TOMOYO_MAC_FILE_UNLINK, 6057c2590fSTetsuo Handa [TOMOYO_TYPE_RMDIR] = TOMOYO_MAC_FILE_RMDIR, 6157c2590fSTetsuo Handa [TOMOYO_TYPE_TRUNCATE] = TOMOYO_MAC_FILE_TRUNCATE, 6257c2590fSTetsuo Handa [TOMOYO_TYPE_SYMLINK] = TOMOYO_MAC_FILE_SYMLINK, 6357c2590fSTetsuo Handa [TOMOYO_TYPE_REWRITE] = TOMOYO_MAC_FILE_REWRITE, 6457c2590fSTetsuo Handa [TOMOYO_TYPE_CHROOT] = TOMOYO_MAC_FILE_CHROOT, 6557c2590fSTetsuo Handa [TOMOYO_TYPE_UMOUNT] = TOMOYO_MAC_FILE_UMOUNT, 6657c2590fSTetsuo Handa }; 6757c2590fSTetsuo Handa 6857c2590fSTetsuo Handa static const u8 tomoyo_pnnn2mac[TOMOYO_MAX_PATH_NUMBER3_OPERATION] = { 6957c2590fSTetsuo Handa [TOMOYO_TYPE_MKBLOCK] = TOMOYO_MAC_FILE_MKBLOCK, 7057c2590fSTetsuo Handa [TOMOYO_TYPE_MKCHAR] = TOMOYO_MAC_FILE_MKCHAR, 7157c2590fSTetsuo Handa }; 7257c2590fSTetsuo Handa 7357c2590fSTetsuo Handa static const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION] = { 7457c2590fSTetsuo Handa [TOMOYO_TYPE_LINK] = TOMOYO_MAC_FILE_LINK, 7557c2590fSTetsuo Handa [TOMOYO_TYPE_RENAME] = TOMOYO_MAC_FILE_RENAME, 7657c2590fSTetsuo Handa [TOMOYO_TYPE_PIVOT_ROOT] = TOMOYO_MAC_FILE_PIVOT_ROOT, 7757c2590fSTetsuo Handa }; 7857c2590fSTetsuo Handa 7957c2590fSTetsuo Handa static const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = { 8057c2590fSTetsuo Handa [TOMOYO_TYPE_CREATE] = TOMOYO_MAC_FILE_CREATE, 8157c2590fSTetsuo Handa [TOMOYO_TYPE_MKDIR] = TOMOYO_MAC_FILE_MKDIR, 8257c2590fSTetsuo Handa [TOMOYO_TYPE_MKFIFO] = TOMOYO_MAC_FILE_MKFIFO, 8357c2590fSTetsuo Handa [TOMOYO_TYPE_MKSOCK] = TOMOYO_MAC_FILE_MKSOCK, 8457c2590fSTetsuo Handa [TOMOYO_TYPE_IOCTL] = TOMOYO_MAC_FILE_IOCTL, 8557c2590fSTetsuo Handa [TOMOYO_TYPE_CHMOD] = TOMOYO_MAC_FILE_CHMOD, 8657c2590fSTetsuo Handa [TOMOYO_TYPE_CHOWN] = TOMOYO_MAC_FILE_CHOWN, 8757c2590fSTetsuo Handa [TOMOYO_TYPE_CHGRP] = TOMOYO_MAC_FILE_CHGRP, 8857c2590fSTetsuo Handa }; 8957c2590fSTetsuo Handa 907762fbffSTetsuo Handa void tomoyo_put_name_union(struct tomoyo_name_union *ptr) 917762fbffSTetsuo Handa { 927762fbffSTetsuo Handa if (!ptr) 937762fbffSTetsuo Handa return; 947762fbffSTetsuo Handa if (ptr->is_group) 957762fbffSTetsuo Handa tomoyo_put_path_group(ptr->group); 967762fbffSTetsuo Handa else 977762fbffSTetsuo Handa tomoyo_put_name(ptr->filename); 987762fbffSTetsuo Handa } 997762fbffSTetsuo Handa 1007762fbffSTetsuo Handa bool tomoyo_compare_name_union(const struct tomoyo_path_info *name, 1017762fbffSTetsuo Handa const struct tomoyo_name_union *ptr) 1027762fbffSTetsuo Handa { 1037762fbffSTetsuo Handa if (ptr->is_group) 1043f629636STetsuo Handa return tomoyo_path_matches_group(name, ptr->group); 1057762fbffSTetsuo Handa return tomoyo_path_matches_pattern(name, ptr->filename); 1067762fbffSTetsuo Handa } 1077762fbffSTetsuo Handa 1084c3e9e2dSTetsuo Handa void tomoyo_put_number_union(struct tomoyo_number_union *ptr) 1094c3e9e2dSTetsuo Handa { 1104c3e9e2dSTetsuo Handa if (ptr && ptr->is_group) 1114c3e9e2dSTetsuo Handa tomoyo_put_number_group(ptr->group); 1124c3e9e2dSTetsuo Handa } 1134c3e9e2dSTetsuo Handa 1144c3e9e2dSTetsuo Handa bool tomoyo_compare_number_union(const unsigned long value, 1154c3e9e2dSTetsuo Handa const struct tomoyo_number_union *ptr) 1164c3e9e2dSTetsuo Handa { 1174c3e9e2dSTetsuo Handa if (ptr->is_group) 1184c3e9e2dSTetsuo Handa return tomoyo_number_matches_group(value, value, ptr->group); 1194c3e9e2dSTetsuo Handa return value >= ptr->values[0] && value <= ptr->values[1]; 1204c3e9e2dSTetsuo Handa } 1214c3e9e2dSTetsuo Handa 122b69a54eeSKentaro Takeda /** 1237ef61233STetsuo Handa * tomoyo_path2keyword - Get the name of single path operation. 124b69a54eeSKentaro Takeda * 125b69a54eeSKentaro Takeda * @operation: Type of operation. 126b69a54eeSKentaro Takeda * 127b69a54eeSKentaro Takeda * Returns the name of single path operation. 128b69a54eeSKentaro Takeda */ 1297ef61233STetsuo Handa const char *tomoyo_path2keyword(const u8 operation) 130b69a54eeSKentaro Takeda { 1317ef61233STetsuo Handa return (operation < TOMOYO_MAX_PATH_OPERATION) 1327ef61233STetsuo Handa ? tomoyo_path_keyword[operation] : NULL; 133b69a54eeSKentaro Takeda } 134b69a54eeSKentaro Takeda 135b69a54eeSKentaro Takeda /** 136a1f9bb6aSTetsuo Handa * tomoyo_path_number32keyword - Get the name of path/number/number/number operations. 137a1f9bb6aSTetsuo Handa * 138a1f9bb6aSTetsuo Handa * @operation: Type of operation. 139a1f9bb6aSTetsuo Handa * 140a1f9bb6aSTetsuo Handa * Returns the name of path/number/number/number operation. 141a1f9bb6aSTetsuo Handa */ 142a1f9bb6aSTetsuo Handa const char *tomoyo_path_number32keyword(const u8 operation) 143a1f9bb6aSTetsuo Handa { 144a1f9bb6aSTetsuo Handa return (operation < TOMOYO_MAX_PATH_NUMBER3_OPERATION) 145a1f9bb6aSTetsuo Handa ? tomoyo_path_number3_keyword[operation] : NULL; 146a1f9bb6aSTetsuo Handa } 147a1f9bb6aSTetsuo Handa 148a1f9bb6aSTetsuo Handa /** 1497ef61233STetsuo Handa * tomoyo_path22keyword - Get the name of double path operation. 150b69a54eeSKentaro Takeda * 151b69a54eeSKentaro Takeda * @operation: Type of operation. 152b69a54eeSKentaro Takeda * 153b69a54eeSKentaro Takeda * Returns the name of double path operation. 154b69a54eeSKentaro Takeda */ 1557ef61233STetsuo Handa const char *tomoyo_path22keyword(const u8 operation) 156b69a54eeSKentaro Takeda { 1577ef61233STetsuo Handa return (operation < TOMOYO_MAX_PATH2_OPERATION) 1587ef61233STetsuo Handa ? tomoyo_path2_keyword[operation] : NULL; 159b69a54eeSKentaro Takeda } 160b69a54eeSKentaro Takeda 161b69a54eeSKentaro Takeda /** 162a1f9bb6aSTetsuo Handa * tomoyo_path_number2keyword - Get the name of path/number operations. 163a1f9bb6aSTetsuo Handa * 164a1f9bb6aSTetsuo Handa * @operation: Type of operation. 165a1f9bb6aSTetsuo Handa * 166a1f9bb6aSTetsuo Handa * Returns the name of path/number operation. 167a1f9bb6aSTetsuo Handa */ 168a1f9bb6aSTetsuo Handa const char *tomoyo_path_number2keyword(const u8 operation) 169a1f9bb6aSTetsuo Handa { 170a1f9bb6aSTetsuo Handa return (operation < TOMOYO_MAX_PATH_NUMBER_OPERATION) 171a1f9bb6aSTetsuo Handa ? tomoyo_path_number_keyword[operation] : NULL; 172a1f9bb6aSTetsuo Handa } 173a1f9bb6aSTetsuo Handa 174c8c57e84STetsuo Handa static void tomoyo_add_slash(struct tomoyo_path_info *buf) 175c8c57e84STetsuo Handa { 176c8c57e84STetsuo Handa if (buf->is_dir) 177c8c57e84STetsuo Handa return; 178c8c57e84STetsuo Handa /* 179c8c57e84STetsuo Handa * This is OK because tomoyo_encode() reserves space for appending "/". 180c8c57e84STetsuo Handa */ 181c8c57e84STetsuo Handa strcat((char *) buf->name, "/"); 182c8c57e84STetsuo Handa tomoyo_fill_path_info(buf); 183c8c57e84STetsuo Handa } 184c8c57e84STetsuo Handa 185a1f9bb6aSTetsuo Handa /** 186b69a54eeSKentaro Takeda * tomoyo_strendswith - Check whether the token ends with the given token. 187b69a54eeSKentaro Takeda * 188b69a54eeSKentaro Takeda * @name: The token to check. 189b69a54eeSKentaro Takeda * @tail: The token to find. 190b69a54eeSKentaro Takeda * 191b69a54eeSKentaro Takeda * Returns true if @name ends with @tail, false otherwise. 192b69a54eeSKentaro Takeda */ 193b69a54eeSKentaro Takeda static bool tomoyo_strendswith(const char *name, const char *tail) 194b69a54eeSKentaro Takeda { 195b69a54eeSKentaro Takeda int len; 196b69a54eeSKentaro Takeda 197b69a54eeSKentaro Takeda if (!name || !tail) 198b69a54eeSKentaro Takeda return false; 199b69a54eeSKentaro Takeda len = strlen(name) - strlen(tail); 200b69a54eeSKentaro Takeda return len >= 0 && !strcmp(name + len, tail); 201b69a54eeSKentaro Takeda } 202b69a54eeSKentaro Takeda 203b69a54eeSKentaro Takeda /** 204c8c57e84STetsuo Handa * tomoyo_get_realpath - Get realpath. 205b69a54eeSKentaro Takeda * 206c8c57e84STetsuo Handa * @buf: Pointer to "struct tomoyo_path_info". 207b69a54eeSKentaro Takeda * @path: Pointer to "struct path". 208b69a54eeSKentaro Takeda * 209c8c57e84STetsuo Handa * Returns true on success, false otherwise. 210b69a54eeSKentaro Takeda */ 211c8c57e84STetsuo Handa static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path) 212b69a54eeSKentaro Takeda { 213c8c57e84STetsuo Handa buf->name = tomoyo_realpath_from_path(path); 214c8c57e84STetsuo Handa if (buf->name) { 215c8c57e84STetsuo Handa tomoyo_fill_path_info(buf); 216c8c57e84STetsuo Handa return true; 217b69a54eeSKentaro Takeda } 218c8c57e84STetsuo Handa return false; 219b69a54eeSKentaro Takeda } 220b69a54eeSKentaro Takeda 2217ef61233STetsuo Handa static int tomoyo_update_path2_acl(const u8 type, const char *filename1, 222b69a54eeSKentaro Takeda const char *filename2, 2237ef61233STetsuo Handa struct tomoyo_domain_info *const domain, 2247ef61233STetsuo Handa const bool is_delete); 2257ef61233STetsuo Handa static int tomoyo_update_path_acl(const u8 type, const char *filename, 2267ef61233STetsuo Handa struct tomoyo_domain_info *const domain, 2277ef61233STetsuo Handa const bool is_delete); 228b69a54eeSKentaro Takeda 229c3fa109aSTetsuo Handa /* 230c3fa109aSTetsuo Handa * tomoyo_globally_readable_list is used for holding list of pathnames which 231c3fa109aSTetsuo Handa * are by default allowed to be open()ed for reading by any process. 232c3fa109aSTetsuo Handa * 233c3fa109aSTetsuo Handa * An entry is added by 234c3fa109aSTetsuo Handa * 235c3fa109aSTetsuo Handa * # echo 'allow_read /lib/libc-2.5.so' > \ 236c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 237c3fa109aSTetsuo Handa * 238c3fa109aSTetsuo Handa * and is deleted by 239c3fa109aSTetsuo Handa * 240c3fa109aSTetsuo Handa * # echo 'delete allow_read /lib/libc-2.5.so' > \ 241c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 242c3fa109aSTetsuo Handa * 243c3fa109aSTetsuo Handa * and all entries are retrieved by 244c3fa109aSTetsuo Handa * 245c3fa109aSTetsuo Handa * # grep ^allow_read /sys/kernel/security/tomoyo/exception_policy 246c3fa109aSTetsuo Handa * 247c3fa109aSTetsuo Handa * In the example above, any process is allowed to 248c3fa109aSTetsuo Handa * open("/lib/libc-2.5.so", O_RDONLY). 249c3fa109aSTetsuo Handa * One exception is, if the domain which current process belongs to is marked 250c3fa109aSTetsuo Handa * as "ignore_global_allow_read", current process can't do so unless explicitly 251c3fa109aSTetsuo Handa * given "allow_read /lib/libc-2.5.so" to the domain which current process 252c3fa109aSTetsuo Handa * belongs to. 253c3fa109aSTetsuo Handa */ 254847b173eSTetsuo Handa LIST_HEAD(tomoyo_globally_readable_list); 255b69a54eeSKentaro Takeda 256b69a54eeSKentaro Takeda /** 257b69a54eeSKentaro Takeda * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list. 258b69a54eeSKentaro Takeda * 259b69a54eeSKentaro Takeda * @filename: Filename unconditionally permitted to open() for reading. 260b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 261b69a54eeSKentaro Takeda * 262b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 263fdb8ebb7STetsuo Handa * 264fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 265b69a54eeSKentaro Takeda */ 266b69a54eeSKentaro Takeda static int tomoyo_update_globally_readable_entry(const char *filename, 267b69a54eeSKentaro Takeda const bool is_delete) 268b69a54eeSKentaro Takeda { 269b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry *ptr; 2709e4b50e9STetsuo Handa struct tomoyo_globally_readable_file_entry e = { }; 271ca0b7df3STetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 272b69a54eeSKentaro Takeda 2733f629636STetsuo Handa if (!tomoyo_is_correct_word(filename)) 274b69a54eeSKentaro Takeda return -EINVAL; 2759e4b50e9STetsuo Handa e.filename = tomoyo_get_name(filename); 2769e4b50e9STetsuo Handa if (!e.filename) 277b69a54eeSKentaro Takeda return -ENOMEM; 27829282381STetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 27929282381STetsuo Handa goto out; 28082e0f001STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, 28182e0f001STetsuo Handa head.list) { 2829e4b50e9STetsuo Handa if (ptr->filename != e.filename) 283b69a54eeSKentaro Takeda continue; 28482e0f001STetsuo Handa ptr->head.is_deleted = is_delete; 285b69a54eeSKentaro Takeda error = 0; 286ca0b7df3STetsuo Handa break; 287b69a54eeSKentaro Takeda } 2889e4b50e9STetsuo Handa if (!is_delete && error) { 2899e4b50e9STetsuo Handa struct tomoyo_globally_readable_file_entry *entry = 2909e4b50e9STetsuo Handa tomoyo_commit_ok(&e, sizeof(e)); 2919e4b50e9STetsuo Handa if (entry) { 29282e0f001STetsuo Handa list_add_tail_rcu(&entry->head.list, 2939e4b50e9STetsuo Handa &tomoyo_globally_readable_list); 294b69a54eeSKentaro Takeda error = 0; 295ca0b7df3STetsuo Handa } 2969e4b50e9STetsuo Handa } 297f737d95dSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 29829282381STetsuo Handa out: 2999e4b50e9STetsuo Handa tomoyo_put_name(e.filename); 300b69a54eeSKentaro Takeda return error; 301b69a54eeSKentaro Takeda } 302b69a54eeSKentaro Takeda 303b69a54eeSKentaro Takeda /** 304b69a54eeSKentaro Takeda * tomoyo_is_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading. 305b69a54eeSKentaro Takeda * 306b69a54eeSKentaro Takeda * @filename: The filename to check. 307b69a54eeSKentaro Takeda * 308b69a54eeSKentaro Takeda * Returns true if any domain can open @filename for reading, false otherwise. 309fdb8ebb7STetsuo Handa * 310fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 311b69a54eeSKentaro Takeda */ 312b69a54eeSKentaro Takeda static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info * 313b69a54eeSKentaro Takeda filename) 314b69a54eeSKentaro Takeda { 315b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry *ptr; 316b69a54eeSKentaro Takeda bool found = false; 317fdb8ebb7STetsuo Handa 31882e0f001STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, 31982e0f001STetsuo Handa head.list) { 32082e0f001STetsuo Handa if (!ptr->head.is_deleted && 321b69a54eeSKentaro Takeda tomoyo_path_matches_pattern(filename, ptr->filename)) { 322b69a54eeSKentaro Takeda found = true; 323b69a54eeSKentaro Takeda break; 324b69a54eeSKentaro Takeda } 325b69a54eeSKentaro Takeda } 326b69a54eeSKentaro Takeda return found; 327b69a54eeSKentaro Takeda } 328b69a54eeSKentaro Takeda 329b69a54eeSKentaro Takeda /** 330b69a54eeSKentaro Takeda * tomoyo_write_globally_readable_policy - Write "struct tomoyo_globally_readable_file_entry" list. 331b69a54eeSKentaro Takeda * 332b69a54eeSKentaro Takeda * @data: String to parse. 333b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 334b69a54eeSKentaro Takeda * 335b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 336fdb8ebb7STetsuo Handa * 337fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 338b69a54eeSKentaro Takeda */ 339b69a54eeSKentaro Takeda int tomoyo_write_globally_readable_policy(char *data, const bool is_delete) 340b69a54eeSKentaro Takeda { 341b69a54eeSKentaro Takeda return tomoyo_update_globally_readable_entry(data, is_delete); 342b69a54eeSKentaro Takeda } 343b69a54eeSKentaro Takeda 344b69a54eeSKentaro Takeda /** 345b69a54eeSKentaro Takeda * tomoyo_read_globally_readable_policy - Read "struct tomoyo_globally_readable_file_entry" list. 346b69a54eeSKentaro Takeda * 347b69a54eeSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 348b69a54eeSKentaro Takeda * 349b69a54eeSKentaro Takeda * Returns true on success, false otherwise. 350fdb8ebb7STetsuo Handa * 351fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 352b69a54eeSKentaro Takeda */ 353b69a54eeSKentaro Takeda bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) 354b69a54eeSKentaro Takeda { 355b69a54eeSKentaro Takeda struct list_head *pos; 356b69a54eeSKentaro Takeda bool done = true; 357b69a54eeSKentaro Takeda 358b69a54eeSKentaro Takeda list_for_each_cookie(pos, head->read_var2, 359b69a54eeSKentaro Takeda &tomoyo_globally_readable_list) { 360b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry *ptr; 361b69a54eeSKentaro Takeda ptr = list_entry(pos, 362b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry, 36382e0f001STetsuo Handa head.list); 36482e0f001STetsuo Handa if (ptr->head.is_deleted) 365b69a54eeSKentaro Takeda continue; 3667d2948b1STetsuo Handa done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n", 3677d2948b1STetsuo Handa ptr->filename->name); 3687d2948b1STetsuo Handa if (!done) 369b69a54eeSKentaro Takeda break; 370b69a54eeSKentaro Takeda } 371b69a54eeSKentaro Takeda return done; 372b69a54eeSKentaro Takeda } 373b69a54eeSKentaro Takeda 374c3fa109aSTetsuo Handa /* tomoyo_pattern_list is used for holding list of pathnames which are used for 375c3fa109aSTetsuo Handa * converting pathnames to pathname patterns during learning mode. 376c3fa109aSTetsuo Handa * 377c3fa109aSTetsuo Handa * An entry is added by 378c3fa109aSTetsuo Handa * 379c3fa109aSTetsuo Handa * # echo 'file_pattern /proc/\$/mounts' > \ 380c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 381c3fa109aSTetsuo Handa * 382c3fa109aSTetsuo Handa * and is deleted by 383c3fa109aSTetsuo Handa * 384c3fa109aSTetsuo Handa * # echo 'delete file_pattern /proc/\$/mounts' > \ 385c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 386c3fa109aSTetsuo Handa * 387c3fa109aSTetsuo Handa * and all entries are retrieved by 388c3fa109aSTetsuo Handa * 389c3fa109aSTetsuo Handa * # grep ^file_pattern /sys/kernel/security/tomoyo/exception_policy 390c3fa109aSTetsuo Handa * 391c3fa109aSTetsuo Handa * In the example above, if a process which belongs to a domain which is in 392c3fa109aSTetsuo Handa * learning mode requested open("/proc/1/mounts", O_RDONLY), 393c3fa109aSTetsuo Handa * "allow_read /proc/\$/mounts" is automatically added to the domain which that 394c3fa109aSTetsuo Handa * process belongs to. 395c3fa109aSTetsuo Handa * 396c3fa109aSTetsuo Handa * It is not a desirable behavior that we have to use /proc/\$/ instead of 397c3fa109aSTetsuo Handa * /proc/self/ when current process needs to access only current process's 398c3fa109aSTetsuo Handa * information. As of now, LSM version of TOMOYO is using __d_path() for 399c3fa109aSTetsuo Handa * calculating pathname. Non LSM version of TOMOYO is using its own function 400c3fa109aSTetsuo Handa * which pretends as if /proc/self/ is not a symlink; so that we can forbid 401c3fa109aSTetsuo Handa * current process from accessing other process's information. 402c3fa109aSTetsuo Handa */ 403847b173eSTetsuo Handa LIST_HEAD(tomoyo_pattern_list); 404b69a54eeSKentaro Takeda 405b69a54eeSKentaro Takeda /** 406b69a54eeSKentaro Takeda * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list. 407b69a54eeSKentaro Takeda * 408b69a54eeSKentaro Takeda * @pattern: Pathname pattern. 409b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 410b69a54eeSKentaro Takeda * 411b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 412fdb8ebb7STetsuo Handa * 413fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 414b69a54eeSKentaro Takeda */ 415b69a54eeSKentaro Takeda static int tomoyo_update_file_pattern_entry(const char *pattern, 416b69a54eeSKentaro Takeda const bool is_delete) 417b69a54eeSKentaro Takeda { 418b69a54eeSKentaro Takeda struct tomoyo_pattern_entry *ptr; 4193f629636STetsuo Handa struct tomoyo_pattern_entry e = { }; 420ca0b7df3STetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 421b69a54eeSKentaro Takeda 4223f629636STetsuo Handa if (!tomoyo_is_correct_word(pattern)) 4233f629636STetsuo Handa return -EINVAL; 4243f629636STetsuo Handa e.pattern = tomoyo_get_name(pattern); 4259e4b50e9STetsuo Handa if (!e.pattern) 426ca0b7df3STetsuo Handa return error; 42729282381STetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 42829282381STetsuo Handa goto out; 42982e0f001STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, head.list) { 4309e4b50e9STetsuo Handa if (e.pattern != ptr->pattern) 431b69a54eeSKentaro Takeda continue; 43282e0f001STetsuo Handa ptr->head.is_deleted = is_delete; 433b69a54eeSKentaro Takeda error = 0; 434ca0b7df3STetsuo Handa break; 435b69a54eeSKentaro Takeda } 4369e4b50e9STetsuo Handa if (!is_delete && error) { 4379e4b50e9STetsuo Handa struct tomoyo_pattern_entry *entry = 4389e4b50e9STetsuo Handa tomoyo_commit_ok(&e, sizeof(e)); 4399e4b50e9STetsuo Handa if (entry) { 44082e0f001STetsuo Handa list_add_tail_rcu(&entry->head.list, 44182e0f001STetsuo Handa &tomoyo_pattern_list); 442b69a54eeSKentaro Takeda error = 0; 443ca0b7df3STetsuo Handa } 4449e4b50e9STetsuo Handa } 445f737d95dSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 446ca0b7df3STetsuo Handa out: 4479e4b50e9STetsuo Handa tomoyo_put_name(e.pattern); 448b69a54eeSKentaro Takeda return error; 449b69a54eeSKentaro Takeda } 450b69a54eeSKentaro Takeda 451b69a54eeSKentaro Takeda /** 45217fcfbd9STetsuo Handa * tomoyo_file_pattern - Get patterned pathname. 453b69a54eeSKentaro Takeda * 454b69a54eeSKentaro Takeda * @filename: The filename to find patterned pathname. 455b69a54eeSKentaro Takeda * 456b69a54eeSKentaro Takeda * Returns pointer to pathname pattern if matched, @filename otherwise. 457fdb8ebb7STetsuo Handa * 458fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 459b69a54eeSKentaro Takeda */ 46017fcfbd9STetsuo Handa const char *tomoyo_file_pattern(const struct tomoyo_path_info *filename) 461b69a54eeSKentaro Takeda { 462b69a54eeSKentaro Takeda struct tomoyo_pattern_entry *ptr; 463b69a54eeSKentaro Takeda const struct tomoyo_path_info *pattern = NULL; 464b69a54eeSKentaro Takeda 46582e0f001STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, head.list) { 46682e0f001STetsuo Handa if (ptr->head.is_deleted) 467b69a54eeSKentaro Takeda continue; 468b69a54eeSKentaro Takeda if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) 469b69a54eeSKentaro Takeda continue; 470b69a54eeSKentaro Takeda pattern = ptr->pattern; 471b69a54eeSKentaro Takeda if (tomoyo_strendswith(pattern->name, "/\\*")) { 472b69a54eeSKentaro Takeda /* Do nothing. Try to find the better match. */ 473b69a54eeSKentaro Takeda } else { 474b69a54eeSKentaro Takeda /* This would be the better match. Use this. */ 475b69a54eeSKentaro Takeda break; 476b69a54eeSKentaro Takeda } 477b69a54eeSKentaro Takeda } 478b69a54eeSKentaro Takeda if (pattern) 479b69a54eeSKentaro Takeda filename = pattern; 48017fcfbd9STetsuo Handa return filename->name; 481b69a54eeSKentaro Takeda } 482b69a54eeSKentaro Takeda 483b69a54eeSKentaro Takeda /** 484b69a54eeSKentaro Takeda * tomoyo_write_pattern_policy - Write "struct tomoyo_pattern_entry" list. 485b69a54eeSKentaro Takeda * 486b69a54eeSKentaro Takeda * @data: String to parse. 487b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 488b69a54eeSKentaro Takeda * 489b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 490fdb8ebb7STetsuo Handa * 491fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 492b69a54eeSKentaro Takeda */ 493b69a54eeSKentaro Takeda int tomoyo_write_pattern_policy(char *data, const bool is_delete) 494b69a54eeSKentaro Takeda { 495b69a54eeSKentaro Takeda return tomoyo_update_file_pattern_entry(data, is_delete); 496b69a54eeSKentaro Takeda } 497b69a54eeSKentaro Takeda 498b69a54eeSKentaro Takeda /** 499b69a54eeSKentaro Takeda * tomoyo_read_file_pattern - Read "struct tomoyo_pattern_entry" list. 500b69a54eeSKentaro Takeda * 501b69a54eeSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 502b69a54eeSKentaro Takeda * 503b69a54eeSKentaro Takeda * Returns true on success, false otherwise. 504fdb8ebb7STetsuo Handa * 505fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 506b69a54eeSKentaro Takeda */ 507b69a54eeSKentaro Takeda bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) 508b69a54eeSKentaro Takeda { 509b69a54eeSKentaro Takeda struct list_head *pos; 510b69a54eeSKentaro Takeda bool done = true; 511b69a54eeSKentaro Takeda 512b69a54eeSKentaro Takeda list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) { 513b69a54eeSKentaro Takeda struct tomoyo_pattern_entry *ptr; 51482e0f001STetsuo Handa ptr = list_entry(pos, struct tomoyo_pattern_entry, head.list); 51582e0f001STetsuo Handa if (ptr->head.is_deleted) 516b69a54eeSKentaro Takeda continue; 5177d2948b1STetsuo Handa done = tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN 5187d2948b1STetsuo Handa "%s\n", ptr->pattern->name); 5197d2948b1STetsuo Handa if (!done) 520b69a54eeSKentaro Takeda break; 521b69a54eeSKentaro Takeda } 522b69a54eeSKentaro Takeda return done; 523b69a54eeSKentaro Takeda } 524b69a54eeSKentaro Takeda 525c3fa109aSTetsuo Handa /* 526c3fa109aSTetsuo Handa * tomoyo_no_rewrite_list is used for holding list of pathnames which are by 527c3fa109aSTetsuo Handa * default forbidden to modify already written content of a file. 528c3fa109aSTetsuo Handa * 529c3fa109aSTetsuo Handa * An entry is added by 530c3fa109aSTetsuo Handa * 531c3fa109aSTetsuo Handa * # echo 'deny_rewrite /var/log/messages' > \ 532c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 533c3fa109aSTetsuo Handa * 534c3fa109aSTetsuo Handa * and is deleted by 535c3fa109aSTetsuo Handa * 536c3fa109aSTetsuo Handa * # echo 'delete deny_rewrite /var/log/messages' > \ 537c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 538c3fa109aSTetsuo Handa * 539c3fa109aSTetsuo Handa * and all entries are retrieved by 540c3fa109aSTetsuo Handa * 541c3fa109aSTetsuo Handa * # grep ^deny_rewrite /sys/kernel/security/tomoyo/exception_policy 542c3fa109aSTetsuo Handa * 543c3fa109aSTetsuo Handa * In the example above, if a process requested to rewrite /var/log/messages , 544c3fa109aSTetsuo Handa * the process can't rewrite unless the domain which that process belongs to 545c3fa109aSTetsuo Handa * has "allow_rewrite /var/log/messages" entry. 546c3fa109aSTetsuo Handa * 547c3fa109aSTetsuo Handa * It is not a desirable behavior that we have to add "\040(deleted)" suffix 548c3fa109aSTetsuo Handa * when we want to allow rewriting already unlink()ed file. As of now, 549c3fa109aSTetsuo Handa * LSM version of TOMOYO is using __d_path() for calculating pathname. 550c3fa109aSTetsuo Handa * Non LSM version of TOMOYO is using its own function which doesn't append 551c3fa109aSTetsuo Handa * " (deleted)" suffix if the file is already unlink()ed; so that we don't 552c3fa109aSTetsuo Handa * need to worry whether the file is already unlink()ed or not. 553c3fa109aSTetsuo Handa */ 554847b173eSTetsuo Handa LIST_HEAD(tomoyo_no_rewrite_list); 555b69a54eeSKentaro Takeda 556b69a54eeSKentaro Takeda /** 557b69a54eeSKentaro Takeda * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list. 558b69a54eeSKentaro Takeda * 559b69a54eeSKentaro Takeda * @pattern: Pathname pattern that are not rewritable by default. 560b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 561b69a54eeSKentaro Takeda * 562b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 563fdb8ebb7STetsuo Handa * 564fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 565b69a54eeSKentaro Takeda */ 566b69a54eeSKentaro Takeda static int tomoyo_update_no_rewrite_entry(const char *pattern, 567b69a54eeSKentaro Takeda const bool is_delete) 568b69a54eeSKentaro Takeda { 569ca0b7df3STetsuo Handa struct tomoyo_no_rewrite_entry *ptr; 5709e4b50e9STetsuo Handa struct tomoyo_no_rewrite_entry e = { }; 571ca0b7df3STetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 572b69a54eeSKentaro Takeda 5733f629636STetsuo Handa if (!tomoyo_is_correct_word(pattern)) 574b69a54eeSKentaro Takeda return -EINVAL; 5759e4b50e9STetsuo Handa e.pattern = tomoyo_get_name(pattern); 5769e4b50e9STetsuo Handa if (!e.pattern) 577ca0b7df3STetsuo Handa return error; 57829282381STetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 57929282381STetsuo Handa goto out; 58082e0f001STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, head.list) { 5819e4b50e9STetsuo Handa if (ptr->pattern != e.pattern) 582b69a54eeSKentaro Takeda continue; 58382e0f001STetsuo Handa ptr->head.is_deleted = is_delete; 584b69a54eeSKentaro Takeda error = 0; 585ca0b7df3STetsuo Handa break; 586b69a54eeSKentaro Takeda } 5879e4b50e9STetsuo Handa if (!is_delete && error) { 5889e4b50e9STetsuo Handa struct tomoyo_no_rewrite_entry *entry = 5899e4b50e9STetsuo Handa tomoyo_commit_ok(&e, sizeof(e)); 5909e4b50e9STetsuo Handa if (entry) { 59182e0f001STetsuo Handa list_add_tail_rcu(&entry->head.list, 5929e4b50e9STetsuo Handa &tomoyo_no_rewrite_list); 593b69a54eeSKentaro Takeda error = 0; 594ca0b7df3STetsuo Handa } 5959e4b50e9STetsuo Handa } 596f737d95dSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 59729282381STetsuo Handa out: 5989e4b50e9STetsuo Handa tomoyo_put_name(e.pattern); 599b69a54eeSKentaro Takeda return error; 600b69a54eeSKentaro Takeda } 601b69a54eeSKentaro Takeda 602b69a54eeSKentaro Takeda /** 603b69a54eeSKentaro Takeda * tomoyo_is_no_rewrite_file - Check if the given pathname is not permitted to be rewrited. 604b69a54eeSKentaro Takeda * 605b69a54eeSKentaro Takeda * @filename: Filename to check. 606b69a54eeSKentaro Takeda * 607b69a54eeSKentaro Takeda * Returns true if @filename is specified by "deny_rewrite" directive, 608b69a54eeSKentaro Takeda * false otherwise. 609fdb8ebb7STetsuo Handa * 610fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 611b69a54eeSKentaro Takeda */ 612b69a54eeSKentaro Takeda static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) 613b69a54eeSKentaro Takeda { 614b69a54eeSKentaro Takeda struct tomoyo_no_rewrite_entry *ptr; 615b69a54eeSKentaro Takeda bool found = false; 616b69a54eeSKentaro Takeda 61782e0f001STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, head.list) { 61882e0f001STetsuo Handa if (ptr->head.is_deleted) 619b69a54eeSKentaro Takeda continue; 620b69a54eeSKentaro Takeda if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) 621b69a54eeSKentaro Takeda continue; 622b69a54eeSKentaro Takeda found = true; 623b69a54eeSKentaro Takeda break; 624b69a54eeSKentaro Takeda } 625b69a54eeSKentaro Takeda return found; 626b69a54eeSKentaro Takeda } 627b69a54eeSKentaro Takeda 628b69a54eeSKentaro Takeda /** 629b69a54eeSKentaro Takeda * tomoyo_write_no_rewrite_policy - Write "struct tomoyo_no_rewrite_entry" list. 630b69a54eeSKentaro Takeda * 631b69a54eeSKentaro Takeda * @data: String to parse. 632b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 633b69a54eeSKentaro Takeda * 634b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 635fdb8ebb7STetsuo Handa * 636fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 637b69a54eeSKentaro Takeda */ 638b69a54eeSKentaro Takeda int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete) 639b69a54eeSKentaro Takeda { 640b69a54eeSKentaro Takeda return tomoyo_update_no_rewrite_entry(data, is_delete); 641b69a54eeSKentaro Takeda } 642b69a54eeSKentaro Takeda 643b69a54eeSKentaro Takeda /** 644b69a54eeSKentaro Takeda * tomoyo_read_no_rewrite_policy - Read "struct tomoyo_no_rewrite_entry" list. 645b69a54eeSKentaro Takeda * 646b69a54eeSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 647b69a54eeSKentaro Takeda * 648b69a54eeSKentaro Takeda * Returns true on success, false otherwise. 649fdb8ebb7STetsuo Handa * 650fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 651b69a54eeSKentaro Takeda */ 652b69a54eeSKentaro Takeda bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) 653b69a54eeSKentaro Takeda { 654b69a54eeSKentaro Takeda struct list_head *pos; 655b69a54eeSKentaro Takeda bool done = true; 656b69a54eeSKentaro Takeda 657b69a54eeSKentaro Takeda list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) { 658b69a54eeSKentaro Takeda struct tomoyo_no_rewrite_entry *ptr; 65982e0f001STetsuo Handa ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, 66082e0f001STetsuo Handa head.list); 66182e0f001STetsuo Handa if (ptr->head.is_deleted) 662b69a54eeSKentaro Takeda continue; 6637d2948b1STetsuo Handa done = tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE 6647d2948b1STetsuo Handa "%s\n", ptr->pattern->name); 6657d2948b1STetsuo Handa if (!done) 666b69a54eeSKentaro Takeda break; 667b69a54eeSKentaro Takeda } 668b69a54eeSKentaro Takeda return done; 669b69a54eeSKentaro Takeda } 670b69a54eeSKentaro Takeda 671b69a54eeSKentaro Takeda /** 672cb0abe6aSTetsuo Handa * tomoyo_path_acl - Check permission for single path operation. 673b69a54eeSKentaro Takeda * 674cb0abe6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 675b69a54eeSKentaro Takeda * @filename: Filename to check. 676b69a54eeSKentaro Takeda * @perm: Permission. 677b69a54eeSKentaro Takeda * 678b69a54eeSKentaro Takeda * Returns 0 on success, -EPERM otherwise. 679fdb8ebb7STetsuo Handa * 680fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 681b69a54eeSKentaro Takeda */ 682cb0abe6aSTetsuo Handa static int tomoyo_path_acl(const struct tomoyo_request_info *r, 6837ef61233STetsuo Handa const struct tomoyo_path_info *filename, 6843f629636STetsuo Handa const u32 perm) 685b69a54eeSKentaro Takeda { 686cb0abe6aSTetsuo Handa struct tomoyo_domain_info *domain = r->domain; 687b69a54eeSKentaro Takeda struct tomoyo_acl_info *ptr; 688b69a54eeSKentaro Takeda int error = -EPERM; 689b69a54eeSKentaro Takeda 690fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 6917ef61233STetsuo Handa struct tomoyo_path_acl *acl; 6927ef61233STetsuo Handa if (ptr->type != TOMOYO_TYPE_PATH_ACL) 693b69a54eeSKentaro Takeda continue; 6947ef61233STetsuo Handa acl = container_of(ptr, struct tomoyo_path_acl, head); 695a1f9bb6aSTetsuo Handa if (!(acl->perm & perm) || 6963f629636STetsuo Handa !tomoyo_compare_name_union(filename, &acl->name)) 697b69a54eeSKentaro Takeda continue; 698b69a54eeSKentaro Takeda error = 0; 699b69a54eeSKentaro Takeda break; 700b69a54eeSKentaro Takeda } 701b69a54eeSKentaro Takeda return error; 702b69a54eeSKentaro Takeda } 703b69a54eeSKentaro Takeda 704b69a54eeSKentaro Takeda /** 705cb0abe6aSTetsuo Handa * tomoyo_file_perm - Check permission for opening files. 706b69a54eeSKentaro Takeda * 707cb0abe6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 708b69a54eeSKentaro Takeda * @filename: Filename to check. 709cb0abe6aSTetsuo Handa * @mode: Mode ("read" or "write" or "read/write" or "execute"). 710b69a54eeSKentaro Takeda * 711b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 712fdb8ebb7STetsuo Handa * 713fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 714b69a54eeSKentaro Takeda */ 715cb0abe6aSTetsuo Handa static int tomoyo_file_perm(struct tomoyo_request_info *r, 716b69a54eeSKentaro Takeda const struct tomoyo_path_info *filename, 717b69a54eeSKentaro Takeda const u8 mode) 718b69a54eeSKentaro Takeda { 719b69a54eeSKentaro Takeda const char *msg = "<unknown>"; 720b69a54eeSKentaro Takeda int error = 0; 721cb0abe6aSTetsuo Handa u32 perm = 0; 722b69a54eeSKentaro Takeda 723b69a54eeSKentaro Takeda if (!filename) 724b69a54eeSKentaro Takeda return 0; 725cb0abe6aSTetsuo Handa 726cb0abe6aSTetsuo Handa if (mode == 6) { 727cb0abe6aSTetsuo Handa msg = tomoyo_path2keyword(TOMOYO_TYPE_READ_WRITE); 728cb0abe6aSTetsuo Handa perm = 1 << TOMOYO_TYPE_READ_WRITE; 729cb0abe6aSTetsuo Handa } else if (mode == 4) { 730cb0abe6aSTetsuo Handa msg = tomoyo_path2keyword(TOMOYO_TYPE_READ); 731cb0abe6aSTetsuo Handa perm = 1 << TOMOYO_TYPE_READ; 732cb0abe6aSTetsuo Handa } else if (mode == 2) { 733cb0abe6aSTetsuo Handa msg = tomoyo_path2keyword(TOMOYO_TYPE_WRITE); 734cb0abe6aSTetsuo Handa perm = 1 << TOMOYO_TYPE_WRITE; 735cb0abe6aSTetsuo Handa } else if (mode == 1) { 736cb0abe6aSTetsuo Handa msg = tomoyo_path2keyword(TOMOYO_TYPE_EXECUTE); 737cb0abe6aSTetsuo Handa perm = 1 << TOMOYO_TYPE_EXECUTE; 738cb0abe6aSTetsuo Handa } else 739cb0abe6aSTetsuo Handa BUG(); 74017fcfbd9STetsuo Handa do { 7413f629636STetsuo Handa error = tomoyo_path_acl(r, filename, perm); 742cb0abe6aSTetsuo Handa if (error && mode == 4 && !r->domain->ignore_global_allow_read 743b69a54eeSKentaro Takeda && tomoyo_is_globally_readable_file(filename)) 744b69a54eeSKentaro Takeda error = 0; 745b69a54eeSKentaro Takeda if (!error) 74617fcfbd9STetsuo Handa break; 747cb0abe6aSTetsuo Handa tomoyo_warn_log(r, "%s %s", msg, filename->name); 74817fcfbd9STetsuo Handa error = tomoyo_supervisor(r, "allow_%s %s\n", msg, 74917fcfbd9STetsuo Handa tomoyo_file_pattern(filename)); 75017fcfbd9STetsuo Handa /* 75117fcfbd9STetsuo Handa * Do not retry for execute request, for alias may have 75217fcfbd9STetsuo Handa * changed. 75317fcfbd9STetsuo Handa */ 75417fcfbd9STetsuo Handa } while (error == TOMOYO_RETRY_REQUEST && mode != 1); 75517fcfbd9STetsuo Handa if (r->mode != TOMOYO_CONFIG_ENFORCING) 75617fcfbd9STetsuo Handa error = 0; 757b69a54eeSKentaro Takeda return error; 758b69a54eeSKentaro Takeda } 759b69a54eeSKentaro Takeda 760237ab459STetsuo Handa static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a, 761237ab459STetsuo Handa const struct tomoyo_acl_info *b) 762237ab459STetsuo Handa { 763237ab459STetsuo Handa const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head); 764237ab459STetsuo Handa const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head); 765237ab459STetsuo Handa return tomoyo_is_same_acl_head(&p1->head, &p2->head) && 766237ab459STetsuo Handa tomoyo_is_same_name_union(&p1->name, &p2->name); 767237ab459STetsuo Handa } 768237ab459STetsuo Handa 769237ab459STetsuo Handa static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a, 770237ab459STetsuo Handa struct tomoyo_acl_info *b, 771237ab459STetsuo Handa const bool is_delete) 772237ab459STetsuo Handa { 773237ab459STetsuo Handa u16 * const a_perm = &container_of(a, struct tomoyo_path_acl, head) 774237ab459STetsuo Handa ->perm; 775237ab459STetsuo Handa u16 perm = *a_perm; 776237ab459STetsuo Handa const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm; 777237ab459STetsuo Handa if (is_delete) { 778237ab459STetsuo Handa perm &= ~b_perm; 779237ab459STetsuo Handa if ((perm & TOMOYO_RW_MASK) != TOMOYO_RW_MASK) 780237ab459STetsuo Handa perm &= ~(1 << TOMOYO_TYPE_READ_WRITE); 781237ab459STetsuo Handa else if (!(perm & (1 << TOMOYO_TYPE_READ_WRITE))) 782237ab459STetsuo Handa perm &= ~TOMOYO_RW_MASK; 783237ab459STetsuo Handa } else { 784237ab459STetsuo Handa perm |= b_perm; 785237ab459STetsuo Handa if ((perm & TOMOYO_RW_MASK) == TOMOYO_RW_MASK) 786237ab459STetsuo Handa perm |= (1 << TOMOYO_TYPE_READ_WRITE); 787237ab459STetsuo Handa else if (perm & (1 << TOMOYO_TYPE_READ_WRITE)) 788237ab459STetsuo Handa perm |= TOMOYO_RW_MASK; 789237ab459STetsuo Handa } 790237ab459STetsuo Handa *a_perm = perm; 791237ab459STetsuo Handa return !perm; 792237ab459STetsuo Handa } 793237ab459STetsuo Handa 794b69a54eeSKentaro Takeda /** 7957ef61233STetsuo Handa * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list. 796b69a54eeSKentaro Takeda * 797b69a54eeSKentaro Takeda * @type: Type of operation. 798b69a54eeSKentaro Takeda * @filename: Filename. 799b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 800b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 801b69a54eeSKentaro Takeda * 802b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 803fdb8ebb7STetsuo Handa * 804fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 805b69a54eeSKentaro Takeda */ 8067ef61233STetsuo Handa static int tomoyo_update_path_acl(const u8 type, const char *filename, 8077ef61233STetsuo Handa struct tomoyo_domain_info * const domain, 8087ef61233STetsuo Handa const bool is_delete) 809b69a54eeSKentaro Takeda { 8109e4b50e9STetsuo Handa struct tomoyo_path_acl e = { 8119e4b50e9STetsuo Handa .head.type = TOMOYO_TYPE_PATH_ACL, 812237ab459STetsuo Handa .perm = 1 << type 8139e4b50e9STetsuo Handa }; 814237ab459STetsuo Handa int error; 815237ab459STetsuo Handa if (e.perm == (1 << TOMOYO_TYPE_READ_WRITE)) 816237ab459STetsuo Handa e.perm |= TOMOYO_RW_MASK; 8177762fbffSTetsuo Handa if (!tomoyo_parse_name_union(filename, &e.name)) 818b69a54eeSKentaro Takeda return -EINVAL; 819237ab459STetsuo Handa error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, 820237ab459STetsuo Handa tomoyo_same_path_acl, 821237ab459STetsuo Handa tomoyo_merge_path_acl); 8227762fbffSTetsuo Handa tomoyo_put_name_union(&e.name); 823b69a54eeSKentaro Takeda return error; 824b69a54eeSKentaro Takeda } 825b69a54eeSKentaro Takeda 826237ab459STetsuo Handa static bool tomoyo_same_path_number3_acl(const struct tomoyo_acl_info *a, 827237ab459STetsuo Handa const struct tomoyo_acl_info *b) 828237ab459STetsuo Handa { 829237ab459STetsuo Handa const struct tomoyo_path_number3_acl *p1 = container_of(a, typeof(*p1), 830237ab459STetsuo Handa head); 831237ab459STetsuo Handa const struct tomoyo_path_number3_acl *p2 = container_of(b, typeof(*p2), 832237ab459STetsuo Handa head); 833237ab459STetsuo Handa return tomoyo_is_same_acl_head(&p1->head, &p2->head) 834237ab459STetsuo Handa && tomoyo_is_same_name_union(&p1->name, &p2->name) 835237ab459STetsuo Handa && tomoyo_is_same_number_union(&p1->mode, &p2->mode) 836237ab459STetsuo Handa && tomoyo_is_same_number_union(&p1->major, &p2->major) 837237ab459STetsuo Handa && tomoyo_is_same_number_union(&p1->minor, &p2->minor); 838237ab459STetsuo Handa } 839237ab459STetsuo Handa 840237ab459STetsuo Handa static bool tomoyo_merge_path_number3_acl(struct tomoyo_acl_info *a, 841237ab459STetsuo Handa struct tomoyo_acl_info *b, 842237ab459STetsuo Handa const bool is_delete) 843237ab459STetsuo Handa { 844237ab459STetsuo Handa u8 *const a_perm = &container_of(a, struct tomoyo_path_number3_acl, 845237ab459STetsuo Handa head)->perm; 846237ab459STetsuo Handa u8 perm = *a_perm; 847237ab459STetsuo Handa const u8 b_perm = container_of(b, struct tomoyo_path_number3_acl, head) 848237ab459STetsuo Handa ->perm; 849237ab459STetsuo Handa if (is_delete) 850237ab459STetsuo Handa perm &= ~b_perm; 851237ab459STetsuo Handa else 852237ab459STetsuo Handa perm |= b_perm; 853237ab459STetsuo Handa *a_perm = perm; 854237ab459STetsuo Handa return !perm; 855237ab459STetsuo Handa } 856237ab459STetsuo Handa 857b69a54eeSKentaro Takeda /** 858a1f9bb6aSTetsuo Handa * tomoyo_update_path_number3_acl - Update "struct tomoyo_path_number3_acl" list. 859a1f9bb6aSTetsuo Handa * 860a1f9bb6aSTetsuo Handa * @type: Type of operation. 861a1f9bb6aSTetsuo Handa * @filename: Filename. 862a1f9bb6aSTetsuo Handa * @mode: Create mode. 863a1f9bb6aSTetsuo Handa * @major: Device major number. 864a1f9bb6aSTetsuo Handa * @minor: Device minor number. 865a1f9bb6aSTetsuo Handa * @domain: Pointer to "struct tomoyo_domain_info". 866a1f9bb6aSTetsuo Handa * @is_delete: True if it is a delete request. 867a1f9bb6aSTetsuo Handa * 868a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 869237ab459STetsuo Handa * 870237ab459STetsuo Handa * Caller holds tomoyo_read_lock(). 871a1f9bb6aSTetsuo Handa */ 872237ab459STetsuo Handa static int tomoyo_update_path_number3_acl(const u8 type, const char *filename, 873237ab459STetsuo Handa char *mode, char *major, char *minor, 874237ab459STetsuo Handa struct tomoyo_domain_info * const 875237ab459STetsuo Handa domain, const bool is_delete) 876a1f9bb6aSTetsuo Handa { 877a1f9bb6aSTetsuo Handa struct tomoyo_path_number3_acl e = { 878a1f9bb6aSTetsuo Handa .head.type = TOMOYO_TYPE_PATH_NUMBER3_ACL, 879237ab459STetsuo Handa .perm = 1 << type 880a1f9bb6aSTetsuo Handa }; 881a1f9bb6aSTetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 882a1f9bb6aSTetsuo Handa if (!tomoyo_parse_name_union(filename, &e.name) || 883a1f9bb6aSTetsuo Handa !tomoyo_parse_number_union(mode, &e.mode) || 884a1f9bb6aSTetsuo Handa !tomoyo_parse_number_union(major, &e.major) || 885a1f9bb6aSTetsuo Handa !tomoyo_parse_number_union(minor, &e.minor)) 886a1f9bb6aSTetsuo Handa goto out; 887237ab459STetsuo Handa error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, 888237ab459STetsuo Handa tomoyo_same_path_number3_acl, 889237ab459STetsuo Handa tomoyo_merge_path_number3_acl); 890a1f9bb6aSTetsuo Handa out: 891a1f9bb6aSTetsuo Handa tomoyo_put_name_union(&e.name); 892a1f9bb6aSTetsuo Handa tomoyo_put_number_union(&e.mode); 893a1f9bb6aSTetsuo Handa tomoyo_put_number_union(&e.major); 894a1f9bb6aSTetsuo Handa tomoyo_put_number_union(&e.minor); 895a1f9bb6aSTetsuo Handa return error; 896a1f9bb6aSTetsuo Handa } 897a1f9bb6aSTetsuo Handa 898237ab459STetsuo Handa static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a, 899237ab459STetsuo Handa const struct tomoyo_acl_info *b) 900237ab459STetsuo Handa { 901237ab459STetsuo Handa const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head); 902237ab459STetsuo Handa const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head); 903237ab459STetsuo Handa return tomoyo_is_same_acl_head(&p1->head, &p2->head) 904237ab459STetsuo Handa && tomoyo_is_same_name_union(&p1->name1, &p2->name1) 905237ab459STetsuo Handa && tomoyo_is_same_name_union(&p1->name2, &p2->name2); 906237ab459STetsuo Handa } 907237ab459STetsuo Handa 908237ab459STetsuo Handa static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a, 909237ab459STetsuo Handa struct tomoyo_acl_info *b, 910237ab459STetsuo Handa const bool is_delete) 911237ab459STetsuo Handa { 912237ab459STetsuo Handa u8 * const a_perm = &container_of(a, struct tomoyo_path2_acl, head) 913237ab459STetsuo Handa ->perm; 914237ab459STetsuo Handa u8 perm = *a_perm; 915237ab459STetsuo Handa const u8 b_perm = container_of(b, struct tomoyo_path2_acl, head)->perm; 916237ab459STetsuo Handa if (is_delete) 917237ab459STetsuo Handa perm &= ~b_perm; 918237ab459STetsuo Handa else 919237ab459STetsuo Handa perm |= b_perm; 920237ab459STetsuo Handa *a_perm = perm; 921237ab459STetsuo Handa return !perm; 922237ab459STetsuo Handa } 923237ab459STetsuo Handa 924a1f9bb6aSTetsuo Handa /** 9257ef61233STetsuo Handa * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list. 926b69a54eeSKentaro Takeda * 927b69a54eeSKentaro Takeda * @type: Type of operation. 928b69a54eeSKentaro Takeda * @filename1: First filename. 929b69a54eeSKentaro Takeda * @filename2: Second filename. 930b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 931b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 932b69a54eeSKentaro Takeda * 933b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 934fdb8ebb7STetsuo Handa * 935fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 936b69a54eeSKentaro Takeda */ 9377ef61233STetsuo Handa static int tomoyo_update_path2_acl(const u8 type, const char *filename1, 938b69a54eeSKentaro Takeda const char *filename2, 9397ef61233STetsuo Handa struct tomoyo_domain_info * const domain, 9407ef61233STetsuo Handa const bool is_delete) 941b69a54eeSKentaro Takeda { 9429e4b50e9STetsuo Handa struct tomoyo_path2_acl e = { 9439e4b50e9STetsuo Handa .head.type = TOMOYO_TYPE_PATH2_ACL, 944237ab459STetsuo Handa .perm = 1 << type 9459e4b50e9STetsuo Handa }; 9469e4b50e9STetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 9477762fbffSTetsuo Handa if (!tomoyo_parse_name_union(filename1, &e.name1) || 9487762fbffSTetsuo Handa !tomoyo_parse_name_union(filename2, &e.name2)) 949ca0b7df3STetsuo Handa goto out; 950237ab459STetsuo Handa error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, 951237ab459STetsuo Handa tomoyo_same_path2_acl, 952237ab459STetsuo Handa tomoyo_merge_path2_acl); 953ca0b7df3STetsuo Handa out: 9547762fbffSTetsuo Handa tomoyo_put_name_union(&e.name1); 9557762fbffSTetsuo Handa tomoyo_put_name_union(&e.name2); 956b69a54eeSKentaro Takeda return error; 957b69a54eeSKentaro Takeda } 958b69a54eeSKentaro Takeda 959b69a54eeSKentaro Takeda /** 960a1f9bb6aSTetsuo Handa * tomoyo_path_number3_acl - Check permission for path/number/number/number operation. 961a1f9bb6aSTetsuo Handa * 962a1f9bb6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 963a1f9bb6aSTetsuo Handa * @filename: Filename to check. 964a1f9bb6aSTetsuo Handa * @perm: Permission. 965a1f9bb6aSTetsuo Handa * @mode: Create mode. 966a1f9bb6aSTetsuo Handa * @major: Device major number. 967a1f9bb6aSTetsuo Handa * @minor: Device minor number. 968a1f9bb6aSTetsuo Handa * 969a1f9bb6aSTetsuo Handa * Returns 0 on success, -EPERM otherwise. 970a1f9bb6aSTetsuo Handa * 971a1f9bb6aSTetsuo Handa * Caller holds tomoyo_read_lock(). 972a1f9bb6aSTetsuo Handa */ 973a1f9bb6aSTetsuo Handa static int tomoyo_path_number3_acl(struct tomoyo_request_info *r, 974a1f9bb6aSTetsuo Handa const struct tomoyo_path_info *filename, 975a1f9bb6aSTetsuo Handa const u16 perm, const unsigned int mode, 976a1f9bb6aSTetsuo Handa const unsigned int major, 977a1f9bb6aSTetsuo Handa const unsigned int minor) 978a1f9bb6aSTetsuo Handa { 979a1f9bb6aSTetsuo Handa struct tomoyo_domain_info *domain = r->domain; 980a1f9bb6aSTetsuo Handa struct tomoyo_acl_info *ptr; 981a1f9bb6aSTetsuo Handa int error = -EPERM; 982a1f9bb6aSTetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 983a1f9bb6aSTetsuo Handa struct tomoyo_path_number3_acl *acl; 984a1f9bb6aSTetsuo Handa if (ptr->type != TOMOYO_TYPE_PATH_NUMBER3_ACL) 985a1f9bb6aSTetsuo Handa continue; 986a1f9bb6aSTetsuo Handa acl = container_of(ptr, struct tomoyo_path_number3_acl, head); 987a1f9bb6aSTetsuo Handa if (!tomoyo_compare_number_union(mode, &acl->mode)) 988a1f9bb6aSTetsuo Handa continue; 989a1f9bb6aSTetsuo Handa if (!tomoyo_compare_number_union(major, &acl->major)) 990a1f9bb6aSTetsuo Handa continue; 991a1f9bb6aSTetsuo Handa if (!tomoyo_compare_number_union(minor, &acl->minor)) 992a1f9bb6aSTetsuo Handa continue; 993a1f9bb6aSTetsuo Handa if (!(acl->perm & perm)) 994a1f9bb6aSTetsuo Handa continue; 995a1f9bb6aSTetsuo Handa if (!tomoyo_compare_name_union(filename, &acl->name)) 996a1f9bb6aSTetsuo Handa continue; 997a1f9bb6aSTetsuo Handa error = 0; 998a1f9bb6aSTetsuo Handa break; 999a1f9bb6aSTetsuo Handa } 1000a1f9bb6aSTetsuo Handa return error; 1001a1f9bb6aSTetsuo Handa } 1002a1f9bb6aSTetsuo Handa 1003a1f9bb6aSTetsuo Handa /** 10047ef61233STetsuo Handa * tomoyo_path2_acl - Check permission for double path operation. 1005b69a54eeSKentaro Takeda * 1006cb0abe6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 1007b69a54eeSKentaro Takeda * @type: Type of operation. 1008b69a54eeSKentaro Takeda * @filename1: First filename to check. 1009b69a54eeSKentaro Takeda * @filename2: Second filename to check. 1010b69a54eeSKentaro Takeda * 1011b69a54eeSKentaro Takeda * Returns 0 on success, -EPERM otherwise. 1012fdb8ebb7STetsuo Handa * 1013fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 1014b69a54eeSKentaro Takeda */ 1015cb0abe6aSTetsuo Handa static int tomoyo_path2_acl(const struct tomoyo_request_info *r, const u8 type, 10167ef61233STetsuo Handa const struct tomoyo_path_info *filename1, 10177ef61233STetsuo Handa const struct tomoyo_path_info *filename2) 1018b69a54eeSKentaro Takeda { 1019cb0abe6aSTetsuo Handa const struct tomoyo_domain_info *domain = r->domain; 1020b69a54eeSKentaro Takeda struct tomoyo_acl_info *ptr; 1021b69a54eeSKentaro Takeda const u8 perm = 1 << type; 1022b69a54eeSKentaro Takeda int error = -EPERM; 1023b69a54eeSKentaro Takeda 1024fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 10257ef61233STetsuo Handa struct tomoyo_path2_acl *acl; 10267ef61233STetsuo Handa if (ptr->type != TOMOYO_TYPE_PATH2_ACL) 1027b69a54eeSKentaro Takeda continue; 10287ef61233STetsuo Handa acl = container_of(ptr, struct tomoyo_path2_acl, head); 1029b69a54eeSKentaro Takeda if (!(acl->perm & perm)) 1030b69a54eeSKentaro Takeda continue; 10317762fbffSTetsuo Handa if (!tomoyo_compare_name_union(filename1, &acl->name1)) 1032b69a54eeSKentaro Takeda continue; 10337762fbffSTetsuo Handa if (!tomoyo_compare_name_union(filename2, &acl->name2)) 1034b69a54eeSKentaro Takeda continue; 1035b69a54eeSKentaro Takeda error = 0; 1036b69a54eeSKentaro Takeda break; 1037b69a54eeSKentaro Takeda } 1038b69a54eeSKentaro Takeda return error; 1039b69a54eeSKentaro Takeda } 1040b69a54eeSKentaro Takeda 1041b69a54eeSKentaro Takeda /** 1042cb0abe6aSTetsuo Handa * tomoyo_path_permission - Check permission for single path operation. 1043b69a54eeSKentaro Takeda * 1044cb0abe6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 1045b69a54eeSKentaro Takeda * @operation: Type of operation. 1046b69a54eeSKentaro Takeda * @filename: Filename to check. 1047b69a54eeSKentaro Takeda * 1048b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1049fdb8ebb7STetsuo Handa * 1050fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 1051b69a54eeSKentaro Takeda */ 1052cb0abe6aSTetsuo Handa static int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, 1053cb0abe6aSTetsuo Handa const struct tomoyo_path_info *filename) 1054b69a54eeSKentaro Takeda { 105517fcfbd9STetsuo Handa const char *msg; 1056b69a54eeSKentaro Takeda int error; 1057b69a54eeSKentaro Takeda 1058b69a54eeSKentaro Takeda next: 105957c2590fSTetsuo Handa r->type = tomoyo_p2mac[operation]; 106057c2590fSTetsuo Handa r->mode = tomoyo_get_mode(r->profile, r->type); 106157c2590fSTetsuo Handa if (r->mode == TOMOYO_CONFIG_DISABLED) 106257c2590fSTetsuo Handa return 0; 106317fcfbd9STetsuo Handa do { 10643f629636STetsuo Handa error = tomoyo_path_acl(r, filename, 1 << operation); 1065b69a54eeSKentaro Takeda if (!error) 106617fcfbd9STetsuo Handa break; 106717fcfbd9STetsuo Handa msg = tomoyo_path2keyword(operation); 106817fcfbd9STetsuo Handa tomoyo_warn_log(r, "%s %s", msg, filename->name); 106917fcfbd9STetsuo Handa error = tomoyo_supervisor(r, "allow_%s %s\n", msg, 107017fcfbd9STetsuo Handa tomoyo_file_pattern(filename)); 107117fcfbd9STetsuo Handa } while (error == TOMOYO_RETRY_REQUEST); 1072cb0abe6aSTetsuo Handa if (r->mode != TOMOYO_CONFIG_ENFORCING) 1073b69a54eeSKentaro Takeda error = 0; 1074b69a54eeSKentaro Takeda /* 1075b69a54eeSKentaro Takeda * Since "allow_truncate" doesn't imply "allow_rewrite" permission, 1076b69a54eeSKentaro Takeda * we need to check "allow_rewrite" permission if the filename is 1077b69a54eeSKentaro Takeda * specified by "deny_rewrite" keyword. 1078b69a54eeSKentaro Takeda */ 10797ef61233STetsuo Handa if (!error && operation == TOMOYO_TYPE_TRUNCATE && 1080b69a54eeSKentaro Takeda tomoyo_is_no_rewrite_file(filename)) { 10817ef61233STetsuo Handa operation = TOMOYO_TYPE_REWRITE; 1082b69a54eeSKentaro Takeda goto next; 1083b69a54eeSKentaro Takeda } 1084b69a54eeSKentaro Takeda return error; 1085b69a54eeSKentaro Takeda } 1086b69a54eeSKentaro Takeda 1087b69a54eeSKentaro Takeda /** 1088a1f9bb6aSTetsuo Handa * tomoyo_path_number_acl - Check permission for ioctl/chmod/chown/chgrp operation. 1089a1f9bb6aSTetsuo Handa * 1090a1f9bb6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 1091a1f9bb6aSTetsuo Handa * @type: Operation. 1092a1f9bb6aSTetsuo Handa * @filename: Filename to check. 1093a1f9bb6aSTetsuo Handa * @number: Number. 1094a1f9bb6aSTetsuo Handa * 1095a1f9bb6aSTetsuo Handa * Returns 0 on success, -EPERM otherwise. 1096a1f9bb6aSTetsuo Handa * 1097a1f9bb6aSTetsuo Handa * Caller holds tomoyo_read_lock(). 1098a1f9bb6aSTetsuo Handa */ 1099a1f9bb6aSTetsuo Handa static int tomoyo_path_number_acl(struct tomoyo_request_info *r, const u8 type, 1100a1f9bb6aSTetsuo Handa const struct tomoyo_path_info *filename, 1101a1f9bb6aSTetsuo Handa const unsigned long number) 1102a1f9bb6aSTetsuo Handa { 1103a1f9bb6aSTetsuo Handa struct tomoyo_domain_info *domain = r->domain; 1104a1f9bb6aSTetsuo Handa struct tomoyo_acl_info *ptr; 1105a1f9bb6aSTetsuo Handa const u8 perm = 1 << type; 1106a1f9bb6aSTetsuo Handa int error = -EPERM; 1107a1f9bb6aSTetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 1108a1f9bb6aSTetsuo Handa struct tomoyo_path_number_acl *acl; 1109a1f9bb6aSTetsuo Handa if (ptr->type != TOMOYO_TYPE_PATH_NUMBER_ACL) 1110a1f9bb6aSTetsuo Handa continue; 1111a1f9bb6aSTetsuo Handa acl = container_of(ptr, struct tomoyo_path_number_acl, 1112a1f9bb6aSTetsuo Handa head); 1113a1f9bb6aSTetsuo Handa if (!(acl->perm & perm) || 1114a1f9bb6aSTetsuo Handa !tomoyo_compare_number_union(number, &acl->number) || 1115a1f9bb6aSTetsuo Handa !tomoyo_compare_name_union(filename, &acl->name)) 1116a1f9bb6aSTetsuo Handa continue; 1117a1f9bb6aSTetsuo Handa error = 0; 1118a1f9bb6aSTetsuo Handa break; 1119a1f9bb6aSTetsuo Handa } 1120a1f9bb6aSTetsuo Handa return error; 1121a1f9bb6aSTetsuo Handa } 1122a1f9bb6aSTetsuo Handa 1123237ab459STetsuo Handa static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a, 1124237ab459STetsuo Handa const struct tomoyo_acl_info *b) 1125237ab459STetsuo Handa { 1126237ab459STetsuo Handa const struct tomoyo_path_number_acl *p1 = container_of(a, typeof(*p1), 1127237ab459STetsuo Handa head); 1128237ab459STetsuo Handa const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2), 1129237ab459STetsuo Handa head); 1130237ab459STetsuo Handa return tomoyo_is_same_acl_head(&p1->head, &p2->head) 1131237ab459STetsuo Handa && tomoyo_is_same_name_union(&p1->name, &p2->name) 1132237ab459STetsuo Handa && tomoyo_is_same_number_union(&p1->number, &p2->number); 1133237ab459STetsuo Handa } 1134237ab459STetsuo Handa 1135237ab459STetsuo Handa static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a, 1136237ab459STetsuo Handa struct tomoyo_acl_info *b, 1137237ab459STetsuo Handa const bool is_delete) 1138237ab459STetsuo Handa { 1139237ab459STetsuo Handa u8 * const a_perm = &container_of(a, struct tomoyo_path_number_acl, 1140237ab459STetsuo Handa head)->perm; 1141237ab459STetsuo Handa u8 perm = *a_perm; 1142237ab459STetsuo Handa const u8 b_perm = container_of(b, struct tomoyo_path_number_acl, head) 1143237ab459STetsuo Handa ->perm; 1144237ab459STetsuo Handa if (is_delete) 1145237ab459STetsuo Handa perm &= ~b_perm; 1146237ab459STetsuo Handa else 1147237ab459STetsuo Handa perm |= b_perm; 1148237ab459STetsuo Handa *a_perm = perm; 1149237ab459STetsuo Handa return !perm; 1150237ab459STetsuo Handa } 1151237ab459STetsuo Handa 1152a1f9bb6aSTetsuo Handa /** 1153a1f9bb6aSTetsuo Handa * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL. 1154a1f9bb6aSTetsuo Handa * 1155a1f9bb6aSTetsuo Handa * @type: Type of operation. 1156a1f9bb6aSTetsuo Handa * @filename: Filename. 1157a1f9bb6aSTetsuo Handa * @number: Number. 1158a1f9bb6aSTetsuo Handa * @domain: Pointer to "struct tomoyo_domain_info". 1159a1f9bb6aSTetsuo Handa * @is_delete: True if it is a delete request. 1160a1f9bb6aSTetsuo Handa * 1161a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1162a1f9bb6aSTetsuo Handa */ 1163237ab459STetsuo Handa static int tomoyo_update_path_number_acl(const u8 type, const char *filename, 1164a1f9bb6aSTetsuo Handa char *number, 1165237ab459STetsuo Handa struct tomoyo_domain_info * const 1166237ab459STetsuo Handa domain, 1167a1f9bb6aSTetsuo Handa const bool is_delete) 1168a1f9bb6aSTetsuo Handa { 1169a1f9bb6aSTetsuo Handa struct tomoyo_path_number_acl e = { 1170a1f9bb6aSTetsuo Handa .head.type = TOMOYO_TYPE_PATH_NUMBER_ACL, 1171237ab459STetsuo Handa .perm = 1 << type 1172a1f9bb6aSTetsuo Handa }; 1173a1f9bb6aSTetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 1174a1f9bb6aSTetsuo Handa if (!tomoyo_parse_name_union(filename, &e.name)) 1175a1f9bb6aSTetsuo Handa return -EINVAL; 1176a1f9bb6aSTetsuo Handa if (!tomoyo_parse_number_union(number, &e.number)) 1177a1f9bb6aSTetsuo Handa goto out; 1178237ab459STetsuo Handa error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, 1179237ab459STetsuo Handa tomoyo_same_path_number_acl, 1180237ab459STetsuo Handa tomoyo_merge_path_number_acl); 1181a1f9bb6aSTetsuo Handa out: 1182a1f9bb6aSTetsuo Handa tomoyo_put_name_union(&e.name); 1183a1f9bb6aSTetsuo Handa tomoyo_put_number_union(&e.number); 1184a1f9bb6aSTetsuo Handa return error; 1185a1f9bb6aSTetsuo Handa } 1186a1f9bb6aSTetsuo Handa 1187a1f9bb6aSTetsuo Handa /** 1188a1f9bb6aSTetsuo Handa * tomoyo_path_number_perm2 - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp". 1189a1f9bb6aSTetsuo Handa * 1190a1f9bb6aSTetsuo Handa * @r: Pointer to "strct tomoyo_request_info". 1191a1f9bb6aSTetsuo Handa * @filename: Filename to check. 1192a1f9bb6aSTetsuo Handa * @number: Number. 1193a1f9bb6aSTetsuo Handa * 1194a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1195a1f9bb6aSTetsuo Handa * 1196a1f9bb6aSTetsuo Handa * Caller holds tomoyo_read_lock(). 1197a1f9bb6aSTetsuo Handa */ 1198a1f9bb6aSTetsuo Handa static int tomoyo_path_number_perm2(struct tomoyo_request_info *r, 1199a1f9bb6aSTetsuo Handa const u8 type, 1200a1f9bb6aSTetsuo Handa const struct tomoyo_path_info *filename, 1201a1f9bb6aSTetsuo Handa const unsigned long number) 1202a1f9bb6aSTetsuo Handa { 1203a1f9bb6aSTetsuo Handa char buffer[64]; 1204a1f9bb6aSTetsuo Handa int error; 1205a1f9bb6aSTetsuo Handa u8 radix; 120617fcfbd9STetsuo Handa const char *msg; 1207a1f9bb6aSTetsuo Handa 1208a1f9bb6aSTetsuo Handa if (!filename) 1209a1f9bb6aSTetsuo Handa return 0; 1210a1f9bb6aSTetsuo Handa switch (type) { 1211a1f9bb6aSTetsuo Handa case TOMOYO_TYPE_CREATE: 1212a1f9bb6aSTetsuo Handa case TOMOYO_TYPE_MKDIR: 1213a1f9bb6aSTetsuo Handa case TOMOYO_TYPE_MKFIFO: 1214a1f9bb6aSTetsuo Handa case TOMOYO_TYPE_MKSOCK: 1215a1f9bb6aSTetsuo Handa case TOMOYO_TYPE_CHMOD: 1216a1f9bb6aSTetsuo Handa radix = TOMOYO_VALUE_TYPE_OCTAL; 1217a1f9bb6aSTetsuo Handa break; 1218a1f9bb6aSTetsuo Handa case TOMOYO_TYPE_IOCTL: 1219a1f9bb6aSTetsuo Handa radix = TOMOYO_VALUE_TYPE_HEXADECIMAL; 1220a1f9bb6aSTetsuo Handa break; 1221a1f9bb6aSTetsuo Handa default: 1222a1f9bb6aSTetsuo Handa radix = TOMOYO_VALUE_TYPE_DECIMAL; 1223a1f9bb6aSTetsuo Handa break; 1224a1f9bb6aSTetsuo Handa } 1225a1f9bb6aSTetsuo Handa tomoyo_print_ulong(buffer, sizeof(buffer), number, radix); 122617fcfbd9STetsuo Handa do { 1227a1f9bb6aSTetsuo Handa error = tomoyo_path_number_acl(r, type, filename, number); 1228a1f9bb6aSTetsuo Handa if (!error) 122917fcfbd9STetsuo Handa break; 123017fcfbd9STetsuo Handa msg = tomoyo_path_number2keyword(type); 123117fcfbd9STetsuo Handa tomoyo_warn_log(r, "%s %s %s", msg, filename->name, buffer); 123217fcfbd9STetsuo Handa error = tomoyo_supervisor(r, "allow_%s %s %s\n", msg, 123317fcfbd9STetsuo Handa tomoyo_file_pattern(filename), 123417fcfbd9STetsuo Handa buffer); 123517fcfbd9STetsuo Handa } while (error == TOMOYO_RETRY_REQUEST); 1236a1f9bb6aSTetsuo Handa if (r->mode != TOMOYO_CONFIG_ENFORCING) 1237a1f9bb6aSTetsuo Handa error = 0; 1238a1f9bb6aSTetsuo Handa return error; 1239a1f9bb6aSTetsuo Handa } 1240a1f9bb6aSTetsuo Handa 1241a1f9bb6aSTetsuo Handa /** 1242a1f9bb6aSTetsuo Handa * tomoyo_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp". 1243a1f9bb6aSTetsuo Handa * 1244a1f9bb6aSTetsuo Handa * @type: Type of operation. 1245a1f9bb6aSTetsuo Handa * @path: Pointer to "struct path". 1246a1f9bb6aSTetsuo Handa * @number: Number. 1247a1f9bb6aSTetsuo Handa * 1248a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1249a1f9bb6aSTetsuo Handa */ 1250a1f9bb6aSTetsuo Handa int tomoyo_path_number_perm(const u8 type, struct path *path, 1251a1f9bb6aSTetsuo Handa unsigned long number) 1252a1f9bb6aSTetsuo Handa { 1253a1f9bb6aSTetsuo Handa struct tomoyo_request_info r; 1254a1f9bb6aSTetsuo Handa int error = -ENOMEM; 1255c8c57e84STetsuo Handa struct tomoyo_path_info buf; 1256a1f9bb6aSTetsuo Handa int idx; 1257a1f9bb6aSTetsuo Handa 125857c2590fSTetsuo Handa if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type]) 125957c2590fSTetsuo Handa == TOMOYO_CONFIG_DISABLED || !path->mnt || !path->dentry) 1260a1f9bb6aSTetsuo Handa return 0; 1261a1f9bb6aSTetsuo Handa idx = tomoyo_read_lock(); 1262c8c57e84STetsuo Handa if (!tomoyo_get_realpath(&buf, path)) 1263a1f9bb6aSTetsuo Handa goto out; 1264c8c57e84STetsuo Handa if (type == TOMOYO_TYPE_MKDIR) 1265c8c57e84STetsuo Handa tomoyo_add_slash(&buf); 1266c8c57e84STetsuo Handa error = tomoyo_path_number_perm2(&r, type, &buf, number); 1267a1f9bb6aSTetsuo Handa out: 1268c8c57e84STetsuo Handa kfree(buf.name); 1269a1f9bb6aSTetsuo Handa tomoyo_read_unlock(idx); 1270a1f9bb6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 1271a1f9bb6aSTetsuo Handa error = 0; 1272a1f9bb6aSTetsuo Handa return error; 1273a1f9bb6aSTetsuo Handa } 1274a1f9bb6aSTetsuo Handa 1275a1f9bb6aSTetsuo Handa /** 1276b69a54eeSKentaro Takeda * tomoyo_check_exec_perm - Check permission for "execute". 1277b69a54eeSKentaro Takeda * 127857c2590fSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 1279b69a54eeSKentaro Takeda * @filename: Check permission for "execute". 1280b69a54eeSKentaro Takeda * 1281b69a54eeSKentaro Takeda * Returns 0 on success, negativevalue otherwise. 1282fdb8ebb7STetsuo Handa * 1283fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 1284b69a54eeSKentaro Takeda */ 128557c2590fSTetsuo Handa int tomoyo_check_exec_perm(struct tomoyo_request_info *r, 1286bcb86975STetsuo Handa const struct tomoyo_path_info *filename) 1287b69a54eeSKentaro Takeda { 128857c2590fSTetsuo Handa if (r->mode == TOMOYO_CONFIG_DISABLED) 1289b69a54eeSKentaro Takeda return 0; 129057c2590fSTetsuo Handa return tomoyo_file_perm(r, filename, 1); 1291b69a54eeSKentaro Takeda } 1292b69a54eeSKentaro Takeda 1293b69a54eeSKentaro Takeda /** 1294b69a54eeSKentaro Takeda * tomoyo_check_open_permission - Check permission for "read" and "write". 1295b69a54eeSKentaro Takeda * 1296b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 1297b69a54eeSKentaro Takeda * @path: Pointer to "struct path". 1298b69a54eeSKentaro Takeda * @flag: Flags for open(). 1299b69a54eeSKentaro Takeda * 1300b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1301b69a54eeSKentaro Takeda */ 1302b69a54eeSKentaro Takeda int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, 1303b69a54eeSKentaro Takeda struct path *path, const int flag) 1304b69a54eeSKentaro Takeda { 1305b69a54eeSKentaro Takeda const u8 acc_mode = ACC_MODE(flag); 1306b69a54eeSKentaro Takeda int error = -ENOMEM; 1307c8c57e84STetsuo Handa struct tomoyo_path_info buf; 1308cb0abe6aSTetsuo Handa struct tomoyo_request_info r; 1309fdb8ebb7STetsuo Handa int idx; 1310b69a54eeSKentaro Takeda 131157c2590fSTetsuo Handa if (!path->mnt || 131257c2590fSTetsuo Handa (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode))) 1313b69a54eeSKentaro Takeda return 0; 131457c2590fSTetsuo Handa buf.name = NULL; 131557c2590fSTetsuo Handa r.mode = TOMOYO_CONFIG_DISABLED; 1316fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 1317c8c57e84STetsuo Handa if (!tomoyo_get_realpath(&buf, path)) 1318b69a54eeSKentaro Takeda goto out; 1319b69a54eeSKentaro Takeda error = 0; 1320b69a54eeSKentaro Takeda /* 1321b69a54eeSKentaro Takeda * If the filename is specified by "deny_rewrite" keyword, 1322b69a54eeSKentaro Takeda * we need to check "allow_rewrite" permission when the filename is not 1323b69a54eeSKentaro Takeda * opened for append mode or the filename is truncated at open time. 1324b69a54eeSKentaro Takeda */ 132557c2590fSTetsuo Handa if ((acc_mode & MAY_WRITE) && !(flag & O_APPEND) 132657c2590fSTetsuo Handa && tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_REWRITE) 132757c2590fSTetsuo Handa != TOMOYO_CONFIG_DISABLED) { 132857c2590fSTetsuo Handa if (!tomoyo_get_realpath(&buf, path)) { 132957c2590fSTetsuo Handa error = -ENOMEM; 133057c2590fSTetsuo Handa goto out; 1331b69a54eeSKentaro Takeda } 133257c2590fSTetsuo Handa if (tomoyo_is_no_rewrite_file(&buf)) 133357c2590fSTetsuo Handa error = tomoyo_path_permission(&r, TOMOYO_TYPE_REWRITE, 133457c2590fSTetsuo Handa &buf); 133557c2590fSTetsuo Handa } 133657c2590fSTetsuo Handa if (!error && acc_mode && 133757c2590fSTetsuo Handa tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN) 133857c2590fSTetsuo Handa != TOMOYO_CONFIG_DISABLED) { 133957c2590fSTetsuo Handa if (!buf.name && !tomoyo_get_realpath(&buf, path)) { 134057c2590fSTetsuo Handa error = -ENOMEM; 134157c2590fSTetsuo Handa goto out; 134257c2590fSTetsuo Handa } 1343c8c57e84STetsuo Handa error = tomoyo_file_perm(&r, &buf, acc_mode); 134457c2590fSTetsuo Handa } 1345b69a54eeSKentaro Takeda out: 1346c8c57e84STetsuo Handa kfree(buf.name); 1347fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 1348cb0abe6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 1349b69a54eeSKentaro Takeda error = 0; 1350b69a54eeSKentaro Takeda return error; 1351b69a54eeSKentaro Takeda } 1352b69a54eeSKentaro Takeda 1353b69a54eeSKentaro Takeda /** 13542106ccd9STetsuo Handa * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "rewrite", "chroot" and "unmount". 1355b69a54eeSKentaro Takeda * 1356b69a54eeSKentaro Takeda * @operation: Type of operation. 1357b69a54eeSKentaro Takeda * @path: Pointer to "struct path". 1358b69a54eeSKentaro Takeda * 1359b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1360b69a54eeSKentaro Takeda */ 136197d6931eSTetsuo Handa int tomoyo_path_perm(const u8 operation, struct path *path) 1362b69a54eeSKentaro Takeda { 1363b69a54eeSKentaro Takeda int error = -ENOMEM; 1364c8c57e84STetsuo Handa struct tomoyo_path_info buf; 1365cb0abe6aSTetsuo Handa struct tomoyo_request_info r; 1366fdb8ebb7STetsuo Handa int idx; 1367b69a54eeSKentaro Takeda 136857c2590fSTetsuo Handa if (!path->mnt) 1369b69a54eeSKentaro Takeda return 0; 137057c2590fSTetsuo Handa if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation]) 137157c2590fSTetsuo Handa == TOMOYO_CONFIG_DISABLED) 137257c2590fSTetsuo Handa return 0; 137357c2590fSTetsuo Handa buf.name = NULL; 1374fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 1375c8c57e84STetsuo Handa if (!tomoyo_get_realpath(&buf, path)) 1376b69a54eeSKentaro Takeda goto out; 1377b69a54eeSKentaro Takeda switch (operation) { 1378cb0abe6aSTetsuo Handa case TOMOYO_TYPE_REWRITE: 1379c8c57e84STetsuo Handa if (!tomoyo_is_no_rewrite_file(&buf)) { 1380cb0abe6aSTetsuo Handa error = 0; 1381cb0abe6aSTetsuo Handa goto out; 1382cb0abe6aSTetsuo Handa } 1383cb0abe6aSTetsuo Handa break; 13847ef61233STetsuo Handa case TOMOYO_TYPE_RMDIR: 13857ef61233STetsuo Handa case TOMOYO_TYPE_CHROOT: 138657c2590fSTetsuo Handa case TOMOYO_TYPE_UMOUNT: 1387c8c57e84STetsuo Handa tomoyo_add_slash(&buf); 1388c8c57e84STetsuo Handa break; 1389b69a54eeSKentaro Takeda } 1390c8c57e84STetsuo Handa error = tomoyo_path_permission(&r, operation, &buf); 1391b69a54eeSKentaro Takeda out: 1392c8c57e84STetsuo Handa kfree(buf.name); 1393fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 1394cb0abe6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 1395b69a54eeSKentaro Takeda error = 0; 1396b69a54eeSKentaro Takeda return error; 1397b69a54eeSKentaro Takeda } 1398b69a54eeSKentaro Takeda 1399b69a54eeSKentaro Takeda /** 1400a1f9bb6aSTetsuo Handa * tomoyo_path_number3_perm2 - Check permission for path/number/number/number operation. 1401a1f9bb6aSTetsuo Handa * 1402a1f9bb6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 1403a1f9bb6aSTetsuo Handa * @operation: Type of operation. 1404a1f9bb6aSTetsuo Handa * @filename: Filename to check. 1405a1f9bb6aSTetsuo Handa * @mode: Create mode. 1406a1f9bb6aSTetsuo Handa * @dev: Device number. 1407a1f9bb6aSTetsuo Handa * 1408a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1409a1f9bb6aSTetsuo Handa * 1410a1f9bb6aSTetsuo Handa * Caller holds tomoyo_read_lock(). 1411a1f9bb6aSTetsuo Handa */ 1412a1f9bb6aSTetsuo Handa static int tomoyo_path_number3_perm2(struct tomoyo_request_info *r, 1413a1f9bb6aSTetsuo Handa const u8 operation, 1414a1f9bb6aSTetsuo Handa const struct tomoyo_path_info *filename, 1415a1f9bb6aSTetsuo Handa const unsigned int mode, 1416a1f9bb6aSTetsuo Handa const unsigned int dev) 1417a1f9bb6aSTetsuo Handa { 1418a1f9bb6aSTetsuo Handa int error; 141917fcfbd9STetsuo Handa const char *msg; 1420a1f9bb6aSTetsuo Handa const unsigned int major = MAJOR(dev); 1421a1f9bb6aSTetsuo Handa const unsigned int minor = MINOR(dev); 1422a1f9bb6aSTetsuo Handa 142317fcfbd9STetsuo Handa do { 142417fcfbd9STetsuo Handa error = tomoyo_path_number3_acl(r, filename, 1 << operation, 142517fcfbd9STetsuo Handa mode, major, minor); 1426a1f9bb6aSTetsuo Handa if (!error) 142717fcfbd9STetsuo Handa break; 142817fcfbd9STetsuo Handa msg = tomoyo_path_number32keyword(operation); 142917fcfbd9STetsuo Handa tomoyo_warn_log(r, "%s %s 0%o %u %u", msg, filename->name, 143017fcfbd9STetsuo Handa mode, major, minor); 143117fcfbd9STetsuo Handa error = tomoyo_supervisor(r, "allow_%s %s 0%o %u %u\n", msg, 143217fcfbd9STetsuo Handa tomoyo_file_pattern(filename), mode, 143317fcfbd9STetsuo Handa major, minor); 143417fcfbd9STetsuo Handa } while (error == TOMOYO_RETRY_REQUEST); 1435a1f9bb6aSTetsuo Handa if (r->mode != TOMOYO_CONFIG_ENFORCING) 1436a1f9bb6aSTetsuo Handa error = 0; 1437a1f9bb6aSTetsuo Handa return error; 1438a1f9bb6aSTetsuo Handa } 1439a1f9bb6aSTetsuo Handa 1440a1f9bb6aSTetsuo Handa /** 1441a1f9bb6aSTetsuo Handa * tomoyo_path_number3_perm - Check permission for "mkblock" and "mkchar". 1442a1f9bb6aSTetsuo Handa * 1443a1f9bb6aSTetsuo Handa * @operation: Type of operation. (TOMOYO_TYPE_MKCHAR or TOMOYO_TYPE_MKBLOCK) 1444a1f9bb6aSTetsuo Handa * @path: Pointer to "struct path". 1445a1f9bb6aSTetsuo Handa * @mode: Create mode. 1446a1f9bb6aSTetsuo Handa * @dev: Device number. 1447a1f9bb6aSTetsuo Handa * 1448a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1449a1f9bb6aSTetsuo Handa */ 1450a1f9bb6aSTetsuo Handa int tomoyo_path_number3_perm(const u8 operation, struct path *path, 1451a1f9bb6aSTetsuo Handa const unsigned int mode, unsigned int dev) 1452a1f9bb6aSTetsuo Handa { 1453a1f9bb6aSTetsuo Handa struct tomoyo_request_info r; 1454a1f9bb6aSTetsuo Handa int error = -ENOMEM; 1455c8c57e84STetsuo Handa struct tomoyo_path_info buf; 1456a1f9bb6aSTetsuo Handa int idx; 1457a1f9bb6aSTetsuo Handa 145857c2590fSTetsuo Handa if (!path->mnt || 145957c2590fSTetsuo Handa tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation]) 146057c2590fSTetsuo Handa == TOMOYO_CONFIG_DISABLED) 1461a1f9bb6aSTetsuo Handa return 0; 1462a1f9bb6aSTetsuo Handa idx = tomoyo_read_lock(); 1463a1f9bb6aSTetsuo Handa error = -ENOMEM; 1464c8c57e84STetsuo Handa if (tomoyo_get_realpath(&buf, path)) { 1465c8c57e84STetsuo Handa error = tomoyo_path_number3_perm2(&r, operation, &buf, mode, 1466a1f9bb6aSTetsuo Handa new_decode_dev(dev)); 1467c8c57e84STetsuo Handa kfree(buf.name); 1468a1f9bb6aSTetsuo Handa } 1469a1f9bb6aSTetsuo Handa tomoyo_read_unlock(idx); 1470a1f9bb6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 1471a1f9bb6aSTetsuo Handa error = 0; 1472a1f9bb6aSTetsuo Handa return error; 1473a1f9bb6aSTetsuo Handa } 1474a1f9bb6aSTetsuo Handa 1475a1f9bb6aSTetsuo Handa /** 14767ef61233STetsuo Handa * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root". 1477b69a54eeSKentaro Takeda * 1478b69a54eeSKentaro Takeda * @operation: Type of operation. 1479b69a54eeSKentaro Takeda * @path1: Pointer to "struct path". 1480b69a54eeSKentaro Takeda * @path2: Pointer to "struct path". 1481b69a54eeSKentaro Takeda * 1482b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1483b69a54eeSKentaro Takeda */ 148497d6931eSTetsuo Handa int tomoyo_path2_perm(const u8 operation, struct path *path1, 1485b69a54eeSKentaro Takeda struct path *path2) 1486b69a54eeSKentaro Takeda { 1487b69a54eeSKentaro Takeda int error = -ENOMEM; 148817fcfbd9STetsuo Handa const char *msg; 1489c8c57e84STetsuo Handa struct tomoyo_path_info buf1; 1490c8c57e84STetsuo Handa struct tomoyo_path_info buf2; 1491cb0abe6aSTetsuo Handa struct tomoyo_request_info r; 1492fdb8ebb7STetsuo Handa int idx; 1493b69a54eeSKentaro Takeda 149457c2590fSTetsuo Handa if (!path1->mnt || !path2->mnt || 149557c2590fSTetsuo Handa tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation]) 149657c2590fSTetsuo Handa == TOMOYO_CONFIG_DISABLED) 1497b69a54eeSKentaro Takeda return 0; 1498c8c57e84STetsuo Handa buf1.name = NULL; 1499c8c57e84STetsuo Handa buf2.name = NULL; 1500fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 1501c8c57e84STetsuo Handa if (!tomoyo_get_realpath(&buf1, path1) || 1502c8c57e84STetsuo Handa !tomoyo_get_realpath(&buf2, path2)) 1503b69a54eeSKentaro Takeda goto out; 150457c2590fSTetsuo Handa switch (operation) { 150557c2590fSTetsuo Handa struct dentry *dentry; 150657c2590fSTetsuo Handa case TOMOYO_TYPE_RENAME: 150757c2590fSTetsuo Handa case TOMOYO_TYPE_LINK: 150857c2590fSTetsuo Handa dentry = path1->dentry; 150957c2590fSTetsuo Handa if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode)) 151057c2590fSTetsuo Handa break; 151157c2590fSTetsuo Handa /* fall through */ 151257c2590fSTetsuo Handa case TOMOYO_TYPE_PIVOT_ROOT: 1513c8c57e84STetsuo Handa tomoyo_add_slash(&buf1); 1514c8c57e84STetsuo Handa tomoyo_add_slash(&buf2); 151557c2590fSTetsuo Handa break; 1516b69a54eeSKentaro Takeda } 151717fcfbd9STetsuo Handa do { 1518c8c57e84STetsuo Handa error = tomoyo_path2_acl(&r, operation, &buf1, &buf2); 1519b69a54eeSKentaro Takeda if (!error) 152017fcfbd9STetsuo Handa break; 152117fcfbd9STetsuo Handa msg = tomoyo_path22keyword(operation); 1522c8c57e84STetsuo Handa tomoyo_warn_log(&r, "%s %s %s", msg, buf1.name, buf2.name); 152317fcfbd9STetsuo Handa error = tomoyo_supervisor(&r, "allow_%s %s %s\n", msg, 1524c8c57e84STetsuo Handa tomoyo_file_pattern(&buf1), 1525c8c57e84STetsuo Handa tomoyo_file_pattern(&buf2)); 152617fcfbd9STetsuo Handa } while (error == TOMOYO_RETRY_REQUEST); 1527b69a54eeSKentaro Takeda out: 1528c8c57e84STetsuo Handa kfree(buf1.name); 1529c8c57e84STetsuo Handa kfree(buf2.name); 1530fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 1531cb0abe6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 1532b69a54eeSKentaro Takeda error = 0; 1533b69a54eeSKentaro Takeda return error; 1534b69a54eeSKentaro Takeda } 1535a1f9bb6aSTetsuo Handa 1536a1f9bb6aSTetsuo Handa /** 1537a1f9bb6aSTetsuo Handa * tomoyo_write_file_policy - Update file related list. 1538a1f9bb6aSTetsuo Handa * 1539a1f9bb6aSTetsuo Handa * @data: String to parse. 1540a1f9bb6aSTetsuo Handa * @domain: Pointer to "struct tomoyo_domain_info". 1541a1f9bb6aSTetsuo Handa * @is_delete: True if it is a delete request. 1542a1f9bb6aSTetsuo Handa * 1543a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1544a1f9bb6aSTetsuo Handa * 1545a1f9bb6aSTetsuo Handa * Caller holds tomoyo_read_lock(). 1546a1f9bb6aSTetsuo Handa */ 1547a1f9bb6aSTetsuo Handa int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, 1548a1f9bb6aSTetsuo Handa const bool is_delete) 1549a1f9bb6aSTetsuo Handa { 1550a1f9bb6aSTetsuo Handa char *w[5]; 1551a1f9bb6aSTetsuo Handa u8 type; 1552a1f9bb6aSTetsuo Handa if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0]) 1553a1f9bb6aSTetsuo Handa return -EINVAL; 1554237ab459STetsuo Handa if (strncmp(w[0], "allow_", 6)) 1555a1f9bb6aSTetsuo Handa goto out; 1556a1f9bb6aSTetsuo Handa w[0] += 6; 1557a1f9bb6aSTetsuo Handa for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) { 1558a1f9bb6aSTetsuo Handa if (strcmp(w[0], tomoyo_path_keyword[type])) 1559a1f9bb6aSTetsuo Handa continue; 1560a1f9bb6aSTetsuo Handa return tomoyo_update_path_acl(type, w[1], domain, is_delete); 1561a1f9bb6aSTetsuo Handa } 1562a1f9bb6aSTetsuo Handa if (!w[2][0]) 1563a1f9bb6aSTetsuo Handa goto out; 1564a1f9bb6aSTetsuo Handa for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) { 1565a1f9bb6aSTetsuo Handa if (strcmp(w[0], tomoyo_path2_keyword[type])) 1566a1f9bb6aSTetsuo Handa continue; 1567a1f9bb6aSTetsuo Handa return tomoyo_update_path2_acl(type, w[1], w[2], domain, 1568a1f9bb6aSTetsuo Handa is_delete); 1569a1f9bb6aSTetsuo Handa } 1570a1f9bb6aSTetsuo Handa for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) { 1571a1f9bb6aSTetsuo Handa if (strcmp(w[0], tomoyo_path_number_keyword[type])) 1572a1f9bb6aSTetsuo Handa continue; 1573a1f9bb6aSTetsuo Handa return tomoyo_update_path_number_acl(type, w[1], w[2], domain, 1574a1f9bb6aSTetsuo Handa is_delete); 1575a1f9bb6aSTetsuo Handa } 1576a1f9bb6aSTetsuo Handa if (!w[3][0] || !w[4][0]) 1577a1f9bb6aSTetsuo Handa goto out; 1578a1f9bb6aSTetsuo Handa for (type = 0; type < TOMOYO_MAX_PATH_NUMBER3_OPERATION; type++) { 1579a1f9bb6aSTetsuo Handa if (strcmp(w[0], tomoyo_path_number3_keyword[type])) 1580a1f9bb6aSTetsuo Handa continue; 1581a1f9bb6aSTetsuo Handa return tomoyo_update_path_number3_acl(type, w[1], w[2], w[3], 1582a1f9bb6aSTetsuo Handa w[4], domain, is_delete); 1583a1f9bb6aSTetsuo Handa } 1584a1f9bb6aSTetsuo Handa out: 1585a1f9bb6aSTetsuo Handa return -EINVAL; 1586a1f9bb6aSTetsuo Handa } 1587