xref: /openbmc/linux/security/tomoyo/file.c (revision 2c47ab93)
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