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 120df7e8b8STetsuo Handa /* 130df7e8b8STetsuo Handa * Mapping table from "enum tomoyo_path_acl_index" to "enum tomoyo_mac_index". 140df7e8b8STetsuo Handa */ 1557c2590fSTetsuo Handa static const u8 tomoyo_p2mac[TOMOYO_MAX_PATH_OPERATION] = { 1657c2590fSTetsuo Handa [TOMOYO_TYPE_EXECUTE] = TOMOYO_MAC_FILE_EXECUTE, 1757c2590fSTetsuo Handa [TOMOYO_TYPE_READ] = TOMOYO_MAC_FILE_OPEN, 1857c2590fSTetsuo Handa [TOMOYO_TYPE_WRITE] = TOMOYO_MAC_FILE_OPEN, 197c75964fSTetsuo Handa [TOMOYO_TYPE_APPEND] = TOMOYO_MAC_FILE_OPEN, 2057c2590fSTetsuo Handa [TOMOYO_TYPE_UNLINK] = TOMOYO_MAC_FILE_UNLINK, 217c75964fSTetsuo Handa [TOMOYO_TYPE_GETATTR] = TOMOYO_MAC_FILE_GETATTR, 2257c2590fSTetsuo Handa [TOMOYO_TYPE_RMDIR] = TOMOYO_MAC_FILE_RMDIR, 2357c2590fSTetsuo Handa [TOMOYO_TYPE_TRUNCATE] = TOMOYO_MAC_FILE_TRUNCATE, 2457c2590fSTetsuo Handa [TOMOYO_TYPE_SYMLINK] = TOMOYO_MAC_FILE_SYMLINK, 2557c2590fSTetsuo Handa [TOMOYO_TYPE_CHROOT] = TOMOYO_MAC_FILE_CHROOT, 2657c2590fSTetsuo Handa [TOMOYO_TYPE_UMOUNT] = TOMOYO_MAC_FILE_UMOUNT, 2757c2590fSTetsuo Handa }; 2857c2590fSTetsuo Handa 290df7e8b8STetsuo Handa /* 300df7e8b8STetsuo Handa * Mapping table from "enum tomoyo_mkdev_acl_index" to "enum tomoyo_mac_index". 310df7e8b8STetsuo Handa */ 320d2171d7STetsuo Handa const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION] = { 3357c2590fSTetsuo Handa [TOMOYO_TYPE_MKBLOCK] = TOMOYO_MAC_FILE_MKBLOCK, 3457c2590fSTetsuo Handa [TOMOYO_TYPE_MKCHAR] = TOMOYO_MAC_FILE_MKCHAR, 3557c2590fSTetsuo Handa }; 3657c2590fSTetsuo Handa 370df7e8b8STetsuo Handa /* 380df7e8b8STetsuo Handa * Mapping table from "enum tomoyo_path2_acl_index" to "enum tomoyo_mac_index". 390df7e8b8STetsuo Handa */ 400d2171d7STetsuo Handa const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION] = { 4157c2590fSTetsuo Handa [TOMOYO_TYPE_LINK] = TOMOYO_MAC_FILE_LINK, 4257c2590fSTetsuo Handa [TOMOYO_TYPE_RENAME] = TOMOYO_MAC_FILE_RENAME, 4357c2590fSTetsuo Handa [TOMOYO_TYPE_PIVOT_ROOT] = TOMOYO_MAC_FILE_PIVOT_ROOT, 4457c2590fSTetsuo Handa }; 4557c2590fSTetsuo Handa 460df7e8b8STetsuo Handa /* 470df7e8b8STetsuo Handa * Mapping table from "enum tomoyo_path_number_acl_index" to 480df7e8b8STetsuo Handa * "enum tomoyo_mac_index". 490df7e8b8STetsuo Handa */ 500d2171d7STetsuo Handa const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = { 5157c2590fSTetsuo Handa [TOMOYO_TYPE_CREATE] = TOMOYO_MAC_FILE_CREATE, 5257c2590fSTetsuo Handa [TOMOYO_TYPE_MKDIR] = TOMOYO_MAC_FILE_MKDIR, 5357c2590fSTetsuo Handa [TOMOYO_TYPE_MKFIFO] = TOMOYO_MAC_FILE_MKFIFO, 5457c2590fSTetsuo Handa [TOMOYO_TYPE_MKSOCK] = TOMOYO_MAC_FILE_MKSOCK, 5557c2590fSTetsuo Handa [TOMOYO_TYPE_IOCTL] = TOMOYO_MAC_FILE_IOCTL, 5657c2590fSTetsuo Handa [TOMOYO_TYPE_CHMOD] = TOMOYO_MAC_FILE_CHMOD, 5757c2590fSTetsuo Handa [TOMOYO_TYPE_CHOWN] = TOMOYO_MAC_FILE_CHOWN, 5857c2590fSTetsuo Handa [TOMOYO_TYPE_CHGRP] = TOMOYO_MAC_FILE_CHGRP, 5957c2590fSTetsuo Handa }; 6057c2590fSTetsuo Handa 610df7e8b8STetsuo Handa /** 620df7e8b8STetsuo Handa * tomoyo_put_name_union - Drop reference on "struct tomoyo_name_union". 630df7e8b8STetsuo Handa * 640df7e8b8STetsuo Handa * @ptr: Pointer to "struct tomoyo_name_union". 650df7e8b8STetsuo Handa * 660df7e8b8STetsuo Handa * Returns nothing. 670df7e8b8STetsuo Handa */ 687762fbffSTetsuo Handa void tomoyo_put_name_union(struct tomoyo_name_union *ptr) 697762fbffSTetsuo Handa { 70a98aa4deSTetsuo Handa tomoyo_put_group(ptr->group); 717762fbffSTetsuo Handa tomoyo_put_name(ptr->filename); 727762fbffSTetsuo Handa } 737762fbffSTetsuo Handa 740df7e8b8STetsuo Handa /** 750df7e8b8STetsuo Handa * tomoyo_compare_name_union - Check whether a name matches "struct tomoyo_name_union" or not. 760df7e8b8STetsuo Handa * 770df7e8b8STetsuo Handa * @name: Pointer to "struct tomoyo_path_info". 780df7e8b8STetsuo Handa * @ptr: Pointer to "struct tomoyo_name_union". 790df7e8b8STetsuo Handa * 800df7e8b8STetsuo Handa * Returns "struct tomoyo_path_info" if @name matches @ptr, NULL otherwise. 810df7e8b8STetsuo Handa */ 82484ca79cSTetsuo Handa const struct tomoyo_path_info * 83484ca79cSTetsuo Handa tomoyo_compare_name_union(const struct tomoyo_path_info *name, 847762fbffSTetsuo Handa const struct tomoyo_name_union *ptr) 857762fbffSTetsuo Handa { 860df7e8b8STetsuo Handa if (ptr->group) 873f629636STetsuo Handa return tomoyo_path_matches_group(name, ptr->group); 88484ca79cSTetsuo Handa if (tomoyo_path_matches_pattern(name, ptr->filename)) 89484ca79cSTetsuo Handa return ptr->filename; 90484ca79cSTetsuo Handa return NULL; 917762fbffSTetsuo Handa } 927762fbffSTetsuo Handa 930df7e8b8STetsuo Handa /** 940df7e8b8STetsuo Handa * tomoyo_put_number_union - Drop reference on "struct tomoyo_number_union". 950df7e8b8STetsuo Handa * 960df7e8b8STetsuo Handa * @ptr: Pointer to "struct tomoyo_number_union". 970df7e8b8STetsuo Handa * 980df7e8b8STetsuo Handa * Returns nothing. 990df7e8b8STetsuo Handa */ 1004c3e9e2dSTetsuo Handa void tomoyo_put_number_union(struct tomoyo_number_union *ptr) 1014c3e9e2dSTetsuo Handa { 102a98aa4deSTetsuo Handa tomoyo_put_group(ptr->group); 1034c3e9e2dSTetsuo Handa } 1044c3e9e2dSTetsuo Handa 1050df7e8b8STetsuo Handa /** 1060df7e8b8STetsuo Handa * tomoyo_compare_number_union - Check whether a value matches "struct tomoyo_number_union" or not. 1070df7e8b8STetsuo Handa * 1080df7e8b8STetsuo Handa * @value: Number to check. 1090df7e8b8STetsuo Handa * @ptr: Pointer to "struct tomoyo_number_union". 1100df7e8b8STetsuo Handa * 1110df7e8b8STetsuo Handa * Returns true if @value matches @ptr, false otherwise. 1120df7e8b8STetsuo Handa */ 1134c3e9e2dSTetsuo Handa bool tomoyo_compare_number_union(const unsigned long value, 1144c3e9e2dSTetsuo Handa const struct tomoyo_number_union *ptr) 1154c3e9e2dSTetsuo Handa { 1160df7e8b8STetsuo Handa if (ptr->group) 1174c3e9e2dSTetsuo Handa return tomoyo_number_matches_group(value, value, ptr->group); 1184c3e9e2dSTetsuo Handa return value >= ptr->values[0] && value <= ptr->values[1]; 1194c3e9e2dSTetsuo Handa } 1204c3e9e2dSTetsuo Handa 1210df7e8b8STetsuo Handa /** 1220df7e8b8STetsuo Handa * tomoyo_add_slash - Add trailing '/' if needed. 1230df7e8b8STetsuo Handa * 1240df7e8b8STetsuo Handa * @buf: Pointer to "struct tomoyo_path_info". 1250df7e8b8STetsuo Handa * 1260df7e8b8STetsuo Handa * Returns nothing. 1270df7e8b8STetsuo Handa * 1280df7e8b8STetsuo Handa * @buf must be generated by tomoyo_encode() because this function does not 1290df7e8b8STetsuo Handa * allocate memory for adding '/'. 1300df7e8b8STetsuo Handa */ 131c8c57e84STetsuo Handa static void tomoyo_add_slash(struct tomoyo_path_info *buf) 132c8c57e84STetsuo Handa { 133c8c57e84STetsuo Handa if (buf->is_dir) 134c8c57e84STetsuo Handa return; 135c8c57e84STetsuo Handa /* 136c8c57e84STetsuo Handa * This is OK because tomoyo_encode() reserves space for appending "/". 137c8c57e84STetsuo Handa */ 138c8c57e84STetsuo Handa strcat((char *) buf->name, "/"); 139c8c57e84STetsuo Handa tomoyo_fill_path_info(buf); 140c8c57e84STetsuo Handa } 141c8c57e84STetsuo Handa 142a1f9bb6aSTetsuo Handa /** 143c8c57e84STetsuo Handa * tomoyo_get_realpath - Get realpath. 144b69a54eeSKentaro Takeda * 145c8c57e84STetsuo Handa * @buf: Pointer to "struct tomoyo_path_info". 146b69a54eeSKentaro Takeda * @path: Pointer to "struct path". 147b69a54eeSKentaro Takeda * 148c8c57e84STetsuo Handa * Returns true on success, false otherwise. 149b69a54eeSKentaro Takeda */ 150c8c57e84STetsuo Handa static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path) 151b69a54eeSKentaro Takeda { 152c8c57e84STetsuo Handa buf->name = tomoyo_realpath_from_path(path); 153c8c57e84STetsuo Handa if (buf->name) { 154c8c57e84STetsuo Handa tomoyo_fill_path_info(buf); 155c8c57e84STetsuo Handa return true; 156b69a54eeSKentaro Takeda } 157c8c57e84STetsuo Handa return false; 158b69a54eeSKentaro Takeda } 159b69a54eeSKentaro Takeda 16099a85259STetsuo Handa /** 16199a85259STetsuo Handa * tomoyo_audit_path_log - Audit path request log. 16299a85259STetsuo Handa * 16399a85259STetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 16499a85259STetsuo Handa * 16599a85259STetsuo Handa * Returns 0 on success, negative value otherwise. 16699a85259STetsuo Handa */ 16799a85259STetsuo Handa static int tomoyo_audit_path_log(struct tomoyo_request_info *r) 16899a85259STetsuo Handa { 169eadd99ccSTetsuo Handa return tomoyo_supervisor(r, "file %s %s\n", tomoyo_path_keyword 170eadd99ccSTetsuo Handa [r->param.path.operation], 171eadd99ccSTetsuo Handa r->param.path.filename->name); 17299a85259STetsuo Handa } 17399a85259STetsuo Handa 17499a85259STetsuo Handa /** 17599a85259STetsuo Handa * tomoyo_audit_path2_log - Audit path/path request log. 17699a85259STetsuo Handa * 17799a85259STetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 17899a85259STetsuo Handa * 17999a85259STetsuo Handa * Returns 0 on success, negative value otherwise. 18099a85259STetsuo Handa */ 18199a85259STetsuo Handa static int tomoyo_audit_path2_log(struct tomoyo_request_info *r) 18299a85259STetsuo Handa { 1832c47ab93STetsuo Handa return tomoyo_supervisor(r, "file %s %s %s\n", tomoyo_mac_keywords 1842c47ab93STetsuo Handa [tomoyo_pp2mac[r->param.path2.operation]], 185eadd99ccSTetsuo Handa r->param.path2.filename1->name, 186eadd99ccSTetsuo Handa r->param.path2.filename2->name); 18799a85259STetsuo Handa } 18899a85259STetsuo Handa 18999a85259STetsuo Handa /** 19099a85259STetsuo Handa * tomoyo_audit_mkdev_log - Audit path/number/number/number request log. 19199a85259STetsuo Handa * 19299a85259STetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 19399a85259STetsuo Handa * 19499a85259STetsuo Handa * Returns 0 on success, negative value otherwise. 19599a85259STetsuo Handa */ 19699a85259STetsuo Handa static int tomoyo_audit_mkdev_log(struct tomoyo_request_info *r) 19799a85259STetsuo Handa { 198eadd99ccSTetsuo Handa return tomoyo_supervisor(r, "file %s %s 0%o %u %u\n", 1992c47ab93STetsuo Handa tomoyo_mac_keywords 2002c47ab93STetsuo Handa [tomoyo_pnnn2mac[r->param.mkdev.operation]], 201eadd99ccSTetsuo Handa r->param.mkdev.filename->name, 202eadd99ccSTetsuo Handa r->param.mkdev.mode, r->param.mkdev.major, 203eadd99ccSTetsuo Handa r->param.mkdev.minor); 20499a85259STetsuo Handa } 20599a85259STetsuo Handa 20699a85259STetsuo Handa /** 20799a85259STetsuo Handa * tomoyo_audit_path_number_log - Audit path/number request log. 20899a85259STetsuo Handa * 20999a85259STetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 21099a85259STetsuo Handa * 21199a85259STetsuo Handa * Returns 0 on success, negative value otherwise. 21299a85259STetsuo Handa */ 21399a85259STetsuo Handa static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r) 21499a85259STetsuo Handa { 21599a85259STetsuo Handa const u8 type = r->param.path_number.operation; 21699a85259STetsuo Handa u8 radix; 21799a85259STetsuo Handa char buffer[64]; 21899a85259STetsuo Handa switch (type) { 21999a85259STetsuo Handa case TOMOYO_TYPE_CREATE: 22099a85259STetsuo Handa case TOMOYO_TYPE_MKDIR: 22199a85259STetsuo Handa case TOMOYO_TYPE_MKFIFO: 22299a85259STetsuo Handa case TOMOYO_TYPE_MKSOCK: 22399a85259STetsuo Handa case TOMOYO_TYPE_CHMOD: 22499a85259STetsuo Handa radix = TOMOYO_VALUE_TYPE_OCTAL; 22599a85259STetsuo Handa break; 22699a85259STetsuo Handa case TOMOYO_TYPE_IOCTL: 22799a85259STetsuo Handa radix = TOMOYO_VALUE_TYPE_HEXADECIMAL; 22899a85259STetsuo Handa break; 22999a85259STetsuo Handa default: 23099a85259STetsuo Handa radix = TOMOYO_VALUE_TYPE_DECIMAL; 23199a85259STetsuo Handa break; 23299a85259STetsuo Handa } 23399a85259STetsuo Handa tomoyo_print_ulong(buffer, sizeof(buffer), r->param.path_number.number, 23499a85259STetsuo Handa radix); 2352c47ab93STetsuo Handa return tomoyo_supervisor(r, "file %s %s %s\n", tomoyo_mac_keywords 2362c47ab93STetsuo Handa [tomoyo_pn2mac[type]], 237eadd99ccSTetsuo Handa r->param.path_number.filename->name, buffer); 238b69a54eeSKentaro Takeda } 239b69a54eeSKentaro Takeda 2400df7e8b8STetsuo Handa /** 2410df7e8b8STetsuo Handa * tomoyo_check_path_acl - Check permission for path operation. 2420df7e8b8STetsuo Handa * 2430df7e8b8STetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 2440df7e8b8STetsuo Handa * @ptr: Pointer to "struct tomoyo_acl_info". 2450df7e8b8STetsuo Handa * 2460df7e8b8STetsuo Handa * Returns true if granted, false otherwise. 2470df7e8b8STetsuo Handa * 2480df7e8b8STetsuo Handa * To be able to use wildcard for domain transition, this function sets 2490df7e8b8STetsuo Handa * matching entry on success. Since the caller holds tomoyo_read_lock(), 2500df7e8b8STetsuo Handa * it is safe to set matching entry. 2510df7e8b8STetsuo Handa */ 252484ca79cSTetsuo Handa static bool tomoyo_check_path_acl(struct tomoyo_request_info *r, 25399a85259STetsuo Handa const struct tomoyo_acl_info *ptr) 254b69a54eeSKentaro Takeda { 25599a85259STetsuo Handa const struct tomoyo_path_acl *acl = container_of(ptr, typeof(*acl), 25699a85259STetsuo Handa head); 257484ca79cSTetsuo Handa if (acl->perm & (1 << r->param.path.operation)) { 258484ca79cSTetsuo Handa r->param.path.matched_path = 259484ca79cSTetsuo Handa tomoyo_compare_name_union(r->param.path.filename, 260484ca79cSTetsuo Handa &acl->name); 261484ca79cSTetsuo Handa return r->param.path.matched_path != NULL; 262484ca79cSTetsuo Handa } 263484ca79cSTetsuo Handa return false; 264b69a54eeSKentaro Takeda } 26599a85259STetsuo Handa 2660df7e8b8STetsuo Handa /** 2670df7e8b8STetsuo Handa * tomoyo_check_path_number_acl - Check permission for path number operation. 2680df7e8b8STetsuo Handa * 2690df7e8b8STetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 2700df7e8b8STetsuo Handa * @ptr: Pointer to "struct tomoyo_acl_info". 2710df7e8b8STetsuo Handa * 2720df7e8b8STetsuo Handa * Returns true if granted, false otherwise. 2730df7e8b8STetsuo Handa */ 274484ca79cSTetsuo Handa static bool tomoyo_check_path_number_acl(struct tomoyo_request_info *r, 27599a85259STetsuo Handa const struct tomoyo_acl_info *ptr) 27699a85259STetsuo Handa { 27799a85259STetsuo Handa const struct tomoyo_path_number_acl *acl = 27899a85259STetsuo Handa container_of(ptr, typeof(*acl), head); 27999a85259STetsuo Handa return (acl->perm & (1 << r->param.path_number.operation)) && 28099a85259STetsuo Handa tomoyo_compare_number_union(r->param.path_number.number, 28199a85259STetsuo Handa &acl->number) && 28299a85259STetsuo Handa tomoyo_compare_name_union(r->param.path_number.filename, 28399a85259STetsuo Handa &acl->name); 28499a85259STetsuo Handa } 28599a85259STetsuo Handa 2860df7e8b8STetsuo Handa /** 2870df7e8b8STetsuo Handa * tomoyo_check_path2_acl - Check permission for path path operation. 2880df7e8b8STetsuo Handa * 2890df7e8b8STetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 2900df7e8b8STetsuo Handa * @ptr: Pointer to "struct tomoyo_acl_info". 2910df7e8b8STetsuo Handa * 2920df7e8b8STetsuo Handa * Returns true if granted, false otherwise. 2930df7e8b8STetsuo Handa */ 294484ca79cSTetsuo Handa static bool tomoyo_check_path2_acl(struct tomoyo_request_info *r, 29599a85259STetsuo Handa const struct tomoyo_acl_info *ptr) 29699a85259STetsuo Handa { 29799a85259STetsuo Handa const struct tomoyo_path2_acl *acl = 29899a85259STetsuo Handa container_of(ptr, typeof(*acl), head); 29999a85259STetsuo Handa return (acl->perm & (1 << r->param.path2.operation)) && 30099a85259STetsuo Handa tomoyo_compare_name_union(r->param.path2.filename1, &acl->name1) 30199a85259STetsuo Handa && tomoyo_compare_name_union(r->param.path2.filename2, 30299a85259STetsuo Handa &acl->name2); 30399a85259STetsuo Handa } 30499a85259STetsuo Handa 3050df7e8b8STetsuo Handa /** 3060df7e8b8STetsuo Handa * tomoyo_check_mkdev_acl - Check permission for path number number number operation. 3070df7e8b8STetsuo Handa * 3080df7e8b8STetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 3090df7e8b8STetsuo Handa * @ptr: Pointer to "struct tomoyo_acl_info". 3100df7e8b8STetsuo Handa * 3110df7e8b8STetsuo Handa * Returns true if granted, false otherwise. 3120df7e8b8STetsuo Handa */ 313484ca79cSTetsuo Handa static bool tomoyo_check_mkdev_acl(struct tomoyo_request_info *r, 31499a85259STetsuo Handa const struct tomoyo_acl_info *ptr) 31599a85259STetsuo Handa { 31675093152STetsuo Handa const struct tomoyo_mkdev_acl *acl = 31799a85259STetsuo Handa container_of(ptr, typeof(*acl), head); 31899a85259STetsuo Handa return (acl->perm & (1 << r->param.mkdev.operation)) && 31999a85259STetsuo Handa tomoyo_compare_number_union(r->param.mkdev.mode, 32099a85259STetsuo Handa &acl->mode) && 32199a85259STetsuo Handa tomoyo_compare_number_union(r->param.mkdev.major, 32299a85259STetsuo Handa &acl->major) && 32399a85259STetsuo Handa tomoyo_compare_number_union(r->param.mkdev.minor, 32499a85259STetsuo Handa &acl->minor) && 32599a85259STetsuo Handa tomoyo_compare_name_union(r->param.mkdev.filename, 32699a85259STetsuo Handa &acl->name); 327b69a54eeSKentaro Takeda } 328b69a54eeSKentaro Takeda 3290df7e8b8STetsuo Handa /** 3300df7e8b8STetsuo Handa * tomoyo_same_path_acl - Check for duplicated "struct tomoyo_path_acl" entry. 3310df7e8b8STetsuo Handa * 3320df7e8b8STetsuo Handa * @a: Pointer to "struct tomoyo_acl_info". 3330df7e8b8STetsuo Handa * @b: Pointer to "struct tomoyo_acl_info". 3340df7e8b8STetsuo Handa * 3350df7e8b8STetsuo Handa * Returns true if @a == @b except permission bits, false otherwise. 3360df7e8b8STetsuo Handa */ 337237ab459STetsuo Handa static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a, 338237ab459STetsuo Handa const struct tomoyo_acl_info *b) 339237ab459STetsuo Handa { 340237ab459STetsuo Handa const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head); 341237ab459STetsuo Handa const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head); 3420df7e8b8STetsuo Handa return tomoyo_same_name_union(&p1->name, &p2->name); 343237ab459STetsuo Handa } 344237ab459STetsuo Handa 3457c75964fSTetsuo Handa /** 3467c75964fSTetsuo Handa * tomoyo_merge_path_acl - Merge duplicated "struct tomoyo_path_acl" entry. 3477c75964fSTetsuo Handa * 3487c75964fSTetsuo Handa * @a: Pointer to "struct tomoyo_acl_info". 3497c75964fSTetsuo Handa * @b: Pointer to "struct tomoyo_acl_info". 3507c75964fSTetsuo Handa * @is_delete: True for @a &= ~@b, false for @a |= @b. 3517c75964fSTetsuo Handa * 3527c75964fSTetsuo Handa * Returns true if @a is empty, false otherwise. 3537c75964fSTetsuo Handa */ 354237ab459STetsuo Handa static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a, 355237ab459STetsuo Handa struct tomoyo_acl_info *b, 356237ab459STetsuo Handa const bool is_delete) 357237ab459STetsuo Handa { 358237ab459STetsuo Handa u16 * const a_perm = &container_of(a, struct tomoyo_path_acl, head) 359237ab459STetsuo Handa ->perm; 360237ab459STetsuo Handa u16 perm = *a_perm; 361237ab459STetsuo Handa const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm; 3627c75964fSTetsuo Handa if (is_delete) 363237ab459STetsuo Handa perm &= ~b_perm; 3647c75964fSTetsuo Handa else 365237ab459STetsuo Handa perm |= b_perm; 366237ab459STetsuo Handa *a_perm = perm; 367237ab459STetsuo Handa return !perm; 368237ab459STetsuo Handa } 369237ab459STetsuo Handa 370b69a54eeSKentaro Takeda /** 3717ef61233STetsuo Handa * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list. 372b69a54eeSKentaro Takeda * 373a238cf5bSTetsuo Handa * @perm: Permission. 374a238cf5bSTetsuo Handa * @param: Pointer to "struct tomoyo_acl_param". 375b69a54eeSKentaro Takeda * 376b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 377fdb8ebb7STetsuo Handa * 378fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 379b69a54eeSKentaro Takeda */ 380a238cf5bSTetsuo Handa static int tomoyo_update_path_acl(const u16 perm, 381a238cf5bSTetsuo Handa struct tomoyo_acl_param *param) 382b69a54eeSKentaro Takeda { 3839e4b50e9STetsuo Handa struct tomoyo_path_acl e = { 3849e4b50e9STetsuo Handa .head.type = TOMOYO_TYPE_PATH_ACL, 385a238cf5bSTetsuo Handa .perm = perm 3869e4b50e9STetsuo Handa }; 387237ab459STetsuo Handa int error; 388a238cf5bSTetsuo Handa if (!tomoyo_parse_name_union(param, &e.name)) 389a238cf5bSTetsuo Handa error = -EINVAL; 390a238cf5bSTetsuo Handa else 391a238cf5bSTetsuo Handa error = tomoyo_update_domain(&e.head, sizeof(e), param, 392237ab459STetsuo Handa tomoyo_same_path_acl, 393237ab459STetsuo Handa tomoyo_merge_path_acl); 3947762fbffSTetsuo Handa tomoyo_put_name_union(&e.name); 395b69a54eeSKentaro Takeda return error; 396b69a54eeSKentaro Takeda } 397b69a54eeSKentaro Takeda 3980df7e8b8STetsuo Handa /** 3990df7e8b8STetsuo Handa * tomoyo_same_mkdev_acl - Check for duplicated "struct tomoyo_mkdev_acl" entry. 4000df7e8b8STetsuo Handa * 4010df7e8b8STetsuo Handa * @a: Pointer to "struct tomoyo_acl_info". 4020df7e8b8STetsuo Handa * @b: Pointer to "struct tomoyo_acl_info". 4030df7e8b8STetsuo Handa * 4040df7e8b8STetsuo Handa * Returns true if @a == @b except permission bits, false otherwise. 4050df7e8b8STetsuo Handa */ 40675093152STetsuo Handa static bool tomoyo_same_mkdev_acl(const struct tomoyo_acl_info *a, 407237ab459STetsuo Handa const struct tomoyo_acl_info *b) 408237ab459STetsuo Handa { 4090df7e8b8STetsuo Handa const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1), head); 4100df7e8b8STetsuo Handa const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2), head); 4110df7e8b8STetsuo Handa return tomoyo_same_name_union(&p1->name, &p2->name) && 4120df7e8b8STetsuo Handa tomoyo_same_number_union(&p1->mode, &p2->mode) && 4130df7e8b8STetsuo Handa tomoyo_same_number_union(&p1->major, &p2->major) && 4140df7e8b8STetsuo Handa tomoyo_same_number_union(&p1->minor, &p2->minor); 415237ab459STetsuo Handa } 416237ab459STetsuo Handa 4170df7e8b8STetsuo Handa /** 4180df7e8b8STetsuo Handa * tomoyo_merge_mkdev_acl - Merge duplicated "struct tomoyo_mkdev_acl" entry. 4190df7e8b8STetsuo Handa * 4200df7e8b8STetsuo Handa * @a: Pointer to "struct tomoyo_acl_info". 4210df7e8b8STetsuo Handa * @b: Pointer to "struct tomoyo_acl_info". 4220df7e8b8STetsuo Handa * @is_delete: True for @a &= ~@b, false for @a |= @b. 4230df7e8b8STetsuo Handa * 4240df7e8b8STetsuo Handa * Returns true if @a is empty, false otherwise. 4250df7e8b8STetsuo Handa */ 42675093152STetsuo Handa static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a, 427237ab459STetsuo Handa struct tomoyo_acl_info *b, 428237ab459STetsuo Handa const bool is_delete) 429237ab459STetsuo Handa { 43075093152STetsuo Handa u8 *const a_perm = &container_of(a, struct tomoyo_mkdev_acl, 431237ab459STetsuo Handa head)->perm; 432237ab459STetsuo Handa u8 perm = *a_perm; 43375093152STetsuo Handa const u8 b_perm = container_of(b, struct tomoyo_mkdev_acl, head) 434237ab459STetsuo Handa ->perm; 435237ab459STetsuo Handa if (is_delete) 436237ab459STetsuo Handa perm &= ~b_perm; 437237ab459STetsuo Handa else 438237ab459STetsuo Handa perm |= b_perm; 439237ab459STetsuo Handa *a_perm = perm; 440237ab459STetsuo Handa return !perm; 441237ab459STetsuo Handa } 442237ab459STetsuo Handa 443b69a54eeSKentaro Takeda /** 44475093152STetsuo Handa * tomoyo_update_mkdev_acl - Update "struct tomoyo_mkdev_acl" list. 445a1f9bb6aSTetsuo Handa * 446a238cf5bSTetsuo Handa * @perm: Permission. 447a238cf5bSTetsuo Handa * @param: Pointer to "struct tomoyo_acl_param". 448a1f9bb6aSTetsuo Handa * 449a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 450237ab459STetsuo Handa * 451237ab459STetsuo Handa * Caller holds tomoyo_read_lock(). 452a1f9bb6aSTetsuo Handa */ 453a238cf5bSTetsuo Handa static int tomoyo_update_mkdev_acl(const u8 perm, 454a238cf5bSTetsuo Handa struct tomoyo_acl_param *param) 455a1f9bb6aSTetsuo Handa { 45675093152STetsuo Handa struct tomoyo_mkdev_acl e = { 45775093152STetsuo Handa .head.type = TOMOYO_TYPE_MKDEV_ACL, 458a238cf5bSTetsuo Handa .perm = perm 459a1f9bb6aSTetsuo Handa }; 460a238cf5bSTetsuo Handa int error; 461a238cf5bSTetsuo Handa if (!tomoyo_parse_name_union(param, &e.name) || 462a238cf5bSTetsuo Handa !tomoyo_parse_number_union(param, &e.mode) || 463a238cf5bSTetsuo Handa !tomoyo_parse_number_union(param, &e.major) || 464a238cf5bSTetsuo Handa !tomoyo_parse_number_union(param, &e.minor)) 465a238cf5bSTetsuo Handa error = -EINVAL; 466a238cf5bSTetsuo Handa else 467a238cf5bSTetsuo Handa error = tomoyo_update_domain(&e.head, sizeof(e), param, 46875093152STetsuo Handa tomoyo_same_mkdev_acl, 46975093152STetsuo Handa tomoyo_merge_mkdev_acl); 470a1f9bb6aSTetsuo Handa tomoyo_put_name_union(&e.name); 471a1f9bb6aSTetsuo Handa tomoyo_put_number_union(&e.mode); 472a1f9bb6aSTetsuo Handa tomoyo_put_number_union(&e.major); 473a1f9bb6aSTetsuo Handa tomoyo_put_number_union(&e.minor); 474a1f9bb6aSTetsuo Handa return error; 475a1f9bb6aSTetsuo Handa } 476a1f9bb6aSTetsuo Handa 4770df7e8b8STetsuo Handa /** 4780df7e8b8STetsuo Handa * tomoyo_same_path2_acl - Check for duplicated "struct tomoyo_path2_acl" entry. 4790df7e8b8STetsuo Handa * 4800df7e8b8STetsuo Handa * @a: Pointer to "struct tomoyo_acl_info". 4810df7e8b8STetsuo Handa * @b: Pointer to "struct tomoyo_acl_info". 4820df7e8b8STetsuo Handa * 4830df7e8b8STetsuo Handa * Returns true if @a == @b except permission bits, false otherwise. 4840df7e8b8STetsuo Handa */ 485237ab459STetsuo Handa static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a, 486237ab459STetsuo Handa const struct tomoyo_acl_info *b) 487237ab459STetsuo Handa { 488237ab459STetsuo Handa const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head); 489237ab459STetsuo Handa const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head); 4900df7e8b8STetsuo Handa return tomoyo_same_name_union(&p1->name1, &p2->name1) && 4910df7e8b8STetsuo Handa tomoyo_same_name_union(&p1->name2, &p2->name2); 492237ab459STetsuo Handa } 493237ab459STetsuo Handa 4940df7e8b8STetsuo Handa /** 4950df7e8b8STetsuo Handa * tomoyo_merge_path2_acl - Merge duplicated "struct tomoyo_path2_acl" entry. 4960df7e8b8STetsuo Handa * 4970df7e8b8STetsuo Handa * @a: Pointer to "struct tomoyo_acl_info". 4980df7e8b8STetsuo Handa * @b: Pointer to "struct tomoyo_acl_info". 4990df7e8b8STetsuo Handa * @is_delete: True for @a &= ~@b, false for @a |= @b. 5000df7e8b8STetsuo Handa * 5010df7e8b8STetsuo Handa * Returns true if @a is empty, false otherwise. 5020df7e8b8STetsuo Handa */ 503237ab459STetsuo Handa static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a, 504237ab459STetsuo Handa struct tomoyo_acl_info *b, 505237ab459STetsuo Handa const bool is_delete) 506237ab459STetsuo Handa { 507237ab459STetsuo Handa u8 * const a_perm = &container_of(a, struct tomoyo_path2_acl, head) 508237ab459STetsuo Handa ->perm; 509237ab459STetsuo Handa u8 perm = *a_perm; 510237ab459STetsuo Handa const u8 b_perm = container_of(b, struct tomoyo_path2_acl, head)->perm; 511237ab459STetsuo Handa if (is_delete) 512237ab459STetsuo Handa perm &= ~b_perm; 513237ab459STetsuo Handa else 514237ab459STetsuo Handa perm |= b_perm; 515237ab459STetsuo Handa *a_perm = perm; 516237ab459STetsuo Handa return !perm; 517237ab459STetsuo Handa } 518237ab459STetsuo Handa 519a1f9bb6aSTetsuo Handa /** 5207ef61233STetsuo Handa * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list. 521b69a54eeSKentaro Takeda * 522a238cf5bSTetsuo Handa * @perm: Permission. 523a238cf5bSTetsuo Handa * @param: Pointer to "struct tomoyo_acl_param". 524b69a54eeSKentaro Takeda * 525b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 526fdb8ebb7STetsuo Handa * 527fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 528b69a54eeSKentaro Takeda */ 529a238cf5bSTetsuo Handa static int tomoyo_update_path2_acl(const u8 perm, 530a238cf5bSTetsuo Handa struct tomoyo_acl_param *param) 531b69a54eeSKentaro Takeda { 5329e4b50e9STetsuo Handa struct tomoyo_path2_acl e = { 5339e4b50e9STetsuo Handa .head.type = TOMOYO_TYPE_PATH2_ACL, 534a238cf5bSTetsuo Handa .perm = perm 5359e4b50e9STetsuo Handa }; 536a238cf5bSTetsuo Handa int error; 537a238cf5bSTetsuo Handa if (!tomoyo_parse_name_union(param, &e.name1) || 538a238cf5bSTetsuo Handa !tomoyo_parse_name_union(param, &e.name2)) 539a238cf5bSTetsuo Handa error = -EINVAL; 540a238cf5bSTetsuo Handa else 541a238cf5bSTetsuo Handa error = tomoyo_update_domain(&e.head, sizeof(e), param, 542237ab459STetsuo Handa tomoyo_same_path2_acl, 543237ab459STetsuo Handa tomoyo_merge_path2_acl); 5447762fbffSTetsuo Handa tomoyo_put_name_union(&e.name1); 5457762fbffSTetsuo Handa tomoyo_put_name_union(&e.name2); 546b69a54eeSKentaro Takeda return error; 547b69a54eeSKentaro Takeda } 548b69a54eeSKentaro Takeda 549b69a54eeSKentaro Takeda /** 550cb0abe6aSTetsuo Handa * tomoyo_path_permission - Check permission for single path operation. 551b69a54eeSKentaro Takeda * 552cb0abe6aSTetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 553b69a54eeSKentaro Takeda * @operation: Type of operation. 554b69a54eeSKentaro Takeda * @filename: Filename to check. 555b69a54eeSKentaro Takeda * 556b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 557fdb8ebb7STetsuo Handa * 558fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 559b69a54eeSKentaro Takeda */ 56005336deeSTetsuo Handa int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, 561cb0abe6aSTetsuo Handa const struct tomoyo_path_info *filename) 562b69a54eeSKentaro Takeda { 563b69a54eeSKentaro Takeda int error; 564b69a54eeSKentaro Takeda 56557c2590fSTetsuo Handa r->type = tomoyo_p2mac[operation]; 566bd03a3e4STetsuo Handa r->mode = tomoyo_get_mode(r->domain->ns, r->profile, r->type); 56757c2590fSTetsuo Handa if (r->mode == TOMOYO_CONFIG_DISABLED) 56857c2590fSTetsuo Handa return 0; 569cf6e9a64STetsuo Handa r->param_type = TOMOYO_TYPE_PATH_ACL; 570cf6e9a64STetsuo Handa r->param.path.filename = filename; 571cf6e9a64STetsuo Handa r->param.path.operation = operation; 57217fcfbd9STetsuo Handa do { 57399a85259STetsuo Handa tomoyo_check_acl(r, tomoyo_check_path_acl); 57499a85259STetsuo Handa error = tomoyo_audit_path_log(r); 57505336deeSTetsuo Handa /* 57605336deeSTetsuo Handa * Do not retry for execute request, for alias may have 57705336deeSTetsuo Handa * changed. 57805336deeSTetsuo Handa */ 57905336deeSTetsuo Handa } while (error == TOMOYO_RETRY_REQUEST && 58005336deeSTetsuo Handa operation != TOMOYO_TYPE_EXECUTE); 581b69a54eeSKentaro Takeda return error; 582b69a54eeSKentaro Takeda } 583b69a54eeSKentaro Takeda 5840df7e8b8STetsuo Handa /** 5850df7e8b8STetsuo Handa * tomoyo_same_path_number_acl - Check for duplicated "struct tomoyo_path_number_acl" entry. 5860df7e8b8STetsuo Handa * 5870df7e8b8STetsuo Handa * @a: Pointer to "struct tomoyo_acl_info". 5880df7e8b8STetsuo Handa * @b: Pointer to "struct tomoyo_acl_info". 5890df7e8b8STetsuo Handa * 5900df7e8b8STetsuo Handa * Returns true if @a == @b except permission bits, false otherwise. 5910df7e8b8STetsuo Handa */ 592237ab459STetsuo Handa static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a, 593237ab459STetsuo Handa const struct tomoyo_acl_info *b) 594237ab459STetsuo Handa { 595237ab459STetsuo Handa const struct tomoyo_path_number_acl *p1 = container_of(a, typeof(*p1), 596237ab459STetsuo Handa head); 597237ab459STetsuo Handa const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2), 598237ab459STetsuo Handa head); 5990df7e8b8STetsuo Handa return tomoyo_same_name_union(&p1->name, &p2->name) && 6000df7e8b8STetsuo Handa tomoyo_same_number_union(&p1->number, &p2->number); 601237ab459STetsuo Handa } 602237ab459STetsuo Handa 6030df7e8b8STetsuo Handa /** 6040df7e8b8STetsuo Handa * tomoyo_merge_path_number_acl - Merge duplicated "struct tomoyo_path_number_acl" entry. 6050df7e8b8STetsuo Handa * 6060df7e8b8STetsuo Handa * @a: Pointer to "struct tomoyo_acl_info". 6070df7e8b8STetsuo Handa * @b: Pointer to "struct tomoyo_acl_info". 6080df7e8b8STetsuo Handa * @is_delete: True for @a &= ~@b, false for @a |= @b. 6090df7e8b8STetsuo Handa * 6100df7e8b8STetsuo Handa * Returns true if @a is empty, false otherwise. 6110df7e8b8STetsuo Handa */ 612237ab459STetsuo Handa static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a, 613237ab459STetsuo Handa struct tomoyo_acl_info *b, 614237ab459STetsuo Handa const bool is_delete) 615237ab459STetsuo Handa { 616237ab459STetsuo Handa u8 * const a_perm = &container_of(a, struct tomoyo_path_number_acl, 617237ab459STetsuo Handa head)->perm; 618237ab459STetsuo Handa u8 perm = *a_perm; 619237ab459STetsuo Handa const u8 b_perm = container_of(b, struct tomoyo_path_number_acl, head) 620237ab459STetsuo Handa ->perm; 621237ab459STetsuo Handa if (is_delete) 622237ab459STetsuo Handa perm &= ~b_perm; 623237ab459STetsuo Handa else 624237ab459STetsuo Handa perm |= b_perm; 625237ab459STetsuo Handa *a_perm = perm; 626237ab459STetsuo Handa return !perm; 627237ab459STetsuo Handa } 628237ab459STetsuo Handa 629a1f9bb6aSTetsuo Handa /** 630a1f9bb6aSTetsuo Handa * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL. 631a1f9bb6aSTetsuo Handa * 632a238cf5bSTetsuo Handa * @perm: Permission. 633a238cf5bSTetsuo Handa * @param: Pointer to "struct tomoyo_acl_param". 634a1f9bb6aSTetsuo Handa * 635a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 636a1f9bb6aSTetsuo Handa */ 637a238cf5bSTetsuo Handa static int tomoyo_update_path_number_acl(const u8 perm, 638a238cf5bSTetsuo Handa struct tomoyo_acl_param *param) 639a1f9bb6aSTetsuo Handa { 640a1f9bb6aSTetsuo Handa struct tomoyo_path_number_acl e = { 641a1f9bb6aSTetsuo Handa .head.type = TOMOYO_TYPE_PATH_NUMBER_ACL, 642a238cf5bSTetsuo Handa .perm = perm 643a1f9bb6aSTetsuo Handa }; 644a238cf5bSTetsuo Handa int error; 645a238cf5bSTetsuo Handa if (!tomoyo_parse_name_union(param, &e.name) || 646a238cf5bSTetsuo Handa !tomoyo_parse_number_union(param, &e.number)) 647a238cf5bSTetsuo Handa error = -EINVAL; 648a238cf5bSTetsuo Handa else 649a238cf5bSTetsuo Handa error = tomoyo_update_domain(&e.head, sizeof(e), param, 650237ab459STetsuo Handa tomoyo_same_path_number_acl, 651237ab459STetsuo Handa tomoyo_merge_path_number_acl); 652a1f9bb6aSTetsuo Handa tomoyo_put_name_union(&e.name); 653a1f9bb6aSTetsuo Handa tomoyo_put_number_union(&e.number); 654a1f9bb6aSTetsuo Handa return error; 655a1f9bb6aSTetsuo Handa } 656a1f9bb6aSTetsuo Handa 657a1f9bb6aSTetsuo Handa /** 658a1f9bb6aSTetsuo Handa * tomoyo_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp". 659a1f9bb6aSTetsuo Handa * 660a1f9bb6aSTetsuo Handa * @type: Type of operation. 661a1f9bb6aSTetsuo Handa * @path: Pointer to "struct path". 662a1f9bb6aSTetsuo Handa * @number: Number. 663a1f9bb6aSTetsuo Handa * 664a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 665a1f9bb6aSTetsuo Handa */ 666a1f9bb6aSTetsuo Handa int tomoyo_path_number_perm(const u8 type, struct path *path, 667a1f9bb6aSTetsuo Handa unsigned long number) 668a1f9bb6aSTetsuo Handa { 669a1f9bb6aSTetsuo Handa struct tomoyo_request_info r; 670a1f9bb6aSTetsuo Handa int error = -ENOMEM; 671c8c57e84STetsuo Handa struct tomoyo_path_info buf; 672a1f9bb6aSTetsuo Handa int idx; 673a1f9bb6aSTetsuo Handa 67457c2590fSTetsuo Handa if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type]) 6755625f2e3STetsuo Handa == TOMOYO_CONFIG_DISABLED || !path->dentry) 676a1f9bb6aSTetsuo Handa return 0; 677a1f9bb6aSTetsuo Handa idx = tomoyo_read_lock(); 678c8c57e84STetsuo Handa if (!tomoyo_get_realpath(&buf, path)) 679a1f9bb6aSTetsuo Handa goto out; 680c8c57e84STetsuo Handa if (type == TOMOYO_TYPE_MKDIR) 681c8c57e84STetsuo Handa tomoyo_add_slash(&buf); 682cb917cf5STetsuo Handa r.param_type = TOMOYO_TYPE_PATH_NUMBER_ACL; 683cb917cf5STetsuo Handa r.param.path_number.operation = type; 684cb917cf5STetsuo Handa r.param.path_number.filename = &buf; 685cb917cf5STetsuo Handa r.param.path_number.number = number; 686cb917cf5STetsuo Handa do { 687cb917cf5STetsuo Handa tomoyo_check_acl(&r, tomoyo_check_path_number_acl); 688cb917cf5STetsuo Handa error = tomoyo_audit_path_number_log(&r); 689cb917cf5STetsuo Handa } while (error == TOMOYO_RETRY_REQUEST); 690c8c57e84STetsuo Handa kfree(buf.name); 691cb917cf5STetsuo Handa out: 692a1f9bb6aSTetsuo Handa tomoyo_read_unlock(idx); 693a1f9bb6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 694a1f9bb6aSTetsuo Handa error = 0; 695a1f9bb6aSTetsuo Handa return error; 696a1f9bb6aSTetsuo Handa } 697a1f9bb6aSTetsuo Handa 698a1f9bb6aSTetsuo Handa /** 699b69a54eeSKentaro Takeda * tomoyo_check_open_permission - Check permission for "read" and "write". 700b69a54eeSKentaro Takeda * 701b69a54eeSKentaro Takeda * @domain: Pointer to "struct tomoyo_domain_info". 702b69a54eeSKentaro Takeda * @path: Pointer to "struct path". 703b69a54eeSKentaro Takeda * @flag: Flags for open(). 704b69a54eeSKentaro Takeda * 705b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 706b69a54eeSKentaro Takeda */ 707b69a54eeSKentaro Takeda int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, 708b69a54eeSKentaro Takeda struct path *path, const int flag) 709b69a54eeSKentaro Takeda { 710b69a54eeSKentaro Takeda const u8 acc_mode = ACC_MODE(flag); 711eae61f3cSTetsuo Handa int error = 0; 712c8c57e84STetsuo Handa struct tomoyo_path_info buf; 713cb0abe6aSTetsuo Handa struct tomoyo_request_info r; 714fdb8ebb7STetsuo Handa int idx; 715b69a54eeSKentaro Takeda 71657c2590fSTetsuo Handa buf.name = NULL; 71757c2590fSTetsuo Handa r.mode = TOMOYO_CONFIG_DISABLED; 718fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 7197c75964fSTetsuo Handa if (acc_mode && 7207c75964fSTetsuo Handa tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN) 72157c2590fSTetsuo Handa != TOMOYO_CONFIG_DISABLED) { 72257c2590fSTetsuo Handa if (!tomoyo_get_realpath(&buf, path)) { 72357c2590fSTetsuo Handa error = -ENOMEM; 72457c2590fSTetsuo Handa goto out; 725b69a54eeSKentaro Takeda } 7267c75964fSTetsuo Handa if (acc_mode & MAY_READ) 7277c75964fSTetsuo Handa error = tomoyo_path_permission(&r, TOMOYO_TYPE_READ, 72857c2590fSTetsuo Handa &buf); 7297c75964fSTetsuo Handa if (!error && (acc_mode & MAY_WRITE)) 7307c75964fSTetsuo Handa error = tomoyo_path_permission(&r, (flag & O_APPEND) ? 7317c75964fSTetsuo Handa TOMOYO_TYPE_APPEND : 7327c75964fSTetsuo Handa TOMOYO_TYPE_WRITE, 7337c75964fSTetsuo Handa &buf); 73457c2590fSTetsuo Handa } 735b69a54eeSKentaro Takeda out: 736c8c57e84STetsuo Handa kfree(buf.name); 737fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 738cb0abe6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 739b69a54eeSKentaro Takeda error = 0; 740b69a54eeSKentaro Takeda return error; 741b69a54eeSKentaro Takeda } 742b69a54eeSKentaro Takeda 743b69a54eeSKentaro Takeda /** 7447c75964fSTetsuo Handa * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "append", "chroot" and "unmount". 745b69a54eeSKentaro Takeda * 746b69a54eeSKentaro Takeda * @operation: Type of operation. 747b69a54eeSKentaro Takeda * @path: Pointer to "struct path". 748b69a54eeSKentaro Takeda * 749b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 750b69a54eeSKentaro Takeda */ 75197d6931eSTetsuo Handa int tomoyo_path_perm(const u8 operation, struct path *path) 752b69a54eeSKentaro Takeda { 753cb0abe6aSTetsuo Handa struct tomoyo_request_info r; 7547c75964fSTetsuo Handa int error; 7557c75964fSTetsuo Handa struct tomoyo_path_info buf; 7567c75964fSTetsuo Handa bool is_enforce; 757fdb8ebb7STetsuo Handa int idx; 758b69a54eeSKentaro Takeda 75957c2590fSTetsuo Handa if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation]) 76057c2590fSTetsuo Handa == TOMOYO_CONFIG_DISABLED) 76157c2590fSTetsuo Handa return 0; 7627c75964fSTetsuo Handa is_enforce = (r.mode == TOMOYO_CONFIG_ENFORCING); 7637c75964fSTetsuo Handa error = -ENOMEM; 76457c2590fSTetsuo Handa buf.name = NULL; 765fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 766c8c57e84STetsuo Handa if (!tomoyo_get_realpath(&buf, path)) 767b69a54eeSKentaro Takeda goto out; 768b69a54eeSKentaro Takeda switch (operation) { 7697ef61233STetsuo Handa case TOMOYO_TYPE_RMDIR: 7707ef61233STetsuo Handa case TOMOYO_TYPE_CHROOT: 771c8c57e84STetsuo Handa tomoyo_add_slash(&buf); 772c8c57e84STetsuo Handa break; 773b69a54eeSKentaro Takeda } 774c8c57e84STetsuo Handa error = tomoyo_path_permission(&r, operation, &buf); 775b69a54eeSKentaro Takeda out: 776c8c57e84STetsuo Handa kfree(buf.name); 777fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 7787c75964fSTetsuo Handa if (!is_enforce) 779b69a54eeSKentaro Takeda error = 0; 780b69a54eeSKentaro Takeda return error; 781b69a54eeSKentaro Takeda } 782b69a54eeSKentaro Takeda 783b69a54eeSKentaro Takeda /** 78475093152STetsuo Handa * tomoyo_mkdev_perm - Check permission for "mkblock" and "mkchar". 785a1f9bb6aSTetsuo Handa * 786a1f9bb6aSTetsuo Handa * @operation: Type of operation. (TOMOYO_TYPE_MKCHAR or TOMOYO_TYPE_MKBLOCK) 787a1f9bb6aSTetsuo Handa * @path: Pointer to "struct path". 788a1f9bb6aSTetsuo Handa * @mode: Create mode. 789a1f9bb6aSTetsuo Handa * @dev: Device number. 790a1f9bb6aSTetsuo Handa * 791a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 792a1f9bb6aSTetsuo Handa */ 79375093152STetsuo Handa int tomoyo_mkdev_perm(const u8 operation, struct path *path, 794a1f9bb6aSTetsuo Handa const unsigned int mode, unsigned int dev) 795a1f9bb6aSTetsuo Handa { 796a1f9bb6aSTetsuo Handa struct tomoyo_request_info r; 797a1f9bb6aSTetsuo Handa int error = -ENOMEM; 798c8c57e84STetsuo Handa struct tomoyo_path_info buf; 799a1f9bb6aSTetsuo Handa int idx; 800a1f9bb6aSTetsuo Handa 8015625f2e3STetsuo Handa if (tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation]) 80257c2590fSTetsuo Handa == TOMOYO_CONFIG_DISABLED) 803a1f9bb6aSTetsuo Handa return 0; 804a1f9bb6aSTetsuo Handa idx = tomoyo_read_lock(); 805a1f9bb6aSTetsuo Handa error = -ENOMEM; 806c8c57e84STetsuo Handa if (tomoyo_get_realpath(&buf, path)) { 807cf6e9a64STetsuo Handa dev = new_decode_dev(dev); 80875093152STetsuo Handa r.param_type = TOMOYO_TYPE_MKDEV_ACL; 809cf6e9a64STetsuo Handa r.param.mkdev.filename = &buf; 810cf6e9a64STetsuo Handa r.param.mkdev.operation = operation; 811cf6e9a64STetsuo Handa r.param.mkdev.mode = mode; 812cf6e9a64STetsuo Handa r.param.mkdev.major = MAJOR(dev); 813cf6e9a64STetsuo Handa r.param.mkdev.minor = MINOR(dev); 81499a85259STetsuo Handa tomoyo_check_acl(&r, tomoyo_check_mkdev_acl); 81599a85259STetsuo Handa error = tomoyo_audit_mkdev_log(&r); 816c8c57e84STetsuo Handa kfree(buf.name); 817a1f9bb6aSTetsuo Handa } 818a1f9bb6aSTetsuo Handa tomoyo_read_unlock(idx); 819a1f9bb6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 820a1f9bb6aSTetsuo Handa error = 0; 821a1f9bb6aSTetsuo Handa return error; 822a1f9bb6aSTetsuo Handa } 823a1f9bb6aSTetsuo Handa 824a1f9bb6aSTetsuo Handa /** 8257ef61233STetsuo Handa * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root". 826b69a54eeSKentaro Takeda * 827b69a54eeSKentaro Takeda * @operation: Type of operation. 828b69a54eeSKentaro Takeda * @path1: Pointer to "struct path". 829b69a54eeSKentaro Takeda * @path2: Pointer to "struct path". 830b69a54eeSKentaro Takeda * 831b69a54eeSKentaro Takeda * Returns 0 on success, negative value otherwise. 832b69a54eeSKentaro Takeda */ 83397d6931eSTetsuo Handa int tomoyo_path2_perm(const u8 operation, struct path *path1, 834b69a54eeSKentaro Takeda struct path *path2) 835b69a54eeSKentaro Takeda { 836b69a54eeSKentaro Takeda int error = -ENOMEM; 837c8c57e84STetsuo Handa struct tomoyo_path_info buf1; 838c8c57e84STetsuo Handa struct tomoyo_path_info buf2; 839cb0abe6aSTetsuo Handa struct tomoyo_request_info r; 840fdb8ebb7STetsuo Handa int idx; 841b69a54eeSKentaro Takeda 8425625f2e3STetsuo Handa if (tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation]) 84357c2590fSTetsuo Handa == TOMOYO_CONFIG_DISABLED) 844b69a54eeSKentaro Takeda return 0; 845c8c57e84STetsuo Handa buf1.name = NULL; 846c8c57e84STetsuo Handa buf2.name = NULL; 847fdb8ebb7STetsuo Handa idx = tomoyo_read_lock(); 848c8c57e84STetsuo Handa if (!tomoyo_get_realpath(&buf1, path1) || 849c8c57e84STetsuo Handa !tomoyo_get_realpath(&buf2, path2)) 850b69a54eeSKentaro Takeda goto out; 85157c2590fSTetsuo Handa switch (operation) { 85257c2590fSTetsuo Handa struct dentry *dentry; 85357c2590fSTetsuo Handa case TOMOYO_TYPE_RENAME: 85457c2590fSTetsuo Handa case TOMOYO_TYPE_LINK: 85557c2590fSTetsuo Handa dentry = path1->dentry; 85657c2590fSTetsuo Handa if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode)) 85757c2590fSTetsuo Handa break; 85857c2590fSTetsuo Handa /* fall through */ 85957c2590fSTetsuo Handa case TOMOYO_TYPE_PIVOT_ROOT: 860c8c57e84STetsuo Handa tomoyo_add_slash(&buf1); 861c8c57e84STetsuo Handa tomoyo_add_slash(&buf2); 86257c2590fSTetsuo Handa break; 863b69a54eeSKentaro Takeda } 864cf6e9a64STetsuo Handa r.param_type = TOMOYO_TYPE_PATH2_ACL; 865cf6e9a64STetsuo Handa r.param.path2.operation = operation; 866cf6e9a64STetsuo Handa r.param.path2.filename1 = &buf1; 867cf6e9a64STetsuo Handa r.param.path2.filename2 = &buf2; 86817fcfbd9STetsuo Handa do { 86999a85259STetsuo Handa tomoyo_check_acl(&r, tomoyo_check_path2_acl); 87099a85259STetsuo Handa error = tomoyo_audit_path2_log(&r); 87117fcfbd9STetsuo Handa } while (error == TOMOYO_RETRY_REQUEST); 872b69a54eeSKentaro Takeda out: 873c8c57e84STetsuo Handa kfree(buf1.name); 874c8c57e84STetsuo Handa kfree(buf2.name); 875fdb8ebb7STetsuo Handa tomoyo_read_unlock(idx); 876cb0abe6aSTetsuo Handa if (r.mode != TOMOYO_CONFIG_ENFORCING) 877b69a54eeSKentaro Takeda error = 0; 878b69a54eeSKentaro Takeda return error; 879b69a54eeSKentaro Takeda } 880a1f9bb6aSTetsuo Handa 881a1f9bb6aSTetsuo Handa /** 882a238cf5bSTetsuo Handa * tomoyo_same_mount_acl - Check for duplicated "struct tomoyo_mount_acl" entry. 883a1f9bb6aSTetsuo Handa * 884a238cf5bSTetsuo Handa * @a: Pointer to "struct tomoyo_acl_info". 885a238cf5bSTetsuo Handa * @b: Pointer to "struct tomoyo_acl_info". 886a238cf5bSTetsuo Handa * 887a238cf5bSTetsuo Handa * Returns true if @a == @b, false otherwise. 888a238cf5bSTetsuo Handa */ 889a238cf5bSTetsuo Handa static bool tomoyo_same_mount_acl(const struct tomoyo_acl_info *a, 890a238cf5bSTetsuo Handa const struct tomoyo_acl_info *b) 891a238cf5bSTetsuo Handa { 892a238cf5bSTetsuo Handa const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head); 893a238cf5bSTetsuo Handa const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head); 894a238cf5bSTetsuo Handa return tomoyo_same_name_union(&p1->dev_name, &p2->dev_name) && 895a238cf5bSTetsuo Handa tomoyo_same_name_union(&p1->dir_name, &p2->dir_name) && 896a238cf5bSTetsuo Handa tomoyo_same_name_union(&p1->fs_type, &p2->fs_type) && 897a238cf5bSTetsuo Handa tomoyo_same_number_union(&p1->flags, &p2->flags); 898a238cf5bSTetsuo Handa } 899a238cf5bSTetsuo Handa 900a238cf5bSTetsuo Handa /** 901a238cf5bSTetsuo Handa * tomoyo_update_mount_acl - Write "struct tomoyo_mount_acl" list. 902a238cf5bSTetsuo Handa * 903a238cf5bSTetsuo Handa * @param: Pointer to "struct tomoyo_acl_param". 904a1f9bb6aSTetsuo Handa * 905a1f9bb6aSTetsuo Handa * Returns 0 on success, negative value otherwise. 906a1f9bb6aSTetsuo Handa * 907a1f9bb6aSTetsuo Handa * Caller holds tomoyo_read_lock(). 908a1f9bb6aSTetsuo Handa */ 909a238cf5bSTetsuo Handa static int tomoyo_update_mount_acl(struct tomoyo_acl_param *param) 910a1f9bb6aSTetsuo Handa { 911a238cf5bSTetsuo Handa struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL }; 912a238cf5bSTetsuo Handa int error; 913a238cf5bSTetsuo Handa if (!tomoyo_parse_name_union(param, &e.dev_name) || 914a238cf5bSTetsuo Handa !tomoyo_parse_name_union(param, &e.dir_name) || 915a238cf5bSTetsuo Handa !tomoyo_parse_name_union(param, &e.fs_type) || 916a238cf5bSTetsuo Handa !tomoyo_parse_number_union(param, &e.flags)) 917a238cf5bSTetsuo Handa error = -EINVAL; 918a238cf5bSTetsuo Handa else 919a238cf5bSTetsuo Handa error = tomoyo_update_domain(&e.head, sizeof(e), param, 920a238cf5bSTetsuo Handa tomoyo_same_mount_acl, NULL); 921a238cf5bSTetsuo Handa tomoyo_put_name_union(&e.dev_name); 922a238cf5bSTetsuo Handa tomoyo_put_name_union(&e.dir_name); 923a238cf5bSTetsuo Handa tomoyo_put_name_union(&e.fs_type); 924a238cf5bSTetsuo Handa tomoyo_put_number_union(&e.flags); 925a238cf5bSTetsuo Handa return error; 926a238cf5bSTetsuo Handa } 927a238cf5bSTetsuo Handa 928a238cf5bSTetsuo Handa /** 929a238cf5bSTetsuo Handa * tomoyo_write_file - Update file related list. 930a238cf5bSTetsuo Handa * 931a238cf5bSTetsuo Handa * @param: Pointer to "struct tomoyo_acl_param". 932a238cf5bSTetsuo Handa * 933a238cf5bSTetsuo Handa * Returns 0 on success, negative value otherwise. 934a238cf5bSTetsuo Handa * 935a238cf5bSTetsuo Handa * Caller holds tomoyo_read_lock(). 936a238cf5bSTetsuo Handa */ 937a238cf5bSTetsuo Handa int tomoyo_write_file(struct tomoyo_acl_param *param) 938a238cf5bSTetsuo Handa { 939a238cf5bSTetsuo Handa u16 perm = 0; 940a1f9bb6aSTetsuo Handa u8 type; 941a238cf5bSTetsuo Handa const char *operation = tomoyo_read_token(param); 942a238cf5bSTetsuo Handa for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) 943a238cf5bSTetsuo Handa if (tomoyo_permstr(operation, tomoyo_path_keyword[type])) 944a238cf5bSTetsuo Handa perm |= 1 << type; 945a238cf5bSTetsuo Handa if (perm) 946a238cf5bSTetsuo Handa return tomoyo_update_path_acl(perm, param); 947a238cf5bSTetsuo Handa for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) 9482c47ab93STetsuo Handa if (tomoyo_permstr(operation, 9492c47ab93STetsuo Handa tomoyo_mac_keywords[tomoyo_pp2mac[type]])) 950a238cf5bSTetsuo Handa perm |= 1 << type; 951a238cf5bSTetsuo Handa if (perm) 952a238cf5bSTetsuo Handa return tomoyo_update_path2_acl(perm, param); 953a238cf5bSTetsuo Handa for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) 954a238cf5bSTetsuo Handa if (tomoyo_permstr(operation, 9552c47ab93STetsuo Handa tomoyo_mac_keywords[tomoyo_pn2mac[type]])) 956a238cf5bSTetsuo Handa perm |= 1 << type; 957a238cf5bSTetsuo Handa if (perm) 958a238cf5bSTetsuo Handa return tomoyo_update_path_number_acl(perm, param); 959a238cf5bSTetsuo Handa for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++) 9602c47ab93STetsuo Handa if (tomoyo_permstr(operation, 9612c47ab93STetsuo Handa tomoyo_mac_keywords[tomoyo_pnnn2mac[type]])) 962a238cf5bSTetsuo Handa perm |= 1 << type; 963a238cf5bSTetsuo Handa if (perm) 964a238cf5bSTetsuo Handa return tomoyo_update_mkdev_acl(perm, param); 9652c47ab93STetsuo Handa if (tomoyo_permstr(operation, 9662c47ab93STetsuo Handa tomoyo_mac_keywords[TOMOYO_MAC_FILE_MOUNT])) 967a238cf5bSTetsuo Handa return tomoyo_update_mount_acl(param); 968a1f9bb6aSTetsuo Handa return -EINVAL; 969a1f9bb6aSTetsuo Handa } 970