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 25636f5e1ffSTetsuo Handa static bool tomoyo_same_globally_readable(const struct tomoyo_acl_head *a, 25736f5e1ffSTetsuo Handa const struct tomoyo_acl_head *b) 25836f5e1ffSTetsuo Handa { 25936f5e1ffSTetsuo Handa return container_of(a, struct tomoyo_globally_readable_file_entry, 26036f5e1ffSTetsuo Handa head)->filename == 26136f5e1ffSTetsuo Handa container_of(b, struct tomoyo_globally_readable_file_entry, 26236f5e1ffSTetsuo Handa head)->filename; 26336f5e1ffSTetsuo Handa } 26436f5e1ffSTetsuo Handa 265b69a54eeSKentaro Takeda /** 266b69a54eeSKentaro Takeda * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list. 267b69a54eeSKentaro Takeda * 268b69a54eeSKentaro Takeda * @filename: Filename unconditionally permitted to open() for reading. 269b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 270b69a54eeSKentaro Takeda * 271b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 272fdb8ebb7STetsuo Handa * 273fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 274b69a54eeSKentaro Takeda */ 275b69a54eeSKentaro Takeda static int tomoyo_update_globally_readable_entry(const char *filename, 276b69a54eeSKentaro Takeda const bool is_delete) 277b69a54eeSKentaro Takeda { 2789e4b50e9STetsuo Handa struct tomoyo_globally_readable_file_entry e = { }; 27936f5e1ffSTetsuo Handa int error; 280b69a54eeSKentaro Takeda 2813f629636STetsuo Handa if (!tomoyo_is_correct_word(filename)) 282b69a54eeSKentaro Takeda return -EINVAL; 2839e4b50e9STetsuo Handa e.filename = tomoyo_get_name(filename); 2849e4b50e9STetsuo Handa if (!e.filename) 285b69a54eeSKentaro Takeda return -ENOMEM; 28636f5e1ffSTetsuo Handa error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, 28736f5e1ffSTetsuo Handa &tomoyo_globally_readable_list, 28836f5e1ffSTetsuo Handa tomoyo_same_globally_readable); 2899e4b50e9STetsuo Handa tomoyo_put_name(e.filename); 290b69a54eeSKentaro Takeda return error; 291b69a54eeSKentaro Takeda } 292b69a54eeSKentaro Takeda 293b69a54eeSKentaro Takeda /** 294b69a54eeSKentaro Takeda * tomoyo_is_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading. 295b69a54eeSKentaro Takeda * 296b69a54eeSKentaro Takeda * @filename: The filename to check. 297b69a54eeSKentaro Takeda * 298b69a54eeSKentaro Takeda * Returns true if any domain can open @filename for reading, false otherwise. 299fdb8ebb7STetsuo Handa * 300fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 301b69a54eeSKentaro Takeda */ 302b69a54eeSKentaro Takeda static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info * 303b69a54eeSKentaro Takeda filename) 304b69a54eeSKentaro Takeda { 305b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry *ptr; 306b69a54eeSKentaro Takeda bool found = false; 307fdb8ebb7STetsuo Handa 30882e0f001STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, 30982e0f001STetsuo Handa head.list) { 31082e0f001STetsuo Handa if (!ptr->head.is_deleted && 311b69a54eeSKentaro Takeda tomoyo_path_matches_pattern(filename, ptr->filename)) { 312b69a54eeSKentaro Takeda found = true; 313b69a54eeSKentaro Takeda break; 314b69a54eeSKentaro Takeda } 315b69a54eeSKentaro Takeda } 316b69a54eeSKentaro Takeda return found; 317b69a54eeSKentaro Takeda } 318b69a54eeSKentaro Takeda 319b69a54eeSKentaro Takeda /** 320b69a54eeSKentaro Takeda * tomoyo_write_globally_readable_policy - Write "struct tomoyo_globally_readable_file_entry" list. 321b69a54eeSKentaro Takeda * 322b69a54eeSKentaro Takeda * @data: String to parse. 323b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 324b69a54eeSKentaro Takeda * 325b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 326fdb8ebb7STetsuo Handa * 327fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 328b69a54eeSKentaro Takeda */ 329b69a54eeSKentaro Takeda int tomoyo_write_globally_readable_policy(char *data, const bool is_delete) 330b69a54eeSKentaro Takeda { 331b69a54eeSKentaro Takeda return tomoyo_update_globally_readable_entry(data, is_delete); 332b69a54eeSKentaro Takeda } 333b69a54eeSKentaro Takeda 334b69a54eeSKentaro Takeda /** 335b69a54eeSKentaro Takeda * tomoyo_read_globally_readable_policy - Read "struct tomoyo_globally_readable_file_entry" list. 336b69a54eeSKentaro Takeda * 337b69a54eeSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 338b69a54eeSKentaro Takeda * 339b69a54eeSKentaro Takeda * Returns true on success, false otherwise. 340fdb8ebb7STetsuo Handa * 341fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 342b69a54eeSKentaro Takeda */ 343b69a54eeSKentaro Takeda bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) 344b69a54eeSKentaro Takeda { 345b69a54eeSKentaro Takeda struct list_head *pos; 346b69a54eeSKentaro Takeda bool done = true; 347b69a54eeSKentaro Takeda 348b69a54eeSKentaro Takeda list_for_each_cookie(pos, head->read_var2, 349b69a54eeSKentaro Takeda &tomoyo_globally_readable_list) { 350b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry *ptr; 351b69a54eeSKentaro Takeda ptr = list_entry(pos, 352b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry, 35382e0f001STetsuo Handa head.list); 35482e0f001STetsuo Handa if (ptr->head.is_deleted) 355b69a54eeSKentaro Takeda continue; 3567d2948b1STetsuo Handa done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n", 3577d2948b1STetsuo Handa ptr->filename->name); 3587d2948b1STetsuo Handa if (!done) 359b69a54eeSKentaro Takeda break; 360b69a54eeSKentaro Takeda } 361b69a54eeSKentaro Takeda return done; 362b69a54eeSKentaro Takeda } 363b69a54eeSKentaro Takeda 364c3fa109aSTetsuo Handa /* tomoyo_pattern_list is used for holding list of pathnames which are used for 365c3fa109aSTetsuo Handa * converting pathnames to pathname patterns during learning mode. 366c3fa109aSTetsuo Handa * 367c3fa109aSTetsuo Handa * An entry is added by 368c3fa109aSTetsuo Handa * 369c3fa109aSTetsuo Handa * # echo 'file_pattern /proc/\$/mounts' > \ 370c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 371c3fa109aSTetsuo Handa * 372c3fa109aSTetsuo Handa * and is deleted by 373c3fa109aSTetsuo Handa * 374c3fa109aSTetsuo Handa * # echo 'delete file_pattern /proc/\$/mounts' > \ 375c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 376c3fa109aSTetsuo Handa * 377c3fa109aSTetsuo Handa * and all entries are retrieved by 378c3fa109aSTetsuo Handa * 379c3fa109aSTetsuo Handa * # grep ^file_pattern /sys/kernel/security/tomoyo/exception_policy 380c3fa109aSTetsuo Handa * 381c3fa109aSTetsuo Handa * In the example above, if a process which belongs to a domain which is in 382c3fa109aSTetsuo Handa * learning mode requested open("/proc/1/mounts", O_RDONLY), 383c3fa109aSTetsuo Handa * "allow_read /proc/\$/mounts" is automatically added to the domain which that 384c3fa109aSTetsuo Handa * process belongs to. 385c3fa109aSTetsuo Handa * 386c3fa109aSTetsuo Handa * It is not a desirable behavior that we have to use /proc/\$/ instead of 387c3fa109aSTetsuo Handa * /proc/self/ when current process needs to access only current process's 388c3fa109aSTetsuo Handa * information. As of now, LSM version of TOMOYO is using __d_path() for 389c3fa109aSTetsuo Handa * calculating pathname. Non LSM version of TOMOYO is using its own function 390c3fa109aSTetsuo Handa * which pretends as if /proc/self/ is not a symlink; so that we can forbid 391c3fa109aSTetsuo Handa * current process from accessing other process's information. 392c3fa109aSTetsuo Handa */ 393847b173eSTetsuo Handa LIST_HEAD(tomoyo_pattern_list); 394b69a54eeSKentaro Takeda 39536f5e1ffSTetsuo Handa static bool tomoyo_same_pattern(const struct tomoyo_acl_head *a, 39636f5e1ffSTetsuo Handa const struct tomoyo_acl_head *b) 39736f5e1ffSTetsuo Handa { 39836f5e1ffSTetsuo Handa return container_of(a, struct tomoyo_pattern_entry, head)->pattern == 39936f5e1ffSTetsuo Handa container_of(b, struct tomoyo_pattern_entry, head)->pattern; 40036f5e1ffSTetsuo Handa } 40136f5e1ffSTetsuo Handa 402b69a54eeSKentaro Takeda /** 403b69a54eeSKentaro Takeda * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list. 404b69a54eeSKentaro Takeda * 405b69a54eeSKentaro Takeda * @pattern: Pathname pattern. 406b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 407b69a54eeSKentaro Takeda * 408b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 409fdb8ebb7STetsuo Handa * 410fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 411b69a54eeSKentaro Takeda */ 412b69a54eeSKentaro Takeda static int tomoyo_update_file_pattern_entry(const char *pattern, 413b69a54eeSKentaro Takeda const bool is_delete) 414b69a54eeSKentaro Takeda { 4153f629636STetsuo Handa struct tomoyo_pattern_entry e = { }; 41636f5e1ffSTetsuo Handa int error; 417b69a54eeSKentaro Takeda 4183f629636STetsuo Handa if (!tomoyo_is_correct_word(pattern)) 4193f629636STetsuo Handa return -EINVAL; 4203f629636STetsuo Handa e.pattern = tomoyo_get_name(pattern); 4219e4b50e9STetsuo Handa if (!e.pattern) 42236f5e1ffSTetsuo Handa return -ENOMEM; 42336f5e1ffSTetsuo Handa error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, 42436f5e1ffSTetsuo Handa &tomoyo_pattern_list, 42536f5e1ffSTetsuo Handa tomoyo_same_pattern); 4269e4b50e9STetsuo Handa tomoyo_put_name(e.pattern); 427b69a54eeSKentaro Takeda return error; 428b69a54eeSKentaro Takeda } 429b69a54eeSKentaro Takeda 430b69a54eeSKentaro Takeda /** 43117fcfbd9STetsuo Handa * tomoyo_file_pattern - Get patterned pathname. 432b69a54eeSKentaro Takeda * 433b69a54eeSKentaro Takeda * @filename: The filename to find patterned pathname. 434b69a54eeSKentaro Takeda * 435b69a54eeSKentaro Takeda * Returns pointer to pathname pattern if matched, @filename otherwise. 436fdb8ebb7STetsuo Handa * 437fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 438b69a54eeSKentaro Takeda */ 43917fcfbd9STetsuo Handa const char *tomoyo_file_pattern(const struct tomoyo_path_info *filename) 440b69a54eeSKentaro Takeda { 441b69a54eeSKentaro Takeda struct tomoyo_pattern_entry *ptr; 442b69a54eeSKentaro Takeda const struct tomoyo_path_info *pattern = NULL; 443b69a54eeSKentaro Takeda 44482e0f001STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, head.list) { 44582e0f001STetsuo Handa if (ptr->head.is_deleted) 446b69a54eeSKentaro Takeda continue; 447b69a54eeSKentaro Takeda if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) 448b69a54eeSKentaro Takeda continue; 449b69a54eeSKentaro Takeda pattern = ptr->pattern; 450b69a54eeSKentaro Takeda if (tomoyo_strendswith(pattern->name, "/\\*")) { 451b69a54eeSKentaro Takeda /* Do nothing. Try to find the better match. */ 452b69a54eeSKentaro Takeda } else { 453b69a54eeSKentaro Takeda /* This would be the better match. Use this. */ 454b69a54eeSKentaro Takeda break; 455b69a54eeSKentaro Takeda } 456b69a54eeSKentaro Takeda } 457b69a54eeSKentaro Takeda if (pattern) 458b69a54eeSKentaro Takeda filename = pattern; 45917fcfbd9STetsuo Handa return filename->name; 460b69a54eeSKentaro Takeda } 461b69a54eeSKentaro Takeda 462b69a54eeSKentaro Takeda /** 463b69a54eeSKentaro Takeda * tomoyo_write_pattern_policy - Write "struct tomoyo_pattern_entry" list. 464b69a54eeSKentaro Takeda * 465b69a54eeSKentaro Takeda * @data: String to parse. 466b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 467b69a54eeSKentaro Takeda * 468b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 469fdb8ebb7STetsuo Handa * 470fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 471b69a54eeSKentaro Takeda */ 472b69a54eeSKentaro Takeda int tomoyo_write_pattern_policy(char *data, const bool is_delete) 473b69a54eeSKentaro Takeda { 474b69a54eeSKentaro Takeda return tomoyo_update_file_pattern_entry(data, is_delete); 475b69a54eeSKentaro Takeda } 476b69a54eeSKentaro Takeda 477b69a54eeSKentaro Takeda /** 478b69a54eeSKentaro Takeda * tomoyo_read_file_pattern - Read "struct tomoyo_pattern_entry" list. 479b69a54eeSKentaro Takeda * 480b69a54eeSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 481b69a54eeSKentaro Takeda * 482b69a54eeSKentaro Takeda * Returns true on success, false otherwise. 483fdb8ebb7STetsuo Handa * 484fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 485b69a54eeSKentaro Takeda */ 486b69a54eeSKentaro Takeda bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) 487b69a54eeSKentaro Takeda { 488b69a54eeSKentaro Takeda struct list_head *pos; 489b69a54eeSKentaro Takeda bool done = true; 490b69a54eeSKentaro Takeda 491b69a54eeSKentaro Takeda list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) { 492b69a54eeSKentaro Takeda struct tomoyo_pattern_entry *ptr; 49382e0f001STetsuo Handa ptr = list_entry(pos, struct tomoyo_pattern_entry, head.list); 49482e0f001STetsuo Handa if (ptr->head.is_deleted) 495b69a54eeSKentaro Takeda continue; 4967d2948b1STetsuo Handa done = tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN 4977d2948b1STetsuo Handa "%s\n", ptr->pattern->name); 4987d2948b1STetsuo Handa if (!done) 499b69a54eeSKentaro Takeda break; 500b69a54eeSKentaro Takeda } 501b69a54eeSKentaro Takeda return done; 502b69a54eeSKentaro Takeda } 503b69a54eeSKentaro Takeda 504c3fa109aSTetsuo Handa /* 505c3fa109aSTetsuo Handa * tomoyo_no_rewrite_list is used for holding list of pathnames which are by 506c3fa109aSTetsuo Handa * default forbidden to modify already written content of a file. 507c3fa109aSTetsuo Handa * 508c3fa109aSTetsuo Handa * An entry is added by 509c3fa109aSTetsuo Handa * 510c3fa109aSTetsuo Handa * # echo 'deny_rewrite /var/log/messages' > \ 511c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 512c3fa109aSTetsuo Handa * 513c3fa109aSTetsuo Handa * and is deleted by 514c3fa109aSTetsuo Handa * 515c3fa109aSTetsuo Handa * # echo 'delete deny_rewrite /var/log/messages' > \ 516c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 517c3fa109aSTetsuo Handa * 518c3fa109aSTetsuo Handa * and all entries are retrieved by 519c3fa109aSTetsuo Handa * 520c3fa109aSTetsuo Handa * # grep ^deny_rewrite /sys/kernel/security/tomoyo/exception_policy 521c3fa109aSTetsuo Handa * 522c3fa109aSTetsuo Handa * In the example above, if a process requested to rewrite /var/log/messages , 523c3fa109aSTetsuo Handa * the process can't rewrite unless the domain which that process belongs to 524c3fa109aSTetsuo Handa * has "allow_rewrite /var/log/messages" entry. 525c3fa109aSTetsuo Handa * 526c3fa109aSTetsuo Handa * It is not a desirable behavior that we have to add "\040(deleted)" suffix 527c3fa109aSTetsuo Handa * when we want to allow rewriting already unlink()ed file. As of now, 528c3fa109aSTetsuo Handa * LSM version of TOMOYO is using __d_path() for calculating pathname. 529c3fa109aSTetsuo Handa * Non LSM version of TOMOYO is using its own function which doesn't append 530c3fa109aSTetsuo Handa * " (deleted)" suffix if the file is already unlink()ed; so that we don't 531c3fa109aSTetsuo Handa * need to worry whether the file is already unlink()ed or not. 532c3fa109aSTetsuo Handa */ 533847b173eSTetsuo Handa LIST_HEAD(tomoyo_no_rewrite_list); 534b69a54eeSKentaro Takeda 53536f5e1ffSTetsuo Handa static bool tomoyo_same_no_rewrite(const struct tomoyo_acl_head *a, 53636f5e1ffSTetsuo Handa const struct tomoyo_acl_head *b) 53736f5e1ffSTetsuo Handa { 53836f5e1ffSTetsuo Handa return container_of(a, struct tomoyo_no_rewrite_entry, head)->pattern 53936f5e1ffSTetsuo Handa == container_of(b, struct tomoyo_no_rewrite_entry, head) 54036f5e1ffSTetsuo Handa ->pattern; 54136f5e1ffSTetsuo Handa } 54236f5e1ffSTetsuo Handa 543b69a54eeSKentaro Takeda /** 544b69a54eeSKentaro Takeda * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list. 545b69a54eeSKentaro Takeda * 546b69a54eeSKentaro Takeda * @pattern: Pathname pattern that are not rewritable by default. 547b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 548b69a54eeSKentaro Takeda * 549b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 550fdb8ebb7STetsuo Handa * 551fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 552b69a54eeSKentaro Takeda */ 553b69a54eeSKentaro Takeda static int tomoyo_update_no_rewrite_entry(const char *pattern, 554b69a54eeSKentaro Takeda const bool is_delete) 555b69a54eeSKentaro Takeda { 5569e4b50e9STetsuo Handa struct tomoyo_no_rewrite_entry e = { }; 55736f5e1ffSTetsuo Handa int error; 558b69a54eeSKentaro Takeda 5593f629636STetsuo Handa if (!tomoyo_is_correct_word(pattern)) 560b69a54eeSKentaro Takeda return -EINVAL; 5619e4b50e9STetsuo Handa e.pattern = tomoyo_get_name(pattern); 5629e4b50e9STetsuo Handa if (!e.pattern) 56336f5e1ffSTetsuo Handa return -ENOMEM; 56436f5e1ffSTetsuo Handa error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, 56536f5e1ffSTetsuo Handa &tomoyo_no_rewrite_list, 56636f5e1ffSTetsuo Handa tomoyo_same_no_rewrite); 5679e4b50e9STetsuo Handa tomoyo_put_name(e.pattern); 568b69a54eeSKentaro Takeda return error; 569b69a54eeSKentaro Takeda } 570b69a54eeSKentaro Takeda 571b69a54eeSKentaro Takeda /** 572b69a54eeSKentaro Takeda * tomoyo_is_no_rewrite_file - Check if the given pathname is not permitted to be rewrited. 573b69a54eeSKentaro Takeda * 574b69a54eeSKentaro Takeda * @filename: Filename to check. 575b69a54eeSKentaro Takeda * 576b69a54eeSKentaro Takeda * Returns true if @filename is specified by "deny_rewrite" directive, 577b69a54eeSKentaro Takeda * false otherwise. 578fdb8ebb7STetsuo Handa * 579fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 580b69a54eeSKentaro Takeda */ 581b69a54eeSKentaro Takeda static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) 582b69a54eeSKentaro Takeda { 583b69a54eeSKentaro Takeda struct tomoyo_no_rewrite_entry *ptr; 584b69a54eeSKentaro Takeda bool found = false; 585b69a54eeSKentaro Takeda 58682e0f001STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, head.list) { 58782e0f001STetsuo Handa if (ptr->head.is_deleted) 588b69a54eeSKentaro Takeda continue; 589b69a54eeSKentaro Takeda if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) 590b69a54eeSKentaro Takeda continue; 591b69a54eeSKentaro Takeda found = true; 592b69a54eeSKentaro Takeda break; 593b69a54eeSKentaro Takeda } 594b69a54eeSKentaro Takeda return found; 595b69a54eeSKentaro Takeda } 596b69a54eeSKentaro Takeda 597b69a54eeSKentaro Takeda /** 598b69a54eeSKentaro Takeda * tomoyo_write_no_rewrite_policy - Write "struct tomoyo_no_rewrite_entry" list. 599b69a54eeSKentaro Takeda * 600b69a54eeSKentaro Takeda * @data: String to parse. 601b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 602b69a54eeSKentaro Takeda * 603b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 604fdb8ebb7STetsuo Handa * 605fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 606b69a54eeSKentaro Takeda */ 607b69a54eeSKentaro Takeda int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete) 608b69a54eeSKentaro Takeda { 609b69a54eeSKentaro Takeda return tomoyo_update_no_rewrite_entry(data, is_delete); 610b69a54eeSKentaro Takeda } 611b69a54eeSKentaro Takeda 612b69a54eeSKentaro Takeda /** 613b69a54eeSKentaro Takeda * tomoyo_read_no_rewrite_policy - Read "struct tomoyo_no_rewrite_entry" list. 614b69a54eeSKentaro Takeda * 615b69a54eeSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 616b69a54eeSKentaro Takeda * 617b69a54eeSKentaro Takeda * Returns true on success, false otherwise. 618fdb8ebb7STetsuo Handa * 619fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 620b69a54eeSKentaro Takeda */ 621b69a54eeSKentaro Takeda bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) 622b69a54eeSKentaro Takeda { 623b69a54eeSKentaro Takeda struct list_head *pos; 624b69a54eeSKentaro Takeda bool done = true; 625b69a54eeSKentaro Takeda 626b69a54eeSKentaro Takeda list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) { 627b69a54eeSKentaro Takeda struct tomoyo_no_rewrite_entry *ptr; 62882e0f001STetsuo Handa ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, 62982e0f001STetsuo Handa head.list); 63082e0f001STetsuo Handa if (ptr->head.is_deleted) 631b69a54eeSKentaro Takeda continue; 6327d2948b1STetsuo Handa done = tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE 6337d2948b1STetsuo Handa "%s\n", ptr->pattern->name); 6347d2948b1STetsuo Handa if (!done) 635b69a54eeSKentaro Takeda break; 636b69a54eeSKentaro Takeda } 637b69a54eeSKentaro Takeda return done; 638b69a54eeSKentaro Takeda } 639b69a54eeSKentaro Takeda 640b69a54eeSKentaro Takeda /** 641cb0abe6aSTetsuo Handa * tomoyo_path_acl - Check permission for single path operation. 642b69a54eeSKentaro Takeda * 643cb0abe6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 644b69a54eeSKentaro Takeda * @filename: Filename to check. 645b69a54eeSKentaro Takeda * @perm: Permission. 646b69a54eeSKentaro Takeda * 647b69a54eeSKentaro Takeda * Returns 0 on success, -EPERM otherwise. 648fdb8ebb7STetsuo Handa * 649fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 650b69a54eeSKentaro Takeda */ 651cb0abe6aSTetsuo Handa static int tomoyo_path_acl(const struct tomoyo_request_info *r, 6527ef61233STetsuo Handa const struct tomoyo_path_info *filename, 6533f629636STetsuo Handa const u32 perm) 654b69a54eeSKentaro Takeda { 655cb0abe6aSTetsuo Handa struct tomoyo_domain_info *domain = r->domain; 656b69a54eeSKentaro Takeda struct tomoyo_acl_info *ptr; 657b69a54eeSKentaro Takeda int error = -EPERM; 658b69a54eeSKentaro Takeda 659fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 6607ef61233STetsuo Handa struct tomoyo_path_acl *acl; 6617ef61233STetsuo Handa if (ptr->type != TOMOYO_TYPE_PATH_ACL) 662b69a54eeSKentaro Takeda continue; 6637ef61233STetsuo Handa acl = container_of(ptr, struct tomoyo_path_acl, head); 664a1f9bb6aSTetsuo Handa if (!(acl->perm & perm) || 6653f629636STetsuo Handa !tomoyo_compare_name_union(filename, &acl->name)) 666b69a54eeSKentaro Takeda continue; 667b69a54eeSKentaro Takeda error = 0; 668b69a54eeSKentaro Takeda break; 669b69a54eeSKentaro Takeda } 670b69a54eeSKentaro Takeda return error; 671b69a54eeSKentaro Takeda } 672b69a54eeSKentaro Takeda 673b69a54eeSKentaro Takeda /** 674cb0abe6aSTetsuo Handa * tomoyo_file_perm - Check permission for opening files. 675b69a54eeSKentaro Takeda * 676cb0abe6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 677b69a54eeSKentaro Takeda * @filename: Filename to check. 678cb0abe6aSTetsuo Handa * @mode: Mode ("read" or "write" or "read/write" or "execute"). 679b69a54eeSKentaro Takeda * 680b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 681fdb8ebb7STetsuo Handa * 682fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 683b69a54eeSKentaro Takeda */ 684cb0abe6aSTetsuo Handa static int tomoyo_file_perm(struct tomoyo_request_info *r, 685b69a54eeSKentaro Takeda const struct tomoyo_path_info *filename, 686b69a54eeSKentaro Takeda const u8 mode) 687b69a54eeSKentaro Takeda { 688b69a54eeSKentaro Takeda const char *msg = "<unknown>"; 689b69a54eeSKentaro Takeda int error = 0; 690cb0abe6aSTetsuo Handa u32 perm = 0; 691b69a54eeSKentaro Takeda 692b69a54eeSKentaro Takeda if (!filename) 693b69a54eeSKentaro Takeda return 0; 694cb0abe6aSTetsuo Handa 695cb0abe6aSTetsuo Handa if (mode == 6) { 696cb0abe6aSTetsuo Handa msg = tomoyo_path2keyword(TOMOYO_TYPE_READ_WRITE); 697cb0abe6aSTetsuo Handa perm = 1 << TOMOYO_TYPE_READ_WRITE; 698cb0abe6aSTetsuo Handa } else if (mode == 4) { 699cb0abe6aSTetsuo Handa msg = tomoyo_path2keyword(TOMOYO_TYPE_READ); 700cb0abe6aSTetsuo Handa perm = 1 << TOMOYO_TYPE_READ; 701cb0abe6aSTetsuo Handa } else if (mode == 2) { 702cb0abe6aSTetsuo Handa msg = tomoyo_path2keyword(TOMOYO_TYPE_WRITE); 703cb0abe6aSTetsuo Handa perm = 1 << TOMOYO_TYPE_WRITE; 704cb0abe6aSTetsuo Handa } else if (mode == 1) { 705cb0abe6aSTetsuo Handa msg = tomoyo_path2keyword(TOMOYO_TYPE_EXECUTE); 706cb0abe6aSTetsuo Handa perm = 1 << TOMOYO_TYPE_EXECUTE; 707cb0abe6aSTetsuo Handa } else 708cb0abe6aSTetsuo Handa BUG(); 70917fcfbd9STetsuo Handa do { 7103f629636STetsuo Handa error = tomoyo_path_acl(r, filename, perm); 711cb0abe6aSTetsuo Handa if (error && mode == 4 && !r->domain->ignore_global_allow_read 712b69a54eeSKentaro Takeda && tomoyo_is_globally_readable_file(filename)) 713b69a54eeSKentaro Takeda error = 0; 714b69a54eeSKentaro Takeda if (!error) 71517fcfbd9STetsuo Handa break; 716cb0abe6aSTetsuo Handa tomoyo_warn_log(r, "%s %s", msg, filename->name); 71717fcfbd9STetsuo Handa error = tomoyo_supervisor(r, "allow_%s %s\n", msg, 71817fcfbd9STetsuo Handa tomoyo_file_pattern(filename)); 71917fcfbd9STetsuo Handa /* 72017fcfbd9STetsuo Handa * Do not retry for execute request, for alias may have 72117fcfbd9STetsuo Handa * changed. 72217fcfbd9STetsuo Handa */ 72317fcfbd9STetsuo Handa } while (error == TOMOYO_RETRY_REQUEST && mode != 1); 72417fcfbd9STetsuo Handa if (r->mode != TOMOYO_CONFIG_ENFORCING) 72517fcfbd9STetsuo Handa error = 0; 726b69a54eeSKentaro Takeda return error; 727b69a54eeSKentaro Takeda } 728b69a54eeSKentaro Takeda 729237ab459STetsuo Handa static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a, 730237ab459STetsuo Handa const struct tomoyo_acl_info *b) 731237ab459STetsuo Handa { 732237ab459STetsuo Handa const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head); 733237ab459STetsuo Handa const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head); 734237ab459STetsuo Handa return tomoyo_is_same_acl_head(&p1->head, &p2->head) && 735237ab459STetsuo Handa tomoyo_is_same_name_union(&p1->name, &p2->name); 736237ab459STetsuo Handa } 737237ab459STetsuo Handa 738237ab459STetsuo Handa static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a, 739237ab459STetsuo Handa struct tomoyo_acl_info *b, 740237ab459STetsuo Handa const bool is_delete) 741237ab459STetsuo Handa { 742237ab459STetsuo Handa u16 * const a_perm = &container_of(a, struct tomoyo_path_acl, head) 743237ab459STetsuo Handa ->perm; 744237ab459STetsuo Handa u16 perm = *a_perm; 745237ab459STetsuo Handa const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm; 746237ab459STetsuo Handa if (is_delete) { 747237ab459STetsuo Handa perm &= ~b_perm; 748237ab459STetsuo Handa if ((perm & TOMOYO_RW_MASK) != TOMOYO_RW_MASK) 749237ab459STetsuo Handa perm &= ~(1 << TOMOYO_TYPE_READ_WRITE); 750237ab459STetsuo Handa else if (!(perm & (1 << TOMOYO_TYPE_READ_WRITE))) 751237ab459STetsuo Handa perm &= ~TOMOYO_RW_MASK; 752237ab459STetsuo Handa } else { 753237ab459STetsuo Handa perm |= b_perm; 754237ab459STetsuo Handa if ((perm & TOMOYO_RW_MASK) == TOMOYO_RW_MASK) 755237ab459STetsuo Handa perm |= (1 << TOMOYO_TYPE_READ_WRITE); 756237ab459STetsuo Handa else if (perm & (1 << TOMOYO_TYPE_READ_WRITE)) 757237ab459STetsuo Handa perm |= TOMOYO_RW_MASK; 758237ab459STetsuo Handa } 759237ab459STetsuo Handa *a_perm = perm; 760237ab459STetsuo Handa return !perm; 761237ab459STetsuo Handa } 762237ab459STetsuo Handa 763b69a54eeSKentaro Takeda /** 7647ef61233STetsuo Handa * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list. 765b69a54eeSKentaro Takeda * 766b69a54eeSKentaro Takeda * @type: Type of operation. 767b69a54eeSKentaro Takeda * @filename: Filename. 768b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 769b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 770b69a54eeSKentaro Takeda * 771b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 772fdb8ebb7STetsuo Handa * 773fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 774b69a54eeSKentaro Takeda */ 7757ef61233STetsuo Handa static int tomoyo_update_path_acl(const u8 type, const char *filename, 7767ef61233STetsuo Handa struct tomoyo_domain_info * const domain, 7777ef61233STetsuo Handa const bool is_delete) 778b69a54eeSKentaro Takeda { 7799e4b50e9STetsuo Handa struct tomoyo_path_acl e = { 7809e4b50e9STetsuo Handa .head.type = TOMOYO_TYPE_PATH_ACL, 781237ab459STetsuo Handa .perm = 1 << type 7829e4b50e9STetsuo Handa }; 783237ab459STetsuo Handa int error; 784237ab459STetsuo Handa if (e.perm == (1 << TOMOYO_TYPE_READ_WRITE)) 785237ab459STetsuo Handa e.perm |= TOMOYO_RW_MASK; 7867762fbffSTetsuo Handa if (!tomoyo_parse_name_union(filename, &e.name)) 787b69a54eeSKentaro Takeda return -EINVAL; 788237ab459STetsuo Handa error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, 789237ab459STetsuo Handa tomoyo_same_path_acl, 790237ab459STetsuo Handa tomoyo_merge_path_acl); 7917762fbffSTetsuo Handa tomoyo_put_name_union(&e.name); 792b69a54eeSKentaro Takeda return error; 793b69a54eeSKentaro Takeda } 794b69a54eeSKentaro Takeda 795237ab459STetsuo Handa static bool tomoyo_same_path_number3_acl(const struct tomoyo_acl_info *a, 796237ab459STetsuo Handa const struct tomoyo_acl_info *b) 797237ab459STetsuo Handa { 798237ab459STetsuo Handa const struct tomoyo_path_number3_acl *p1 = container_of(a, typeof(*p1), 799237ab459STetsuo Handa head); 800237ab459STetsuo Handa const struct tomoyo_path_number3_acl *p2 = container_of(b, typeof(*p2), 801237ab459STetsuo Handa head); 802237ab459STetsuo Handa return tomoyo_is_same_acl_head(&p1->head, &p2->head) 803237ab459STetsuo Handa && tomoyo_is_same_name_union(&p1->name, &p2->name) 804237ab459STetsuo Handa && tomoyo_is_same_number_union(&p1->mode, &p2->mode) 805237ab459STetsuo Handa && tomoyo_is_same_number_union(&p1->major, &p2->major) 806237ab459STetsuo Handa && tomoyo_is_same_number_union(&p1->minor, &p2->minor); 807237ab459STetsuo Handa } 808237ab459STetsuo Handa 809237ab459STetsuo Handa static bool tomoyo_merge_path_number3_acl(struct tomoyo_acl_info *a, 810237ab459STetsuo Handa struct tomoyo_acl_info *b, 811237ab459STetsuo Handa const bool is_delete) 812237ab459STetsuo Handa { 813237ab459STetsuo Handa u8 *const a_perm = &container_of(a, struct tomoyo_path_number3_acl, 814237ab459STetsuo Handa head)->perm; 815237ab459STetsuo Handa u8 perm = *a_perm; 816237ab459STetsuo Handa const u8 b_perm = container_of(b, struct tomoyo_path_number3_acl, head) 817237ab459STetsuo Handa ->perm; 818237ab459STetsuo Handa if (is_delete) 819237ab459STetsuo Handa perm &= ~b_perm; 820237ab459STetsuo Handa else 821237ab459STetsuo Handa perm |= b_perm; 822237ab459STetsuo Handa *a_perm = perm; 823237ab459STetsuo Handa return !perm; 824237ab459STetsuo Handa } 825237ab459STetsuo Handa 826b69a54eeSKentaro Takeda /** 827a1f9bb6aSTetsuo Handa * tomoyo_update_path_number3_acl - Update "struct tomoyo_path_number3_acl" list. 828a1f9bb6aSTetsuo Handa * 829a1f9bb6aSTetsuo Handa * @type: Type of operation. 830a1f9bb6aSTetsuo Handa * @filename: Filename. 831a1f9bb6aSTetsuo Handa * @mode: Create mode. 832a1f9bb6aSTetsuo Handa * @major: Device major number. 833a1f9bb6aSTetsuo Handa * @minor: Device minor number. 834a1f9bb6aSTetsuo Handa * @domain: Pointer to "struct tomoyo_domain_info". 835a1f9bb6aSTetsuo Handa * @is_delete: True if it is a delete request. 836a1f9bb6aSTetsuo Handa * 837a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 838237ab459STetsuo Handa * 839237ab459STetsuo Handa * Caller holds tomoyo_read_lock(). 840a1f9bb6aSTetsuo Handa */ 841237ab459STetsuo Handa static int tomoyo_update_path_number3_acl(const u8 type, const char *filename, 842237ab459STetsuo Handa char *mode, char *major, char *minor, 843237ab459STetsuo Handa struct tomoyo_domain_info * const 844237ab459STetsuo Handa domain, const bool is_delete) 845a1f9bb6aSTetsuo Handa { 846a1f9bb6aSTetsuo Handa struct tomoyo_path_number3_acl e = { 847a1f9bb6aSTetsuo Handa .head.type = TOMOYO_TYPE_PATH_NUMBER3_ACL, 848237ab459STetsuo Handa .perm = 1 << type 849a1f9bb6aSTetsuo Handa }; 850a1f9bb6aSTetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 851a1f9bb6aSTetsuo Handa if (!tomoyo_parse_name_union(filename, &e.name) || 852a1f9bb6aSTetsuo Handa !tomoyo_parse_number_union(mode, &e.mode) || 853a1f9bb6aSTetsuo Handa !tomoyo_parse_number_union(major, &e.major) || 854a1f9bb6aSTetsuo Handa !tomoyo_parse_number_union(minor, &e.minor)) 855a1f9bb6aSTetsuo Handa goto out; 856237ab459STetsuo Handa error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, 857237ab459STetsuo Handa tomoyo_same_path_number3_acl, 858237ab459STetsuo Handa tomoyo_merge_path_number3_acl); 859a1f9bb6aSTetsuo Handa out: 860a1f9bb6aSTetsuo Handa tomoyo_put_name_union(&e.name); 861a1f9bb6aSTetsuo Handa tomoyo_put_number_union(&e.mode); 862a1f9bb6aSTetsuo Handa tomoyo_put_number_union(&e.major); 863a1f9bb6aSTetsuo Handa tomoyo_put_number_union(&e.minor); 864a1f9bb6aSTetsuo Handa return error; 865a1f9bb6aSTetsuo Handa } 866a1f9bb6aSTetsuo Handa 867237ab459STetsuo Handa static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a, 868237ab459STetsuo Handa const struct tomoyo_acl_info *b) 869237ab459STetsuo Handa { 870237ab459STetsuo Handa const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head); 871237ab459STetsuo Handa const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head); 872237ab459STetsuo Handa return tomoyo_is_same_acl_head(&p1->head, &p2->head) 873237ab459STetsuo Handa && tomoyo_is_same_name_union(&p1->name1, &p2->name1) 874237ab459STetsuo Handa && tomoyo_is_same_name_union(&p1->name2, &p2->name2); 875237ab459STetsuo Handa } 876237ab459STetsuo Handa 877237ab459STetsuo Handa static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a, 878237ab459STetsuo Handa struct tomoyo_acl_info *b, 879237ab459STetsuo Handa const bool is_delete) 880237ab459STetsuo Handa { 881237ab459STetsuo Handa u8 * const a_perm = &container_of(a, struct tomoyo_path2_acl, head) 882237ab459STetsuo Handa ->perm; 883237ab459STetsuo Handa u8 perm = *a_perm; 884237ab459STetsuo Handa const u8 b_perm = container_of(b, struct tomoyo_path2_acl, head)->perm; 885237ab459STetsuo Handa if (is_delete) 886237ab459STetsuo Handa perm &= ~b_perm; 887237ab459STetsuo Handa else 888237ab459STetsuo Handa perm |= b_perm; 889237ab459STetsuo Handa *a_perm = perm; 890237ab459STetsuo Handa return !perm; 891237ab459STetsuo Handa } 892237ab459STetsuo Handa 893a1f9bb6aSTetsuo Handa /** 8947ef61233STetsuo Handa * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list. 895b69a54eeSKentaro Takeda * 896b69a54eeSKentaro Takeda * @type: Type of operation. 897b69a54eeSKentaro Takeda * @filename1: First filename. 898b69a54eeSKentaro Takeda * @filename2: Second filename. 899b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 900b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 901b69a54eeSKentaro Takeda * 902b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 903fdb8ebb7STetsuo Handa * 904fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 905b69a54eeSKentaro Takeda */ 9067ef61233STetsuo Handa static int tomoyo_update_path2_acl(const u8 type, const char *filename1, 907b69a54eeSKentaro Takeda const char *filename2, 9087ef61233STetsuo Handa struct tomoyo_domain_info * const domain, 9097ef61233STetsuo Handa const bool is_delete) 910b69a54eeSKentaro Takeda { 9119e4b50e9STetsuo Handa struct tomoyo_path2_acl e = { 9129e4b50e9STetsuo Handa .head.type = TOMOYO_TYPE_PATH2_ACL, 913237ab459STetsuo Handa .perm = 1 << type 9149e4b50e9STetsuo Handa }; 9159e4b50e9STetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 9167762fbffSTetsuo Handa if (!tomoyo_parse_name_union(filename1, &e.name1) || 9177762fbffSTetsuo Handa !tomoyo_parse_name_union(filename2, &e.name2)) 918ca0b7df3STetsuo Handa goto out; 919237ab459STetsuo Handa error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, 920237ab459STetsuo Handa tomoyo_same_path2_acl, 921237ab459STetsuo Handa tomoyo_merge_path2_acl); 922ca0b7df3STetsuo Handa out: 9237762fbffSTetsuo Handa tomoyo_put_name_union(&e.name1); 9247762fbffSTetsuo Handa tomoyo_put_name_union(&e.name2); 925b69a54eeSKentaro Takeda return error; 926b69a54eeSKentaro Takeda } 927b69a54eeSKentaro Takeda 928b69a54eeSKentaro Takeda /** 929a1f9bb6aSTetsuo Handa * tomoyo_path_number3_acl - Check permission for path/number/number/number operation. 930a1f9bb6aSTetsuo Handa * 931a1f9bb6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 932a1f9bb6aSTetsuo Handa * @filename: Filename to check. 933a1f9bb6aSTetsuo Handa * @perm: Permission. 934a1f9bb6aSTetsuo Handa * @mode: Create mode. 935a1f9bb6aSTetsuo Handa * @major: Device major number. 936a1f9bb6aSTetsuo Handa * @minor: Device minor number. 937a1f9bb6aSTetsuo Handa * 938a1f9bb6aSTetsuo Handa * Returns 0 on success, -EPERM otherwise. 939a1f9bb6aSTetsuo Handa * 940a1f9bb6aSTetsuo Handa * Caller holds tomoyo_read_lock(). 941a1f9bb6aSTetsuo Handa */ 942a1f9bb6aSTetsuo Handa static int tomoyo_path_number3_acl(struct tomoyo_request_info *r, 943a1f9bb6aSTetsuo Handa const struct tomoyo_path_info *filename, 944a1f9bb6aSTetsuo Handa const u16 perm, const unsigned int mode, 945a1f9bb6aSTetsuo Handa const unsigned int major, 946a1f9bb6aSTetsuo Handa const unsigned int minor) 947a1f9bb6aSTetsuo Handa { 948a1f9bb6aSTetsuo Handa struct tomoyo_domain_info *domain = r->domain; 949a1f9bb6aSTetsuo Handa struct tomoyo_acl_info *ptr; 950a1f9bb6aSTetsuo Handa int error = -EPERM; 951a1f9bb6aSTetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 952a1f9bb6aSTetsuo Handa struct tomoyo_path_number3_acl *acl; 953a1f9bb6aSTetsuo Handa if (ptr->type != TOMOYO_TYPE_PATH_NUMBER3_ACL) 954a1f9bb6aSTetsuo Handa continue; 955a1f9bb6aSTetsuo Handa acl = container_of(ptr, struct tomoyo_path_number3_acl, head); 956a1f9bb6aSTetsuo Handa if (!tomoyo_compare_number_union(mode, &acl->mode)) 957a1f9bb6aSTetsuo Handa continue; 958a1f9bb6aSTetsuo Handa if (!tomoyo_compare_number_union(major, &acl->major)) 959a1f9bb6aSTetsuo Handa continue; 960a1f9bb6aSTetsuo Handa if (!tomoyo_compare_number_union(minor, &acl->minor)) 961a1f9bb6aSTetsuo Handa continue; 962a1f9bb6aSTetsuo Handa if (!(acl->perm & perm)) 963a1f9bb6aSTetsuo Handa continue; 964a1f9bb6aSTetsuo Handa if (!tomoyo_compare_name_union(filename, &acl->name)) 965a1f9bb6aSTetsuo Handa continue; 966a1f9bb6aSTetsuo Handa error = 0; 967a1f9bb6aSTetsuo Handa break; 968a1f9bb6aSTetsuo Handa } 969a1f9bb6aSTetsuo Handa return error; 970a1f9bb6aSTetsuo Handa } 971a1f9bb6aSTetsuo Handa 972a1f9bb6aSTetsuo Handa /** 9737ef61233STetsuo Handa * tomoyo_path2_acl - Check permission for double path operation. 974b69a54eeSKentaro Takeda * 975cb0abe6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 976b69a54eeSKentaro Takeda * @type: Type of operation. 977b69a54eeSKentaro Takeda * @filename1: First filename to check. 978b69a54eeSKentaro Takeda * @filename2: Second filename to check. 979b69a54eeSKentaro Takeda * 980b69a54eeSKentaro Takeda * Returns 0 on success, -EPERM otherwise. 981fdb8ebb7STetsuo Handa * 982fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 983b69a54eeSKentaro Takeda */ 984cb0abe6aSTetsuo Handa static int tomoyo_path2_acl(const struct tomoyo_request_info *r, const u8 type, 9857ef61233STetsuo Handa const struct tomoyo_path_info *filename1, 9867ef61233STetsuo Handa const struct tomoyo_path_info *filename2) 987b69a54eeSKentaro Takeda { 988cb0abe6aSTetsuo Handa const struct tomoyo_domain_info *domain = r->domain; 989b69a54eeSKentaro Takeda struct tomoyo_acl_info *ptr; 990b69a54eeSKentaro Takeda const u8 perm = 1 << type; 991b69a54eeSKentaro Takeda int error = -EPERM; 992b69a54eeSKentaro Takeda 993fdb8ebb7STetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 9947ef61233STetsuo Handa struct tomoyo_path2_acl *acl; 9957ef61233STetsuo Handa if (ptr->type != TOMOYO_TYPE_PATH2_ACL) 996b69a54eeSKentaro Takeda continue; 9977ef61233STetsuo Handa acl = container_of(ptr, struct tomoyo_path2_acl, head); 998b69a54eeSKentaro Takeda if (!(acl->perm & perm)) 999b69a54eeSKentaro Takeda continue; 10007762fbffSTetsuo Handa if (!tomoyo_compare_name_union(filename1, &acl->name1)) 1001b69a54eeSKentaro Takeda continue; 10027762fbffSTetsuo Handa if (!tomoyo_compare_name_union(filename2, &acl->name2)) 1003b69a54eeSKentaro Takeda continue; 1004b69a54eeSKentaro Takeda error = 0; 1005b69a54eeSKentaro Takeda break; 1006b69a54eeSKentaro Takeda } 1007b69a54eeSKentaro Takeda return error; 1008b69a54eeSKentaro Takeda } 1009b69a54eeSKentaro Takeda 1010b69a54eeSKentaro Takeda /** 1011cb0abe6aSTetsuo Handa * tomoyo_path_permission - Check permission for single path operation. 1012b69a54eeSKentaro Takeda * 1013cb0abe6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 1014b69a54eeSKentaro Takeda * @operation: Type of operation. 1015b69a54eeSKentaro Takeda * @filename: Filename to check. 1016b69a54eeSKentaro Takeda * 1017b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1018fdb8ebb7STetsuo Handa * 1019fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 1020b69a54eeSKentaro Takeda */ 1021cb0abe6aSTetsuo Handa static int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, 1022cb0abe6aSTetsuo Handa const struct tomoyo_path_info *filename) 1023b69a54eeSKentaro Takeda { 102417fcfbd9STetsuo Handa const char *msg; 1025b69a54eeSKentaro Takeda int error; 1026b69a54eeSKentaro Takeda 1027b69a54eeSKentaro Takeda next: 102857c2590fSTetsuo Handa r->type = tomoyo_p2mac[operation]; 102957c2590fSTetsuo Handa r->mode = tomoyo_get_mode(r->profile, r->type); 103057c2590fSTetsuo Handa if (r->mode == TOMOYO_CONFIG_DISABLED) 103157c2590fSTetsuo Handa return 0; 103217fcfbd9STetsuo Handa do { 10333f629636STetsuo Handa error = tomoyo_path_acl(r, filename, 1 << operation); 1034b69a54eeSKentaro Takeda if (!error) 103517fcfbd9STetsuo Handa break; 103617fcfbd9STetsuo Handa msg = tomoyo_path2keyword(operation); 103717fcfbd9STetsuo Handa tomoyo_warn_log(r, "%s %s", msg, filename->name); 103817fcfbd9STetsuo Handa error = tomoyo_supervisor(r, "allow_%s %s\n", msg, 103917fcfbd9STetsuo Handa tomoyo_file_pattern(filename)); 104017fcfbd9STetsuo Handa } while (error == TOMOYO_RETRY_REQUEST); 1041cb0abe6aSTetsuo Handa if (r->mode != TOMOYO_CONFIG_ENFORCING) 1042b69a54eeSKentaro Takeda error = 0; 1043b69a54eeSKentaro Takeda /* 1044b69a54eeSKentaro Takeda * Since "allow_truncate" doesn't imply "allow_rewrite" permission, 1045b69a54eeSKentaro Takeda * we need to check "allow_rewrite" permission if the filename is 1046b69a54eeSKentaro Takeda * specified by "deny_rewrite" keyword. 1047b69a54eeSKentaro Takeda */ 10487ef61233STetsuo Handa if (!error && operation == TOMOYO_TYPE_TRUNCATE && 1049b69a54eeSKentaro Takeda tomoyo_is_no_rewrite_file(filename)) { 10507ef61233STetsuo Handa operation = TOMOYO_TYPE_REWRITE; 1051b69a54eeSKentaro Takeda goto next; 1052b69a54eeSKentaro Takeda } 1053b69a54eeSKentaro Takeda return error; 1054b69a54eeSKentaro Takeda } 1055b69a54eeSKentaro Takeda 1056b69a54eeSKentaro Takeda /** 1057a1f9bb6aSTetsuo Handa * tomoyo_path_number_acl - Check permission for ioctl/chmod/chown/chgrp operation. 1058a1f9bb6aSTetsuo Handa * 1059a1f9bb6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 1060a1f9bb6aSTetsuo Handa * @type: Operation. 1061a1f9bb6aSTetsuo Handa * @filename: Filename to check. 1062a1f9bb6aSTetsuo Handa * @number: Number. 1063a1f9bb6aSTetsuo Handa * 1064a1f9bb6aSTetsuo Handa * Returns 0 on success, -EPERM otherwise. 1065a1f9bb6aSTetsuo Handa * 1066a1f9bb6aSTetsuo Handa * Caller holds tomoyo_read_lock(). 1067a1f9bb6aSTetsuo Handa */ 1068a1f9bb6aSTetsuo Handa static int tomoyo_path_number_acl(struct tomoyo_request_info *r, const u8 type, 1069a1f9bb6aSTetsuo Handa const struct tomoyo_path_info *filename, 1070a1f9bb6aSTetsuo Handa const unsigned long number) 1071a1f9bb6aSTetsuo Handa { 1072a1f9bb6aSTetsuo Handa struct tomoyo_domain_info *domain = r->domain; 1073a1f9bb6aSTetsuo Handa struct tomoyo_acl_info *ptr; 1074a1f9bb6aSTetsuo Handa const u8 perm = 1 << type; 1075a1f9bb6aSTetsuo Handa int error = -EPERM; 1076a1f9bb6aSTetsuo Handa list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 1077a1f9bb6aSTetsuo Handa struct tomoyo_path_number_acl *acl; 1078a1f9bb6aSTetsuo Handa if (ptr->type != TOMOYO_TYPE_PATH_NUMBER_ACL) 1079a1f9bb6aSTetsuo Handa continue; 1080a1f9bb6aSTetsuo Handa acl = container_of(ptr, struct tomoyo_path_number_acl, 1081a1f9bb6aSTetsuo Handa head); 1082a1f9bb6aSTetsuo Handa if (!(acl->perm & perm) || 1083a1f9bb6aSTetsuo Handa !tomoyo_compare_number_union(number, &acl->number) || 1084a1f9bb6aSTetsuo Handa !tomoyo_compare_name_union(filename, &acl->name)) 1085a1f9bb6aSTetsuo Handa continue; 1086a1f9bb6aSTetsuo Handa error = 0; 1087a1f9bb6aSTetsuo Handa break; 1088a1f9bb6aSTetsuo Handa } 1089a1f9bb6aSTetsuo Handa return error; 1090a1f9bb6aSTetsuo Handa } 1091a1f9bb6aSTetsuo Handa 1092237ab459STetsuo Handa static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a, 1093237ab459STetsuo Handa const struct tomoyo_acl_info *b) 1094237ab459STetsuo Handa { 1095237ab459STetsuo Handa const struct tomoyo_path_number_acl *p1 = container_of(a, typeof(*p1), 1096237ab459STetsuo Handa head); 1097237ab459STetsuo Handa const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2), 1098237ab459STetsuo Handa head); 1099237ab459STetsuo Handa return tomoyo_is_same_acl_head(&p1->head, &p2->head) 1100237ab459STetsuo Handa && tomoyo_is_same_name_union(&p1->name, &p2->name) 1101237ab459STetsuo Handa && tomoyo_is_same_number_union(&p1->number, &p2->number); 1102237ab459STetsuo Handa } 1103237ab459STetsuo Handa 1104237ab459STetsuo Handa static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a, 1105237ab459STetsuo Handa struct tomoyo_acl_info *b, 1106237ab459STetsuo Handa const bool is_delete) 1107237ab459STetsuo Handa { 1108237ab459STetsuo Handa u8 * const a_perm = &container_of(a, struct tomoyo_path_number_acl, 1109237ab459STetsuo Handa head)->perm; 1110237ab459STetsuo Handa u8 perm = *a_perm; 1111237ab459STetsuo Handa const u8 b_perm = container_of(b, struct tomoyo_path_number_acl, head) 1112237ab459STetsuo Handa ->perm; 1113237ab459STetsuo Handa if (is_delete) 1114237ab459STetsuo Handa perm &= ~b_perm; 1115237ab459STetsuo Handa else 1116237ab459STetsuo Handa perm |= b_perm; 1117237ab459STetsuo Handa *a_perm = perm; 1118237ab459STetsuo Handa return !perm; 1119237ab459STetsuo Handa } 1120237ab459STetsuo Handa 1121a1f9bb6aSTetsuo Handa /** 1122a1f9bb6aSTetsuo Handa * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL. 1123a1f9bb6aSTetsuo Handa * 1124a1f9bb6aSTetsuo Handa * @type: Type of operation. 1125a1f9bb6aSTetsuo Handa * @filename: Filename. 1126a1f9bb6aSTetsuo Handa * @number: Number. 1127a1f9bb6aSTetsuo Handa * @domain: Pointer to "struct tomoyo_domain_info". 1128a1f9bb6aSTetsuo Handa * @is_delete: True if it is a delete request. 1129a1f9bb6aSTetsuo Handa * 1130a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1131a1f9bb6aSTetsuo Handa */ 1132237ab459STetsuo Handa static int tomoyo_update_path_number_acl(const u8 type, const char *filename, 1133a1f9bb6aSTetsuo Handa char *number, 1134237ab459STetsuo Handa struct tomoyo_domain_info * const 1135237ab459STetsuo Handa domain, 1136a1f9bb6aSTetsuo Handa const bool is_delete) 1137a1f9bb6aSTetsuo Handa { 1138a1f9bb6aSTetsuo Handa struct tomoyo_path_number_acl e = { 1139a1f9bb6aSTetsuo Handa .head.type = TOMOYO_TYPE_PATH_NUMBER_ACL, 1140237ab459STetsuo Handa .perm = 1 << type 1141a1f9bb6aSTetsuo Handa }; 1142a1f9bb6aSTetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 1143a1f9bb6aSTetsuo Handa if (!tomoyo_parse_name_union(filename, &e.name)) 1144a1f9bb6aSTetsuo Handa return -EINVAL; 1145a1f9bb6aSTetsuo Handa if (!tomoyo_parse_number_union(number, &e.number)) 1146a1f9bb6aSTetsuo Handa goto out; 1147237ab459STetsuo Handa error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, 1148237ab459STetsuo Handa tomoyo_same_path_number_acl, 1149237ab459STetsuo Handa tomoyo_merge_path_number_acl); 1150a1f9bb6aSTetsuo Handa out: 1151a1f9bb6aSTetsuo Handa tomoyo_put_name_union(&e.name); 1152a1f9bb6aSTetsuo Handa tomoyo_put_number_union(&e.number); 1153a1f9bb6aSTetsuo Handa return error; 1154a1f9bb6aSTetsuo Handa } 1155a1f9bb6aSTetsuo Handa 1156a1f9bb6aSTetsuo Handa /** 1157a1f9bb6aSTetsuo Handa * tomoyo_path_number_perm2 - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp". 1158a1f9bb6aSTetsuo Handa * 1159a1f9bb6aSTetsuo Handa * @r: Pointer to "strct tomoyo_request_info". 1160a1f9bb6aSTetsuo Handa * @filename: Filename to check. 1161a1f9bb6aSTetsuo Handa * @number: Number. 1162a1f9bb6aSTetsuo Handa * 1163a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1164a1f9bb6aSTetsuo Handa * 1165a1f9bb6aSTetsuo Handa * Caller holds tomoyo_read_lock(). 1166a1f9bb6aSTetsuo Handa */ 1167a1f9bb6aSTetsuo Handa static int tomoyo_path_number_perm2(struct tomoyo_request_info *r, 1168a1f9bb6aSTetsuo Handa const u8 type, 1169a1f9bb6aSTetsuo Handa const struct tomoyo_path_info *filename, 1170a1f9bb6aSTetsuo Handa const unsigned long number) 1171a1f9bb6aSTetsuo Handa { 1172a1f9bb6aSTetsuo Handa char buffer[64]; 1173a1f9bb6aSTetsuo Handa int error; 1174a1f9bb6aSTetsuo Handa u8 radix; 117517fcfbd9STetsuo Handa const char *msg; 1176a1f9bb6aSTetsuo Handa 1177a1f9bb6aSTetsuo Handa if (!filename) 1178a1f9bb6aSTetsuo Handa return 0; 1179a1f9bb6aSTetsuo Handa switch (type) { 1180a1f9bb6aSTetsuo Handa case TOMOYO_TYPE_CREATE: 1181a1f9bb6aSTetsuo Handa case TOMOYO_TYPE_MKDIR: 1182a1f9bb6aSTetsuo Handa case TOMOYO_TYPE_MKFIFO: 1183a1f9bb6aSTetsuo Handa case TOMOYO_TYPE_MKSOCK: 1184a1f9bb6aSTetsuo Handa case TOMOYO_TYPE_CHMOD: 1185a1f9bb6aSTetsuo Handa radix = TOMOYO_VALUE_TYPE_OCTAL; 1186a1f9bb6aSTetsuo Handa break; 1187a1f9bb6aSTetsuo Handa case TOMOYO_TYPE_IOCTL: 1188a1f9bb6aSTetsuo Handa radix = TOMOYO_VALUE_TYPE_HEXADECIMAL; 1189a1f9bb6aSTetsuo Handa break; 1190a1f9bb6aSTetsuo Handa default: 1191a1f9bb6aSTetsuo Handa radix = TOMOYO_VALUE_TYPE_DECIMAL; 1192a1f9bb6aSTetsuo Handa break; 1193a1f9bb6aSTetsuo Handa } 1194a1f9bb6aSTetsuo Handa tomoyo_print_ulong(buffer, sizeof(buffer), number, radix); 119517fcfbd9STetsuo Handa do { 1196a1f9bb6aSTetsuo Handa error = tomoyo_path_number_acl(r, type, filename, number); 1197a1f9bb6aSTetsuo Handa if (!error) 119817fcfbd9STetsuo Handa break; 119917fcfbd9STetsuo Handa msg = tomoyo_path_number2keyword(type); 120017fcfbd9STetsuo Handa tomoyo_warn_log(r, "%s %s %s", msg, filename->name, buffer); 120117fcfbd9STetsuo Handa error = tomoyo_supervisor(r, "allow_%s %s %s\n", msg, 120217fcfbd9STetsuo Handa tomoyo_file_pattern(filename), 120317fcfbd9STetsuo Handa buffer); 120417fcfbd9STetsuo Handa } while (error == TOMOYO_RETRY_REQUEST); 1205a1f9bb6aSTetsuo Handa if (r->mode != TOMOYO_CONFIG_ENFORCING) 1206a1f9bb6aSTetsuo Handa error = 0; 1207a1f9bb6aSTetsuo Handa return error; 1208a1f9bb6aSTetsuo Handa } 1209a1f9bb6aSTetsuo Handa 1210a1f9bb6aSTetsuo Handa /** 1211a1f9bb6aSTetsuo Handa * tomoyo_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp". 1212a1f9bb6aSTetsuo Handa * 1213a1f9bb6aSTetsuo Handa * @type: Type of operation. 1214a1f9bb6aSTetsuo Handa * @path: Pointer to "struct path". 1215a1f9bb6aSTetsuo Handa * @number: Number. 1216a1f9bb6aSTetsuo Handa * 1217a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1218a1f9bb6aSTetsuo Handa */ 1219a1f9bb6aSTetsuo Handa int tomoyo_path_number_perm(const u8 type, struct path *path, 1220a1f9bb6aSTetsuo Handa unsigned long number) 1221a1f9bb6aSTetsuo Handa { 1222a1f9bb6aSTetsuo Handa struct tomoyo_request_info r; 1223a1f9bb6aSTetsuo Handa int error = -ENOMEM; 1224c8c57e84STetsuo Handa struct tomoyo_path_info buf; 1225a1f9bb6aSTetsuo Handa int idx; 1226a1f9bb6aSTetsuo Handa 122757c2590fSTetsuo Handa if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type]) 122857c2590fSTetsuo Handa == TOMOYO_CONFIG_DISABLED || !path->mnt || !path->dentry) 1229a1f9bb6aSTetsuo Handa return 0; 1230a1f9bb6aSTetsuo Handa idx = tomoyo_read_lock(); 1231c8c57e84STetsuo Handa if (!tomoyo_get_realpath(&buf, path)) 1232a1f9bb6aSTetsuo Handa goto out; 1233c8c57e84STetsuo Handa if (type == TOMOYO_TYPE_MKDIR) 1234c8c57e84STetsuo Handa tomoyo_add_slash(&buf); 1235c8c57e84STetsuo Handa error = tomoyo_path_number_perm2(&r, type, &buf, number); 1236a1f9bb6aSTetsuo Handa out: 1237c8c57e84STetsuo Handa kfree(buf.name); 1238a1f9bb6aSTetsuo Handa tomoyo_read_unlock(idx); 1239a1f9bb6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 1240a1f9bb6aSTetsuo Handa error = 0; 1241a1f9bb6aSTetsuo Handa return error; 1242a1f9bb6aSTetsuo Handa } 1243a1f9bb6aSTetsuo Handa 1244a1f9bb6aSTetsuo Handa /** 1245b69a54eeSKentaro Takeda * tomoyo_check_exec_perm - Check permission for "execute". 1246b69a54eeSKentaro Takeda * 124757c2590fSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 1248b69a54eeSKentaro Takeda * @filename: Check permission for "execute". 1249b69a54eeSKentaro Takeda * 1250b69a54eeSKentaro Takeda * Returns 0 on success, negativevalue otherwise. 1251fdb8ebb7STetsuo Handa * 1252fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 1253b69a54eeSKentaro Takeda */ 125457c2590fSTetsuo Handa int tomoyo_check_exec_perm(struct tomoyo_request_info *r, 1255bcb86975STetsuo Handa const struct tomoyo_path_info *filename) 1256b69a54eeSKentaro Takeda { 125757c2590fSTetsuo Handa if (r->mode == TOMOYO_CONFIG_DISABLED) 1258b69a54eeSKentaro Takeda return 0; 125957c2590fSTetsuo Handa return tomoyo_file_perm(r, filename, 1); 1260b69a54eeSKentaro Takeda } 1261b69a54eeSKentaro Takeda 1262b69a54eeSKentaro Takeda /** 1263b69a54eeSKentaro Takeda * tomoyo_check_open_permission - Check permission for "read" and "write". 1264b69a54eeSKentaro Takeda * 1265b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 1266b69a54eeSKentaro Takeda * @path: Pointer to "struct path". 1267b69a54eeSKentaro Takeda * @flag: Flags for open(). 1268b69a54eeSKentaro Takeda * 1269b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1270b69a54eeSKentaro Takeda */ 1271b69a54eeSKentaro Takeda int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, 1272b69a54eeSKentaro Takeda struct path *path, const int flag) 1273b69a54eeSKentaro Takeda { 1274b69a54eeSKentaro Takeda const u8 acc_mode = ACC_MODE(flag); 1275b69a54eeSKentaro Takeda int error = -ENOMEM; 1276c8c57e84STetsuo Handa struct tomoyo_path_info buf; 1277cb0abe6aSTetsuo Handa struct tomoyo_request_info r; 1278fdb8ebb7STetsuo Handa int idx; 1279b69a54eeSKentaro Takeda 128057c2590fSTetsuo Handa if (!path->mnt || 128157c2590fSTetsuo Handa (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode))) 1282b69a54eeSKentaro Takeda return 0; 128357c2590fSTetsuo Handa buf.name = NULL; 128457c2590fSTetsuo Handa r.mode = TOMOYO_CONFIG_DISABLED; 1285fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 1286c8c57e84STetsuo Handa if (!tomoyo_get_realpath(&buf, path)) 1287b69a54eeSKentaro Takeda goto out; 1288b69a54eeSKentaro Takeda error = 0; 1289b69a54eeSKentaro Takeda /* 1290b69a54eeSKentaro Takeda * If the filename is specified by "deny_rewrite" keyword, 1291b69a54eeSKentaro Takeda * we need to check "allow_rewrite" permission when the filename is not 1292b69a54eeSKentaro Takeda * opened for append mode or the filename is truncated at open time. 1293b69a54eeSKentaro Takeda */ 129457c2590fSTetsuo Handa if ((acc_mode & MAY_WRITE) && !(flag & O_APPEND) 129557c2590fSTetsuo Handa && tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_REWRITE) 129657c2590fSTetsuo Handa != TOMOYO_CONFIG_DISABLED) { 129757c2590fSTetsuo Handa if (!tomoyo_get_realpath(&buf, path)) { 129857c2590fSTetsuo Handa error = -ENOMEM; 129957c2590fSTetsuo Handa goto out; 1300b69a54eeSKentaro Takeda } 130157c2590fSTetsuo Handa if (tomoyo_is_no_rewrite_file(&buf)) 130257c2590fSTetsuo Handa error = tomoyo_path_permission(&r, TOMOYO_TYPE_REWRITE, 130357c2590fSTetsuo Handa &buf); 130457c2590fSTetsuo Handa } 130557c2590fSTetsuo Handa if (!error && acc_mode && 130657c2590fSTetsuo Handa tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN) 130757c2590fSTetsuo Handa != TOMOYO_CONFIG_DISABLED) { 130857c2590fSTetsuo Handa if (!buf.name && !tomoyo_get_realpath(&buf, path)) { 130957c2590fSTetsuo Handa error = -ENOMEM; 131057c2590fSTetsuo Handa goto out; 131157c2590fSTetsuo Handa } 1312c8c57e84STetsuo Handa error = tomoyo_file_perm(&r, &buf, acc_mode); 131357c2590fSTetsuo Handa } 1314b69a54eeSKentaro Takeda out: 1315c8c57e84STetsuo Handa kfree(buf.name); 1316fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 1317cb0abe6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 1318b69a54eeSKentaro Takeda error = 0; 1319b69a54eeSKentaro Takeda return error; 1320b69a54eeSKentaro Takeda } 1321b69a54eeSKentaro Takeda 1322b69a54eeSKentaro Takeda /** 13232106ccd9STetsuo Handa * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "rewrite", "chroot" and "unmount". 1324b69a54eeSKentaro Takeda * 1325b69a54eeSKentaro Takeda * @operation: Type of operation. 1326b69a54eeSKentaro Takeda * @path: Pointer to "struct path". 1327b69a54eeSKentaro Takeda * 1328b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1329b69a54eeSKentaro Takeda */ 133097d6931eSTetsuo Handa int tomoyo_path_perm(const u8 operation, struct path *path) 1331b69a54eeSKentaro Takeda { 1332b69a54eeSKentaro Takeda int error = -ENOMEM; 1333c8c57e84STetsuo Handa struct tomoyo_path_info buf; 1334cb0abe6aSTetsuo Handa struct tomoyo_request_info r; 1335fdb8ebb7STetsuo Handa int idx; 1336b69a54eeSKentaro Takeda 133757c2590fSTetsuo Handa if (!path->mnt) 1338b69a54eeSKentaro Takeda return 0; 133957c2590fSTetsuo Handa if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation]) 134057c2590fSTetsuo Handa == TOMOYO_CONFIG_DISABLED) 134157c2590fSTetsuo Handa return 0; 134257c2590fSTetsuo Handa buf.name = NULL; 1343fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 1344c8c57e84STetsuo Handa if (!tomoyo_get_realpath(&buf, path)) 1345b69a54eeSKentaro Takeda goto out; 1346b69a54eeSKentaro Takeda switch (operation) { 1347cb0abe6aSTetsuo Handa case TOMOYO_TYPE_REWRITE: 1348c8c57e84STetsuo Handa if (!tomoyo_is_no_rewrite_file(&buf)) { 1349cb0abe6aSTetsuo Handa error = 0; 1350cb0abe6aSTetsuo Handa goto out; 1351cb0abe6aSTetsuo Handa } 1352cb0abe6aSTetsuo Handa break; 13537ef61233STetsuo Handa case TOMOYO_TYPE_RMDIR: 13547ef61233STetsuo Handa case TOMOYO_TYPE_CHROOT: 135557c2590fSTetsuo Handa case TOMOYO_TYPE_UMOUNT: 1356c8c57e84STetsuo Handa tomoyo_add_slash(&buf); 1357c8c57e84STetsuo Handa break; 1358b69a54eeSKentaro Takeda } 1359c8c57e84STetsuo Handa error = tomoyo_path_permission(&r, operation, &buf); 1360b69a54eeSKentaro Takeda out: 1361c8c57e84STetsuo Handa kfree(buf.name); 1362fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 1363cb0abe6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 1364b69a54eeSKentaro Takeda error = 0; 1365b69a54eeSKentaro Takeda return error; 1366b69a54eeSKentaro Takeda } 1367b69a54eeSKentaro Takeda 1368b69a54eeSKentaro Takeda /** 1369a1f9bb6aSTetsuo Handa * tomoyo_path_number3_perm2 - Check permission for path/number/number/number operation. 1370a1f9bb6aSTetsuo Handa * 1371a1f9bb6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 1372a1f9bb6aSTetsuo Handa * @operation: Type of operation. 1373a1f9bb6aSTetsuo Handa * @filename: Filename to check. 1374a1f9bb6aSTetsuo Handa * @mode: Create mode. 1375a1f9bb6aSTetsuo Handa * @dev: Device number. 1376a1f9bb6aSTetsuo Handa * 1377a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1378a1f9bb6aSTetsuo Handa * 1379a1f9bb6aSTetsuo Handa * Caller holds tomoyo_read_lock(). 1380a1f9bb6aSTetsuo Handa */ 1381a1f9bb6aSTetsuo Handa static int tomoyo_path_number3_perm2(struct tomoyo_request_info *r, 1382a1f9bb6aSTetsuo Handa const u8 operation, 1383a1f9bb6aSTetsuo Handa const struct tomoyo_path_info *filename, 1384a1f9bb6aSTetsuo Handa const unsigned int mode, 1385a1f9bb6aSTetsuo Handa const unsigned int dev) 1386a1f9bb6aSTetsuo Handa { 1387a1f9bb6aSTetsuo Handa int error; 138817fcfbd9STetsuo Handa const char *msg; 1389a1f9bb6aSTetsuo Handa const unsigned int major = MAJOR(dev); 1390a1f9bb6aSTetsuo Handa const unsigned int minor = MINOR(dev); 1391a1f9bb6aSTetsuo Handa 139217fcfbd9STetsuo Handa do { 139317fcfbd9STetsuo Handa error = tomoyo_path_number3_acl(r, filename, 1 << operation, 139417fcfbd9STetsuo Handa mode, major, minor); 1395a1f9bb6aSTetsuo Handa if (!error) 139617fcfbd9STetsuo Handa break; 139717fcfbd9STetsuo Handa msg = tomoyo_path_number32keyword(operation); 139817fcfbd9STetsuo Handa tomoyo_warn_log(r, "%s %s 0%o %u %u", msg, filename->name, 139917fcfbd9STetsuo Handa mode, major, minor); 140017fcfbd9STetsuo Handa error = tomoyo_supervisor(r, "allow_%s %s 0%o %u %u\n", msg, 140117fcfbd9STetsuo Handa tomoyo_file_pattern(filename), mode, 140217fcfbd9STetsuo Handa major, minor); 140317fcfbd9STetsuo Handa } while (error == TOMOYO_RETRY_REQUEST); 1404a1f9bb6aSTetsuo Handa if (r->mode != TOMOYO_CONFIG_ENFORCING) 1405a1f9bb6aSTetsuo Handa error = 0; 1406a1f9bb6aSTetsuo Handa return error; 1407a1f9bb6aSTetsuo Handa } 1408a1f9bb6aSTetsuo Handa 1409a1f9bb6aSTetsuo Handa /** 1410a1f9bb6aSTetsuo Handa * tomoyo_path_number3_perm - Check permission for "mkblock" and "mkchar". 1411a1f9bb6aSTetsuo Handa * 1412a1f9bb6aSTetsuo Handa * @operation: Type of operation. (TOMOYO_TYPE_MKCHAR or TOMOYO_TYPE_MKBLOCK) 1413a1f9bb6aSTetsuo Handa * @path: Pointer to "struct path". 1414a1f9bb6aSTetsuo Handa * @mode: Create mode. 1415a1f9bb6aSTetsuo Handa * @dev: Device number. 1416a1f9bb6aSTetsuo Handa * 1417a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1418a1f9bb6aSTetsuo Handa */ 1419a1f9bb6aSTetsuo Handa int tomoyo_path_number3_perm(const u8 operation, struct path *path, 1420a1f9bb6aSTetsuo Handa const unsigned int mode, unsigned int dev) 1421a1f9bb6aSTetsuo Handa { 1422a1f9bb6aSTetsuo Handa struct tomoyo_request_info r; 1423a1f9bb6aSTetsuo Handa int error = -ENOMEM; 1424c8c57e84STetsuo Handa struct tomoyo_path_info buf; 1425a1f9bb6aSTetsuo Handa int idx; 1426a1f9bb6aSTetsuo Handa 142757c2590fSTetsuo Handa if (!path->mnt || 142857c2590fSTetsuo Handa tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation]) 142957c2590fSTetsuo Handa == TOMOYO_CONFIG_DISABLED) 1430a1f9bb6aSTetsuo Handa return 0; 1431a1f9bb6aSTetsuo Handa idx = tomoyo_read_lock(); 1432a1f9bb6aSTetsuo Handa error = -ENOMEM; 1433c8c57e84STetsuo Handa if (tomoyo_get_realpath(&buf, path)) { 1434c8c57e84STetsuo Handa error = tomoyo_path_number3_perm2(&r, operation, &buf, mode, 1435a1f9bb6aSTetsuo Handa new_decode_dev(dev)); 1436c8c57e84STetsuo Handa kfree(buf.name); 1437a1f9bb6aSTetsuo Handa } 1438a1f9bb6aSTetsuo Handa tomoyo_read_unlock(idx); 1439a1f9bb6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 1440a1f9bb6aSTetsuo Handa error = 0; 1441a1f9bb6aSTetsuo Handa return error; 1442a1f9bb6aSTetsuo Handa } 1443a1f9bb6aSTetsuo Handa 1444a1f9bb6aSTetsuo Handa /** 14457ef61233STetsuo Handa * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root". 1446b69a54eeSKentaro Takeda * 1447b69a54eeSKentaro Takeda * @operation: Type of operation. 1448b69a54eeSKentaro Takeda * @path1: Pointer to "struct path". 1449b69a54eeSKentaro Takeda * @path2: Pointer to "struct path". 1450b69a54eeSKentaro Takeda * 1451b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1452b69a54eeSKentaro Takeda */ 145397d6931eSTetsuo Handa int tomoyo_path2_perm(const u8 operation, struct path *path1, 1454b69a54eeSKentaro Takeda struct path *path2) 1455b69a54eeSKentaro Takeda { 1456b69a54eeSKentaro Takeda int error = -ENOMEM; 145717fcfbd9STetsuo Handa const char *msg; 1458c8c57e84STetsuo Handa struct tomoyo_path_info buf1; 1459c8c57e84STetsuo Handa struct tomoyo_path_info buf2; 1460cb0abe6aSTetsuo Handa struct tomoyo_request_info r; 1461fdb8ebb7STetsuo Handa int idx; 1462b69a54eeSKentaro Takeda 146357c2590fSTetsuo Handa if (!path1->mnt || !path2->mnt || 146457c2590fSTetsuo Handa tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation]) 146557c2590fSTetsuo Handa == TOMOYO_CONFIG_DISABLED) 1466b69a54eeSKentaro Takeda return 0; 1467c8c57e84STetsuo Handa buf1.name = NULL; 1468c8c57e84STetsuo Handa buf2.name = NULL; 1469fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 1470c8c57e84STetsuo Handa if (!tomoyo_get_realpath(&buf1, path1) || 1471c8c57e84STetsuo Handa !tomoyo_get_realpath(&buf2, path2)) 1472b69a54eeSKentaro Takeda goto out; 147357c2590fSTetsuo Handa switch (operation) { 147457c2590fSTetsuo Handa struct dentry *dentry; 147557c2590fSTetsuo Handa case TOMOYO_TYPE_RENAME: 147657c2590fSTetsuo Handa case TOMOYO_TYPE_LINK: 147757c2590fSTetsuo Handa dentry = path1->dentry; 147857c2590fSTetsuo Handa if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode)) 147957c2590fSTetsuo Handa break; 148057c2590fSTetsuo Handa /* fall through */ 148157c2590fSTetsuo Handa case TOMOYO_TYPE_PIVOT_ROOT: 1482c8c57e84STetsuo Handa tomoyo_add_slash(&buf1); 1483c8c57e84STetsuo Handa tomoyo_add_slash(&buf2); 148457c2590fSTetsuo Handa break; 1485b69a54eeSKentaro Takeda } 148617fcfbd9STetsuo Handa do { 1487c8c57e84STetsuo Handa error = tomoyo_path2_acl(&r, operation, &buf1, &buf2); 1488b69a54eeSKentaro Takeda if (!error) 148917fcfbd9STetsuo Handa break; 149017fcfbd9STetsuo Handa msg = tomoyo_path22keyword(operation); 1491c8c57e84STetsuo Handa tomoyo_warn_log(&r, "%s %s %s", msg, buf1.name, buf2.name); 149217fcfbd9STetsuo Handa error = tomoyo_supervisor(&r, "allow_%s %s %s\n", msg, 1493c8c57e84STetsuo Handa tomoyo_file_pattern(&buf1), 1494c8c57e84STetsuo Handa tomoyo_file_pattern(&buf2)); 149517fcfbd9STetsuo Handa } while (error == TOMOYO_RETRY_REQUEST); 1496b69a54eeSKentaro Takeda out: 1497c8c57e84STetsuo Handa kfree(buf1.name); 1498c8c57e84STetsuo Handa kfree(buf2.name); 1499fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 1500cb0abe6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 1501b69a54eeSKentaro Takeda error = 0; 1502b69a54eeSKentaro Takeda return error; 1503b69a54eeSKentaro Takeda } 1504a1f9bb6aSTetsuo Handa 1505a1f9bb6aSTetsuo Handa /** 1506a1f9bb6aSTetsuo Handa * tomoyo_write_file_policy - Update file related list. 1507a1f9bb6aSTetsuo Handa * 1508a1f9bb6aSTetsuo Handa * @data: String to parse. 1509a1f9bb6aSTetsuo Handa * @domain: Pointer to "struct tomoyo_domain_info". 1510a1f9bb6aSTetsuo Handa * @is_delete: True if it is a delete request. 1511a1f9bb6aSTetsuo Handa * 1512a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1513a1f9bb6aSTetsuo Handa * 1514a1f9bb6aSTetsuo Handa * Caller holds tomoyo_read_lock(). 1515a1f9bb6aSTetsuo Handa */ 1516a1f9bb6aSTetsuo Handa int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, 1517a1f9bb6aSTetsuo Handa const bool is_delete) 1518a1f9bb6aSTetsuo Handa { 1519a1f9bb6aSTetsuo Handa char *w[5]; 1520a1f9bb6aSTetsuo Handa u8 type; 1521a1f9bb6aSTetsuo Handa if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0]) 1522a1f9bb6aSTetsuo Handa return -EINVAL; 1523237ab459STetsuo Handa if (strncmp(w[0], "allow_", 6)) 1524a1f9bb6aSTetsuo Handa goto out; 1525a1f9bb6aSTetsuo Handa w[0] += 6; 1526a1f9bb6aSTetsuo Handa for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) { 1527a1f9bb6aSTetsuo Handa if (strcmp(w[0], tomoyo_path_keyword[type])) 1528a1f9bb6aSTetsuo Handa continue; 1529a1f9bb6aSTetsuo Handa return tomoyo_update_path_acl(type, w[1], domain, is_delete); 1530a1f9bb6aSTetsuo Handa } 1531a1f9bb6aSTetsuo Handa if (!w[2][0]) 1532a1f9bb6aSTetsuo Handa goto out; 1533a1f9bb6aSTetsuo Handa for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) { 1534a1f9bb6aSTetsuo Handa if (strcmp(w[0], tomoyo_path2_keyword[type])) 1535a1f9bb6aSTetsuo Handa continue; 1536a1f9bb6aSTetsuo Handa return tomoyo_update_path2_acl(type, w[1], w[2], domain, 1537a1f9bb6aSTetsuo Handa is_delete); 1538a1f9bb6aSTetsuo Handa } 1539a1f9bb6aSTetsuo Handa for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) { 1540a1f9bb6aSTetsuo Handa if (strcmp(w[0], tomoyo_path_number_keyword[type])) 1541a1f9bb6aSTetsuo Handa continue; 1542a1f9bb6aSTetsuo Handa return tomoyo_update_path_number_acl(type, w[1], w[2], domain, 1543a1f9bb6aSTetsuo Handa is_delete); 1544a1f9bb6aSTetsuo Handa } 1545a1f9bb6aSTetsuo Handa if (!w[3][0] || !w[4][0]) 1546a1f9bb6aSTetsuo Handa goto out; 1547a1f9bb6aSTetsuo Handa for (type = 0; type < TOMOYO_MAX_PATH_NUMBER3_OPERATION; type++) { 1548a1f9bb6aSTetsuo Handa if (strcmp(w[0], tomoyo_path_number3_keyword[type])) 1549a1f9bb6aSTetsuo Handa continue; 1550a1f9bb6aSTetsuo Handa return tomoyo_update_path_number3_acl(type, w[1], w[2], w[3], 1551a1f9bb6aSTetsuo Handa w[4], domain, is_delete); 1552a1f9bb6aSTetsuo Handa } 1553a1f9bb6aSTetsuo Handa out: 1554a1f9bb6aSTetsuo Handa return -EINVAL; 1555a1f9bb6aSTetsuo Handa } 1556