xref: /openbmc/linux/security/tomoyo/file.c (revision 467cf8ef)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2b69a54eeSKentaro Takeda /*
3b69a54eeSKentaro Takeda  * security/tomoyo/file.c
4b69a54eeSKentaro Takeda  *
50f2a55d5STetsuo Handa  * Copyright (C) 2005-2011  NTT DATA CORPORATION
6b69a54eeSKentaro Takeda  */
7b69a54eeSKentaro Takeda 
8b69a54eeSKentaro Takeda #include "common.h"
95a0e3ad6STejun Heo #include <linux/slab.h>
10b69a54eeSKentaro Takeda 
110df7e8b8STetsuo Handa /*
120df7e8b8STetsuo Handa  * Mapping table from "enum tomoyo_path_acl_index" to "enum tomoyo_mac_index".
130df7e8b8STetsuo Handa  */
1457c2590fSTetsuo Handa static const u8 tomoyo_p2mac[TOMOYO_MAX_PATH_OPERATION] = {
1557c2590fSTetsuo Handa 	[TOMOYO_TYPE_EXECUTE]    = TOMOYO_MAC_FILE_EXECUTE,
1657c2590fSTetsuo Handa 	[TOMOYO_TYPE_READ]       = TOMOYO_MAC_FILE_OPEN,
1757c2590fSTetsuo Handa 	[TOMOYO_TYPE_WRITE]      = TOMOYO_MAC_FILE_OPEN,
187c75964fSTetsuo Handa 	[TOMOYO_TYPE_APPEND]     = TOMOYO_MAC_FILE_OPEN,
1957c2590fSTetsuo Handa 	[TOMOYO_TYPE_UNLINK]     = TOMOYO_MAC_FILE_UNLINK,
207c75964fSTetsuo Handa 	[TOMOYO_TYPE_GETATTR]    = TOMOYO_MAC_FILE_GETATTR,
2157c2590fSTetsuo Handa 	[TOMOYO_TYPE_RMDIR]      = TOMOYO_MAC_FILE_RMDIR,
2257c2590fSTetsuo Handa 	[TOMOYO_TYPE_TRUNCATE]   = TOMOYO_MAC_FILE_TRUNCATE,
2357c2590fSTetsuo Handa 	[TOMOYO_TYPE_SYMLINK]    = TOMOYO_MAC_FILE_SYMLINK,
2457c2590fSTetsuo Handa 	[TOMOYO_TYPE_CHROOT]     = TOMOYO_MAC_FILE_CHROOT,
2557c2590fSTetsuo Handa 	[TOMOYO_TYPE_UMOUNT]     = TOMOYO_MAC_FILE_UMOUNT,
2657c2590fSTetsuo Handa };
2757c2590fSTetsuo Handa 
280df7e8b8STetsuo Handa /*
290df7e8b8STetsuo Handa  * Mapping table from "enum tomoyo_mkdev_acl_index" to "enum tomoyo_mac_index".
300df7e8b8STetsuo Handa  */
310d2171d7STetsuo Handa const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION] = {
3257c2590fSTetsuo Handa 	[TOMOYO_TYPE_MKBLOCK] = TOMOYO_MAC_FILE_MKBLOCK,
3357c2590fSTetsuo Handa 	[TOMOYO_TYPE_MKCHAR]  = TOMOYO_MAC_FILE_MKCHAR,
3457c2590fSTetsuo Handa };
3557c2590fSTetsuo Handa 
360df7e8b8STetsuo Handa /*
370df7e8b8STetsuo Handa  * Mapping table from "enum tomoyo_path2_acl_index" to "enum tomoyo_mac_index".
380df7e8b8STetsuo Handa  */
390d2171d7STetsuo Handa const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION] = {
4057c2590fSTetsuo Handa 	[TOMOYO_TYPE_LINK]       = TOMOYO_MAC_FILE_LINK,
4157c2590fSTetsuo Handa 	[TOMOYO_TYPE_RENAME]     = TOMOYO_MAC_FILE_RENAME,
4257c2590fSTetsuo Handa 	[TOMOYO_TYPE_PIVOT_ROOT] = TOMOYO_MAC_FILE_PIVOT_ROOT,
4357c2590fSTetsuo Handa };
4457c2590fSTetsuo Handa 
450df7e8b8STetsuo Handa /*
460df7e8b8STetsuo Handa  * Mapping table from "enum tomoyo_path_number_acl_index" to
470df7e8b8STetsuo Handa  * "enum tomoyo_mac_index".
480df7e8b8STetsuo Handa  */
490d2171d7STetsuo Handa const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = {
5057c2590fSTetsuo Handa 	[TOMOYO_TYPE_CREATE] = TOMOYO_MAC_FILE_CREATE,
5157c2590fSTetsuo Handa 	[TOMOYO_TYPE_MKDIR]  = TOMOYO_MAC_FILE_MKDIR,
5257c2590fSTetsuo Handa 	[TOMOYO_TYPE_MKFIFO] = TOMOYO_MAC_FILE_MKFIFO,
5357c2590fSTetsuo Handa 	[TOMOYO_TYPE_MKSOCK] = TOMOYO_MAC_FILE_MKSOCK,
5457c2590fSTetsuo Handa 	[TOMOYO_TYPE_IOCTL]  = TOMOYO_MAC_FILE_IOCTL,
5557c2590fSTetsuo Handa 	[TOMOYO_TYPE_CHMOD]  = TOMOYO_MAC_FILE_CHMOD,
5657c2590fSTetsuo Handa 	[TOMOYO_TYPE_CHOWN]  = TOMOYO_MAC_FILE_CHOWN,
5757c2590fSTetsuo Handa 	[TOMOYO_TYPE_CHGRP]  = TOMOYO_MAC_FILE_CHGRP,
5857c2590fSTetsuo Handa };
5957c2590fSTetsuo Handa 
600df7e8b8STetsuo Handa /**
610df7e8b8STetsuo Handa  * tomoyo_put_name_union - Drop reference on "struct tomoyo_name_union".
620df7e8b8STetsuo Handa  *
630df7e8b8STetsuo Handa  * @ptr: Pointer to "struct tomoyo_name_union".
640df7e8b8STetsuo Handa  *
650df7e8b8STetsuo Handa  * Returns nothing.
660df7e8b8STetsuo Handa  */
tomoyo_put_name_union(struct tomoyo_name_union * ptr)677762fbffSTetsuo Handa void tomoyo_put_name_union(struct tomoyo_name_union *ptr)
687762fbffSTetsuo Handa {
69a98aa4deSTetsuo Handa 	tomoyo_put_group(ptr->group);
707762fbffSTetsuo Handa 	tomoyo_put_name(ptr->filename);
717762fbffSTetsuo Handa }
727762fbffSTetsuo Handa 
730df7e8b8STetsuo Handa /**
740df7e8b8STetsuo Handa  * tomoyo_compare_name_union - Check whether a name matches "struct tomoyo_name_union" or not.
750df7e8b8STetsuo Handa  *
760df7e8b8STetsuo Handa  * @name: Pointer to "struct tomoyo_path_info".
770df7e8b8STetsuo Handa  * @ptr:  Pointer to "struct tomoyo_name_union".
780df7e8b8STetsuo Handa  *
790df7e8b8STetsuo Handa  * Returns "struct tomoyo_path_info" if @name matches @ptr, NULL otherwise.
800df7e8b8STetsuo Handa  */
81484ca79cSTetsuo Handa const struct tomoyo_path_info *
tomoyo_compare_name_union(const struct tomoyo_path_info * name,const struct tomoyo_name_union * ptr)82484ca79cSTetsuo Handa tomoyo_compare_name_union(const struct tomoyo_path_info *name,
837762fbffSTetsuo Handa 			  const struct tomoyo_name_union *ptr)
847762fbffSTetsuo Handa {
850df7e8b8STetsuo Handa 	if (ptr->group)
863f629636STetsuo Handa 		return tomoyo_path_matches_group(name, ptr->group);
87484ca79cSTetsuo Handa 	if (tomoyo_path_matches_pattern(name, ptr->filename))
88484ca79cSTetsuo Handa 		return ptr->filename;
89484ca79cSTetsuo Handa 	return NULL;
907762fbffSTetsuo Handa }
917762fbffSTetsuo Handa 
920df7e8b8STetsuo Handa /**
930df7e8b8STetsuo Handa  * tomoyo_put_number_union - Drop reference on "struct tomoyo_number_union".
940df7e8b8STetsuo Handa  *
950df7e8b8STetsuo Handa  * @ptr: Pointer to "struct tomoyo_number_union".
960df7e8b8STetsuo Handa  *
970df7e8b8STetsuo Handa  * Returns nothing.
980df7e8b8STetsuo Handa  */
tomoyo_put_number_union(struct tomoyo_number_union * ptr)994c3e9e2dSTetsuo Handa void tomoyo_put_number_union(struct tomoyo_number_union *ptr)
1004c3e9e2dSTetsuo Handa {
101a98aa4deSTetsuo Handa 	tomoyo_put_group(ptr->group);
1024c3e9e2dSTetsuo Handa }
1034c3e9e2dSTetsuo Handa 
1040df7e8b8STetsuo Handa /**
1050df7e8b8STetsuo Handa  * tomoyo_compare_number_union - Check whether a value matches "struct tomoyo_number_union" or not.
1060df7e8b8STetsuo Handa  *
1070df7e8b8STetsuo Handa  * @value: Number to check.
1080df7e8b8STetsuo Handa  * @ptr:   Pointer to "struct tomoyo_number_union".
1090df7e8b8STetsuo Handa  *
1100df7e8b8STetsuo Handa  * Returns true if @value matches @ptr, false otherwise.
1110df7e8b8STetsuo Handa  */
tomoyo_compare_number_union(const unsigned long value,const struct tomoyo_number_union * ptr)1124c3e9e2dSTetsuo Handa bool tomoyo_compare_number_union(const unsigned long value,
1134c3e9e2dSTetsuo Handa 				 const struct tomoyo_number_union *ptr)
1144c3e9e2dSTetsuo Handa {
1150df7e8b8STetsuo Handa 	if (ptr->group)
1164c3e9e2dSTetsuo Handa 		return tomoyo_number_matches_group(value, value, ptr->group);
1174c3e9e2dSTetsuo Handa 	return value >= ptr->values[0] && value <= ptr->values[1];
1184c3e9e2dSTetsuo Handa }
1194c3e9e2dSTetsuo Handa 
1200df7e8b8STetsuo Handa /**
1210df7e8b8STetsuo Handa  * tomoyo_add_slash - Add trailing '/' if needed.
1220df7e8b8STetsuo Handa  *
1230df7e8b8STetsuo Handa  * @buf: Pointer to "struct tomoyo_path_info".
1240df7e8b8STetsuo Handa  *
1250df7e8b8STetsuo Handa  * Returns nothing.
1260df7e8b8STetsuo Handa  *
1270df7e8b8STetsuo Handa  * @buf must be generated by tomoyo_encode() because this function does not
1280df7e8b8STetsuo Handa  * allocate memory for adding '/'.
1290df7e8b8STetsuo Handa  */
tomoyo_add_slash(struct tomoyo_path_info * buf)130c8c57e84STetsuo Handa static void tomoyo_add_slash(struct tomoyo_path_info *buf)
131c8c57e84STetsuo Handa {
132c8c57e84STetsuo Handa 	if (buf->is_dir)
133c8c57e84STetsuo Handa 		return;
134c8c57e84STetsuo Handa 	/*
135c8c57e84STetsuo Handa 	 * This is OK because tomoyo_encode() reserves space for appending "/".
136c8c57e84STetsuo Handa 	 */
137c8c57e84STetsuo Handa 	strcat((char *) buf->name, "/");
138c8c57e84STetsuo Handa 	tomoyo_fill_path_info(buf);
139c8c57e84STetsuo Handa }
140c8c57e84STetsuo Handa 
141a1f9bb6aSTetsuo Handa /**
142c8c57e84STetsuo Handa  * tomoyo_get_realpath - Get realpath.
143b69a54eeSKentaro Takeda  *
144c8c57e84STetsuo Handa  * @buf:  Pointer to "struct tomoyo_path_info".
145b69a54eeSKentaro Takeda  * @path: Pointer to "struct path".
146b69a54eeSKentaro Takeda  *
147c8c57e84STetsuo Handa  * Returns true on success, false otherwise.
148b69a54eeSKentaro Takeda  */
tomoyo_get_realpath(struct tomoyo_path_info * buf,const struct path * path)1493f7036a0SAl Viro static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, const struct path *path)
150b69a54eeSKentaro Takeda {
151c8c57e84STetsuo Handa 	buf->name = tomoyo_realpath_from_path(path);
152c8c57e84STetsuo Handa 	if (buf->name) {
153c8c57e84STetsuo Handa 		tomoyo_fill_path_info(buf);
154c8c57e84STetsuo Handa 		return true;
155b69a54eeSKentaro Takeda 	}
156c8c57e84STetsuo Handa 	return false;
157b69a54eeSKentaro Takeda }
158b69a54eeSKentaro Takeda 
15999a85259STetsuo Handa /**
16099a85259STetsuo Handa  * tomoyo_audit_path_log - Audit path request log.
16199a85259STetsuo Handa  *
16299a85259STetsuo Handa  * @r: Pointer to "struct tomoyo_request_info".
16399a85259STetsuo Handa  *
16499a85259STetsuo Handa  * Returns 0 on success, negative value otherwise.
16599a85259STetsuo Handa  */
tomoyo_audit_path_log(struct tomoyo_request_info * r)16699a85259STetsuo Handa static int tomoyo_audit_path_log(struct tomoyo_request_info *r)
16799a85259STetsuo Handa {
168eadd99ccSTetsuo Handa 	return tomoyo_supervisor(r, "file %s %s\n", tomoyo_path_keyword
169eadd99ccSTetsuo Handa 				 [r->param.path.operation],
170eadd99ccSTetsuo Handa 				 r->param.path.filename->name);
17199a85259STetsuo Handa }
17299a85259STetsuo Handa 
17399a85259STetsuo Handa /**
17499a85259STetsuo Handa  * tomoyo_audit_path2_log - Audit path/path request log.
17599a85259STetsuo Handa  *
17699a85259STetsuo Handa  * @r: Pointer to "struct tomoyo_request_info".
17799a85259STetsuo Handa  *
17899a85259STetsuo Handa  * Returns 0 on success, negative value otherwise.
17999a85259STetsuo Handa  */
tomoyo_audit_path2_log(struct tomoyo_request_info * r)18099a85259STetsuo Handa static int tomoyo_audit_path2_log(struct tomoyo_request_info *r)
18199a85259STetsuo Handa {
1822c47ab93STetsuo Handa 	return tomoyo_supervisor(r, "file %s %s %s\n", tomoyo_mac_keywords
1832c47ab93STetsuo Handa 				 [tomoyo_pp2mac[r->param.path2.operation]],
184eadd99ccSTetsuo Handa 				 r->param.path2.filename1->name,
185eadd99ccSTetsuo Handa 				 r->param.path2.filename2->name);
18699a85259STetsuo Handa }
18799a85259STetsuo Handa 
18899a85259STetsuo Handa /**
18999a85259STetsuo Handa  * tomoyo_audit_mkdev_log - Audit path/number/number/number request log.
19099a85259STetsuo Handa  *
19199a85259STetsuo Handa  * @r: Pointer to "struct tomoyo_request_info".
19299a85259STetsuo Handa  *
19399a85259STetsuo Handa  * Returns 0 on success, negative value otherwise.
19499a85259STetsuo Handa  */
tomoyo_audit_mkdev_log(struct tomoyo_request_info * r)19599a85259STetsuo Handa static int tomoyo_audit_mkdev_log(struct tomoyo_request_info *r)
19699a85259STetsuo Handa {
197eadd99ccSTetsuo Handa 	return tomoyo_supervisor(r, "file %s %s 0%o %u %u\n",
1982c47ab93STetsuo Handa 				 tomoyo_mac_keywords
1992c47ab93STetsuo Handa 				 [tomoyo_pnnn2mac[r->param.mkdev.operation]],
200eadd99ccSTetsuo Handa 				 r->param.mkdev.filename->name,
201eadd99ccSTetsuo Handa 				 r->param.mkdev.mode, r->param.mkdev.major,
202eadd99ccSTetsuo Handa 				 r->param.mkdev.minor);
20399a85259STetsuo Handa }
20499a85259STetsuo Handa 
20599a85259STetsuo Handa /**
20699a85259STetsuo Handa  * tomoyo_audit_path_number_log - Audit path/number request log.
20799a85259STetsuo Handa  *
20899a85259STetsuo Handa  * @r: Pointer to "struct tomoyo_request_info".
20999a85259STetsuo Handa  *
21099a85259STetsuo Handa  * Returns 0 on success, negative value otherwise.
21199a85259STetsuo Handa  */
tomoyo_audit_path_number_log(struct tomoyo_request_info * r)21299a85259STetsuo Handa static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r)
21399a85259STetsuo Handa {
21499a85259STetsuo Handa 	const u8 type = r->param.path_number.operation;
21599a85259STetsuo Handa 	u8 radix;
21699a85259STetsuo Handa 	char buffer[64];
217cdcf6723STetsuo Handa 
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  */
tomoyo_check_path_acl(struct tomoyo_request_info * r,const struct tomoyo_acl_info * ptr)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);
257cdcf6723STetsuo Handa 
258484ca79cSTetsuo Handa 	if (acl->perm & (1 << r->param.path.operation)) {
259484ca79cSTetsuo Handa 		r->param.path.matched_path =
260484ca79cSTetsuo Handa 			tomoyo_compare_name_union(r->param.path.filename,
261484ca79cSTetsuo Handa 						  &acl->name);
262484ca79cSTetsuo Handa 		return r->param.path.matched_path != NULL;
263484ca79cSTetsuo Handa 	}
264484ca79cSTetsuo Handa 	return false;
265b69a54eeSKentaro Takeda }
26699a85259STetsuo Handa 
2670df7e8b8STetsuo Handa /**
2680df7e8b8STetsuo Handa  * tomoyo_check_path_number_acl - Check permission for path number operation.
2690df7e8b8STetsuo Handa  *
2700df7e8b8STetsuo Handa  * @r:   Pointer to "struct tomoyo_request_info".
2710df7e8b8STetsuo Handa  * @ptr: Pointer to "struct tomoyo_acl_info".
2720df7e8b8STetsuo Handa  *
2730df7e8b8STetsuo Handa  * Returns true if granted, false otherwise.
2740df7e8b8STetsuo Handa  */
tomoyo_check_path_number_acl(struct tomoyo_request_info * r,const struct tomoyo_acl_info * ptr)275484ca79cSTetsuo Handa static bool tomoyo_check_path_number_acl(struct tomoyo_request_info *r,
27699a85259STetsuo Handa 					 const struct tomoyo_acl_info *ptr)
27799a85259STetsuo Handa {
27899a85259STetsuo Handa 	const struct tomoyo_path_number_acl *acl =
27999a85259STetsuo Handa 		container_of(ptr, typeof(*acl), head);
280cdcf6723STetsuo Handa 
28199a85259STetsuo Handa 	return (acl->perm & (1 << r->param.path_number.operation)) &&
28299a85259STetsuo Handa 		tomoyo_compare_number_union(r->param.path_number.number,
28399a85259STetsuo Handa 					    &acl->number) &&
28499a85259STetsuo Handa 		tomoyo_compare_name_union(r->param.path_number.filename,
28599a85259STetsuo Handa 					  &acl->name);
28699a85259STetsuo Handa }
28799a85259STetsuo Handa 
2880df7e8b8STetsuo Handa /**
2890df7e8b8STetsuo Handa  * tomoyo_check_path2_acl - Check permission for path path operation.
2900df7e8b8STetsuo Handa  *
2910df7e8b8STetsuo Handa  * @r:   Pointer to "struct tomoyo_request_info".
2920df7e8b8STetsuo Handa  * @ptr: Pointer to "struct tomoyo_acl_info".
2930df7e8b8STetsuo Handa  *
2940df7e8b8STetsuo Handa  * Returns true if granted, false otherwise.
2950df7e8b8STetsuo Handa  */
tomoyo_check_path2_acl(struct tomoyo_request_info * r,const struct tomoyo_acl_info * ptr)296484ca79cSTetsuo Handa static bool tomoyo_check_path2_acl(struct tomoyo_request_info *r,
29799a85259STetsuo Handa 				   const struct tomoyo_acl_info *ptr)
29899a85259STetsuo Handa {
29999a85259STetsuo Handa 	const struct tomoyo_path2_acl *acl =
30099a85259STetsuo Handa 		container_of(ptr, typeof(*acl), head);
301cdcf6723STetsuo Handa 
30299a85259STetsuo Handa 	return (acl->perm & (1 << r->param.path2.operation)) &&
30399a85259STetsuo Handa 		tomoyo_compare_name_union(r->param.path2.filename1, &acl->name1)
30499a85259STetsuo Handa 		&& tomoyo_compare_name_union(r->param.path2.filename2,
30599a85259STetsuo Handa 					     &acl->name2);
30699a85259STetsuo Handa }
30799a85259STetsuo Handa 
3080df7e8b8STetsuo Handa /**
3090df7e8b8STetsuo Handa  * tomoyo_check_mkdev_acl - Check permission for path number number number operation.
3100df7e8b8STetsuo Handa  *
3110df7e8b8STetsuo Handa  * @r:   Pointer to "struct tomoyo_request_info".
3120df7e8b8STetsuo Handa  * @ptr: Pointer to "struct tomoyo_acl_info".
3130df7e8b8STetsuo Handa  *
3140df7e8b8STetsuo Handa  * Returns true if granted, false otherwise.
3150df7e8b8STetsuo Handa  */
tomoyo_check_mkdev_acl(struct tomoyo_request_info * r,const struct tomoyo_acl_info * ptr)316484ca79cSTetsuo Handa static bool tomoyo_check_mkdev_acl(struct tomoyo_request_info *r,
31799a85259STetsuo Handa 				   const struct tomoyo_acl_info *ptr)
31899a85259STetsuo Handa {
31975093152STetsuo Handa 	const struct tomoyo_mkdev_acl *acl =
32099a85259STetsuo Handa 		container_of(ptr, typeof(*acl), head);
321cdcf6723STetsuo Handa 
32299a85259STetsuo Handa 	return (acl->perm & (1 << r->param.mkdev.operation)) &&
32399a85259STetsuo Handa 		tomoyo_compare_number_union(r->param.mkdev.mode,
32499a85259STetsuo Handa 					    &acl->mode) &&
32599a85259STetsuo Handa 		tomoyo_compare_number_union(r->param.mkdev.major,
32699a85259STetsuo Handa 					    &acl->major) &&
32799a85259STetsuo Handa 		tomoyo_compare_number_union(r->param.mkdev.minor,
32899a85259STetsuo Handa 					    &acl->minor) &&
32999a85259STetsuo Handa 		tomoyo_compare_name_union(r->param.mkdev.filename,
33099a85259STetsuo Handa 					  &acl->name);
331b69a54eeSKentaro Takeda }
332b69a54eeSKentaro Takeda 
3330df7e8b8STetsuo Handa /**
3340df7e8b8STetsuo Handa  * tomoyo_same_path_acl - Check for duplicated "struct tomoyo_path_acl" entry.
3350df7e8b8STetsuo Handa  *
3360df7e8b8STetsuo Handa  * @a: Pointer to "struct tomoyo_acl_info".
3370df7e8b8STetsuo Handa  * @b: Pointer to "struct tomoyo_acl_info".
3380df7e8b8STetsuo Handa  *
3390df7e8b8STetsuo Handa  * Returns true if @a == @b except permission bits, false otherwise.
3400df7e8b8STetsuo Handa  */
tomoyo_same_path_acl(const struct tomoyo_acl_info * a,const struct tomoyo_acl_info * b)341237ab459STetsuo Handa static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a,
342237ab459STetsuo Handa 				 const struct tomoyo_acl_info *b)
343237ab459STetsuo Handa {
344237ab459STetsuo Handa 	const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head);
345237ab459STetsuo Handa 	const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head);
346cdcf6723STetsuo Handa 
3470df7e8b8STetsuo Handa 	return tomoyo_same_name_union(&p1->name, &p2->name);
348237ab459STetsuo Handa }
349237ab459STetsuo Handa 
3507c75964fSTetsuo Handa /**
3517c75964fSTetsuo Handa  * tomoyo_merge_path_acl - Merge duplicated "struct tomoyo_path_acl" entry.
3527c75964fSTetsuo Handa  *
3537c75964fSTetsuo Handa  * @a:         Pointer to "struct tomoyo_acl_info".
3547c75964fSTetsuo Handa  * @b:         Pointer to "struct tomoyo_acl_info".
3557c75964fSTetsuo Handa  * @is_delete: True for @a &= ~@b, false for @a |= @b.
3567c75964fSTetsuo Handa  *
3577c75964fSTetsuo Handa  * Returns true if @a is empty, false otherwise.
3587c75964fSTetsuo Handa  */
tomoyo_merge_path_acl(struct tomoyo_acl_info * a,struct tomoyo_acl_info * b,const bool is_delete)359237ab459STetsuo Handa static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a,
360237ab459STetsuo Handa 				  struct tomoyo_acl_info *b,
361237ab459STetsuo Handa 				  const bool is_delete)
362237ab459STetsuo Handa {
363237ab459STetsuo Handa 	u16 * const a_perm = &container_of(a, struct tomoyo_path_acl, head)
364237ab459STetsuo Handa 		->perm;
3655797e861STetsuo Handa 	u16 perm = READ_ONCE(*a_perm);
366237ab459STetsuo Handa 	const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm;
367cdcf6723STetsuo Handa 
3687c75964fSTetsuo Handa 	if (is_delete)
369237ab459STetsuo Handa 		perm &= ~b_perm;
3707c75964fSTetsuo Handa 	else
371237ab459STetsuo Handa 		perm |= b_perm;
3725797e861STetsuo Handa 	WRITE_ONCE(*a_perm, perm);
373237ab459STetsuo Handa 	return !perm;
374237ab459STetsuo Handa }
375237ab459STetsuo Handa 
376b69a54eeSKentaro Takeda /**
3777ef61233STetsuo Handa  * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list.
378b69a54eeSKentaro Takeda  *
379a238cf5bSTetsuo Handa  * @perm:  Permission.
380a238cf5bSTetsuo Handa  * @param: Pointer to "struct tomoyo_acl_param".
381b69a54eeSKentaro Takeda  *
382b69a54eeSKentaro Takeda  * Returns 0 on success, negative value otherwise.
383fdb8ebb7STetsuo Handa  *
384fdb8ebb7STetsuo Handa  * Caller holds tomoyo_read_lock().
385b69a54eeSKentaro Takeda  */
tomoyo_update_path_acl(const u16 perm,struct tomoyo_acl_param * param)386a238cf5bSTetsuo Handa static int tomoyo_update_path_acl(const u16 perm,
387a238cf5bSTetsuo Handa 				  struct tomoyo_acl_param *param)
388b69a54eeSKentaro Takeda {
3899e4b50e9STetsuo Handa 	struct tomoyo_path_acl e = {
3909e4b50e9STetsuo Handa 		.head.type = TOMOYO_TYPE_PATH_ACL,
391a238cf5bSTetsuo Handa 		.perm = perm
3929e4b50e9STetsuo Handa 	};
393237ab459STetsuo Handa 	int error;
394cdcf6723STetsuo Handa 
395a238cf5bSTetsuo Handa 	if (!tomoyo_parse_name_union(param, &e.name))
396a238cf5bSTetsuo Handa 		error = -EINVAL;
397a238cf5bSTetsuo Handa 	else
398a238cf5bSTetsuo Handa 		error = tomoyo_update_domain(&e.head, sizeof(e), param,
399237ab459STetsuo Handa 					     tomoyo_same_path_acl,
400237ab459STetsuo Handa 					     tomoyo_merge_path_acl);
4017762fbffSTetsuo Handa 	tomoyo_put_name_union(&e.name);
402b69a54eeSKentaro Takeda 	return error;
403b69a54eeSKentaro Takeda }
404b69a54eeSKentaro Takeda 
4050df7e8b8STetsuo Handa /**
4060df7e8b8STetsuo Handa  * tomoyo_same_mkdev_acl - Check for duplicated "struct tomoyo_mkdev_acl" entry.
4070df7e8b8STetsuo Handa  *
4080df7e8b8STetsuo Handa  * @a: Pointer to "struct tomoyo_acl_info".
4090df7e8b8STetsuo Handa  * @b: Pointer to "struct tomoyo_acl_info".
4100df7e8b8STetsuo Handa  *
4110df7e8b8STetsuo Handa  * Returns true if @a == @b except permission bits, false otherwise.
4120df7e8b8STetsuo Handa  */
tomoyo_same_mkdev_acl(const struct tomoyo_acl_info * a,const struct tomoyo_acl_info * b)41375093152STetsuo Handa static bool tomoyo_same_mkdev_acl(const struct tomoyo_acl_info *a,
414237ab459STetsuo Handa 					 const struct tomoyo_acl_info *b)
415237ab459STetsuo Handa {
4160df7e8b8STetsuo Handa 	const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1), head);
4170df7e8b8STetsuo Handa 	const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2), head);
418cdcf6723STetsuo Handa 
4190df7e8b8STetsuo Handa 	return tomoyo_same_name_union(&p1->name, &p2->name) &&
4200df7e8b8STetsuo Handa 		tomoyo_same_number_union(&p1->mode, &p2->mode) &&
4210df7e8b8STetsuo Handa 		tomoyo_same_number_union(&p1->major, &p2->major) &&
4220df7e8b8STetsuo Handa 		tomoyo_same_number_union(&p1->minor, &p2->minor);
423237ab459STetsuo Handa }
424237ab459STetsuo Handa 
4250df7e8b8STetsuo Handa /**
4260df7e8b8STetsuo Handa  * tomoyo_merge_mkdev_acl - Merge duplicated "struct tomoyo_mkdev_acl" entry.
4270df7e8b8STetsuo Handa  *
4280df7e8b8STetsuo Handa  * @a:         Pointer to "struct tomoyo_acl_info".
4290df7e8b8STetsuo Handa  * @b:         Pointer to "struct tomoyo_acl_info".
4300df7e8b8STetsuo Handa  * @is_delete: True for @a &= ~@b, false for @a |= @b.
4310df7e8b8STetsuo Handa  *
4320df7e8b8STetsuo Handa  * Returns true if @a is empty, false otherwise.
4330df7e8b8STetsuo Handa  */
tomoyo_merge_mkdev_acl(struct tomoyo_acl_info * a,struct tomoyo_acl_info * b,const bool is_delete)43475093152STetsuo Handa static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a,
435237ab459STetsuo Handa 				   struct tomoyo_acl_info *b,
436237ab459STetsuo Handa 				   const bool is_delete)
437237ab459STetsuo Handa {
43875093152STetsuo Handa 	u8 *const a_perm = &container_of(a, struct tomoyo_mkdev_acl,
439237ab459STetsuo Handa 					 head)->perm;
4405797e861STetsuo Handa 	u8 perm = READ_ONCE(*a_perm);
44175093152STetsuo Handa 	const u8 b_perm = container_of(b, struct tomoyo_mkdev_acl, head)
442237ab459STetsuo Handa 		->perm;
443cdcf6723STetsuo Handa 
444237ab459STetsuo Handa 	if (is_delete)
445237ab459STetsuo Handa 		perm &= ~b_perm;
446237ab459STetsuo Handa 	else
447237ab459STetsuo Handa 		perm |= b_perm;
4485797e861STetsuo Handa 	WRITE_ONCE(*a_perm, perm);
449237ab459STetsuo Handa 	return !perm;
450237ab459STetsuo Handa }
451237ab459STetsuo Handa 
452b69a54eeSKentaro Takeda /**
45375093152STetsuo Handa  * tomoyo_update_mkdev_acl - Update "struct tomoyo_mkdev_acl" list.
454a1f9bb6aSTetsuo Handa  *
455a238cf5bSTetsuo Handa  * @perm:  Permission.
456a238cf5bSTetsuo Handa  * @param: Pointer to "struct tomoyo_acl_param".
457a1f9bb6aSTetsuo Handa  *
458a1f9bb6aSTetsuo Handa  * Returns 0 on success, negative value otherwise.
459237ab459STetsuo Handa  *
460237ab459STetsuo Handa  * Caller holds tomoyo_read_lock().
461a1f9bb6aSTetsuo Handa  */
tomoyo_update_mkdev_acl(const u8 perm,struct tomoyo_acl_param * param)462a238cf5bSTetsuo Handa static int tomoyo_update_mkdev_acl(const u8 perm,
463a238cf5bSTetsuo Handa 				   struct tomoyo_acl_param *param)
464a1f9bb6aSTetsuo Handa {
46575093152STetsuo Handa 	struct tomoyo_mkdev_acl e = {
46675093152STetsuo Handa 		.head.type = TOMOYO_TYPE_MKDEV_ACL,
467a238cf5bSTetsuo Handa 		.perm = perm
468a1f9bb6aSTetsuo Handa 	};
469a238cf5bSTetsuo Handa 	int error;
470cdcf6723STetsuo Handa 
471a238cf5bSTetsuo Handa 	if (!tomoyo_parse_name_union(param, &e.name) ||
472a238cf5bSTetsuo Handa 	    !tomoyo_parse_number_union(param, &e.mode) ||
473a238cf5bSTetsuo Handa 	    !tomoyo_parse_number_union(param, &e.major) ||
474a238cf5bSTetsuo Handa 	    !tomoyo_parse_number_union(param, &e.minor))
475a238cf5bSTetsuo Handa 		error = -EINVAL;
476a238cf5bSTetsuo Handa 	else
477a238cf5bSTetsuo Handa 		error = tomoyo_update_domain(&e.head, sizeof(e), param,
47875093152STetsuo Handa 					     tomoyo_same_mkdev_acl,
47975093152STetsuo Handa 					     tomoyo_merge_mkdev_acl);
480a1f9bb6aSTetsuo Handa 	tomoyo_put_name_union(&e.name);
481a1f9bb6aSTetsuo Handa 	tomoyo_put_number_union(&e.mode);
482a1f9bb6aSTetsuo Handa 	tomoyo_put_number_union(&e.major);
483a1f9bb6aSTetsuo Handa 	tomoyo_put_number_union(&e.minor);
484a1f9bb6aSTetsuo Handa 	return error;
485a1f9bb6aSTetsuo Handa }
486a1f9bb6aSTetsuo Handa 
4870df7e8b8STetsuo Handa /**
4880df7e8b8STetsuo Handa  * tomoyo_same_path2_acl - Check for duplicated "struct tomoyo_path2_acl" entry.
4890df7e8b8STetsuo Handa  *
4900df7e8b8STetsuo Handa  * @a: Pointer to "struct tomoyo_acl_info".
4910df7e8b8STetsuo Handa  * @b: Pointer to "struct tomoyo_acl_info".
4920df7e8b8STetsuo Handa  *
4930df7e8b8STetsuo Handa  * Returns true if @a == @b except permission bits, false otherwise.
4940df7e8b8STetsuo Handa  */
tomoyo_same_path2_acl(const struct tomoyo_acl_info * a,const struct tomoyo_acl_info * b)495237ab459STetsuo Handa static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a,
496237ab459STetsuo Handa 				  const struct tomoyo_acl_info *b)
497237ab459STetsuo Handa {
498237ab459STetsuo Handa 	const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head);
499237ab459STetsuo Handa 	const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head);
500cdcf6723STetsuo Handa 
5010df7e8b8STetsuo Handa 	return tomoyo_same_name_union(&p1->name1, &p2->name1) &&
5020df7e8b8STetsuo Handa 		tomoyo_same_name_union(&p1->name2, &p2->name2);
503237ab459STetsuo Handa }
504237ab459STetsuo Handa 
5050df7e8b8STetsuo Handa /**
5060df7e8b8STetsuo Handa  * tomoyo_merge_path2_acl - Merge duplicated "struct tomoyo_path2_acl" entry.
5070df7e8b8STetsuo Handa  *
5080df7e8b8STetsuo Handa  * @a:         Pointer to "struct tomoyo_acl_info".
5090df7e8b8STetsuo Handa  * @b:         Pointer to "struct tomoyo_acl_info".
5100df7e8b8STetsuo Handa  * @is_delete: True for @a &= ~@b, false for @a |= @b.
5110df7e8b8STetsuo Handa  *
5120df7e8b8STetsuo Handa  * Returns true if @a is empty, false otherwise.
5130df7e8b8STetsuo Handa  */
tomoyo_merge_path2_acl(struct tomoyo_acl_info * a,struct tomoyo_acl_info * b,const bool is_delete)514237ab459STetsuo Handa static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a,
515237ab459STetsuo Handa 				   struct tomoyo_acl_info *b,
516237ab459STetsuo Handa 				   const bool is_delete)
517237ab459STetsuo Handa {
518237ab459STetsuo Handa 	u8 * const a_perm = &container_of(a, struct tomoyo_path2_acl, head)
519237ab459STetsuo Handa 		->perm;
5205797e861STetsuo Handa 	u8 perm = READ_ONCE(*a_perm);
521237ab459STetsuo Handa 	const u8 b_perm = container_of(b, struct tomoyo_path2_acl, head)->perm;
522cdcf6723STetsuo Handa 
523237ab459STetsuo Handa 	if (is_delete)
524237ab459STetsuo Handa 		perm &= ~b_perm;
525237ab459STetsuo Handa 	else
526237ab459STetsuo Handa 		perm |= b_perm;
5275797e861STetsuo Handa 	WRITE_ONCE(*a_perm, perm);
528237ab459STetsuo Handa 	return !perm;
529237ab459STetsuo Handa }
530237ab459STetsuo Handa 
531a1f9bb6aSTetsuo Handa /**
5327ef61233STetsuo Handa  * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list.
533b69a54eeSKentaro Takeda  *
534a238cf5bSTetsuo Handa  * @perm:  Permission.
535a238cf5bSTetsuo Handa  * @param: Pointer to "struct tomoyo_acl_param".
536b69a54eeSKentaro Takeda  *
537b69a54eeSKentaro Takeda  * Returns 0 on success, negative value otherwise.
538fdb8ebb7STetsuo Handa  *
539fdb8ebb7STetsuo Handa  * Caller holds tomoyo_read_lock().
540b69a54eeSKentaro Takeda  */
tomoyo_update_path2_acl(const u8 perm,struct tomoyo_acl_param * param)541a238cf5bSTetsuo Handa static int tomoyo_update_path2_acl(const u8 perm,
542a238cf5bSTetsuo Handa 				   struct tomoyo_acl_param *param)
543b69a54eeSKentaro Takeda {
5449e4b50e9STetsuo Handa 	struct tomoyo_path2_acl e = {
5459e4b50e9STetsuo Handa 		.head.type = TOMOYO_TYPE_PATH2_ACL,
546a238cf5bSTetsuo Handa 		.perm = perm
5479e4b50e9STetsuo Handa 	};
548a238cf5bSTetsuo Handa 	int error;
549cdcf6723STetsuo Handa 
550a238cf5bSTetsuo Handa 	if (!tomoyo_parse_name_union(param, &e.name1) ||
551a238cf5bSTetsuo Handa 	    !tomoyo_parse_name_union(param, &e.name2))
552a238cf5bSTetsuo Handa 		error = -EINVAL;
553a238cf5bSTetsuo Handa 	else
554a238cf5bSTetsuo Handa 		error = tomoyo_update_domain(&e.head, sizeof(e), param,
555237ab459STetsuo Handa 					     tomoyo_same_path2_acl,
556237ab459STetsuo Handa 					     tomoyo_merge_path2_acl);
5577762fbffSTetsuo Handa 	tomoyo_put_name_union(&e.name1);
5587762fbffSTetsuo Handa 	tomoyo_put_name_union(&e.name2);
559b69a54eeSKentaro Takeda 	return error;
560b69a54eeSKentaro Takeda }
561b69a54eeSKentaro Takeda 
562b69a54eeSKentaro Takeda /**
563cb0abe6aSTetsuo Handa  * tomoyo_path_permission - Check permission for single path operation.
564b69a54eeSKentaro Takeda  *
565cb0abe6aSTetsuo Handa  * @r:         Pointer to "struct tomoyo_request_info".
566b69a54eeSKentaro Takeda  * @operation: Type of operation.
567b69a54eeSKentaro Takeda  * @filename:  Filename to check.
568b69a54eeSKentaro Takeda  *
569b69a54eeSKentaro Takeda  * Returns 0 on success, negative value otherwise.
570fdb8ebb7STetsuo Handa  *
571fdb8ebb7STetsuo Handa  * Caller holds tomoyo_read_lock().
572b69a54eeSKentaro Takeda  */
tomoyo_path_permission(struct tomoyo_request_info * r,u8 operation,const struct tomoyo_path_info * filename)573778c4a4dSTetsuo Handa static int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
574cb0abe6aSTetsuo Handa 				  const struct tomoyo_path_info *filename)
575b69a54eeSKentaro Takeda {
576b69a54eeSKentaro Takeda 	int error;
577b69a54eeSKentaro Takeda 
57857c2590fSTetsuo Handa 	r->type = tomoyo_p2mac[operation];
579bd03a3e4STetsuo Handa 	r->mode = tomoyo_get_mode(r->domain->ns, r->profile, r->type);
58057c2590fSTetsuo Handa 	if (r->mode == TOMOYO_CONFIG_DISABLED)
58157c2590fSTetsuo Handa 		return 0;
582cf6e9a64STetsuo Handa 	r->param_type = TOMOYO_TYPE_PATH_ACL;
583cf6e9a64STetsuo Handa 	r->param.path.filename = filename;
584cf6e9a64STetsuo Handa 	r->param.path.operation = operation;
58517fcfbd9STetsuo Handa 	do {
58699a85259STetsuo Handa 		tomoyo_check_acl(r, tomoyo_check_path_acl);
58799a85259STetsuo Handa 		error = tomoyo_audit_path_log(r);
5886bce98edSTetsuo Handa 	} while (error == TOMOYO_RETRY_REQUEST);
589b69a54eeSKentaro Takeda 	return error;
590b69a54eeSKentaro Takeda }
591b69a54eeSKentaro Takeda 
5920df7e8b8STetsuo Handa /**
5936bce98edSTetsuo Handa  * tomoyo_execute_permission - Check permission for execute operation.
5946bce98edSTetsuo Handa  *
5956bce98edSTetsuo Handa  * @r:         Pointer to "struct tomoyo_request_info".
5966bce98edSTetsuo Handa  * @filename:  Filename to check.
5976bce98edSTetsuo Handa  *
5986bce98edSTetsuo Handa  * Returns 0 on success, negative value otherwise.
5996bce98edSTetsuo Handa  *
6006bce98edSTetsuo Handa  * Caller holds tomoyo_read_lock().
6016bce98edSTetsuo Handa  */
tomoyo_execute_permission(struct tomoyo_request_info * r,const struct tomoyo_path_info * filename)6026bce98edSTetsuo Handa int tomoyo_execute_permission(struct tomoyo_request_info *r,
6036bce98edSTetsuo Handa 			      const struct tomoyo_path_info *filename)
6046bce98edSTetsuo Handa {
6056bce98edSTetsuo Handa 	/*
6066bce98edSTetsuo Handa 	 * Unlike other permission checks, this check is done regardless of
6076bce98edSTetsuo Handa 	 * profile mode settings in order to check for domain transition
6086bce98edSTetsuo Handa 	 * preference.
6096bce98edSTetsuo Handa 	 */
6106bce98edSTetsuo Handa 	r->type = TOMOYO_MAC_FILE_EXECUTE;
6116bce98edSTetsuo Handa 	r->mode = tomoyo_get_mode(r->domain->ns, r->profile, r->type);
6126bce98edSTetsuo Handa 	r->param_type = TOMOYO_TYPE_PATH_ACL;
6136bce98edSTetsuo Handa 	r->param.path.filename = filename;
6146bce98edSTetsuo Handa 	r->param.path.operation = TOMOYO_TYPE_EXECUTE;
6156bce98edSTetsuo Handa 	tomoyo_check_acl(r, tomoyo_check_path_acl);
6166bce98edSTetsuo Handa 	r->ee->transition = r->matched_acl && r->matched_acl->cond ?
6176bce98edSTetsuo Handa 		r->matched_acl->cond->transit : NULL;
6186bce98edSTetsuo Handa 	if (r->mode != TOMOYO_CONFIG_DISABLED)
6196bce98edSTetsuo Handa 		return tomoyo_audit_path_log(r);
6206bce98edSTetsuo Handa 	return 0;
6216bce98edSTetsuo Handa }
6226bce98edSTetsuo Handa 
6236bce98edSTetsuo Handa /**
6240df7e8b8STetsuo Handa  * tomoyo_same_path_number_acl - Check for duplicated "struct tomoyo_path_number_acl" entry.
6250df7e8b8STetsuo Handa  *
6260df7e8b8STetsuo Handa  * @a: Pointer to "struct tomoyo_acl_info".
6270df7e8b8STetsuo Handa  * @b: Pointer to "struct tomoyo_acl_info".
6280df7e8b8STetsuo Handa  *
6290df7e8b8STetsuo Handa  * Returns true if @a == @b except permission bits, false otherwise.
6300df7e8b8STetsuo Handa  */
tomoyo_same_path_number_acl(const struct tomoyo_acl_info * a,const struct tomoyo_acl_info * b)631237ab459STetsuo Handa static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a,
632237ab459STetsuo Handa 					const struct tomoyo_acl_info *b)
633237ab459STetsuo Handa {
634237ab459STetsuo Handa 	const struct tomoyo_path_number_acl *p1 = container_of(a, typeof(*p1),
635237ab459STetsuo Handa 							       head);
636237ab459STetsuo Handa 	const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2),
637237ab459STetsuo Handa 							       head);
638cdcf6723STetsuo Handa 
6390df7e8b8STetsuo Handa 	return tomoyo_same_name_union(&p1->name, &p2->name) &&
6400df7e8b8STetsuo Handa 		tomoyo_same_number_union(&p1->number, &p2->number);
641237ab459STetsuo Handa }
642237ab459STetsuo Handa 
6430df7e8b8STetsuo Handa /**
6440df7e8b8STetsuo Handa  * tomoyo_merge_path_number_acl - Merge duplicated "struct tomoyo_path_number_acl" entry.
6450df7e8b8STetsuo Handa  *
6460df7e8b8STetsuo Handa  * @a:         Pointer to "struct tomoyo_acl_info".
6470df7e8b8STetsuo Handa  * @b:         Pointer to "struct tomoyo_acl_info".
6480df7e8b8STetsuo Handa  * @is_delete: True for @a &= ~@b, false for @a |= @b.
6490df7e8b8STetsuo Handa  *
6500df7e8b8STetsuo Handa  * Returns true if @a is empty, false otherwise.
6510df7e8b8STetsuo Handa  */
tomoyo_merge_path_number_acl(struct tomoyo_acl_info * a,struct tomoyo_acl_info * b,const bool is_delete)652237ab459STetsuo Handa static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a,
653237ab459STetsuo Handa 					 struct tomoyo_acl_info *b,
654237ab459STetsuo Handa 					 const bool is_delete)
655237ab459STetsuo Handa {
656237ab459STetsuo Handa 	u8 * const a_perm = &container_of(a, struct tomoyo_path_number_acl,
657237ab459STetsuo Handa 					  head)->perm;
6585797e861STetsuo Handa 	u8 perm = READ_ONCE(*a_perm);
659237ab459STetsuo Handa 	const u8 b_perm = container_of(b, struct tomoyo_path_number_acl, head)
660237ab459STetsuo Handa 		->perm;
661cdcf6723STetsuo Handa 
662237ab459STetsuo Handa 	if (is_delete)
663237ab459STetsuo Handa 		perm &= ~b_perm;
664237ab459STetsuo Handa 	else
665237ab459STetsuo Handa 		perm |= b_perm;
6665797e861STetsuo Handa 	WRITE_ONCE(*a_perm, perm);
667237ab459STetsuo Handa 	return !perm;
668237ab459STetsuo Handa }
669237ab459STetsuo Handa 
670a1f9bb6aSTetsuo Handa /**
671a1f9bb6aSTetsuo Handa  * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL.
672a1f9bb6aSTetsuo Handa  *
673a238cf5bSTetsuo Handa  * @perm:  Permission.
674a238cf5bSTetsuo Handa  * @param: Pointer to "struct tomoyo_acl_param".
675a1f9bb6aSTetsuo Handa  *
676a1f9bb6aSTetsuo Handa  * Returns 0 on success, negative value otherwise.
677a1f9bb6aSTetsuo Handa  */
tomoyo_update_path_number_acl(const u8 perm,struct tomoyo_acl_param * param)678a238cf5bSTetsuo Handa static int tomoyo_update_path_number_acl(const u8 perm,
679a238cf5bSTetsuo Handa 					 struct tomoyo_acl_param *param)
680a1f9bb6aSTetsuo Handa {
681a1f9bb6aSTetsuo Handa 	struct tomoyo_path_number_acl e = {
682a1f9bb6aSTetsuo Handa 		.head.type = TOMOYO_TYPE_PATH_NUMBER_ACL,
683a238cf5bSTetsuo Handa 		.perm = perm
684a1f9bb6aSTetsuo Handa 	};
685a238cf5bSTetsuo Handa 	int error;
686cdcf6723STetsuo Handa 
687a238cf5bSTetsuo Handa 	if (!tomoyo_parse_name_union(param, &e.name) ||
688a238cf5bSTetsuo Handa 	    !tomoyo_parse_number_union(param, &e.number))
689a238cf5bSTetsuo Handa 		error = -EINVAL;
690a238cf5bSTetsuo Handa 	else
691a238cf5bSTetsuo Handa 		error = tomoyo_update_domain(&e.head, sizeof(e), param,
692237ab459STetsuo Handa 					     tomoyo_same_path_number_acl,
693237ab459STetsuo Handa 					     tomoyo_merge_path_number_acl);
694a1f9bb6aSTetsuo Handa 	tomoyo_put_name_union(&e.name);
695a1f9bb6aSTetsuo Handa 	tomoyo_put_number_union(&e.number);
696a1f9bb6aSTetsuo Handa 	return error;
697a1f9bb6aSTetsuo Handa }
698a1f9bb6aSTetsuo Handa 
699a1f9bb6aSTetsuo Handa /**
700a1f9bb6aSTetsuo Handa  * tomoyo_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp".
701a1f9bb6aSTetsuo Handa  *
702a1f9bb6aSTetsuo Handa  * @type:   Type of operation.
703a1f9bb6aSTetsuo Handa  * @path:   Pointer to "struct path".
704a1f9bb6aSTetsuo Handa  * @number: Number.
705a1f9bb6aSTetsuo Handa  *
706a1f9bb6aSTetsuo Handa  * Returns 0 on success, negative value otherwise.
707a1f9bb6aSTetsuo Handa  */
tomoyo_path_number_perm(const u8 type,const struct path * path,unsigned long number)708e6641eddSAl Viro int tomoyo_path_number_perm(const u8 type, const struct path *path,
709a1f9bb6aSTetsuo Handa 			    unsigned long number)
710a1f9bb6aSTetsuo Handa {
711a1f9bb6aSTetsuo Handa 	struct tomoyo_request_info r;
71297fb35e4STetsuo Handa 	struct tomoyo_obj_info obj = {
7138291798dSKees Cook 		.path1 = { .mnt = path->mnt, .dentry = path->dentry },
71497fb35e4STetsuo Handa 	};
715a1f9bb6aSTetsuo Handa 	int error = -ENOMEM;
716c8c57e84STetsuo Handa 	struct tomoyo_path_info buf;
717a1f9bb6aSTetsuo Handa 	int idx;
718a1f9bb6aSTetsuo Handa 
71957c2590fSTetsuo Handa 	if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type])
720*467cf8efSAl Viro 	    == TOMOYO_CONFIG_DISABLED)
721a1f9bb6aSTetsuo Handa 		return 0;
722a1f9bb6aSTetsuo Handa 	idx = tomoyo_read_lock();
723c8c57e84STetsuo Handa 	if (!tomoyo_get_realpath(&buf, path))
724a1f9bb6aSTetsuo Handa 		goto out;
72597fb35e4STetsuo Handa 	r.obj = &obj;
726c8c57e84STetsuo Handa 	if (type == TOMOYO_TYPE_MKDIR)
727c8c57e84STetsuo Handa 		tomoyo_add_slash(&buf);
728cb917cf5STetsuo Handa 	r.param_type = TOMOYO_TYPE_PATH_NUMBER_ACL;
729cb917cf5STetsuo Handa 	r.param.path_number.operation = type;
730cb917cf5STetsuo Handa 	r.param.path_number.filename = &buf;
731cb917cf5STetsuo Handa 	r.param.path_number.number = number;
732cb917cf5STetsuo Handa 	do {
733cb917cf5STetsuo Handa 		tomoyo_check_acl(&r, tomoyo_check_path_number_acl);
734cb917cf5STetsuo Handa 		error = tomoyo_audit_path_number_log(&r);
735cb917cf5STetsuo Handa 	} while (error == TOMOYO_RETRY_REQUEST);
736c8c57e84STetsuo Handa 	kfree(buf.name);
737cb917cf5STetsuo Handa  out:
738a1f9bb6aSTetsuo Handa 	tomoyo_read_unlock(idx);
739a1f9bb6aSTetsuo Handa 	if (r.mode != TOMOYO_CONFIG_ENFORCING)
740a1f9bb6aSTetsuo Handa 		error = 0;
741a1f9bb6aSTetsuo Handa 	return error;
742a1f9bb6aSTetsuo Handa }
743a1f9bb6aSTetsuo Handa 
744a1f9bb6aSTetsuo Handa /**
745b69a54eeSKentaro Takeda  * tomoyo_check_open_permission - Check permission for "read" and "write".
746b69a54eeSKentaro Takeda  *
747b69a54eeSKentaro Takeda  * @domain: Pointer to "struct tomoyo_domain_info".
748b69a54eeSKentaro Takeda  * @path:   Pointer to "struct path".
749b69a54eeSKentaro Takeda  * @flag:   Flags for open().
750b69a54eeSKentaro Takeda  *
751b69a54eeSKentaro Takeda  * Returns 0 on success, negative value otherwise.
752b69a54eeSKentaro Takeda  */
tomoyo_check_open_permission(struct tomoyo_domain_info * domain,const struct path * path,const int flag)753b69a54eeSKentaro Takeda int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
754e6641eddSAl Viro 				 const struct path *path, const int flag)
755b69a54eeSKentaro Takeda {
756b69a54eeSKentaro Takeda 	const u8 acc_mode = ACC_MODE(flag);
757eae61f3cSTetsuo Handa 	int error = 0;
758c8c57e84STetsuo Handa 	struct tomoyo_path_info buf;
759cb0abe6aSTetsuo Handa 	struct tomoyo_request_info r;
76097fb35e4STetsuo Handa 	struct tomoyo_obj_info obj = {
7618291798dSKees Cook 		.path1 = { .mnt = path->mnt, .dentry = path->dentry },
76297fb35e4STetsuo Handa 	};
763fdb8ebb7STetsuo Handa 	int idx;
764b69a54eeSKentaro Takeda 
76557c2590fSTetsuo Handa 	buf.name = NULL;
76657c2590fSTetsuo Handa 	r.mode = TOMOYO_CONFIG_DISABLED;
767fdb8ebb7STetsuo Handa 	idx = tomoyo_read_lock();
7687c75964fSTetsuo Handa 	if (acc_mode &&
7697c75964fSTetsuo Handa 	    tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN)
77057c2590fSTetsuo Handa 	    != TOMOYO_CONFIG_DISABLED) {
77157c2590fSTetsuo Handa 		if (!tomoyo_get_realpath(&buf, path)) {
77257c2590fSTetsuo Handa 			error = -ENOMEM;
77357c2590fSTetsuo Handa 			goto out;
774b69a54eeSKentaro Takeda 		}
77597fb35e4STetsuo Handa 		r.obj = &obj;
7767c75964fSTetsuo Handa 		if (acc_mode & MAY_READ)
7777c75964fSTetsuo Handa 			error = tomoyo_path_permission(&r, TOMOYO_TYPE_READ,
77857c2590fSTetsuo Handa 						       &buf);
7797c75964fSTetsuo Handa 		if (!error && (acc_mode & MAY_WRITE))
7807c75964fSTetsuo Handa 			error = tomoyo_path_permission(&r, (flag & O_APPEND) ?
7817c75964fSTetsuo Handa 						       TOMOYO_TYPE_APPEND :
7827c75964fSTetsuo Handa 						       TOMOYO_TYPE_WRITE,
7837c75964fSTetsuo Handa 						       &buf);
78457c2590fSTetsuo Handa 	}
785b69a54eeSKentaro Takeda  out:
786c8c57e84STetsuo Handa 	kfree(buf.name);
787fdb8ebb7STetsuo Handa 	tomoyo_read_unlock(idx);
788cb0abe6aSTetsuo Handa 	if (r.mode != TOMOYO_CONFIG_ENFORCING)
789b69a54eeSKentaro Takeda 		error = 0;
790b69a54eeSKentaro Takeda 	return error;
791b69a54eeSKentaro Takeda }
792b69a54eeSKentaro Takeda 
793b69a54eeSKentaro Takeda /**
7947c75964fSTetsuo Handa  * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "append", "chroot" and "unmount".
795b69a54eeSKentaro Takeda  *
796b69a54eeSKentaro Takeda  * @operation: Type of operation.
797b69a54eeSKentaro Takeda  * @path:      Pointer to "struct path".
79897fb35e4STetsuo Handa  * @target:    Symlink's target if @operation is TOMOYO_TYPE_SYMLINK,
79997fb35e4STetsuo Handa  *             NULL otherwise.
800b69a54eeSKentaro Takeda  *
801b69a54eeSKentaro Takeda  * Returns 0 on success, negative value otherwise.
802b69a54eeSKentaro Takeda  */
tomoyo_path_perm(const u8 operation,const struct path * path,const char * target)8033f7036a0SAl Viro int tomoyo_path_perm(const u8 operation, const struct path *path, const char *target)
804b69a54eeSKentaro Takeda {
805cb0abe6aSTetsuo Handa 	struct tomoyo_request_info r;
80697fb35e4STetsuo Handa 	struct tomoyo_obj_info obj = {
8078291798dSKees Cook 		.path1 = { .mnt = path->mnt, .dentry = path->dentry },
80897fb35e4STetsuo Handa 	};
8097c75964fSTetsuo Handa 	int error;
8107c75964fSTetsuo Handa 	struct tomoyo_path_info buf;
8117c75964fSTetsuo Handa 	bool is_enforce;
81297fb35e4STetsuo Handa 	struct tomoyo_path_info symlink_target;
813fdb8ebb7STetsuo Handa 	int idx;
814b69a54eeSKentaro Takeda 
81557c2590fSTetsuo Handa 	if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation])
81657c2590fSTetsuo Handa 	    == TOMOYO_CONFIG_DISABLED)
81757c2590fSTetsuo Handa 		return 0;
8187c75964fSTetsuo Handa 	is_enforce = (r.mode == TOMOYO_CONFIG_ENFORCING);
8197c75964fSTetsuo Handa 	error = -ENOMEM;
82057c2590fSTetsuo Handa 	buf.name = NULL;
821fdb8ebb7STetsuo Handa 	idx = tomoyo_read_lock();
822c8c57e84STetsuo Handa 	if (!tomoyo_get_realpath(&buf, path))
823b69a54eeSKentaro Takeda 		goto out;
82497fb35e4STetsuo Handa 	r.obj = &obj;
825b69a54eeSKentaro Takeda 	switch (operation) {
8267ef61233STetsuo Handa 	case TOMOYO_TYPE_RMDIR:
8277ef61233STetsuo Handa 	case TOMOYO_TYPE_CHROOT:
828c8c57e84STetsuo Handa 		tomoyo_add_slash(&buf);
829c8c57e84STetsuo Handa 		break;
83097fb35e4STetsuo Handa 	case TOMOYO_TYPE_SYMLINK:
83197fb35e4STetsuo Handa 		symlink_target.name = tomoyo_encode(target);
83297fb35e4STetsuo Handa 		if (!symlink_target.name)
83397fb35e4STetsuo Handa 			goto out;
83497fb35e4STetsuo Handa 		tomoyo_fill_path_info(&symlink_target);
83597fb35e4STetsuo Handa 		obj.symlink_target = &symlink_target;
83697fb35e4STetsuo Handa 		break;
837b69a54eeSKentaro Takeda 	}
838c8c57e84STetsuo Handa 	error = tomoyo_path_permission(&r, operation, &buf);
83997fb35e4STetsuo Handa 	if (operation == TOMOYO_TYPE_SYMLINK)
84097fb35e4STetsuo Handa 		kfree(symlink_target.name);
841b69a54eeSKentaro Takeda  out:
842c8c57e84STetsuo Handa 	kfree(buf.name);
843fdb8ebb7STetsuo Handa 	tomoyo_read_unlock(idx);
8447c75964fSTetsuo Handa 	if (!is_enforce)
845b69a54eeSKentaro Takeda 		error = 0;
846b69a54eeSKentaro Takeda 	return error;
847b69a54eeSKentaro Takeda }
848b69a54eeSKentaro Takeda 
849b69a54eeSKentaro Takeda /**
85075093152STetsuo Handa  * tomoyo_mkdev_perm - Check permission for "mkblock" and "mkchar".
851a1f9bb6aSTetsuo Handa  *
852a1f9bb6aSTetsuo Handa  * @operation: Type of operation. (TOMOYO_TYPE_MKCHAR or TOMOYO_TYPE_MKBLOCK)
853a1f9bb6aSTetsuo Handa  * @path:      Pointer to "struct path".
854a1f9bb6aSTetsuo Handa  * @mode:      Create mode.
855a1f9bb6aSTetsuo Handa  * @dev:       Device number.
856a1f9bb6aSTetsuo Handa  *
857a1f9bb6aSTetsuo Handa  * Returns 0 on success, negative value otherwise.
858a1f9bb6aSTetsuo Handa  */
tomoyo_mkdev_perm(const u8 operation,const struct path * path,const unsigned int mode,unsigned int dev)859e6641eddSAl Viro int tomoyo_mkdev_perm(const u8 operation, const struct path *path,
860a1f9bb6aSTetsuo Handa 		      const unsigned int mode, unsigned int dev)
861a1f9bb6aSTetsuo Handa {
862a1f9bb6aSTetsuo Handa 	struct tomoyo_request_info r;
86397fb35e4STetsuo Handa 	struct tomoyo_obj_info obj = {
8648291798dSKees Cook 		.path1 = { .mnt = path->mnt, .dentry = path->dentry },
86597fb35e4STetsuo Handa 	};
866a1f9bb6aSTetsuo Handa 	int error = -ENOMEM;
867c8c57e84STetsuo Handa 	struct tomoyo_path_info buf;
868a1f9bb6aSTetsuo Handa 	int idx;
869a1f9bb6aSTetsuo Handa 
8705625f2e3STetsuo Handa 	if (tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation])
87157c2590fSTetsuo Handa 	    == TOMOYO_CONFIG_DISABLED)
872a1f9bb6aSTetsuo Handa 		return 0;
873a1f9bb6aSTetsuo Handa 	idx = tomoyo_read_lock();
874a1f9bb6aSTetsuo Handa 	error = -ENOMEM;
875c8c57e84STetsuo Handa 	if (tomoyo_get_realpath(&buf, path)) {
87697fb35e4STetsuo Handa 		r.obj = &obj;
877cf6e9a64STetsuo Handa 		dev = new_decode_dev(dev);
87875093152STetsuo Handa 		r.param_type = TOMOYO_TYPE_MKDEV_ACL;
879cf6e9a64STetsuo Handa 		r.param.mkdev.filename = &buf;
880cf6e9a64STetsuo Handa 		r.param.mkdev.operation = operation;
881cf6e9a64STetsuo Handa 		r.param.mkdev.mode = mode;
882cf6e9a64STetsuo Handa 		r.param.mkdev.major = MAJOR(dev);
883cf6e9a64STetsuo Handa 		r.param.mkdev.minor = MINOR(dev);
88499a85259STetsuo Handa 		tomoyo_check_acl(&r, tomoyo_check_mkdev_acl);
88599a85259STetsuo Handa 		error = tomoyo_audit_mkdev_log(&r);
886c8c57e84STetsuo Handa 		kfree(buf.name);
887a1f9bb6aSTetsuo Handa 	}
888a1f9bb6aSTetsuo Handa 	tomoyo_read_unlock(idx);
889a1f9bb6aSTetsuo Handa 	if (r.mode != TOMOYO_CONFIG_ENFORCING)
890a1f9bb6aSTetsuo Handa 		error = 0;
891a1f9bb6aSTetsuo Handa 	return error;
892a1f9bb6aSTetsuo Handa }
893a1f9bb6aSTetsuo Handa 
894a1f9bb6aSTetsuo Handa /**
8957ef61233STetsuo Handa  * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root".
896b69a54eeSKentaro Takeda  *
897b69a54eeSKentaro Takeda  * @operation: Type of operation.
898b69a54eeSKentaro Takeda  * @path1:      Pointer to "struct path".
899b69a54eeSKentaro Takeda  * @path2:      Pointer to "struct path".
900b69a54eeSKentaro Takeda  *
901b69a54eeSKentaro Takeda  * Returns 0 on success, negative value otherwise.
902b69a54eeSKentaro Takeda  */
tomoyo_path2_perm(const u8 operation,const struct path * path1,const struct path * path2)903e6641eddSAl Viro int tomoyo_path2_perm(const u8 operation, const struct path *path1,
904e6641eddSAl Viro 		      const struct path *path2)
905b69a54eeSKentaro Takeda {
906b69a54eeSKentaro Takeda 	int error = -ENOMEM;
907c8c57e84STetsuo Handa 	struct tomoyo_path_info buf1;
908c8c57e84STetsuo Handa 	struct tomoyo_path_info buf2;
909cb0abe6aSTetsuo Handa 	struct tomoyo_request_info r;
91097fb35e4STetsuo Handa 	struct tomoyo_obj_info obj = {
9118291798dSKees Cook 		.path1 = { .mnt = path1->mnt, .dentry = path1->dentry },
9128291798dSKees Cook 		.path2 = { .mnt = path2->mnt, .dentry = path2->dentry }
91397fb35e4STetsuo Handa 	};
914fdb8ebb7STetsuo Handa 	int idx;
915b69a54eeSKentaro Takeda 
9165625f2e3STetsuo Handa 	if (tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation])
91757c2590fSTetsuo Handa 	    == TOMOYO_CONFIG_DISABLED)
918b69a54eeSKentaro Takeda 		return 0;
919c8c57e84STetsuo Handa 	buf1.name = NULL;
920c8c57e84STetsuo Handa 	buf2.name = NULL;
921fdb8ebb7STetsuo Handa 	idx = tomoyo_read_lock();
922c8c57e84STetsuo Handa 	if (!tomoyo_get_realpath(&buf1, path1) ||
923c8c57e84STetsuo Handa 	    !tomoyo_get_realpath(&buf2, path2))
924b69a54eeSKentaro Takeda 		goto out;
92557c2590fSTetsuo Handa 	switch (operation) {
92657c2590fSTetsuo Handa 	case TOMOYO_TYPE_RENAME:
92757c2590fSTetsuo Handa 	case TOMOYO_TYPE_LINK:
928e656a8ebSDavid Howells 		if (!d_is_dir(path1->dentry))
92957c2590fSTetsuo Handa 			break;
930df561f66SGustavo A. R. Silva 		fallthrough;
93157c2590fSTetsuo Handa 	case TOMOYO_TYPE_PIVOT_ROOT:
932c8c57e84STetsuo Handa 		tomoyo_add_slash(&buf1);
933c8c57e84STetsuo Handa 		tomoyo_add_slash(&buf2);
93457c2590fSTetsuo Handa 		break;
935b69a54eeSKentaro Takeda 	}
93697fb35e4STetsuo Handa 	r.obj = &obj;
937cf6e9a64STetsuo Handa 	r.param_type = TOMOYO_TYPE_PATH2_ACL;
938cf6e9a64STetsuo Handa 	r.param.path2.operation = operation;
939cf6e9a64STetsuo Handa 	r.param.path2.filename1 = &buf1;
940cf6e9a64STetsuo Handa 	r.param.path2.filename2 = &buf2;
94117fcfbd9STetsuo Handa 	do {
94299a85259STetsuo Handa 		tomoyo_check_acl(&r, tomoyo_check_path2_acl);
94399a85259STetsuo Handa 		error = tomoyo_audit_path2_log(&r);
94417fcfbd9STetsuo Handa 	} while (error == TOMOYO_RETRY_REQUEST);
945b69a54eeSKentaro Takeda  out:
946c8c57e84STetsuo Handa 	kfree(buf1.name);
947c8c57e84STetsuo Handa 	kfree(buf2.name);
948fdb8ebb7STetsuo Handa 	tomoyo_read_unlock(idx);
949cb0abe6aSTetsuo Handa 	if (r.mode != TOMOYO_CONFIG_ENFORCING)
950b69a54eeSKentaro Takeda 		error = 0;
951b69a54eeSKentaro Takeda 	return error;
952b69a54eeSKentaro Takeda }
953a1f9bb6aSTetsuo Handa 
954a1f9bb6aSTetsuo Handa /**
955a238cf5bSTetsuo Handa  * tomoyo_same_mount_acl - Check for duplicated "struct tomoyo_mount_acl" entry.
956a1f9bb6aSTetsuo Handa  *
957a238cf5bSTetsuo Handa  * @a: Pointer to "struct tomoyo_acl_info".
958a238cf5bSTetsuo Handa  * @b: Pointer to "struct tomoyo_acl_info".
959a238cf5bSTetsuo Handa  *
960a238cf5bSTetsuo Handa  * Returns true if @a == @b, false otherwise.
961a238cf5bSTetsuo Handa  */
tomoyo_same_mount_acl(const struct tomoyo_acl_info * a,const struct tomoyo_acl_info * b)962a238cf5bSTetsuo Handa static bool tomoyo_same_mount_acl(const struct tomoyo_acl_info *a,
963a238cf5bSTetsuo Handa 				  const struct tomoyo_acl_info *b)
964a238cf5bSTetsuo Handa {
965a238cf5bSTetsuo Handa 	const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head);
966a238cf5bSTetsuo Handa 	const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head);
967cdcf6723STetsuo Handa 
968a238cf5bSTetsuo Handa 	return tomoyo_same_name_union(&p1->dev_name, &p2->dev_name) &&
969a238cf5bSTetsuo Handa 		tomoyo_same_name_union(&p1->dir_name, &p2->dir_name) &&
970a238cf5bSTetsuo Handa 		tomoyo_same_name_union(&p1->fs_type, &p2->fs_type) &&
971a238cf5bSTetsuo Handa 		tomoyo_same_number_union(&p1->flags, &p2->flags);
972a238cf5bSTetsuo Handa }
973a238cf5bSTetsuo Handa 
974a238cf5bSTetsuo Handa /**
975a238cf5bSTetsuo Handa  * tomoyo_update_mount_acl - Write "struct tomoyo_mount_acl" list.
976a238cf5bSTetsuo Handa  *
977a238cf5bSTetsuo Handa  * @param: Pointer to "struct tomoyo_acl_param".
978a1f9bb6aSTetsuo Handa  *
979a1f9bb6aSTetsuo Handa  * Returns 0 on success, negative value otherwise.
980a1f9bb6aSTetsuo Handa  *
981a1f9bb6aSTetsuo Handa  * Caller holds tomoyo_read_lock().
982a1f9bb6aSTetsuo Handa  */
tomoyo_update_mount_acl(struct tomoyo_acl_param * param)983a238cf5bSTetsuo Handa static int tomoyo_update_mount_acl(struct tomoyo_acl_param *param)
984a1f9bb6aSTetsuo Handa {
985a238cf5bSTetsuo Handa 	struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL };
986a238cf5bSTetsuo Handa 	int error;
987cdcf6723STetsuo Handa 
988a238cf5bSTetsuo Handa 	if (!tomoyo_parse_name_union(param, &e.dev_name) ||
989a238cf5bSTetsuo Handa 	    !tomoyo_parse_name_union(param, &e.dir_name) ||
990a238cf5bSTetsuo Handa 	    !tomoyo_parse_name_union(param, &e.fs_type) ||
991a238cf5bSTetsuo Handa 	    !tomoyo_parse_number_union(param, &e.flags))
992a238cf5bSTetsuo Handa 		error = -EINVAL;
993a238cf5bSTetsuo Handa 	else
994a238cf5bSTetsuo Handa 		error = tomoyo_update_domain(&e.head, sizeof(e), param,
995a238cf5bSTetsuo Handa 					     tomoyo_same_mount_acl, NULL);
996a238cf5bSTetsuo Handa 	tomoyo_put_name_union(&e.dev_name);
997a238cf5bSTetsuo Handa 	tomoyo_put_name_union(&e.dir_name);
998a238cf5bSTetsuo Handa 	tomoyo_put_name_union(&e.fs_type);
999a238cf5bSTetsuo Handa 	tomoyo_put_number_union(&e.flags);
1000a238cf5bSTetsuo Handa 	return error;
1001a238cf5bSTetsuo Handa }
1002a238cf5bSTetsuo Handa 
1003a238cf5bSTetsuo Handa /**
1004a238cf5bSTetsuo Handa  * tomoyo_write_file - Update file related list.
1005a238cf5bSTetsuo Handa  *
1006a238cf5bSTetsuo Handa  * @param: Pointer to "struct tomoyo_acl_param".
1007a238cf5bSTetsuo Handa  *
1008a238cf5bSTetsuo Handa  * Returns 0 on success, negative value otherwise.
1009a238cf5bSTetsuo Handa  *
1010a238cf5bSTetsuo Handa  * Caller holds tomoyo_read_lock().
1011a238cf5bSTetsuo Handa  */
tomoyo_write_file(struct tomoyo_acl_param * param)1012a238cf5bSTetsuo Handa int tomoyo_write_file(struct tomoyo_acl_param *param)
1013a238cf5bSTetsuo Handa {
1014a238cf5bSTetsuo Handa 	u16 perm = 0;
1015a1f9bb6aSTetsuo Handa 	u8 type;
1016a238cf5bSTetsuo Handa 	const char *operation = tomoyo_read_token(param);
1017cdcf6723STetsuo Handa 
1018a238cf5bSTetsuo Handa 	for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++)
1019a238cf5bSTetsuo Handa 		if (tomoyo_permstr(operation, tomoyo_path_keyword[type]))
1020a238cf5bSTetsuo Handa 			perm |= 1 << type;
1021a238cf5bSTetsuo Handa 	if (perm)
1022a238cf5bSTetsuo Handa 		return tomoyo_update_path_acl(perm, param);
1023a238cf5bSTetsuo Handa 	for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++)
10242c47ab93STetsuo Handa 		if (tomoyo_permstr(operation,
10252c47ab93STetsuo Handa 				   tomoyo_mac_keywords[tomoyo_pp2mac[type]]))
1026a238cf5bSTetsuo Handa 			perm |= 1 << type;
1027a238cf5bSTetsuo Handa 	if (perm)
1028a238cf5bSTetsuo Handa 		return tomoyo_update_path2_acl(perm, param);
1029a238cf5bSTetsuo Handa 	for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++)
1030a238cf5bSTetsuo Handa 		if (tomoyo_permstr(operation,
10312c47ab93STetsuo Handa 				   tomoyo_mac_keywords[tomoyo_pn2mac[type]]))
1032a238cf5bSTetsuo Handa 			perm |= 1 << type;
1033a238cf5bSTetsuo Handa 	if (perm)
1034a238cf5bSTetsuo Handa 		return tomoyo_update_path_number_acl(perm, param);
1035a238cf5bSTetsuo Handa 	for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++)
10362c47ab93STetsuo Handa 		if (tomoyo_permstr(operation,
10372c47ab93STetsuo Handa 				   tomoyo_mac_keywords[tomoyo_pnnn2mac[type]]))
1038a238cf5bSTetsuo Handa 			perm |= 1 << type;
1039a238cf5bSTetsuo Handa 	if (perm)
1040a238cf5bSTetsuo Handa 		return tomoyo_update_mkdev_acl(perm, param);
10412c47ab93STetsuo Handa 	if (tomoyo_permstr(operation,
10422c47ab93STetsuo Handa 			   tomoyo_mac_keywords[TOMOYO_MAC_FILE_MOUNT]))
1043a238cf5bSTetsuo Handa 		return tomoyo_update_mount_acl(param);
1044a1f9bb6aSTetsuo Handa 	return -EINVAL;
1045a1f9bb6aSTetsuo Handa }
1046