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. */ 2875093152STetsuo Handa static const char *tomoyo_mkdev_keyword 2975093152STetsuo Handa [TOMOYO_MAX_MKDEV_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 6875093152STetsuo Handa static const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_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 /** 13675093152STetsuo Handa * tomoyo_mkdev2keyword - 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 */ 14275093152STetsuo Handa const char *tomoyo_mkdev2keyword(const u8 operation) 143a1f9bb6aSTetsuo Handa { 14475093152STetsuo Handa return (operation < TOMOYO_MAX_MKDEV_OPERATION) 14575093152STetsuo Handa ? tomoyo_mkdev_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 22199a85259STetsuo Handa /** 22299a85259STetsuo Handa * tomoyo_audit_path_log - Audit path request log. 22399a85259STetsuo Handa * 22499a85259STetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 22599a85259STetsuo Handa * 22699a85259STetsuo Handa * Returns 0 on success, negative value otherwise. 22799a85259STetsuo Handa */ 22899a85259STetsuo Handa static int tomoyo_audit_path_log(struct tomoyo_request_info *r) 22999a85259STetsuo Handa { 23099a85259STetsuo Handa const char *operation = tomoyo_path_keyword[r->param.path.operation]; 23199a85259STetsuo Handa const struct tomoyo_path_info *filename = r->param.path.filename; 23299a85259STetsuo Handa if (r->granted) 23399a85259STetsuo Handa return 0; 23499a85259STetsuo Handa tomoyo_warn_log(r, "%s %s", operation, filename->name); 23599a85259STetsuo Handa return tomoyo_supervisor(r, "allow_%s %s\n", operation, 23699a85259STetsuo Handa tomoyo_file_pattern(filename)); 23799a85259STetsuo Handa } 23899a85259STetsuo Handa 23999a85259STetsuo Handa /** 24099a85259STetsuo Handa * tomoyo_audit_path2_log - Audit path/path request log. 24199a85259STetsuo Handa * 24299a85259STetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 24399a85259STetsuo Handa * 24499a85259STetsuo Handa * Returns 0 on success, negative value otherwise. 24599a85259STetsuo Handa */ 24699a85259STetsuo Handa static int tomoyo_audit_path2_log(struct tomoyo_request_info *r) 24799a85259STetsuo Handa { 24899a85259STetsuo Handa const char *operation = tomoyo_path2_keyword[r->param.path2.operation]; 24999a85259STetsuo Handa const struct tomoyo_path_info *filename1 = r->param.path2.filename1; 25099a85259STetsuo Handa const struct tomoyo_path_info *filename2 = r->param.path2.filename2; 25199a85259STetsuo Handa if (r->granted) 25299a85259STetsuo Handa return 0; 25399a85259STetsuo Handa tomoyo_warn_log(r, "%s %s %s", operation, filename1->name, 25499a85259STetsuo Handa filename2->name); 25599a85259STetsuo Handa return tomoyo_supervisor(r, "allow_%s %s %s\n", operation, 25699a85259STetsuo Handa tomoyo_file_pattern(filename1), 25799a85259STetsuo Handa tomoyo_file_pattern(filename2)); 25899a85259STetsuo Handa } 25999a85259STetsuo Handa 26099a85259STetsuo Handa /** 26199a85259STetsuo Handa * tomoyo_audit_mkdev_log - Audit path/number/number/number request log. 26299a85259STetsuo Handa * 26399a85259STetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 26499a85259STetsuo Handa * 26599a85259STetsuo Handa * Returns 0 on success, negative value otherwise. 26699a85259STetsuo Handa */ 26799a85259STetsuo Handa static int tomoyo_audit_mkdev_log(struct tomoyo_request_info *r) 26899a85259STetsuo Handa { 26975093152STetsuo Handa const char *operation = tomoyo_mkdev2keyword(r->param.mkdev. 27099a85259STetsuo Handa operation); 27199a85259STetsuo Handa const struct tomoyo_path_info *filename = r->param.mkdev.filename; 27299a85259STetsuo Handa const unsigned int major = r->param.mkdev.major; 27399a85259STetsuo Handa const unsigned int minor = r->param.mkdev.minor; 27499a85259STetsuo Handa const unsigned int mode = r->param.mkdev.mode; 27599a85259STetsuo Handa if (r->granted) 27699a85259STetsuo Handa return 0; 27799a85259STetsuo Handa tomoyo_warn_log(r, "%s %s 0%o %u %u", operation, filename->name, mode, 27899a85259STetsuo Handa major, minor); 27999a85259STetsuo Handa return tomoyo_supervisor(r, "allow_%s %s 0%o %u %u\n", operation, 28099a85259STetsuo Handa tomoyo_file_pattern(filename), mode, major, 28199a85259STetsuo Handa minor); 28299a85259STetsuo Handa } 28399a85259STetsuo Handa 28499a85259STetsuo Handa /** 28599a85259STetsuo Handa * tomoyo_audit_path_number_log - Audit path/number request log. 28699a85259STetsuo Handa * 28799a85259STetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 28899a85259STetsuo Handa * @error: Error code. 28999a85259STetsuo Handa * 29099a85259STetsuo Handa * Returns 0 on success, negative value otherwise. 29199a85259STetsuo Handa */ 29299a85259STetsuo Handa static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r) 29399a85259STetsuo Handa { 29499a85259STetsuo Handa const u8 type = r->param.path_number.operation; 29599a85259STetsuo Handa u8 radix; 29699a85259STetsuo Handa const struct tomoyo_path_info *filename = r->param.path_number.filename; 29799a85259STetsuo Handa const char *operation = tomoyo_path_number_keyword[type]; 29899a85259STetsuo Handa char buffer[64]; 29999a85259STetsuo Handa if (r->granted) 30099a85259STetsuo Handa return 0; 30199a85259STetsuo Handa switch (type) { 30299a85259STetsuo Handa case TOMOYO_TYPE_CREATE: 30399a85259STetsuo Handa case TOMOYO_TYPE_MKDIR: 30499a85259STetsuo Handa case TOMOYO_TYPE_MKFIFO: 30599a85259STetsuo Handa case TOMOYO_TYPE_MKSOCK: 30699a85259STetsuo Handa case TOMOYO_TYPE_CHMOD: 30799a85259STetsuo Handa radix = TOMOYO_VALUE_TYPE_OCTAL; 30899a85259STetsuo Handa break; 30999a85259STetsuo Handa case TOMOYO_TYPE_IOCTL: 31099a85259STetsuo Handa radix = TOMOYO_VALUE_TYPE_HEXADECIMAL; 31199a85259STetsuo Handa break; 31299a85259STetsuo Handa default: 31399a85259STetsuo Handa radix = TOMOYO_VALUE_TYPE_DECIMAL; 31499a85259STetsuo Handa break; 31599a85259STetsuo Handa } 31699a85259STetsuo Handa tomoyo_print_ulong(buffer, sizeof(buffer), r->param.path_number.number, 31799a85259STetsuo Handa radix); 31899a85259STetsuo Handa tomoyo_warn_log(r, "%s %s %s", operation, filename->name, buffer); 31999a85259STetsuo Handa return tomoyo_supervisor(r, "allow_%s %s %s\n", operation, 32099a85259STetsuo Handa tomoyo_file_pattern(filename), buffer); 32199a85259STetsuo Handa } 32299a85259STetsuo Handa 3237ef61233STetsuo Handa static int tomoyo_update_path2_acl(const u8 type, const char *filename1, 324b69a54eeSKentaro Takeda const char *filename2, 3257ef61233STetsuo Handa struct tomoyo_domain_info *const domain, 3267ef61233STetsuo Handa const bool is_delete); 3277ef61233STetsuo Handa static int tomoyo_update_path_acl(const u8 type, const char *filename, 3287ef61233STetsuo Handa struct tomoyo_domain_info *const domain, 3297ef61233STetsuo Handa const bool is_delete); 330b69a54eeSKentaro Takeda 331c3fa109aSTetsuo Handa /* 332c3fa109aSTetsuo Handa * tomoyo_globally_readable_list is used for holding list of pathnames which 333c3fa109aSTetsuo Handa * are by default allowed to be open()ed for reading by any process. 334c3fa109aSTetsuo Handa * 335c3fa109aSTetsuo Handa * An entry is added by 336c3fa109aSTetsuo Handa * 337c3fa109aSTetsuo Handa * # echo 'allow_read /lib/libc-2.5.so' > \ 338c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 339c3fa109aSTetsuo Handa * 340c3fa109aSTetsuo Handa * and is deleted by 341c3fa109aSTetsuo Handa * 342c3fa109aSTetsuo Handa * # echo 'delete allow_read /lib/libc-2.5.so' > \ 343c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 344c3fa109aSTetsuo Handa * 345c3fa109aSTetsuo Handa * and all entries are retrieved by 346c3fa109aSTetsuo Handa * 347c3fa109aSTetsuo Handa * # grep ^allow_read /sys/kernel/security/tomoyo/exception_policy 348c3fa109aSTetsuo Handa * 349c3fa109aSTetsuo Handa * In the example above, any process is allowed to 350c3fa109aSTetsuo Handa * open("/lib/libc-2.5.so", O_RDONLY). 351c3fa109aSTetsuo Handa * One exception is, if the domain which current process belongs to is marked 352c3fa109aSTetsuo Handa * as "ignore_global_allow_read", current process can't do so unless explicitly 353c3fa109aSTetsuo Handa * given "allow_read /lib/libc-2.5.so" to the domain which current process 354c3fa109aSTetsuo Handa * belongs to. 355c3fa109aSTetsuo Handa */ 356847b173eSTetsuo Handa LIST_HEAD(tomoyo_globally_readable_list); 357b69a54eeSKentaro Takeda 35836f5e1ffSTetsuo Handa static bool tomoyo_same_globally_readable(const struct tomoyo_acl_head *a, 35936f5e1ffSTetsuo Handa const struct tomoyo_acl_head *b) 36036f5e1ffSTetsuo Handa { 36136f5e1ffSTetsuo Handa return container_of(a, struct tomoyo_globally_readable_file_entry, 36236f5e1ffSTetsuo Handa head)->filename == 36336f5e1ffSTetsuo Handa container_of(b, struct tomoyo_globally_readable_file_entry, 36436f5e1ffSTetsuo Handa head)->filename; 36536f5e1ffSTetsuo Handa } 36636f5e1ffSTetsuo Handa 367b69a54eeSKentaro Takeda /** 368b69a54eeSKentaro Takeda * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list. 369b69a54eeSKentaro Takeda * 370b69a54eeSKentaro Takeda * @filename: Filename unconditionally permitted to open() for reading. 371b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 372b69a54eeSKentaro Takeda * 373b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 374fdb8ebb7STetsuo Handa * 375fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 376b69a54eeSKentaro Takeda */ 377b69a54eeSKentaro Takeda static int tomoyo_update_globally_readable_entry(const char *filename, 378b69a54eeSKentaro Takeda const bool is_delete) 379b69a54eeSKentaro Takeda { 3809e4b50e9STetsuo Handa struct tomoyo_globally_readable_file_entry e = { }; 38136f5e1ffSTetsuo Handa int error; 382b69a54eeSKentaro Takeda 38375093152STetsuo Handa if (!tomoyo_correct_word(filename)) 384b69a54eeSKentaro Takeda return -EINVAL; 3859e4b50e9STetsuo Handa e.filename = tomoyo_get_name(filename); 3869e4b50e9STetsuo Handa if (!e.filename) 387b69a54eeSKentaro Takeda return -ENOMEM; 38836f5e1ffSTetsuo Handa error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, 38936f5e1ffSTetsuo Handa &tomoyo_globally_readable_list, 39036f5e1ffSTetsuo Handa tomoyo_same_globally_readable); 3919e4b50e9STetsuo Handa tomoyo_put_name(e.filename); 392b69a54eeSKentaro Takeda return error; 393b69a54eeSKentaro Takeda } 394b69a54eeSKentaro Takeda 395b69a54eeSKentaro Takeda /** 39675093152STetsuo Handa * tomoyo_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading. 397b69a54eeSKentaro Takeda * 398b69a54eeSKentaro Takeda * @filename: The filename to check. 399b69a54eeSKentaro Takeda * 400b69a54eeSKentaro Takeda * Returns true if any domain can open @filename for reading, false otherwise. 401fdb8ebb7STetsuo Handa * 402fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 403b69a54eeSKentaro Takeda */ 40475093152STetsuo Handa static bool tomoyo_globally_readable_file(const struct tomoyo_path_info * 405b69a54eeSKentaro Takeda filename) 406b69a54eeSKentaro Takeda { 407b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry *ptr; 408b69a54eeSKentaro Takeda bool found = false; 409fdb8ebb7STetsuo Handa 41082e0f001STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, 41182e0f001STetsuo Handa head.list) { 41282e0f001STetsuo Handa if (!ptr->head.is_deleted && 413b69a54eeSKentaro Takeda tomoyo_path_matches_pattern(filename, ptr->filename)) { 414b69a54eeSKentaro Takeda found = true; 415b69a54eeSKentaro Takeda break; 416b69a54eeSKentaro Takeda } 417b69a54eeSKentaro Takeda } 418b69a54eeSKentaro Takeda return found; 419b69a54eeSKentaro Takeda } 420b69a54eeSKentaro Takeda 421b69a54eeSKentaro Takeda /** 422b69a54eeSKentaro Takeda * tomoyo_write_globally_readable_policy - Write "struct tomoyo_globally_readable_file_entry" list. 423b69a54eeSKentaro Takeda * 424b69a54eeSKentaro Takeda * @data: String to parse. 425b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 426b69a54eeSKentaro Takeda * 427b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 428fdb8ebb7STetsuo Handa * 429fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 430b69a54eeSKentaro Takeda */ 431b69a54eeSKentaro Takeda int tomoyo_write_globally_readable_policy(char *data, const bool is_delete) 432b69a54eeSKentaro Takeda { 433b69a54eeSKentaro Takeda return tomoyo_update_globally_readable_entry(data, is_delete); 434b69a54eeSKentaro Takeda } 435b69a54eeSKentaro Takeda 436b69a54eeSKentaro Takeda /** 437b69a54eeSKentaro Takeda * tomoyo_read_globally_readable_policy - Read "struct tomoyo_globally_readable_file_entry" list. 438b69a54eeSKentaro Takeda * 439b69a54eeSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 440b69a54eeSKentaro Takeda * 441b69a54eeSKentaro Takeda * Returns true on success, false otherwise. 442fdb8ebb7STetsuo Handa * 443fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 444b69a54eeSKentaro Takeda */ 445b69a54eeSKentaro Takeda bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) 446b69a54eeSKentaro Takeda { 447b69a54eeSKentaro Takeda struct list_head *pos; 448b69a54eeSKentaro Takeda bool done = true; 449b69a54eeSKentaro Takeda 450b69a54eeSKentaro Takeda list_for_each_cookie(pos, head->read_var2, 451b69a54eeSKentaro Takeda &tomoyo_globally_readable_list) { 452b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry *ptr; 453b69a54eeSKentaro Takeda ptr = list_entry(pos, 454b69a54eeSKentaro Takeda struct tomoyo_globally_readable_file_entry, 45582e0f001STetsuo Handa head.list); 45682e0f001STetsuo Handa if (ptr->head.is_deleted) 457b69a54eeSKentaro Takeda continue; 4587d2948b1STetsuo Handa done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n", 4597d2948b1STetsuo Handa ptr->filename->name); 4607d2948b1STetsuo Handa if (!done) 461b69a54eeSKentaro Takeda break; 462b69a54eeSKentaro Takeda } 463b69a54eeSKentaro Takeda return done; 464b69a54eeSKentaro Takeda } 465b69a54eeSKentaro Takeda 466c3fa109aSTetsuo Handa /* tomoyo_pattern_list is used for holding list of pathnames which are used for 467c3fa109aSTetsuo Handa * converting pathnames to pathname patterns during learning mode. 468c3fa109aSTetsuo Handa * 469c3fa109aSTetsuo Handa * An entry is added by 470c3fa109aSTetsuo Handa * 471c3fa109aSTetsuo Handa * # echo 'file_pattern /proc/\$/mounts' > \ 472c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 473c3fa109aSTetsuo Handa * 474c3fa109aSTetsuo Handa * and is deleted by 475c3fa109aSTetsuo Handa * 476c3fa109aSTetsuo Handa * # echo 'delete file_pattern /proc/\$/mounts' > \ 477c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 478c3fa109aSTetsuo Handa * 479c3fa109aSTetsuo Handa * and all entries are retrieved by 480c3fa109aSTetsuo Handa * 481c3fa109aSTetsuo Handa * # grep ^file_pattern /sys/kernel/security/tomoyo/exception_policy 482c3fa109aSTetsuo Handa * 483c3fa109aSTetsuo Handa * In the example above, if a process which belongs to a domain which is in 484c3fa109aSTetsuo Handa * learning mode requested open("/proc/1/mounts", O_RDONLY), 485c3fa109aSTetsuo Handa * "allow_read /proc/\$/mounts" is automatically added to the domain which that 486c3fa109aSTetsuo Handa * process belongs to. 487c3fa109aSTetsuo Handa * 488c3fa109aSTetsuo Handa * It is not a desirable behavior that we have to use /proc/\$/ instead of 489c3fa109aSTetsuo Handa * /proc/self/ when current process needs to access only current process's 490c3fa109aSTetsuo Handa * information. As of now, LSM version of TOMOYO is using __d_path() for 491c3fa109aSTetsuo Handa * calculating pathname. Non LSM version of TOMOYO is using its own function 492c3fa109aSTetsuo Handa * which pretends as if /proc/self/ is not a symlink; so that we can forbid 493c3fa109aSTetsuo Handa * current process from accessing other process's information. 494c3fa109aSTetsuo Handa */ 495847b173eSTetsuo Handa LIST_HEAD(tomoyo_pattern_list); 496b69a54eeSKentaro Takeda 49736f5e1ffSTetsuo Handa static bool tomoyo_same_pattern(const struct tomoyo_acl_head *a, 49836f5e1ffSTetsuo Handa const struct tomoyo_acl_head *b) 49936f5e1ffSTetsuo Handa { 50036f5e1ffSTetsuo Handa return container_of(a, struct tomoyo_pattern_entry, head)->pattern == 50136f5e1ffSTetsuo Handa container_of(b, struct tomoyo_pattern_entry, head)->pattern; 50236f5e1ffSTetsuo Handa } 50336f5e1ffSTetsuo Handa 504b69a54eeSKentaro Takeda /** 505b69a54eeSKentaro Takeda * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list. 506b69a54eeSKentaro Takeda * 507b69a54eeSKentaro Takeda * @pattern: Pathname pattern. 508b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 509b69a54eeSKentaro Takeda * 510b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 511fdb8ebb7STetsuo Handa * 512fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 513b69a54eeSKentaro Takeda */ 514b69a54eeSKentaro Takeda static int tomoyo_update_file_pattern_entry(const char *pattern, 515b69a54eeSKentaro Takeda const bool is_delete) 516b69a54eeSKentaro Takeda { 5173f629636STetsuo Handa struct tomoyo_pattern_entry e = { }; 51836f5e1ffSTetsuo Handa int error; 519b69a54eeSKentaro Takeda 52075093152STetsuo Handa if (!tomoyo_correct_word(pattern)) 5213f629636STetsuo Handa return -EINVAL; 5223f629636STetsuo Handa e.pattern = tomoyo_get_name(pattern); 5239e4b50e9STetsuo Handa if (!e.pattern) 52436f5e1ffSTetsuo Handa return -ENOMEM; 52536f5e1ffSTetsuo Handa error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, 52636f5e1ffSTetsuo Handa &tomoyo_pattern_list, 52736f5e1ffSTetsuo Handa tomoyo_same_pattern); 5289e4b50e9STetsuo Handa tomoyo_put_name(e.pattern); 529b69a54eeSKentaro Takeda return error; 530b69a54eeSKentaro Takeda } 531b69a54eeSKentaro Takeda 532b69a54eeSKentaro Takeda /** 53317fcfbd9STetsuo Handa * tomoyo_file_pattern - Get patterned pathname. 534b69a54eeSKentaro Takeda * 535b69a54eeSKentaro Takeda * @filename: The filename to find patterned pathname. 536b69a54eeSKentaro Takeda * 537b69a54eeSKentaro Takeda * Returns pointer to pathname pattern if matched, @filename otherwise. 538fdb8ebb7STetsuo Handa * 539fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 540b69a54eeSKentaro Takeda */ 54117fcfbd9STetsuo Handa const char *tomoyo_file_pattern(const struct tomoyo_path_info *filename) 542b69a54eeSKentaro Takeda { 543b69a54eeSKentaro Takeda struct tomoyo_pattern_entry *ptr; 544b69a54eeSKentaro Takeda const struct tomoyo_path_info *pattern = NULL; 545b69a54eeSKentaro Takeda 54682e0f001STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, head.list) { 54782e0f001STetsuo Handa if (ptr->head.is_deleted) 548b69a54eeSKentaro Takeda continue; 549b69a54eeSKentaro Takeda if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) 550b69a54eeSKentaro Takeda continue; 551b69a54eeSKentaro Takeda pattern = ptr->pattern; 552b69a54eeSKentaro Takeda if (tomoyo_strendswith(pattern->name, "/\\*")) { 553b69a54eeSKentaro Takeda /* Do nothing. Try to find the better match. */ 554b69a54eeSKentaro Takeda } else { 555b69a54eeSKentaro Takeda /* This would be the better match. Use this. */ 556b69a54eeSKentaro Takeda break; 557b69a54eeSKentaro Takeda } 558b69a54eeSKentaro Takeda } 559b69a54eeSKentaro Takeda if (pattern) 560b69a54eeSKentaro Takeda filename = pattern; 56117fcfbd9STetsuo Handa return filename->name; 562b69a54eeSKentaro Takeda } 563b69a54eeSKentaro Takeda 564b69a54eeSKentaro Takeda /** 565b69a54eeSKentaro Takeda * tomoyo_write_pattern_policy - Write "struct tomoyo_pattern_entry" list. 566b69a54eeSKentaro Takeda * 567b69a54eeSKentaro Takeda * @data: String to parse. 568b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 569b69a54eeSKentaro Takeda * 570b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 571fdb8ebb7STetsuo Handa * 572fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 573b69a54eeSKentaro Takeda */ 574b69a54eeSKentaro Takeda int tomoyo_write_pattern_policy(char *data, const bool is_delete) 575b69a54eeSKentaro Takeda { 576b69a54eeSKentaro Takeda return tomoyo_update_file_pattern_entry(data, is_delete); 577b69a54eeSKentaro Takeda } 578b69a54eeSKentaro Takeda 579b69a54eeSKentaro Takeda /** 580b69a54eeSKentaro Takeda * tomoyo_read_file_pattern - Read "struct tomoyo_pattern_entry" list. 581b69a54eeSKentaro Takeda * 582b69a54eeSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 583b69a54eeSKentaro Takeda * 584b69a54eeSKentaro Takeda * Returns true on success, false otherwise. 585fdb8ebb7STetsuo Handa * 586fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 587b69a54eeSKentaro Takeda */ 588b69a54eeSKentaro Takeda bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) 589b69a54eeSKentaro Takeda { 590b69a54eeSKentaro Takeda struct list_head *pos; 591b69a54eeSKentaro Takeda bool done = true; 592b69a54eeSKentaro Takeda 593b69a54eeSKentaro Takeda list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) { 594b69a54eeSKentaro Takeda struct tomoyo_pattern_entry *ptr; 59582e0f001STetsuo Handa ptr = list_entry(pos, struct tomoyo_pattern_entry, head.list); 59682e0f001STetsuo Handa if (ptr->head.is_deleted) 597b69a54eeSKentaro Takeda continue; 5987d2948b1STetsuo Handa done = tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN 5997d2948b1STetsuo Handa "%s\n", ptr->pattern->name); 6007d2948b1STetsuo Handa if (!done) 601b69a54eeSKentaro Takeda break; 602b69a54eeSKentaro Takeda } 603b69a54eeSKentaro Takeda return done; 604b69a54eeSKentaro Takeda } 605b69a54eeSKentaro Takeda 606c3fa109aSTetsuo Handa /* 607c3fa109aSTetsuo Handa * tomoyo_no_rewrite_list is used for holding list of pathnames which are by 608c3fa109aSTetsuo Handa * default forbidden to modify already written content of a file. 609c3fa109aSTetsuo Handa * 610c3fa109aSTetsuo Handa * An entry is added by 611c3fa109aSTetsuo Handa * 612c3fa109aSTetsuo Handa * # echo 'deny_rewrite /var/log/messages' > \ 613c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 614c3fa109aSTetsuo Handa * 615c3fa109aSTetsuo Handa * and is deleted by 616c3fa109aSTetsuo Handa * 617c3fa109aSTetsuo Handa * # echo 'delete deny_rewrite /var/log/messages' > \ 618c3fa109aSTetsuo Handa * /sys/kernel/security/tomoyo/exception_policy 619c3fa109aSTetsuo Handa * 620c3fa109aSTetsuo Handa * and all entries are retrieved by 621c3fa109aSTetsuo Handa * 622c3fa109aSTetsuo Handa * # grep ^deny_rewrite /sys/kernel/security/tomoyo/exception_policy 623c3fa109aSTetsuo Handa * 624c3fa109aSTetsuo Handa * In the example above, if a process requested to rewrite /var/log/messages , 625c3fa109aSTetsuo Handa * the process can't rewrite unless the domain which that process belongs to 626c3fa109aSTetsuo Handa * has "allow_rewrite /var/log/messages" entry. 627c3fa109aSTetsuo Handa * 628c3fa109aSTetsuo Handa * It is not a desirable behavior that we have to add "\040(deleted)" suffix 629c3fa109aSTetsuo Handa * when we want to allow rewriting already unlink()ed file. As of now, 630c3fa109aSTetsuo Handa * LSM version of TOMOYO is using __d_path() for calculating pathname. 631c3fa109aSTetsuo Handa * Non LSM version of TOMOYO is using its own function which doesn't append 632c3fa109aSTetsuo Handa * " (deleted)" suffix if the file is already unlink()ed; so that we don't 633c3fa109aSTetsuo Handa * need to worry whether the file is already unlink()ed or not. 634c3fa109aSTetsuo Handa */ 635847b173eSTetsuo Handa LIST_HEAD(tomoyo_no_rewrite_list); 636b69a54eeSKentaro Takeda 63736f5e1ffSTetsuo Handa static bool tomoyo_same_no_rewrite(const struct tomoyo_acl_head *a, 63836f5e1ffSTetsuo Handa const struct tomoyo_acl_head *b) 63936f5e1ffSTetsuo Handa { 64036f5e1ffSTetsuo Handa return container_of(a, struct tomoyo_no_rewrite_entry, head)->pattern 64136f5e1ffSTetsuo Handa == container_of(b, struct tomoyo_no_rewrite_entry, head) 64236f5e1ffSTetsuo Handa ->pattern; 64336f5e1ffSTetsuo Handa } 64436f5e1ffSTetsuo Handa 645b69a54eeSKentaro Takeda /** 646b69a54eeSKentaro Takeda * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list. 647b69a54eeSKentaro Takeda * 648b69a54eeSKentaro Takeda * @pattern: Pathname pattern that are not rewritable by default. 649b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 650b69a54eeSKentaro Takeda * 651b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 652fdb8ebb7STetsuo Handa * 653fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 654b69a54eeSKentaro Takeda */ 655b69a54eeSKentaro Takeda static int tomoyo_update_no_rewrite_entry(const char *pattern, 656b69a54eeSKentaro Takeda const bool is_delete) 657b69a54eeSKentaro Takeda { 6589e4b50e9STetsuo Handa struct tomoyo_no_rewrite_entry e = { }; 65936f5e1ffSTetsuo Handa int error; 660b69a54eeSKentaro Takeda 66175093152STetsuo Handa if (!tomoyo_correct_word(pattern)) 662b69a54eeSKentaro Takeda return -EINVAL; 6639e4b50e9STetsuo Handa e.pattern = tomoyo_get_name(pattern); 6649e4b50e9STetsuo Handa if (!e.pattern) 66536f5e1ffSTetsuo Handa return -ENOMEM; 66636f5e1ffSTetsuo Handa error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, 66736f5e1ffSTetsuo Handa &tomoyo_no_rewrite_list, 66836f5e1ffSTetsuo Handa tomoyo_same_no_rewrite); 6699e4b50e9STetsuo Handa tomoyo_put_name(e.pattern); 670b69a54eeSKentaro Takeda return error; 671b69a54eeSKentaro Takeda } 672b69a54eeSKentaro Takeda 673b69a54eeSKentaro Takeda /** 67475093152STetsuo Handa * tomoyo_no_rewrite_file - Check if the given pathname is not permitted to be rewrited. 675b69a54eeSKentaro Takeda * 676b69a54eeSKentaro Takeda * @filename: Filename to check. 677b69a54eeSKentaro Takeda * 678b69a54eeSKentaro Takeda * Returns true if @filename is specified by "deny_rewrite" directive, 679b69a54eeSKentaro Takeda * false otherwise. 680fdb8ebb7STetsuo Handa * 681fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 682b69a54eeSKentaro Takeda */ 68375093152STetsuo Handa static bool tomoyo_no_rewrite_file(const struct tomoyo_path_info *filename) 684b69a54eeSKentaro Takeda { 685b69a54eeSKentaro Takeda struct tomoyo_no_rewrite_entry *ptr; 686b69a54eeSKentaro Takeda bool found = false; 687b69a54eeSKentaro Takeda 68882e0f001STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, head.list) { 68982e0f001STetsuo Handa if (ptr->head.is_deleted) 690b69a54eeSKentaro Takeda continue; 691b69a54eeSKentaro Takeda if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) 692b69a54eeSKentaro Takeda continue; 693b69a54eeSKentaro Takeda found = true; 694b69a54eeSKentaro Takeda break; 695b69a54eeSKentaro Takeda } 696b69a54eeSKentaro Takeda return found; 697b69a54eeSKentaro Takeda } 698b69a54eeSKentaro Takeda 699b69a54eeSKentaro Takeda /** 700b69a54eeSKentaro Takeda * tomoyo_write_no_rewrite_policy - Write "struct tomoyo_no_rewrite_entry" list. 701b69a54eeSKentaro Takeda * 702b69a54eeSKentaro Takeda * @data: String to parse. 703b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 704b69a54eeSKentaro Takeda * 705b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 706fdb8ebb7STetsuo Handa * 707fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 708b69a54eeSKentaro Takeda */ 709b69a54eeSKentaro Takeda int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete) 710b69a54eeSKentaro Takeda { 711b69a54eeSKentaro Takeda return tomoyo_update_no_rewrite_entry(data, is_delete); 712b69a54eeSKentaro Takeda } 713b69a54eeSKentaro Takeda 714b69a54eeSKentaro Takeda /** 715b69a54eeSKentaro Takeda * tomoyo_read_no_rewrite_policy - Read "struct tomoyo_no_rewrite_entry" list. 716b69a54eeSKentaro Takeda * 717b69a54eeSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 718b69a54eeSKentaro Takeda * 719b69a54eeSKentaro Takeda * Returns true on success, false otherwise. 720fdb8ebb7STetsuo Handa * 721fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 722b69a54eeSKentaro Takeda */ 723b69a54eeSKentaro Takeda bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) 724b69a54eeSKentaro Takeda { 725b69a54eeSKentaro Takeda struct list_head *pos; 726b69a54eeSKentaro Takeda bool done = true; 727b69a54eeSKentaro Takeda 728b69a54eeSKentaro Takeda list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) { 729b69a54eeSKentaro Takeda struct tomoyo_no_rewrite_entry *ptr; 73082e0f001STetsuo Handa ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, 73182e0f001STetsuo Handa head.list); 73282e0f001STetsuo Handa if (ptr->head.is_deleted) 733b69a54eeSKentaro Takeda continue; 7347d2948b1STetsuo Handa done = tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE 7357d2948b1STetsuo Handa "%s\n", ptr->pattern->name); 7367d2948b1STetsuo Handa if (!done) 737b69a54eeSKentaro Takeda break; 738b69a54eeSKentaro Takeda } 739b69a54eeSKentaro Takeda return done; 740b69a54eeSKentaro Takeda } 741b69a54eeSKentaro Takeda 74299a85259STetsuo Handa static bool tomoyo_check_path_acl(const struct tomoyo_request_info *r, 74399a85259STetsuo Handa const struct tomoyo_acl_info *ptr) 744b69a54eeSKentaro Takeda { 74599a85259STetsuo Handa const struct tomoyo_path_acl *acl = container_of(ptr, typeof(*acl), 74699a85259STetsuo Handa head); 74799a85259STetsuo Handa return (acl->perm & (1 << r->param.path.operation)) && 74899a85259STetsuo Handa tomoyo_compare_name_union(r->param.path.filename, &acl->name); 749b69a54eeSKentaro Takeda } 75099a85259STetsuo Handa 75199a85259STetsuo Handa static bool tomoyo_check_path_number_acl(const struct tomoyo_request_info *r, 75299a85259STetsuo Handa const struct tomoyo_acl_info *ptr) 75399a85259STetsuo Handa { 75499a85259STetsuo Handa const struct tomoyo_path_number_acl *acl = 75599a85259STetsuo Handa container_of(ptr, typeof(*acl), head); 75699a85259STetsuo Handa return (acl->perm & (1 << r->param.path_number.operation)) && 75799a85259STetsuo Handa tomoyo_compare_number_union(r->param.path_number.number, 75899a85259STetsuo Handa &acl->number) && 75999a85259STetsuo Handa tomoyo_compare_name_union(r->param.path_number.filename, 76099a85259STetsuo Handa &acl->name); 76199a85259STetsuo Handa } 76299a85259STetsuo Handa 76399a85259STetsuo Handa static bool tomoyo_check_path2_acl(const struct tomoyo_request_info *r, 76499a85259STetsuo Handa const struct tomoyo_acl_info *ptr) 76599a85259STetsuo Handa { 76699a85259STetsuo Handa const struct tomoyo_path2_acl *acl = 76799a85259STetsuo Handa container_of(ptr, typeof(*acl), head); 76899a85259STetsuo Handa return (acl->perm & (1 << r->param.path2.operation)) && 76999a85259STetsuo Handa tomoyo_compare_name_union(r->param.path2.filename1, &acl->name1) 77099a85259STetsuo Handa && tomoyo_compare_name_union(r->param.path2.filename2, 77199a85259STetsuo Handa &acl->name2); 77299a85259STetsuo Handa } 77399a85259STetsuo Handa 77499a85259STetsuo Handa static bool tomoyo_check_mkdev_acl(const struct tomoyo_request_info *r, 77599a85259STetsuo Handa const struct tomoyo_acl_info *ptr) 77699a85259STetsuo Handa { 77775093152STetsuo Handa const struct tomoyo_mkdev_acl *acl = 77899a85259STetsuo Handa container_of(ptr, typeof(*acl), head); 77999a85259STetsuo Handa return (acl->perm & (1 << r->param.mkdev.operation)) && 78099a85259STetsuo Handa tomoyo_compare_number_union(r->param.mkdev.mode, 78199a85259STetsuo Handa &acl->mode) && 78299a85259STetsuo Handa tomoyo_compare_number_union(r->param.mkdev.major, 78399a85259STetsuo Handa &acl->major) && 78499a85259STetsuo Handa tomoyo_compare_number_union(r->param.mkdev.minor, 78599a85259STetsuo Handa &acl->minor) && 78699a85259STetsuo Handa tomoyo_compare_name_union(r->param.mkdev.filename, 78799a85259STetsuo Handa &acl->name); 788b69a54eeSKentaro Takeda } 789b69a54eeSKentaro Takeda 790237ab459STetsuo Handa static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a, 791237ab459STetsuo Handa const struct tomoyo_acl_info *b) 792237ab459STetsuo Handa { 793237ab459STetsuo Handa const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head); 794237ab459STetsuo Handa const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head); 79575093152STetsuo Handa return tomoyo_same_acl_head(&p1->head, &p2->head) && 79675093152STetsuo Handa tomoyo_same_name_union(&p1->name, &p2->name); 797237ab459STetsuo Handa } 798237ab459STetsuo Handa 799237ab459STetsuo Handa static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a, 800237ab459STetsuo Handa struct tomoyo_acl_info *b, 801237ab459STetsuo Handa const bool is_delete) 802237ab459STetsuo Handa { 803237ab459STetsuo Handa u16 * const a_perm = &container_of(a, struct tomoyo_path_acl, head) 804237ab459STetsuo Handa ->perm; 805237ab459STetsuo Handa u16 perm = *a_perm; 806237ab459STetsuo Handa const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm; 807237ab459STetsuo Handa if (is_delete) { 808237ab459STetsuo Handa perm &= ~b_perm; 809237ab459STetsuo Handa if ((perm & TOMOYO_RW_MASK) != TOMOYO_RW_MASK) 810237ab459STetsuo Handa perm &= ~(1 << TOMOYO_TYPE_READ_WRITE); 811237ab459STetsuo Handa else if (!(perm & (1 << TOMOYO_TYPE_READ_WRITE))) 812237ab459STetsuo Handa perm &= ~TOMOYO_RW_MASK; 813237ab459STetsuo Handa } else { 814237ab459STetsuo Handa perm |= b_perm; 815237ab459STetsuo Handa if ((perm & TOMOYO_RW_MASK) == TOMOYO_RW_MASK) 816237ab459STetsuo Handa perm |= (1 << TOMOYO_TYPE_READ_WRITE); 817237ab459STetsuo Handa else if (perm & (1 << TOMOYO_TYPE_READ_WRITE)) 818237ab459STetsuo Handa perm |= TOMOYO_RW_MASK; 819237ab459STetsuo Handa } 820237ab459STetsuo Handa *a_perm = perm; 821237ab459STetsuo Handa return !perm; 822237ab459STetsuo Handa } 823237ab459STetsuo Handa 824b69a54eeSKentaro Takeda /** 8257ef61233STetsuo Handa * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list. 826b69a54eeSKentaro Takeda * 827b69a54eeSKentaro Takeda * @type: Type of operation. 828b69a54eeSKentaro Takeda * @filename: Filename. 829b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 830b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 831b69a54eeSKentaro Takeda * 832b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 833fdb8ebb7STetsuo Handa * 834fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 835b69a54eeSKentaro Takeda */ 8367ef61233STetsuo Handa static int tomoyo_update_path_acl(const u8 type, const char *filename, 8377ef61233STetsuo Handa struct tomoyo_domain_info * const domain, 8387ef61233STetsuo Handa const bool is_delete) 839b69a54eeSKentaro Takeda { 8409e4b50e9STetsuo Handa struct tomoyo_path_acl e = { 8419e4b50e9STetsuo Handa .head.type = TOMOYO_TYPE_PATH_ACL, 842237ab459STetsuo Handa .perm = 1 << type 8439e4b50e9STetsuo Handa }; 844237ab459STetsuo Handa int error; 845237ab459STetsuo Handa if (e.perm == (1 << TOMOYO_TYPE_READ_WRITE)) 846237ab459STetsuo Handa e.perm |= TOMOYO_RW_MASK; 8477762fbffSTetsuo Handa if (!tomoyo_parse_name_union(filename, &e.name)) 848b69a54eeSKentaro Takeda return -EINVAL; 849237ab459STetsuo Handa error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, 850237ab459STetsuo Handa tomoyo_same_path_acl, 851237ab459STetsuo Handa tomoyo_merge_path_acl); 8527762fbffSTetsuo Handa tomoyo_put_name_union(&e.name); 853b69a54eeSKentaro Takeda return error; 854b69a54eeSKentaro Takeda } 855b69a54eeSKentaro Takeda 85675093152STetsuo Handa static bool tomoyo_same_mkdev_acl(const struct tomoyo_acl_info *a, 857237ab459STetsuo Handa const struct tomoyo_acl_info *b) 858237ab459STetsuo Handa { 85975093152STetsuo Handa const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1), 860237ab459STetsuo Handa head); 86175093152STetsuo Handa const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2), 862237ab459STetsuo Handa head); 86375093152STetsuo Handa return tomoyo_same_acl_head(&p1->head, &p2->head) 86475093152STetsuo Handa && tomoyo_same_name_union(&p1->name, &p2->name) 86575093152STetsuo Handa && tomoyo_same_number_union(&p1->mode, &p2->mode) 86675093152STetsuo Handa && tomoyo_same_number_union(&p1->major, &p2->major) 86775093152STetsuo Handa && tomoyo_same_number_union(&p1->minor, &p2->minor); 868237ab459STetsuo Handa } 869237ab459STetsuo Handa 87075093152STetsuo Handa static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a, 871237ab459STetsuo Handa struct tomoyo_acl_info *b, 872237ab459STetsuo Handa const bool is_delete) 873237ab459STetsuo Handa { 87475093152STetsuo Handa u8 *const a_perm = &container_of(a, struct tomoyo_mkdev_acl, 875237ab459STetsuo Handa head)->perm; 876237ab459STetsuo Handa u8 perm = *a_perm; 87775093152STetsuo Handa const u8 b_perm = container_of(b, struct tomoyo_mkdev_acl, head) 878237ab459STetsuo Handa ->perm; 879237ab459STetsuo Handa if (is_delete) 880237ab459STetsuo Handa perm &= ~b_perm; 881237ab459STetsuo Handa else 882237ab459STetsuo Handa perm |= b_perm; 883237ab459STetsuo Handa *a_perm = perm; 884237ab459STetsuo Handa return !perm; 885237ab459STetsuo Handa } 886237ab459STetsuo Handa 887b69a54eeSKentaro Takeda /** 88875093152STetsuo Handa * tomoyo_update_mkdev_acl - Update "struct tomoyo_mkdev_acl" list. 889a1f9bb6aSTetsuo Handa * 890a1f9bb6aSTetsuo Handa * @type: Type of operation. 891a1f9bb6aSTetsuo Handa * @filename: Filename. 892a1f9bb6aSTetsuo Handa * @mode: Create mode. 893a1f9bb6aSTetsuo Handa * @major: Device major number. 894a1f9bb6aSTetsuo Handa * @minor: Device minor number. 895a1f9bb6aSTetsuo Handa * @domain: Pointer to "struct tomoyo_domain_info". 896a1f9bb6aSTetsuo Handa * @is_delete: True if it is a delete request. 897a1f9bb6aSTetsuo Handa * 898a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 899237ab459STetsuo Handa * 900237ab459STetsuo Handa * Caller holds tomoyo_read_lock(). 901a1f9bb6aSTetsuo Handa */ 90275093152STetsuo Handa static int tomoyo_update_mkdev_acl(const u8 type, const char *filename, 903237ab459STetsuo Handa char *mode, char *major, char *minor, 904237ab459STetsuo Handa struct tomoyo_domain_info * const 905237ab459STetsuo Handa domain, const bool is_delete) 906a1f9bb6aSTetsuo Handa { 90775093152STetsuo Handa struct tomoyo_mkdev_acl e = { 90875093152STetsuo Handa .head.type = TOMOYO_TYPE_MKDEV_ACL, 909237ab459STetsuo Handa .perm = 1 << type 910a1f9bb6aSTetsuo Handa }; 911a1f9bb6aSTetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 912a1f9bb6aSTetsuo Handa if (!tomoyo_parse_name_union(filename, &e.name) || 913a1f9bb6aSTetsuo Handa !tomoyo_parse_number_union(mode, &e.mode) || 914a1f9bb6aSTetsuo Handa !tomoyo_parse_number_union(major, &e.major) || 915a1f9bb6aSTetsuo Handa !tomoyo_parse_number_union(minor, &e.minor)) 916a1f9bb6aSTetsuo Handa goto out; 917237ab459STetsuo Handa error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, 91875093152STetsuo Handa tomoyo_same_mkdev_acl, 91975093152STetsuo Handa tomoyo_merge_mkdev_acl); 920a1f9bb6aSTetsuo Handa out: 921a1f9bb6aSTetsuo Handa tomoyo_put_name_union(&e.name); 922a1f9bb6aSTetsuo Handa tomoyo_put_number_union(&e.mode); 923a1f9bb6aSTetsuo Handa tomoyo_put_number_union(&e.major); 924a1f9bb6aSTetsuo Handa tomoyo_put_number_union(&e.minor); 925a1f9bb6aSTetsuo Handa return error; 926a1f9bb6aSTetsuo Handa } 927a1f9bb6aSTetsuo Handa 928237ab459STetsuo Handa static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a, 929237ab459STetsuo Handa const struct tomoyo_acl_info *b) 930237ab459STetsuo Handa { 931237ab459STetsuo Handa const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head); 932237ab459STetsuo Handa const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head); 93375093152STetsuo Handa return tomoyo_same_acl_head(&p1->head, &p2->head) 93475093152STetsuo Handa && tomoyo_same_name_union(&p1->name1, &p2->name1) 93575093152STetsuo Handa && tomoyo_same_name_union(&p1->name2, &p2->name2); 936237ab459STetsuo Handa } 937237ab459STetsuo Handa 938237ab459STetsuo Handa static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a, 939237ab459STetsuo Handa struct tomoyo_acl_info *b, 940237ab459STetsuo Handa const bool is_delete) 941237ab459STetsuo Handa { 942237ab459STetsuo Handa u8 * const a_perm = &container_of(a, struct tomoyo_path2_acl, head) 943237ab459STetsuo Handa ->perm; 944237ab459STetsuo Handa u8 perm = *a_perm; 945237ab459STetsuo Handa const u8 b_perm = container_of(b, struct tomoyo_path2_acl, head)->perm; 946237ab459STetsuo Handa if (is_delete) 947237ab459STetsuo Handa perm &= ~b_perm; 948237ab459STetsuo Handa else 949237ab459STetsuo Handa perm |= b_perm; 950237ab459STetsuo Handa *a_perm = perm; 951237ab459STetsuo Handa return !perm; 952237ab459STetsuo Handa } 953237ab459STetsuo Handa 954a1f9bb6aSTetsuo Handa /** 9557ef61233STetsuo Handa * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list. 956b69a54eeSKentaro Takeda * 957b69a54eeSKentaro Takeda * @type: Type of operation. 958b69a54eeSKentaro Takeda * @filename1: First filename. 959b69a54eeSKentaro Takeda * @filename2: Second filename. 960b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 961b69a54eeSKentaro Takeda * @is_delete: True if it is a delete request. 962b69a54eeSKentaro Takeda * 963b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 964fdb8ebb7STetsuo Handa * 965fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 966b69a54eeSKentaro Takeda */ 9677ef61233STetsuo Handa static int tomoyo_update_path2_acl(const u8 type, const char *filename1, 968b69a54eeSKentaro Takeda const char *filename2, 9697ef61233STetsuo Handa struct tomoyo_domain_info * const domain, 9707ef61233STetsuo Handa const bool is_delete) 971b69a54eeSKentaro Takeda { 9729e4b50e9STetsuo Handa struct tomoyo_path2_acl e = { 9739e4b50e9STetsuo Handa .head.type = TOMOYO_TYPE_PATH2_ACL, 974237ab459STetsuo Handa .perm = 1 << type 9759e4b50e9STetsuo Handa }; 9769e4b50e9STetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 9777762fbffSTetsuo Handa if (!tomoyo_parse_name_union(filename1, &e.name1) || 9787762fbffSTetsuo Handa !tomoyo_parse_name_union(filename2, &e.name2)) 979ca0b7df3STetsuo Handa goto out; 980237ab459STetsuo Handa error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, 981237ab459STetsuo Handa tomoyo_same_path2_acl, 982237ab459STetsuo Handa tomoyo_merge_path2_acl); 983ca0b7df3STetsuo Handa out: 9847762fbffSTetsuo Handa tomoyo_put_name_union(&e.name1); 9857762fbffSTetsuo Handa tomoyo_put_name_union(&e.name2); 986b69a54eeSKentaro Takeda return error; 987b69a54eeSKentaro Takeda } 988b69a54eeSKentaro Takeda 989b69a54eeSKentaro Takeda /** 990cb0abe6aSTetsuo Handa * tomoyo_path_permission - Check permission for single path operation. 991b69a54eeSKentaro Takeda * 992cb0abe6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 993b69a54eeSKentaro Takeda * @operation: Type of operation. 994b69a54eeSKentaro Takeda * @filename: Filename to check. 995b69a54eeSKentaro Takeda * 996b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 997fdb8ebb7STetsuo Handa * 998fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 999b69a54eeSKentaro Takeda */ 100005336deeSTetsuo Handa int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, 1001cb0abe6aSTetsuo Handa const struct tomoyo_path_info *filename) 1002b69a54eeSKentaro Takeda { 1003b69a54eeSKentaro Takeda int error; 1004b69a54eeSKentaro Takeda 1005b69a54eeSKentaro Takeda next: 100657c2590fSTetsuo Handa r->type = tomoyo_p2mac[operation]; 100757c2590fSTetsuo Handa r->mode = tomoyo_get_mode(r->profile, r->type); 100857c2590fSTetsuo Handa if (r->mode == TOMOYO_CONFIG_DISABLED) 100957c2590fSTetsuo Handa return 0; 1010cf6e9a64STetsuo Handa r->param_type = TOMOYO_TYPE_PATH_ACL; 1011cf6e9a64STetsuo Handa r->param.path.filename = filename; 1012cf6e9a64STetsuo Handa r->param.path.operation = operation; 101317fcfbd9STetsuo Handa do { 101499a85259STetsuo Handa tomoyo_check_acl(r, tomoyo_check_path_acl); 101599a85259STetsuo Handa if (!r->granted && operation == TOMOYO_TYPE_READ && 101605336deeSTetsuo Handa !r->domain->ignore_global_allow_read && 101775093152STetsuo Handa tomoyo_globally_readable_file(filename)) 101899a85259STetsuo Handa r->granted = true; 101999a85259STetsuo Handa error = tomoyo_audit_path_log(r); 102005336deeSTetsuo Handa /* 102105336deeSTetsuo Handa * Do not retry for execute request, for alias may have 102205336deeSTetsuo Handa * changed. 102305336deeSTetsuo Handa */ 102405336deeSTetsuo Handa } while (error == TOMOYO_RETRY_REQUEST && 102505336deeSTetsuo Handa operation != TOMOYO_TYPE_EXECUTE); 1026b69a54eeSKentaro Takeda /* 1027b69a54eeSKentaro Takeda * Since "allow_truncate" doesn't imply "allow_rewrite" permission, 1028b69a54eeSKentaro Takeda * we need to check "allow_rewrite" permission if the filename is 1029b69a54eeSKentaro Takeda * specified by "deny_rewrite" keyword. 1030b69a54eeSKentaro Takeda */ 10317ef61233STetsuo Handa if (!error && operation == TOMOYO_TYPE_TRUNCATE && 103275093152STetsuo Handa tomoyo_no_rewrite_file(filename)) { 10337ef61233STetsuo Handa operation = TOMOYO_TYPE_REWRITE; 1034b69a54eeSKentaro Takeda goto next; 1035b69a54eeSKentaro Takeda } 1036b69a54eeSKentaro Takeda return error; 1037b69a54eeSKentaro Takeda } 1038b69a54eeSKentaro Takeda 1039237ab459STetsuo Handa static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a, 1040237ab459STetsuo Handa const struct tomoyo_acl_info *b) 1041237ab459STetsuo Handa { 1042237ab459STetsuo Handa const struct tomoyo_path_number_acl *p1 = container_of(a, typeof(*p1), 1043237ab459STetsuo Handa head); 1044237ab459STetsuo Handa const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2), 1045237ab459STetsuo Handa head); 104675093152STetsuo Handa return tomoyo_same_acl_head(&p1->head, &p2->head) 104775093152STetsuo Handa && tomoyo_same_name_union(&p1->name, &p2->name) 104875093152STetsuo Handa && tomoyo_same_number_union(&p1->number, &p2->number); 1049237ab459STetsuo Handa } 1050237ab459STetsuo Handa 1051237ab459STetsuo Handa static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a, 1052237ab459STetsuo Handa struct tomoyo_acl_info *b, 1053237ab459STetsuo Handa const bool is_delete) 1054237ab459STetsuo Handa { 1055237ab459STetsuo Handa u8 * const a_perm = &container_of(a, struct tomoyo_path_number_acl, 1056237ab459STetsuo Handa head)->perm; 1057237ab459STetsuo Handa u8 perm = *a_perm; 1058237ab459STetsuo Handa const u8 b_perm = container_of(b, struct tomoyo_path_number_acl, head) 1059237ab459STetsuo Handa ->perm; 1060237ab459STetsuo Handa if (is_delete) 1061237ab459STetsuo Handa perm &= ~b_perm; 1062237ab459STetsuo Handa else 1063237ab459STetsuo Handa perm |= b_perm; 1064237ab459STetsuo Handa *a_perm = perm; 1065237ab459STetsuo Handa return !perm; 1066237ab459STetsuo Handa } 1067237ab459STetsuo Handa 1068a1f9bb6aSTetsuo Handa /** 1069a1f9bb6aSTetsuo Handa * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL. 1070a1f9bb6aSTetsuo Handa * 1071a1f9bb6aSTetsuo Handa * @type: Type of operation. 1072a1f9bb6aSTetsuo Handa * @filename: Filename. 1073a1f9bb6aSTetsuo Handa * @number: Number. 1074a1f9bb6aSTetsuo Handa * @domain: Pointer to "struct tomoyo_domain_info". 1075a1f9bb6aSTetsuo Handa * @is_delete: True if it is a delete request. 1076a1f9bb6aSTetsuo Handa * 1077a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1078a1f9bb6aSTetsuo Handa */ 1079237ab459STetsuo Handa static int tomoyo_update_path_number_acl(const u8 type, const char *filename, 1080a1f9bb6aSTetsuo Handa char *number, 1081237ab459STetsuo Handa struct tomoyo_domain_info * const 1082237ab459STetsuo Handa domain, 1083a1f9bb6aSTetsuo Handa const bool is_delete) 1084a1f9bb6aSTetsuo Handa { 1085a1f9bb6aSTetsuo Handa struct tomoyo_path_number_acl e = { 1086a1f9bb6aSTetsuo Handa .head.type = TOMOYO_TYPE_PATH_NUMBER_ACL, 1087237ab459STetsuo Handa .perm = 1 << type 1088a1f9bb6aSTetsuo Handa }; 1089a1f9bb6aSTetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 1090a1f9bb6aSTetsuo Handa if (!tomoyo_parse_name_union(filename, &e.name)) 1091a1f9bb6aSTetsuo Handa return -EINVAL; 1092a1f9bb6aSTetsuo Handa if (!tomoyo_parse_number_union(number, &e.number)) 1093a1f9bb6aSTetsuo Handa goto out; 1094237ab459STetsuo Handa error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, 1095237ab459STetsuo Handa tomoyo_same_path_number_acl, 1096237ab459STetsuo Handa tomoyo_merge_path_number_acl); 1097a1f9bb6aSTetsuo Handa out: 1098a1f9bb6aSTetsuo Handa tomoyo_put_name_union(&e.name); 1099a1f9bb6aSTetsuo Handa tomoyo_put_number_union(&e.number); 1100a1f9bb6aSTetsuo Handa return error; 1101a1f9bb6aSTetsuo Handa } 1102a1f9bb6aSTetsuo Handa 1103a1f9bb6aSTetsuo Handa /** 1104a1f9bb6aSTetsuo Handa * tomoyo_path_number_perm2 - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp". 1105a1f9bb6aSTetsuo Handa * 1106a1f9bb6aSTetsuo Handa * @r: Pointer to "strct tomoyo_request_info". 1107a1f9bb6aSTetsuo Handa * @filename: Filename to check. 1108a1f9bb6aSTetsuo Handa * @number: Number. 1109a1f9bb6aSTetsuo Handa * 1110a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1111a1f9bb6aSTetsuo Handa * 1112a1f9bb6aSTetsuo Handa * Caller holds tomoyo_read_lock(). 1113a1f9bb6aSTetsuo Handa */ 1114a1f9bb6aSTetsuo Handa static int tomoyo_path_number_perm2(struct tomoyo_request_info *r, 1115a1f9bb6aSTetsuo Handa const u8 type, 1116a1f9bb6aSTetsuo Handa const struct tomoyo_path_info *filename, 1117a1f9bb6aSTetsuo Handa const unsigned long number) 1118a1f9bb6aSTetsuo Handa { 1119a1f9bb6aSTetsuo Handa int error; 1120a1f9bb6aSTetsuo Handa 1121a1f9bb6aSTetsuo Handa if (!filename) 1122a1f9bb6aSTetsuo Handa return 0; 1123cf6e9a64STetsuo Handa r->param_type = TOMOYO_TYPE_PATH_NUMBER_ACL; 1124cf6e9a64STetsuo Handa r->param.path_number.operation = type; 1125cf6e9a64STetsuo Handa r->param.path_number.filename = filename; 1126cf6e9a64STetsuo Handa r->param.path_number.number = number; 112717fcfbd9STetsuo Handa do { 112899a85259STetsuo Handa tomoyo_check_acl(r, tomoyo_check_path_number_acl); 112999a85259STetsuo Handa error = tomoyo_audit_path_number_log(r); 113017fcfbd9STetsuo Handa } while (error == TOMOYO_RETRY_REQUEST); 1131a1f9bb6aSTetsuo Handa return error; 1132a1f9bb6aSTetsuo Handa } 1133a1f9bb6aSTetsuo Handa 1134a1f9bb6aSTetsuo Handa /** 1135a1f9bb6aSTetsuo Handa * tomoyo_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp". 1136a1f9bb6aSTetsuo Handa * 1137a1f9bb6aSTetsuo Handa * @type: Type of operation. 1138a1f9bb6aSTetsuo Handa * @path: Pointer to "struct path". 1139a1f9bb6aSTetsuo Handa * @number: Number. 1140a1f9bb6aSTetsuo Handa * 1141a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1142a1f9bb6aSTetsuo Handa */ 1143a1f9bb6aSTetsuo Handa int tomoyo_path_number_perm(const u8 type, struct path *path, 1144a1f9bb6aSTetsuo Handa unsigned long number) 1145a1f9bb6aSTetsuo Handa { 1146a1f9bb6aSTetsuo Handa struct tomoyo_request_info r; 1147a1f9bb6aSTetsuo Handa int error = -ENOMEM; 1148c8c57e84STetsuo Handa struct tomoyo_path_info buf; 1149a1f9bb6aSTetsuo Handa int idx; 1150a1f9bb6aSTetsuo Handa 115157c2590fSTetsuo Handa if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type]) 115257c2590fSTetsuo Handa == TOMOYO_CONFIG_DISABLED || !path->mnt || !path->dentry) 1153a1f9bb6aSTetsuo Handa return 0; 1154a1f9bb6aSTetsuo Handa idx = tomoyo_read_lock(); 1155c8c57e84STetsuo Handa if (!tomoyo_get_realpath(&buf, path)) 1156a1f9bb6aSTetsuo Handa goto out; 1157c8c57e84STetsuo Handa if (type == TOMOYO_TYPE_MKDIR) 1158c8c57e84STetsuo Handa tomoyo_add_slash(&buf); 1159c8c57e84STetsuo Handa error = tomoyo_path_number_perm2(&r, type, &buf, number); 1160a1f9bb6aSTetsuo Handa out: 1161c8c57e84STetsuo Handa kfree(buf.name); 1162a1f9bb6aSTetsuo Handa tomoyo_read_unlock(idx); 1163a1f9bb6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 1164a1f9bb6aSTetsuo Handa error = 0; 1165a1f9bb6aSTetsuo Handa return error; 1166a1f9bb6aSTetsuo Handa } 1167a1f9bb6aSTetsuo Handa 1168a1f9bb6aSTetsuo Handa /** 1169b69a54eeSKentaro Takeda * tomoyo_check_open_permission - Check permission for "read" and "write". 1170b69a54eeSKentaro Takeda * 1171b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 1172b69a54eeSKentaro Takeda * @path: Pointer to "struct path". 1173b69a54eeSKentaro Takeda * @flag: Flags for open(). 1174b69a54eeSKentaro Takeda * 1175b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1176b69a54eeSKentaro Takeda */ 1177b69a54eeSKentaro Takeda int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, 1178b69a54eeSKentaro Takeda struct path *path, const int flag) 1179b69a54eeSKentaro Takeda { 1180b69a54eeSKentaro Takeda const u8 acc_mode = ACC_MODE(flag); 1181b69a54eeSKentaro Takeda int error = -ENOMEM; 1182c8c57e84STetsuo Handa struct tomoyo_path_info buf; 1183cb0abe6aSTetsuo Handa struct tomoyo_request_info r; 1184fdb8ebb7STetsuo Handa int idx; 1185b69a54eeSKentaro Takeda 118657c2590fSTetsuo Handa if (!path->mnt || 118757c2590fSTetsuo Handa (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode))) 1188b69a54eeSKentaro Takeda return 0; 118957c2590fSTetsuo Handa buf.name = NULL; 119057c2590fSTetsuo Handa r.mode = TOMOYO_CONFIG_DISABLED; 1191fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 1192c8c57e84STetsuo Handa if (!tomoyo_get_realpath(&buf, path)) 1193b69a54eeSKentaro Takeda goto out; 1194b69a54eeSKentaro Takeda error = 0; 1195b69a54eeSKentaro Takeda /* 1196b69a54eeSKentaro Takeda * If the filename is specified by "deny_rewrite" keyword, 1197b69a54eeSKentaro Takeda * we need to check "allow_rewrite" permission when the filename is not 1198b69a54eeSKentaro Takeda * opened for append mode or the filename is truncated at open time. 1199b69a54eeSKentaro Takeda */ 120057c2590fSTetsuo Handa if ((acc_mode & MAY_WRITE) && !(flag & O_APPEND) 120157c2590fSTetsuo Handa && tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_REWRITE) 120257c2590fSTetsuo Handa != TOMOYO_CONFIG_DISABLED) { 120357c2590fSTetsuo Handa if (!tomoyo_get_realpath(&buf, path)) { 120457c2590fSTetsuo Handa error = -ENOMEM; 120557c2590fSTetsuo Handa goto out; 1206b69a54eeSKentaro Takeda } 120775093152STetsuo Handa if (tomoyo_no_rewrite_file(&buf)) 120857c2590fSTetsuo Handa error = tomoyo_path_permission(&r, TOMOYO_TYPE_REWRITE, 120957c2590fSTetsuo Handa &buf); 121057c2590fSTetsuo Handa } 121157c2590fSTetsuo Handa if (!error && acc_mode && 121257c2590fSTetsuo Handa tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN) 121357c2590fSTetsuo Handa != TOMOYO_CONFIG_DISABLED) { 121405336deeSTetsuo Handa u8 operation; 121557c2590fSTetsuo Handa if (!buf.name && !tomoyo_get_realpath(&buf, path)) { 121657c2590fSTetsuo Handa error = -ENOMEM; 121757c2590fSTetsuo Handa goto out; 121857c2590fSTetsuo Handa } 121905336deeSTetsuo Handa if (acc_mode == (MAY_READ | MAY_WRITE)) 122005336deeSTetsuo Handa operation = TOMOYO_TYPE_READ_WRITE; 122105336deeSTetsuo Handa else if (acc_mode == MAY_READ) 122205336deeSTetsuo Handa operation = TOMOYO_TYPE_READ; 122305336deeSTetsuo Handa else 122405336deeSTetsuo Handa operation = TOMOYO_TYPE_WRITE; 122505336deeSTetsuo Handa error = tomoyo_path_permission(&r, operation, &buf); 122657c2590fSTetsuo Handa } 1227b69a54eeSKentaro Takeda out: 1228c8c57e84STetsuo Handa kfree(buf.name); 1229fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 1230cb0abe6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 1231b69a54eeSKentaro Takeda error = 0; 1232b69a54eeSKentaro Takeda return error; 1233b69a54eeSKentaro Takeda } 1234b69a54eeSKentaro Takeda 1235b69a54eeSKentaro Takeda /** 12362106ccd9STetsuo Handa * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "rewrite", "chroot" and "unmount". 1237b69a54eeSKentaro Takeda * 1238b69a54eeSKentaro Takeda * @operation: Type of operation. 1239b69a54eeSKentaro Takeda * @path: Pointer to "struct path". 1240b69a54eeSKentaro Takeda * 1241b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1242b69a54eeSKentaro Takeda */ 124397d6931eSTetsuo Handa int tomoyo_path_perm(const u8 operation, struct path *path) 1244b69a54eeSKentaro Takeda { 1245b69a54eeSKentaro Takeda int error = -ENOMEM; 1246c8c57e84STetsuo Handa struct tomoyo_path_info buf; 1247cb0abe6aSTetsuo Handa struct tomoyo_request_info r; 1248fdb8ebb7STetsuo Handa int idx; 1249b69a54eeSKentaro Takeda 125057c2590fSTetsuo Handa if (!path->mnt) 1251b69a54eeSKentaro Takeda return 0; 125257c2590fSTetsuo Handa if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation]) 125357c2590fSTetsuo Handa == TOMOYO_CONFIG_DISABLED) 125457c2590fSTetsuo Handa return 0; 125557c2590fSTetsuo Handa buf.name = NULL; 1256fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 1257c8c57e84STetsuo Handa if (!tomoyo_get_realpath(&buf, path)) 1258b69a54eeSKentaro Takeda goto out; 1259b69a54eeSKentaro Takeda switch (operation) { 1260cb0abe6aSTetsuo Handa case TOMOYO_TYPE_REWRITE: 126175093152STetsuo Handa if (!tomoyo_no_rewrite_file(&buf)) { 1262cb0abe6aSTetsuo Handa error = 0; 1263cb0abe6aSTetsuo Handa goto out; 1264cb0abe6aSTetsuo Handa } 1265cb0abe6aSTetsuo Handa break; 12667ef61233STetsuo Handa case TOMOYO_TYPE_RMDIR: 12677ef61233STetsuo Handa case TOMOYO_TYPE_CHROOT: 126857c2590fSTetsuo Handa case TOMOYO_TYPE_UMOUNT: 1269c8c57e84STetsuo Handa tomoyo_add_slash(&buf); 1270c8c57e84STetsuo Handa break; 1271b69a54eeSKentaro Takeda } 1272c8c57e84STetsuo Handa error = tomoyo_path_permission(&r, operation, &buf); 1273b69a54eeSKentaro Takeda out: 1274c8c57e84STetsuo Handa kfree(buf.name); 1275fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 1276cb0abe6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 1277b69a54eeSKentaro Takeda error = 0; 1278b69a54eeSKentaro Takeda return error; 1279b69a54eeSKentaro Takeda } 1280b69a54eeSKentaro Takeda 1281b69a54eeSKentaro Takeda /** 128275093152STetsuo Handa * tomoyo_mkdev_perm - Check permission for "mkblock" and "mkchar". 1283a1f9bb6aSTetsuo Handa * 1284a1f9bb6aSTetsuo Handa * @operation: Type of operation. (TOMOYO_TYPE_MKCHAR or TOMOYO_TYPE_MKBLOCK) 1285a1f9bb6aSTetsuo Handa * @path: Pointer to "struct path". 1286a1f9bb6aSTetsuo Handa * @mode: Create mode. 1287a1f9bb6aSTetsuo Handa * @dev: Device number. 1288a1f9bb6aSTetsuo Handa * 1289a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1290a1f9bb6aSTetsuo Handa */ 129175093152STetsuo Handa int tomoyo_mkdev_perm(const u8 operation, struct path *path, 1292a1f9bb6aSTetsuo Handa const unsigned int mode, unsigned int dev) 1293a1f9bb6aSTetsuo Handa { 1294a1f9bb6aSTetsuo Handa struct tomoyo_request_info r; 1295a1f9bb6aSTetsuo Handa int error = -ENOMEM; 1296c8c57e84STetsuo Handa struct tomoyo_path_info buf; 1297a1f9bb6aSTetsuo Handa int idx; 1298a1f9bb6aSTetsuo Handa 129957c2590fSTetsuo Handa if (!path->mnt || 130057c2590fSTetsuo Handa tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation]) 130157c2590fSTetsuo Handa == TOMOYO_CONFIG_DISABLED) 1302a1f9bb6aSTetsuo Handa return 0; 1303a1f9bb6aSTetsuo Handa idx = tomoyo_read_lock(); 1304a1f9bb6aSTetsuo Handa error = -ENOMEM; 1305c8c57e84STetsuo Handa if (tomoyo_get_realpath(&buf, path)) { 1306cf6e9a64STetsuo Handa dev = new_decode_dev(dev); 130775093152STetsuo Handa r.param_type = TOMOYO_TYPE_MKDEV_ACL; 1308cf6e9a64STetsuo Handa r.param.mkdev.filename = &buf; 1309cf6e9a64STetsuo Handa r.param.mkdev.operation = operation; 1310cf6e9a64STetsuo Handa r.param.mkdev.mode = mode; 1311cf6e9a64STetsuo Handa r.param.mkdev.major = MAJOR(dev); 1312cf6e9a64STetsuo Handa r.param.mkdev.minor = MINOR(dev); 131399a85259STetsuo Handa tomoyo_check_acl(&r, tomoyo_check_mkdev_acl); 131499a85259STetsuo Handa error = tomoyo_audit_mkdev_log(&r); 1315c8c57e84STetsuo Handa kfree(buf.name); 1316a1f9bb6aSTetsuo Handa } 1317a1f9bb6aSTetsuo Handa tomoyo_read_unlock(idx); 1318a1f9bb6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 1319a1f9bb6aSTetsuo Handa error = 0; 1320a1f9bb6aSTetsuo Handa return error; 1321a1f9bb6aSTetsuo Handa } 1322a1f9bb6aSTetsuo Handa 1323a1f9bb6aSTetsuo Handa /** 13247ef61233STetsuo Handa * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root". 1325b69a54eeSKentaro Takeda * 1326b69a54eeSKentaro Takeda * @operation: Type of operation. 1327b69a54eeSKentaro Takeda * @path1: Pointer to "struct path". 1328b69a54eeSKentaro Takeda * @path2: Pointer to "struct path". 1329b69a54eeSKentaro Takeda * 1330b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 1331b69a54eeSKentaro Takeda */ 133297d6931eSTetsuo Handa int tomoyo_path2_perm(const u8 operation, struct path *path1, 1333b69a54eeSKentaro Takeda struct path *path2) 1334b69a54eeSKentaro Takeda { 1335b69a54eeSKentaro Takeda int error = -ENOMEM; 1336c8c57e84STetsuo Handa struct tomoyo_path_info buf1; 1337c8c57e84STetsuo Handa struct tomoyo_path_info buf2; 1338cb0abe6aSTetsuo Handa struct tomoyo_request_info r; 1339fdb8ebb7STetsuo Handa int idx; 1340b69a54eeSKentaro Takeda 134157c2590fSTetsuo Handa if (!path1->mnt || !path2->mnt || 134257c2590fSTetsuo Handa tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation]) 134357c2590fSTetsuo Handa == TOMOYO_CONFIG_DISABLED) 1344b69a54eeSKentaro Takeda return 0; 1345c8c57e84STetsuo Handa buf1.name = NULL; 1346c8c57e84STetsuo Handa buf2.name = NULL; 1347fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 1348c8c57e84STetsuo Handa if (!tomoyo_get_realpath(&buf1, path1) || 1349c8c57e84STetsuo Handa !tomoyo_get_realpath(&buf2, path2)) 1350b69a54eeSKentaro Takeda goto out; 135157c2590fSTetsuo Handa switch (operation) { 135257c2590fSTetsuo Handa struct dentry *dentry; 135357c2590fSTetsuo Handa case TOMOYO_TYPE_RENAME: 135457c2590fSTetsuo Handa case TOMOYO_TYPE_LINK: 135557c2590fSTetsuo Handa dentry = path1->dentry; 135657c2590fSTetsuo Handa if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode)) 135757c2590fSTetsuo Handa break; 135857c2590fSTetsuo Handa /* fall through */ 135957c2590fSTetsuo Handa case TOMOYO_TYPE_PIVOT_ROOT: 1360c8c57e84STetsuo Handa tomoyo_add_slash(&buf1); 1361c8c57e84STetsuo Handa tomoyo_add_slash(&buf2); 136257c2590fSTetsuo Handa break; 1363b69a54eeSKentaro Takeda } 1364cf6e9a64STetsuo Handa r.param_type = TOMOYO_TYPE_PATH2_ACL; 1365cf6e9a64STetsuo Handa r.param.path2.operation = operation; 1366cf6e9a64STetsuo Handa r.param.path2.filename1 = &buf1; 1367cf6e9a64STetsuo Handa r.param.path2.filename2 = &buf2; 136817fcfbd9STetsuo Handa do { 136999a85259STetsuo Handa tomoyo_check_acl(&r, tomoyo_check_path2_acl); 137099a85259STetsuo Handa error = tomoyo_audit_path2_log(&r); 137117fcfbd9STetsuo Handa } while (error == TOMOYO_RETRY_REQUEST); 1372b69a54eeSKentaro Takeda out: 1373c8c57e84STetsuo Handa kfree(buf1.name); 1374c8c57e84STetsuo Handa kfree(buf2.name); 1375fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 1376cb0abe6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 1377b69a54eeSKentaro Takeda error = 0; 1378b69a54eeSKentaro Takeda return error; 1379b69a54eeSKentaro Takeda } 1380a1f9bb6aSTetsuo Handa 1381a1f9bb6aSTetsuo Handa /** 1382a1f9bb6aSTetsuo Handa * tomoyo_write_file_policy - Update file related list. 1383a1f9bb6aSTetsuo Handa * 1384a1f9bb6aSTetsuo Handa * @data: String to parse. 1385a1f9bb6aSTetsuo Handa * @domain: Pointer to "struct tomoyo_domain_info". 1386a1f9bb6aSTetsuo Handa * @is_delete: True if it is a delete request. 1387a1f9bb6aSTetsuo Handa * 1388a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 1389a1f9bb6aSTetsuo Handa * 1390a1f9bb6aSTetsuo Handa * Caller holds tomoyo_read_lock(). 1391a1f9bb6aSTetsuo Handa */ 1392a1f9bb6aSTetsuo Handa int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, 1393a1f9bb6aSTetsuo Handa const bool is_delete) 1394a1f9bb6aSTetsuo Handa { 1395a1f9bb6aSTetsuo Handa char *w[5]; 1396a1f9bb6aSTetsuo Handa u8 type; 1397a1f9bb6aSTetsuo Handa if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0]) 1398a1f9bb6aSTetsuo Handa return -EINVAL; 1399237ab459STetsuo Handa if (strncmp(w[0], "allow_", 6)) 1400a1f9bb6aSTetsuo Handa goto out; 1401a1f9bb6aSTetsuo Handa w[0] += 6; 1402a1f9bb6aSTetsuo Handa for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) { 1403a1f9bb6aSTetsuo Handa if (strcmp(w[0], tomoyo_path_keyword[type])) 1404a1f9bb6aSTetsuo Handa continue; 1405a1f9bb6aSTetsuo Handa return tomoyo_update_path_acl(type, w[1], domain, is_delete); 1406a1f9bb6aSTetsuo Handa } 1407a1f9bb6aSTetsuo Handa if (!w[2][0]) 1408a1f9bb6aSTetsuo Handa goto out; 1409a1f9bb6aSTetsuo Handa for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) { 1410a1f9bb6aSTetsuo Handa if (strcmp(w[0], tomoyo_path2_keyword[type])) 1411a1f9bb6aSTetsuo Handa continue; 1412a1f9bb6aSTetsuo Handa return tomoyo_update_path2_acl(type, w[1], w[2], domain, 1413a1f9bb6aSTetsuo Handa is_delete); 1414a1f9bb6aSTetsuo Handa } 1415a1f9bb6aSTetsuo Handa for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) { 1416a1f9bb6aSTetsuo Handa if (strcmp(w[0], tomoyo_path_number_keyword[type])) 1417a1f9bb6aSTetsuo Handa continue; 1418a1f9bb6aSTetsuo Handa return tomoyo_update_path_number_acl(type, w[1], w[2], domain, 1419a1f9bb6aSTetsuo Handa is_delete); 1420a1f9bb6aSTetsuo Handa } 1421a1f9bb6aSTetsuo Handa if (!w[3][0] || !w[4][0]) 1422a1f9bb6aSTetsuo Handa goto out; 142375093152STetsuo Handa for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++) { 142475093152STetsuo Handa if (strcmp(w[0], tomoyo_mkdev_keyword[type])) 1425a1f9bb6aSTetsuo Handa continue; 142675093152STetsuo Handa return tomoyo_update_mkdev_acl(type, w[1], w[2], w[3], 1427a1f9bb6aSTetsuo Handa w[4], domain, is_delete); 1428a1f9bb6aSTetsuo Handa } 1429a1f9bb6aSTetsuo Handa out: 1430a1f9bb6aSTetsuo Handa return -EINVAL; 1431a1f9bb6aSTetsuo Handa } 1432