xref: /openbmc/linux/security/tomoyo/file.c (revision a238cf5b)
1b69a54eeSKentaro Takeda /*
2b69a54eeSKentaro Takeda  * security/tomoyo/file.c
3b69a54eeSKentaro Takeda  *
4c3ef1500STetsuo Handa  * Pathname restriction functions.
5b69a54eeSKentaro Takeda  *
6c3ef1500STetsuo Handa  * Copyright (C) 2005-2010  NTT DATA CORPORATION
7b69a54eeSKentaro Takeda  */
8b69a54eeSKentaro Takeda 
9b69a54eeSKentaro Takeda #include "common.h"
105a0e3ad6STejun Heo #include <linux/slab.h>
11b69a54eeSKentaro Takeda 
12a1f9bb6aSTetsuo Handa /* Keyword array for operations with one pathname. */
1371c28236STetsuo Handa const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = {
147ef61233STetsuo Handa 	[TOMOYO_TYPE_EXECUTE]    = "execute",
157ef61233STetsuo Handa 	[TOMOYO_TYPE_READ]       = "read",
167ef61233STetsuo Handa 	[TOMOYO_TYPE_WRITE]      = "write",
177c75964fSTetsuo Handa 	[TOMOYO_TYPE_APPEND]     = "append",
187ef61233STetsuo Handa 	[TOMOYO_TYPE_UNLINK]     = "unlink",
197c75964fSTetsuo Handa 	[TOMOYO_TYPE_GETATTR]    = "getattr",
207ef61233STetsuo Handa 	[TOMOYO_TYPE_RMDIR]      = "rmdir",
217ef61233STetsuo Handa 	[TOMOYO_TYPE_TRUNCATE]   = "truncate",
227ef61233STetsuo Handa 	[TOMOYO_TYPE_SYMLINK]    = "symlink",
237ef61233STetsuo Handa 	[TOMOYO_TYPE_CHROOT]     = "chroot",
247ef61233STetsuo Handa 	[TOMOYO_TYPE_UMOUNT]     = "unmount",
25b69a54eeSKentaro Takeda };
26b69a54eeSKentaro Takeda 
27a1f9bb6aSTetsuo Handa /* Keyword array for operations with one pathname and three numbers. */
2871c28236STetsuo Handa const char *tomoyo_mkdev_keyword[TOMOYO_MAX_MKDEV_OPERATION] = {
29a1f9bb6aSTetsuo Handa 	[TOMOYO_TYPE_MKBLOCK]    = "mkblock",
30a1f9bb6aSTetsuo Handa 	[TOMOYO_TYPE_MKCHAR]     = "mkchar",
31a1f9bb6aSTetsuo Handa };
32a1f9bb6aSTetsuo Handa 
33a1f9bb6aSTetsuo Handa /* Keyword array for operations with two pathnames. */
3471c28236STetsuo Handa const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = {
357ef61233STetsuo Handa 	[TOMOYO_TYPE_LINK]       = "link",
367ef61233STetsuo Handa 	[TOMOYO_TYPE_RENAME]     = "rename",
377ef61233STetsuo Handa 	[TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root",
38b69a54eeSKentaro Takeda };
39b69a54eeSKentaro Takeda 
40a1f9bb6aSTetsuo Handa /* Keyword array for operations with one pathname and one number. */
4171c28236STetsuo Handa const char *tomoyo_path_number_keyword[TOMOYO_MAX_PATH_NUMBER_OPERATION] = {
42a1f9bb6aSTetsuo Handa 	[TOMOYO_TYPE_CREATE]     = "create",
43a1f9bb6aSTetsuo Handa 	[TOMOYO_TYPE_MKDIR]      = "mkdir",
44a1f9bb6aSTetsuo Handa 	[TOMOYO_TYPE_MKFIFO]     = "mkfifo",
45a1f9bb6aSTetsuo Handa 	[TOMOYO_TYPE_MKSOCK]     = "mksock",
46a1f9bb6aSTetsuo Handa 	[TOMOYO_TYPE_IOCTL]      = "ioctl",
47a1f9bb6aSTetsuo Handa 	[TOMOYO_TYPE_CHMOD]      = "chmod",
48a1f9bb6aSTetsuo Handa 	[TOMOYO_TYPE_CHOWN]      = "chown",
49a1f9bb6aSTetsuo Handa 	[TOMOYO_TYPE_CHGRP]      = "chgrp",
50a1f9bb6aSTetsuo Handa };
51a1f9bb6aSTetsuo Handa 
520df7e8b8STetsuo Handa /*
530df7e8b8STetsuo Handa  * Mapping table from "enum tomoyo_path_acl_index" to "enum tomoyo_mac_index".
540df7e8b8STetsuo Handa  */
5557c2590fSTetsuo Handa static const u8 tomoyo_p2mac[TOMOYO_MAX_PATH_OPERATION] = {
5657c2590fSTetsuo Handa 	[TOMOYO_TYPE_EXECUTE]    = TOMOYO_MAC_FILE_EXECUTE,
5757c2590fSTetsuo Handa 	[TOMOYO_TYPE_READ]       = TOMOYO_MAC_FILE_OPEN,
5857c2590fSTetsuo Handa 	[TOMOYO_TYPE_WRITE]      = TOMOYO_MAC_FILE_OPEN,
597c75964fSTetsuo Handa 	[TOMOYO_TYPE_APPEND]     = TOMOYO_MAC_FILE_OPEN,
6057c2590fSTetsuo Handa 	[TOMOYO_TYPE_UNLINK]     = TOMOYO_MAC_FILE_UNLINK,
617c75964fSTetsuo Handa 	[TOMOYO_TYPE_GETATTR]    = TOMOYO_MAC_FILE_GETATTR,
6257c2590fSTetsuo Handa 	[TOMOYO_TYPE_RMDIR]      = TOMOYO_MAC_FILE_RMDIR,
6357c2590fSTetsuo Handa 	[TOMOYO_TYPE_TRUNCATE]   = TOMOYO_MAC_FILE_TRUNCATE,
6457c2590fSTetsuo Handa 	[TOMOYO_TYPE_SYMLINK]    = TOMOYO_MAC_FILE_SYMLINK,
6557c2590fSTetsuo Handa 	[TOMOYO_TYPE_CHROOT]     = TOMOYO_MAC_FILE_CHROOT,
6657c2590fSTetsuo Handa 	[TOMOYO_TYPE_UMOUNT]     = TOMOYO_MAC_FILE_UMOUNT,
6757c2590fSTetsuo Handa };
6857c2590fSTetsuo Handa 
690df7e8b8STetsuo Handa /*
700df7e8b8STetsuo Handa  * Mapping table from "enum tomoyo_mkdev_acl_index" to "enum tomoyo_mac_index".
710df7e8b8STetsuo Handa  */
7275093152STetsuo Handa static const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION] = {
7357c2590fSTetsuo Handa 	[TOMOYO_TYPE_MKBLOCK] = TOMOYO_MAC_FILE_MKBLOCK,
7457c2590fSTetsuo Handa 	[TOMOYO_TYPE_MKCHAR]  = TOMOYO_MAC_FILE_MKCHAR,
7557c2590fSTetsuo Handa };
7657c2590fSTetsuo Handa 
770df7e8b8STetsuo Handa /*
780df7e8b8STetsuo Handa  * Mapping table from "enum tomoyo_path2_acl_index" to "enum tomoyo_mac_index".
790df7e8b8STetsuo Handa  */
8057c2590fSTetsuo Handa static const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION] = {
8157c2590fSTetsuo Handa 	[TOMOYO_TYPE_LINK]       = TOMOYO_MAC_FILE_LINK,
8257c2590fSTetsuo Handa 	[TOMOYO_TYPE_RENAME]     = TOMOYO_MAC_FILE_RENAME,
8357c2590fSTetsuo Handa 	[TOMOYO_TYPE_PIVOT_ROOT] = TOMOYO_MAC_FILE_PIVOT_ROOT,
8457c2590fSTetsuo Handa };
8557c2590fSTetsuo Handa 
860df7e8b8STetsuo Handa /*
870df7e8b8STetsuo Handa  * Mapping table from "enum tomoyo_path_number_acl_index" to
880df7e8b8STetsuo Handa  * "enum tomoyo_mac_index".
890df7e8b8STetsuo Handa  */
9057c2590fSTetsuo Handa static const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = {
9157c2590fSTetsuo Handa 	[TOMOYO_TYPE_CREATE] = TOMOYO_MAC_FILE_CREATE,
9257c2590fSTetsuo Handa 	[TOMOYO_TYPE_MKDIR]  = TOMOYO_MAC_FILE_MKDIR,
9357c2590fSTetsuo Handa 	[TOMOYO_TYPE_MKFIFO] = TOMOYO_MAC_FILE_MKFIFO,
9457c2590fSTetsuo Handa 	[TOMOYO_TYPE_MKSOCK] = TOMOYO_MAC_FILE_MKSOCK,
9557c2590fSTetsuo Handa 	[TOMOYO_TYPE_IOCTL]  = TOMOYO_MAC_FILE_IOCTL,
9657c2590fSTetsuo Handa 	[TOMOYO_TYPE_CHMOD]  = TOMOYO_MAC_FILE_CHMOD,
9757c2590fSTetsuo Handa 	[TOMOYO_TYPE_CHOWN]  = TOMOYO_MAC_FILE_CHOWN,
9857c2590fSTetsuo Handa 	[TOMOYO_TYPE_CHGRP]  = TOMOYO_MAC_FILE_CHGRP,
9957c2590fSTetsuo Handa };
10057c2590fSTetsuo Handa 
1010df7e8b8STetsuo Handa /**
1020df7e8b8STetsuo Handa  * tomoyo_put_name_union - Drop reference on "struct tomoyo_name_union".
1030df7e8b8STetsuo Handa  *
1040df7e8b8STetsuo Handa  * @ptr: Pointer to "struct tomoyo_name_union".
1050df7e8b8STetsuo Handa  *
1060df7e8b8STetsuo Handa  * Returns nothing.
1070df7e8b8STetsuo Handa  */
1087762fbffSTetsuo Handa void tomoyo_put_name_union(struct tomoyo_name_union *ptr)
1097762fbffSTetsuo Handa {
110a98aa4deSTetsuo Handa 	tomoyo_put_group(ptr->group);
1117762fbffSTetsuo Handa 	tomoyo_put_name(ptr->filename);
1127762fbffSTetsuo Handa }
1137762fbffSTetsuo Handa 
1140df7e8b8STetsuo Handa /**
1150df7e8b8STetsuo Handa  * tomoyo_compare_name_union - Check whether a name matches "struct tomoyo_name_union" or not.
1160df7e8b8STetsuo Handa  *
1170df7e8b8STetsuo Handa  * @name: Pointer to "struct tomoyo_path_info".
1180df7e8b8STetsuo Handa  * @ptr:  Pointer to "struct tomoyo_name_union".
1190df7e8b8STetsuo Handa  *
1200df7e8b8STetsuo Handa  * Returns "struct tomoyo_path_info" if @name matches @ptr, NULL otherwise.
1210df7e8b8STetsuo Handa  */
122484ca79cSTetsuo Handa const struct tomoyo_path_info *
123484ca79cSTetsuo Handa tomoyo_compare_name_union(const struct tomoyo_path_info *name,
1247762fbffSTetsuo Handa 			  const struct tomoyo_name_union *ptr)
1257762fbffSTetsuo Handa {
1260df7e8b8STetsuo Handa 	if (ptr->group)
1273f629636STetsuo Handa 		return tomoyo_path_matches_group(name, ptr->group);
128484ca79cSTetsuo Handa 	if (tomoyo_path_matches_pattern(name, ptr->filename))
129484ca79cSTetsuo Handa 		return ptr->filename;
130484ca79cSTetsuo Handa 	return NULL;
1317762fbffSTetsuo Handa }
1327762fbffSTetsuo Handa 
1330df7e8b8STetsuo Handa /**
1340df7e8b8STetsuo Handa  * tomoyo_put_number_union - Drop reference on "struct tomoyo_number_union".
1350df7e8b8STetsuo Handa  *
1360df7e8b8STetsuo Handa  * @ptr: Pointer to "struct tomoyo_number_union".
1370df7e8b8STetsuo Handa  *
1380df7e8b8STetsuo Handa  * Returns nothing.
1390df7e8b8STetsuo Handa  */
1404c3e9e2dSTetsuo Handa void tomoyo_put_number_union(struct tomoyo_number_union *ptr)
1414c3e9e2dSTetsuo Handa {
142a98aa4deSTetsuo Handa 	tomoyo_put_group(ptr->group);
1434c3e9e2dSTetsuo Handa }
1444c3e9e2dSTetsuo Handa 
1450df7e8b8STetsuo Handa /**
1460df7e8b8STetsuo Handa  * tomoyo_compare_number_union - Check whether a value matches "struct tomoyo_number_union" or not.
1470df7e8b8STetsuo Handa  *
1480df7e8b8STetsuo Handa  * @value: Number to check.
1490df7e8b8STetsuo Handa  * @ptr:   Pointer to "struct tomoyo_number_union".
1500df7e8b8STetsuo Handa  *
1510df7e8b8STetsuo Handa  * Returns true if @value matches @ptr, false otherwise.
1520df7e8b8STetsuo Handa  */
1534c3e9e2dSTetsuo Handa bool tomoyo_compare_number_union(const unsigned long value,
1544c3e9e2dSTetsuo Handa 				 const struct tomoyo_number_union *ptr)
1554c3e9e2dSTetsuo Handa {
1560df7e8b8STetsuo Handa 	if (ptr->group)
1574c3e9e2dSTetsuo Handa 		return tomoyo_number_matches_group(value, value, ptr->group);
1584c3e9e2dSTetsuo Handa 	return value >= ptr->values[0] && value <= ptr->values[1];
1594c3e9e2dSTetsuo Handa }
1604c3e9e2dSTetsuo Handa 
1610df7e8b8STetsuo Handa /**
1620df7e8b8STetsuo Handa  * tomoyo_add_slash - Add trailing '/' if needed.
1630df7e8b8STetsuo Handa  *
1640df7e8b8STetsuo Handa  * @buf: Pointer to "struct tomoyo_path_info".
1650df7e8b8STetsuo Handa  *
1660df7e8b8STetsuo Handa  * Returns nothing.
1670df7e8b8STetsuo Handa  *
1680df7e8b8STetsuo Handa  * @buf must be generated by tomoyo_encode() because this function does not
1690df7e8b8STetsuo Handa  * allocate memory for adding '/'.
1700df7e8b8STetsuo Handa  */
171c8c57e84STetsuo Handa static void tomoyo_add_slash(struct tomoyo_path_info *buf)
172c8c57e84STetsuo Handa {
173c8c57e84STetsuo Handa 	if (buf->is_dir)
174c8c57e84STetsuo Handa 		return;
175c8c57e84STetsuo Handa 	/*
176c8c57e84STetsuo Handa 	 * This is OK because tomoyo_encode() reserves space for appending "/".
177c8c57e84STetsuo Handa 	 */
178c8c57e84STetsuo Handa 	strcat((char *) buf->name, "/");
179c8c57e84STetsuo Handa 	tomoyo_fill_path_info(buf);
180c8c57e84STetsuo Handa }
181c8c57e84STetsuo Handa 
182a1f9bb6aSTetsuo Handa /**
183c8c57e84STetsuo Handa  * tomoyo_get_realpath - Get realpath.
184b69a54eeSKentaro Takeda  *
185c8c57e84STetsuo Handa  * @buf:  Pointer to "struct tomoyo_path_info".
186b69a54eeSKentaro Takeda  * @path: Pointer to "struct path".
187b69a54eeSKentaro Takeda  *
188c8c57e84STetsuo Handa  * Returns true on success, false otherwise.
189b69a54eeSKentaro Takeda  */
190c8c57e84STetsuo Handa static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path)
191b69a54eeSKentaro Takeda {
192c8c57e84STetsuo Handa 	buf->name = tomoyo_realpath_from_path(path);
193c8c57e84STetsuo Handa 	if (buf->name) {
194c8c57e84STetsuo Handa 		tomoyo_fill_path_info(buf);
195c8c57e84STetsuo Handa 		return true;
196b69a54eeSKentaro Takeda 	}
197c8c57e84STetsuo Handa         return false;
198b69a54eeSKentaro Takeda }
199b69a54eeSKentaro Takeda 
20099a85259STetsuo Handa /**
20199a85259STetsuo Handa  * tomoyo_audit_path_log - Audit path request log.
20299a85259STetsuo Handa  *
20399a85259STetsuo Handa  * @r: Pointer to "struct tomoyo_request_info".
20499a85259STetsuo Handa  *
20599a85259STetsuo Handa  * Returns 0 on success, negative value otherwise.
20699a85259STetsuo Handa  */
20799a85259STetsuo Handa static int tomoyo_audit_path_log(struct tomoyo_request_info *r)
20899a85259STetsuo Handa {
20999a85259STetsuo Handa 	const char *operation = tomoyo_path_keyword[r->param.path.operation];
21099a85259STetsuo Handa 	const struct tomoyo_path_info *filename = r->param.path.filename;
21199a85259STetsuo Handa 	if (r->granted)
21299a85259STetsuo Handa 		return 0;
21399a85259STetsuo Handa 	tomoyo_warn_log(r, "%s %s", operation, filename->name);
21499a85259STetsuo Handa 	return tomoyo_supervisor(r, "allow_%s %s\n", operation,
2157c75964fSTetsuo Handa 				 filename->name);
21699a85259STetsuo Handa }
21799a85259STetsuo Handa 
21899a85259STetsuo Handa /**
21999a85259STetsuo Handa  * tomoyo_audit_path2_log - Audit path/path request log.
22099a85259STetsuo Handa  *
22199a85259STetsuo Handa  * @r: Pointer to "struct tomoyo_request_info".
22299a85259STetsuo Handa  *
22399a85259STetsuo Handa  * Returns 0 on success, negative value otherwise.
22499a85259STetsuo Handa  */
22599a85259STetsuo Handa static int tomoyo_audit_path2_log(struct tomoyo_request_info *r)
22699a85259STetsuo Handa {
22799a85259STetsuo Handa 	const char *operation = tomoyo_path2_keyword[r->param.path2.operation];
22899a85259STetsuo Handa 	const struct tomoyo_path_info *filename1 = r->param.path2.filename1;
22999a85259STetsuo Handa 	const struct tomoyo_path_info *filename2 = r->param.path2.filename2;
23099a85259STetsuo Handa 	if (r->granted)
23199a85259STetsuo Handa 		return 0;
23299a85259STetsuo Handa 	tomoyo_warn_log(r, "%s %s %s", operation, filename1->name,
23399a85259STetsuo Handa 			filename2->name);
23499a85259STetsuo Handa 	return tomoyo_supervisor(r, "allow_%s %s %s\n", operation,
2357c75964fSTetsuo Handa 				 filename1->name, filename2->name);
23699a85259STetsuo Handa }
23799a85259STetsuo Handa 
23899a85259STetsuo Handa /**
23999a85259STetsuo Handa  * tomoyo_audit_mkdev_log - Audit path/number/number/number request log.
24099a85259STetsuo Handa  *
24199a85259STetsuo Handa  * @r: Pointer to "struct tomoyo_request_info".
24299a85259STetsuo Handa  *
24399a85259STetsuo Handa  * Returns 0 on success, negative value otherwise.
24499a85259STetsuo Handa  */
24599a85259STetsuo Handa static int tomoyo_audit_mkdev_log(struct tomoyo_request_info *r)
24699a85259STetsuo Handa {
24771c28236STetsuo Handa 	const char *operation = tomoyo_mkdev_keyword[r->param.mkdev.operation];
24899a85259STetsuo Handa 	const struct tomoyo_path_info *filename = r->param.mkdev.filename;
24999a85259STetsuo Handa 	const unsigned int major = r->param.mkdev.major;
25099a85259STetsuo Handa 	const unsigned int minor = r->param.mkdev.minor;
25199a85259STetsuo Handa 	const unsigned int mode = r->param.mkdev.mode;
25299a85259STetsuo Handa 	if (r->granted)
25399a85259STetsuo Handa 		return 0;
25499a85259STetsuo Handa 	tomoyo_warn_log(r, "%s %s 0%o %u %u", operation, filename->name, mode,
25599a85259STetsuo Handa 			major, minor);
25699a85259STetsuo Handa 	return tomoyo_supervisor(r, "allow_%s %s 0%o %u %u\n", operation,
2577c75964fSTetsuo Handa 				 filename->name, mode, major, minor);
25899a85259STetsuo Handa }
25999a85259STetsuo Handa 
26099a85259STetsuo Handa /**
26199a85259STetsuo Handa  * tomoyo_audit_path_number_log - Audit path/number request log.
26299a85259STetsuo Handa  *
26399a85259STetsuo Handa  * @r: Pointer to "struct tomoyo_request_info".
26499a85259STetsuo Handa  *
26599a85259STetsuo Handa  * Returns 0 on success, negative value otherwise.
26699a85259STetsuo Handa  */
26799a85259STetsuo Handa static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r)
26899a85259STetsuo Handa {
26999a85259STetsuo Handa 	const u8 type = r->param.path_number.operation;
27099a85259STetsuo Handa 	u8 radix;
27199a85259STetsuo Handa 	const struct tomoyo_path_info *filename = r->param.path_number.filename;
27299a85259STetsuo Handa 	const char *operation = tomoyo_path_number_keyword[type];
27399a85259STetsuo Handa 	char buffer[64];
27499a85259STetsuo Handa 	if (r->granted)
27599a85259STetsuo Handa 		return 0;
27699a85259STetsuo Handa 	switch (type) {
27799a85259STetsuo Handa 	case TOMOYO_TYPE_CREATE:
27899a85259STetsuo Handa 	case TOMOYO_TYPE_MKDIR:
27999a85259STetsuo Handa 	case TOMOYO_TYPE_MKFIFO:
28099a85259STetsuo Handa 	case TOMOYO_TYPE_MKSOCK:
28199a85259STetsuo Handa 	case TOMOYO_TYPE_CHMOD:
28299a85259STetsuo Handa 		radix = TOMOYO_VALUE_TYPE_OCTAL;
28399a85259STetsuo Handa 		break;
28499a85259STetsuo Handa 	case TOMOYO_TYPE_IOCTL:
28599a85259STetsuo Handa 		radix = TOMOYO_VALUE_TYPE_HEXADECIMAL;
28699a85259STetsuo Handa 		break;
28799a85259STetsuo Handa 	default:
28899a85259STetsuo Handa 		radix = TOMOYO_VALUE_TYPE_DECIMAL;
28999a85259STetsuo Handa 		break;
29099a85259STetsuo Handa 	}
29199a85259STetsuo Handa 	tomoyo_print_ulong(buffer, sizeof(buffer), r->param.path_number.number,
29299a85259STetsuo Handa 			   radix);
29399a85259STetsuo Handa 	tomoyo_warn_log(r, "%s %s %s", operation, filename->name, buffer);
29499a85259STetsuo Handa 	return tomoyo_supervisor(r, "allow_%s %s %s\n", operation,
2957c75964fSTetsuo Handa 				 filename->name, buffer);
296b69a54eeSKentaro Takeda }
297b69a54eeSKentaro Takeda 
2980df7e8b8STetsuo Handa /**
2990df7e8b8STetsuo Handa  * tomoyo_check_path_acl - Check permission for path operation.
3000df7e8b8STetsuo Handa  *
3010df7e8b8STetsuo Handa  * @r:   Pointer to "struct tomoyo_request_info".
3020df7e8b8STetsuo Handa  * @ptr: Pointer to "struct tomoyo_acl_info".
3030df7e8b8STetsuo Handa  *
3040df7e8b8STetsuo Handa  * Returns true if granted, false otherwise.
3050df7e8b8STetsuo Handa  *
3060df7e8b8STetsuo Handa  * To be able to use wildcard for domain transition, this function sets
3070df7e8b8STetsuo Handa  * matching entry on success. Since the caller holds tomoyo_read_lock(),
3080df7e8b8STetsuo Handa  * it is safe to set matching entry.
3090df7e8b8STetsuo Handa  */
310484ca79cSTetsuo Handa static bool tomoyo_check_path_acl(struct tomoyo_request_info *r,
31199a85259STetsuo Handa 				  const struct tomoyo_acl_info *ptr)
312b69a54eeSKentaro Takeda {
31399a85259STetsuo Handa 	const struct tomoyo_path_acl *acl = container_of(ptr, typeof(*acl),
31499a85259STetsuo Handa 							 head);
315484ca79cSTetsuo Handa 	if (acl->perm & (1 << r->param.path.operation)) {
316484ca79cSTetsuo Handa 		r->param.path.matched_path =
317484ca79cSTetsuo Handa 			tomoyo_compare_name_union(r->param.path.filename,
318484ca79cSTetsuo Handa 						  &acl->name);
319484ca79cSTetsuo Handa 		return r->param.path.matched_path != NULL;
320484ca79cSTetsuo Handa 	}
321484ca79cSTetsuo Handa 	return false;
322b69a54eeSKentaro Takeda }
32399a85259STetsuo Handa 
3240df7e8b8STetsuo Handa /**
3250df7e8b8STetsuo Handa  * tomoyo_check_path_number_acl - Check permission for path number operation.
3260df7e8b8STetsuo Handa  *
3270df7e8b8STetsuo Handa  * @r:   Pointer to "struct tomoyo_request_info".
3280df7e8b8STetsuo Handa  * @ptr: Pointer to "struct tomoyo_acl_info".
3290df7e8b8STetsuo Handa  *
3300df7e8b8STetsuo Handa  * Returns true if granted, false otherwise.
3310df7e8b8STetsuo Handa  */
332484ca79cSTetsuo Handa static bool tomoyo_check_path_number_acl(struct tomoyo_request_info *r,
33399a85259STetsuo Handa 					 const struct tomoyo_acl_info *ptr)
33499a85259STetsuo Handa {
33599a85259STetsuo Handa 	const struct tomoyo_path_number_acl *acl =
33699a85259STetsuo Handa 		container_of(ptr, typeof(*acl), head);
33799a85259STetsuo Handa 	return (acl->perm & (1 << r->param.path_number.operation)) &&
33899a85259STetsuo Handa 		tomoyo_compare_number_union(r->param.path_number.number,
33999a85259STetsuo Handa 					    &acl->number) &&
34099a85259STetsuo Handa 		tomoyo_compare_name_union(r->param.path_number.filename,
34199a85259STetsuo Handa 					  &acl->name);
34299a85259STetsuo Handa }
34399a85259STetsuo Handa 
3440df7e8b8STetsuo Handa /**
3450df7e8b8STetsuo Handa  * tomoyo_check_path2_acl - Check permission for path path operation.
3460df7e8b8STetsuo Handa  *
3470df7e8b8STetsuo Handa  * @r:   Pointer to "struct tomoyo_request_info".
3480df7e8b8STetsuo Handa  * @ptr: Pointer to "struct tomoyo_acl_info".
3490df7e8b8STetsuo Handa  *
3500df7e8b8STetsuo Handa  * Returns true if granted, false otherwise.
3510df7e8b8STetsuo Handa  */
352484ca79cSTetsuo Handa static bool tomoyo_check_path2_acl(struct tomoyo_request_info *r,
35399a85259STetsuo Handa 				   const struct tomoyo_acl_info *ptr)
35499a85259STetsuo Handa {
35599a85259STetsuo Handa 	const struct tomoyo_path2_acl *acl =
35699a85259STetsuo Handa 		container_of(ptr, typeof(*acl), head);
35799a85259STetsuo Handa 	return (acl->perm & (1 << r->param.path2.operation)) &&
35899a85259STetsuo Handa 		tomoyo_compare_name_union(r->param.path2.filename1, &acl->name1)
35999a85259STetsuo Handa 		&& tomoyo_compare_name_union(r->param.path2.filename2,
36099a85259STetsuo Handa 					     &acl->name2);
36199a85259STetsuo Handa }
36299a85259STetsuo Handa 
3630df7e8b8STetsuo Handa /**
3640df7e8b8STetsuo Handa  * tomoyo_check_mkdev_acl - Check permission for path number number number operation.
3650df7e8b8STetsuo Handa  *
3660df7e8b8STetsuo Handa  * @r:   Pointer to "struct tomoyo_request_info".
3670df7e8b8STetsuo Handa  * @ptr: Pointer to "struct tomoyo_acl_info".
3680df7e8b8STetsuo Handa  *
3690df7e8b8STetsuo Handa  * Returns true if granted, false otherwise.
3700df7e8b8STetsuo Handa  */
371484ca79cSTetsuo Handa static bool tomoyo_check_mkdev_acl(struct tomoyo_request_info *r,
37299a85259STetsuo Handa 				   const struct tomoyo_acl_info *ptr)
37399a85259STetsuo Handa {
37475093152STetsuo Handa 	const struct tomoyo_mkdev_acl *acl =
37599a85259STetsuo Handa 		container_of(ptr, typeof(*acl), head);
37699a85259STetsuo Handa 	return (acl->perm & (1 << r->param.mkdev.operation)) &&
37799a85259STetsuo Handa 		tomoyo_compare_number_union(r->param.mkdev.mode,
37899a85259STetsuo Handa 					    &acl->mode) &&
37999a85259STetsuo Handa 		tomoyo_compare_number_union(r->param.mkdev.major,
38099a85259STetsuo Handa 					    &acl->major) &&
38199a85259STetsuo Handa 		tomoyo_compare_number_union(r->param.mkdev.minor,
38299a85259STetsuo Handa 					    &acl->minor) &&
38399a85259STetsuo Handa 		tomoyo_compare_name_union(r->param.mkdev.filename,
38499a85259STetsuo Handa 					  &acl->name);
385b69a54eeSKentaro Takeda }
386b69a54eeSKentaro Takeda 
3870df7e8b8STetsuo Handa /**
3880df7e8b8STetsuo Handa  * tomoyo_same_path_acl - Check for duplicated "struct tomoyo_path_acl" entry.
3890df7e8b8STetsuo Handa  *
3900df7e8b8STetsuo Handa  * @a: Pointer to "struct tomoyo_acl_info".
3910df7e8b8STetsuo Handa  * @b: Pointer to "struct tomoyo_acl_info".
3920df7e8b8STetsuo Handa  *
3930df7e8b8STetsuo Handa  * Returns true if @a == @b except permission bits, false otherwise.
3940df7e8b8STetsuo Handa  */
395237ab459STetsuo Handa static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a,
396237ab459STetsuo Handa 				 const struct tomoyo_acl_info *b)
397237ab459STetsuo Handa {
398237ab459STetsuo Handa 	const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head);
399237ab459STetsuo Handa 	const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head);
4000df7e8b8STetsuo Handa 	return tomoyo_same_name_union(&p1->name, &p2->name);
401237ab459STetsuo Handa }
402237ab459STetsuo Handa 
4037c75964fSTetsuo Handa /**
4047c75964fSTetsuo Handa  * tomoyo_merge_path_acl - Merge duplicated "struct tomoyo_path_acl" entry.
4057c75964fSTetsuo Handa  *
4067c75964fSTetsuo Handa  * @a:         Pointer to "struct tomoyo_acl_info".
4077c75964fSTetsuo Handa  * @b:         Pointer to "struct tomoyo_acl_info".
4087c75964fSTetsuo Handa  * @is_delete: True for @a &= ~@b, false for @a |= @b.
4097c75964fSTetsuo Handa  *
4107c75964fSTetsuo Handa  * Returns true if @a is empty, false otherwise.
4117c75964fSTetsuo Handa  */
412237ab459STetsuo Handa static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a,
413237ab459STetsuo Handa 				  struct tomoyo_acl_info *b,
414237ab459STetsuo Handa 				  const bool is_delete)
415237ab459STetsuo Handa {
416237ab459STetsuo Handa 	u16 * const a_perm = &container_of(a, struct tomoyo_path_acl, head)
417237ab459STetsuo Handa 		->perm;
418237ab459STetsuo Handa 	u16 perm = *a_perm;
419237ab459STetsuo Handa 	const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm;
4207c75964fSTetsuo Handa 	if (is_delete)
421237ab459STetsuo Handa 		perm &= ~b_perm;
4227c75964fSTetsuo Handa 	else
423237ab459STetsuo Handa 		perm |= b_perm;
424237ab459STetsuo Handa 	*a_perm = perm;
425237ab459STetsuo Handa 	return !perm;
426237ab459STetsuo Handa }
427237ab459STetsuo Handa 
428b69a54eeSKentaro Takeda /**
4297ef61233STetsuo Handa  * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list.
430b69a54eeSKentaro Takeda  *
431a238cf5bSTetsuo Handa  * @perm:  Permission.
432a238cf5bSTetsuo Handa  * @param: Pointer to "struct tomoyo_acl_param".
433b69a54eeSKentaro Takeda  *
434b69a54eeSKentaro Takeda  * Returns 0 on success, negative value otherwise.
435fdb8ebb7STetsuo Handa  *
436fdb8ebb7STetsuo Handa  * Caller holds tomoyo_read_lock().
437b69a54eeSKentaro Takeda  */
438a238cf5bSTetsuo Handa static int tomoyo_update_path_acl(const u16 perm,
439a238cf5bSTetsuo Handa 				  struct tomoyo_acl_param *param)
440b69a54eeSKentaro Takeda {
4419e4b50e9STetsuo Handa 	struct tomoyo_path_acl e = {
4429e4b50e9STetsuo Handa 		.head.type = TOMOYO_TYPE_PATH_ACL,
443a238cf5bSTetsuo Handa 		.perm = perm
4449e4b50e9STetsuo Handa 	};
445237ab459STetsuo Handa 	int error;
446a238cf5bSTetsuo Handa 	if (!tomoyo_parse_name_union(param, &e.name))
447a238cf5bSTetsuo Handa 		error = -EINVAL;
448a238cf5bSTetsuo Handa 	else
449a238cf5bSTetsuo Handa 		error = tomoyo_update_domain(&e.head, sizeof(e), param,
450237ab459STetsuo Handa 					     tomoyo_same_path_acl,
451237ab459STetsuo Handa 					     tomoyo_merge_path_acl);
4527762fbffSTetsuo Handa 	tomoyo_put_name_union(&e.name);
453b69a54eeSKentaro Takeda 	return error;
454b69a54eeSKentaro Takeda }
455b69a54eeSKentaro Takeda 
4560df7e8b8STetsuo Handa /**
4570df7e8b8STetsuo Handa  * tomoyo_same_mkdev_acl - Check for duplicated "struct tomoyo_mkdev_acl" entry.
4580df7e8b8STetsuo Handa  *
4590df7e8b8STetsuo Handa  * @a: Pointer to "struct tomoyo_acl_info".
4600df7e8b8STetsuo Handa  * @b: Pointer to "struct tomoyo_acl_info".
4610df7e8b8STetsuo Handa  *
4620df7e8b8STetsuo Handa  * Returns true if @a == @b except permission bits, false otherwise.
4630df7e8b8STetsuo Handa  */
46475093152STetsuo Handa static bool tomoyo_same_mkdev_acl(const struct tomoyo_acl_info *a,
465237ab459STetsuo Handa 					 const struct tomoyo_acl_info *b)
466237ab459STetsuo Handa {
4670df7e8b8STetsuo Handa 	const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1), head);
4680df7e8b8STetsuo Handa 	const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2), head);
4690df7e8b8STetsuo Handa 	return tomoyo_same_name_union(&p1->name, &p2->name) &&
4700df7e8b8STetsuo Handa 		tomoyo_same_number_union(&p1->mode, &p2->mode) &&
4710df7e8b8STetsuo Handa 		tomoyo_same_number_union(&p1->major, &p2->major) &&
4720df7e8b8STetsuo Handa 		tomoyo_same_number_union(&p1->minor, &p2->minor);
473237ab459STetsuo Handa }
474237ab459STetsuo Handa 
4750df7e8b8STetsuo Handa /**
4760df7e8b8STetsuo Handa  * tomoyo_merge_mkdev_acl - Merge duplicated "struct tomoyo_mkdev_acl" entry.
4770df7e8b8STetsuo Handa  *
4780df7e8b8STetsuo Handa  * @a:         Pointer to "struct tomoyo_acl_info".
4790df7e8b8STetsuo Handa  * @b:         Pointer to "struct tomoyo_acl_info".
4800df7e8b8STetsuo Handa  * @is_delete: True for @a &= ~@b, false for @a |= @b.
4810df7e8b8STetsuo Handa  *
4820df7e8b8STetsuo Handa  * Returns true if @a is empty, false otherwise.
4830df7e8b8STetsuo Handa  */
48475093152STetsuo Handa static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a,
485237ab459STetsuo Handa 				   struct tomoyo_acl_info *b,
486237ab459STetsuo Handa 				   const bool is_delete)
487237ab459STetsuo Handa {
48875093152STetsuo Handa 	u8 *const a_perm = &container_of(a, struct tomoyo_mkdev_acl,
489237ab459STetsuo Handa 					 head)->perm;
490237ab459STetsuo Handa 	u8 perm = *a_perm;
49175093152STetsuo Handa 	const u8 b_perm = container_of(b, struct tomoyo_mkdev_acl, head)
492237ab459STetsuo Handa 		->perm;
493237ab459STetsuo Handa 	if (is_delete)
494237ab459STetsuo Handa 		perm &= ~b_perm;
495237ab459STetsuo Handa 	else
496237ab459STetsuo Handa 		perm |= b_perm;
497237ab459STetsuo Handa 	*a_perm = perm;
498237ab459STetsuo Handa 	return !perm;
499237ab459STetsuo Handa }
500237ab459STetsuo Handa 
501b69a54eeSKentaro Takeda /**
50275093152STetsuo Handa  * tomoyo_update_mkdev_acl - Update "struct tomoyo_mkdev_acl" list.
503a1f9bb6aSTetsuo Handa  *
504a238cf5bSTetsuo Handa  * @perm:  Permission.
505a238cf5bSTetsuo Handa  * @param: Pointer to "struct tomoyo_acl_param".
506a1f9bb6aSTetsuo Handa  *
507a1f9bb6aSTetsuo Handa  * Returns 0 on success, negative value otherwise.
508237ab459STetsuo Handa  *
509237ab459STetsuo Handa  * Caller holds tomoyo_read_lock().
510a1f9bb6aSTetsuo Handa  */
511a238cf5bSTetsuo Handa static int tomoyo_update_mkdev_acl(const u8 perm,
512a238cf5bSTetsuo Handa 				   struct tomoyo_acl_param *param)
513a1f9bb6aSTetsuo Handa {
51475093152STetsuo Handa 	struct tomoyo_mkdev_acl e = {
51575093152STetsuo Handa 		.head.type = TOMOYO_TYPE_MKDEV_ACL,
516a238cf5bSTetsuo Handa 		.perm = perm
517a1f9bb6aSTetsuo Handa 	};
518a238cf5bSTetsuo Handa 	int error;
519a238cf5bSTetsuo Handa 	if (!tomoyo_parse_name_union(param, &e.name) ||
520a238cf5bSTetsuo Handa 	    !tomoyo_parse_number_union(param, &e.mode) ||
521a238cf5bSTetsuo Handa 	    !tomoyo_parse_number_union(param, &e.major) ||
522a238cf5bSTetsuo Handa 	    !tomoyo_parse_number_union(param, &e.minor))
523a238cf5bSTetsuo Handa 		error = -EINVAL;
524a238cf5bSTetsuo Handa 	else
525a238cf5bSTetsuo Handa 		error = tomoyo_update_domain(&e.head, sizeof(e), param,
52675093152STetsuo Handa 					     tomoyo_same_mkdev_acl,
52775093152STetsuo Handa 					     tomoyo_merge_mkdev_acl);
528a1f9bb6aSTetsuo Handa 	tomoyo_put_name_union(&e.name);
529a1f9bb6aSTetsuo Handa 	tomoyo_put_number_union(&e.mode);
530a1f9bb6aSTetsuo Handa 	tomoyo_put_number_union(&e.major);
531a1f9bb6aSTetsuo Handa 	tomoyo_put_number_union(&e.minor);
532a1f9bb6aSTetsuo Handa 	return error;
533a1f9bb6aSTetsuo Handa }
534a1f9bb6aSTetsuo Handa 
5350df7e8b8STetsuo Handa /**
5360df7e8b8STetsuo Handa  * tomoyo_same_path2_acl - Check for duplicated "struct tomoyo_path2_acl" entry.
5370df7e8b8STetsuo Handa  *
5380df7e8b8STetsuo Handa  * @a: Pointer to "struct tomoyo_acl_info".
5390df7e8b8STetsuo Handa  * @b: Pointer to "struct tomoyo_acl_info".
5400df7e8b8STetsuo Handa  *
5410df7e8b8STetsuo Handa  * Returns true if @a == @b except permission bits, false otherwise.
5420df7e8b8STetsuo Handa  */
543237ab459STetsuo Handa static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a,
544237ab459STetsuo Handa 				  const struct tomoyo_acl_info *b)
545237ab459STetsuo Handa {
546237ab459STetsuo Handa 	const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head);
547237ab459STetsuo Handa 	const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head);
5480df7e8b8STetsuo Handa 	return tomoyo_same_name_union(&p1->name1, &p2->name1) &&
5490df7e8b8STetsuo Handa 		tomoyo_same_name_union(&p1->name2, &p2->name2);
550237ab459STetsuo Handa }
551237ab459STetsuo Handa 
5520df7e8b8STetsuo Handa /**
5530df7e8b8STetsuo Handa  * tomoyo_merge_path2_acl - Merge duplicated "struct tomoyo_path2_acl" entry.
5540df7e8b8STetsuo Handa  *
5550df7e8b8STetsuo Handa  * @a:         Pointer to "struct tomoyo_acl_info".
5560df7e8b8STetsuo Handa  * @b:         Pointer to "struct tomoyo_acl_info".
5570df7e8b8STetsuo Handa  * @is_delete: True for @a &= ~@b, false for @a |= @b.
5580df7e8b8STetsuo Handa  *
5590df7e8b8STetsuo Handa  * Returns true if @a is empty, false otherwise.
5600df7e8b8STetsuo Handa  */
561237ab459STetsuo Handa static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a,
562237ab459STetsuo Handa 				   struct tomoyo_acl_info *b,
563237ab459STetsuo Handa 				   const bool is_delete)
564237ab459STetsuo Handa {
565237ab459STetsuo Handa 	u8 * const a_perm = &container_of(a, struct tomoyo_path2_acl, head)
566237ab459STetsuo Handa 		->perm;
567237ab459STetsuo Handa 	u8 perm = *a_perm;
568237ab459STetsuo Handa 	const u8 b_perm = container_of(b, struct tomoyo_path2_acl, head)->perm;
569237ab459STetsuo Handa 	if (is_delete)
570237ab459STetsuo Handa 		perm &= ~b_perm;
571237ab459STetsuo Handa 	else
572237ab459STetsuo Handa 		perm |= b_perm;
573237ab459STetsuo Handa 	*a_perm = perm;
574237ab459STetsuo Handa 	return !perm;
575237ab459STetsuo Handa }
576237ab459STetsuo Handa 
577a1f9bb6aSTetsuo Handa /**
5787ef61233STetsuo Handa  * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list.
579b69a54eeSKentaro Takeda  *
580a238cf5bSTetsuo Handa  * @perm:  Permission.
581a238cf5bSTetsuo Handa  * @param: Pointer to "struct tomoyo_acl_param".
582b69a54eeSKentaro Takeda  *
583b69a54eeSKentaro Takeda  * Returns 0 on success, negative value otherwise.
584fdb8ebb7STetsuo Handa  *
585fdb8ebb7STetsuo Handa  * Caller holds tomoyo_read_lock().
586b69a54eeSKentaro Takeda  */
587a238cf5bSTetsuo Handa static int tomoyo_update_path2_acl(const u8 perm,
588a238cf5bSTetsuo Handa 				   struct tomoyo_acl_param *param)
589b69a54eeSKentaro Takeda {
5909e4b50e9STetsuo Handa 	struct tomoyo_path2_acl e = {
5919e4b50e9STetsuo Handa 		.head.type = TOMOYO_TYPE_PATH2_ACL,
592a238cf5bSTetsuo Handa 		.perm = perm
5939e4b50e9STetsuo Handa 	};
594a238cf5bSTetsuo Handa 	int error;
595a238cf5bSTetsuo Handa 	if (!tomoyo_parse_name_union(param, &e.name1) ||
596a238cf5bSTetsuo Handa 	    !tomoyo_parse_name_union(param, &e.name2))
597a238cf5bSTetsuo Handa 		error = -EINVAL;
598a238cf5bSTetsuo Handa 	else
599a238cf5bSTetsuo Handa 		error = tomoyo_update_domain(&e.head, sizeof(e), param,
600237ab459STetsuo Handa 					     tomoyo_same_path2_acl,
601237ab459STetsuo Handa 					     tomoyo_merge_path2_acl);
6027762fbffSTetsuo Handa 	tomoyo_put_name_union(&e.name1);
6037762fbffSTetsuo Handa 	tomoyo_put_name_union(&e.name2);
604b69a54eeSKentaro Takeda 	return error;
605b69a54eeSKentaro Takeda }
606b69a54eeSKentaro Takeda 
607b69a54eeSKentaro Takeda /**
608cb0abe6aSTetsuo Handa  * tomoyo_path_permission - Check permission for single path operation.
609b69a54eeSKentaro Takeda  *
610cb0abe6aSTetsuo Handa  * @r:         Pointer to "struct tomoyo_request_info".
611b69a54eeSKentaro Takeda  * @operation: Type of operation.
612b69a54eeSKentaro Takeda  * @filename:  Filename to check.
613b69a54eeSKentaro Takeda  *
614b69a54eeSKentaro Takeda  * Returns 0 on success, negative value otherwise.
615fdb8ebb7STetsuo Handa  *
616fdb8ebb7STetsuo Handa  * Caller holds tomoyo_read_lock().
617b69a54eeSKentaro Takeda  */
61805336deeSTetsuo Handa int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
619cb0abe6aSTetsuo Handa 			   const struct tomoyo_path_info *filename)
620b69a54eeSKentaro Takeda {
621b69a54eeSKentaro Takeda 	int error;
622b69a54eeSKentaro Takeda 
62357c2590fSTetsuo Handa 	r->type = tomoyo_p2mac[operation];
62457c2590fSTetsuo Handa 	r->mode = tomoyo_get_mode(r->profile, r->type);
62557c2590fSTetsuo Handa 	if (r->mode == TOMOYO_CONFIG_DISABLED)
62657c2590fSTetsuo Handa 		return 0;
627cf6e9a64STetsuo Handa 	r->param_type = TOMOYO_TYPE_PATH_ACL;
628cf6e9a64STetsuo Handa 	r->param.path.filename = filename;
629cf6e9a64STetsuo Handa 	r->param.path.operation = operation;
63017fcfbd9STetsuo Handa 	do {
63199a85259STetsuo Handa 		tomoyo_check_acl(r, tomoyo_check_path_acl);
63299a85259STetsuo Handa 		error = tomoyo_audit_path_log(r);
63305336deeSTetsuo Handa 		/*
63405336deeSTetsuo Handa 		 * Do not retry for execute request, for alias may have
63505336deeSTetsuo Handa 		 * changed.
63605336deeSTetsuo Handa 		 */
63705336deeSTetsuo Handa 	} while (error == TOMOYO_RETRY_REQUEST &&
63805336deeSTetsuo Handa 		 operation != TOMOYO_TYPE_EXECUTE);
639b69a54eeSKentaro Takeda 	return error;
640b69a54eeSKentaro Takeda }
641b69a54eeSKentaro Takeda 
6420df7e8b8STetsuo Handa /**
6430df7e8b8STetsuo Handa  * tomoyo_same_path_number_acl - Check for duplicated "struct tomoyo_path_number_acl" entry.
6440df7e8b8STetsuo Handa  *
6450df7e8b8STetsuo Handa  * @a: Pointer to "struct tomoyo_acl_info".
6460df7e8b8STetsuo Handa  * @b: Pointer to "struct tomoyo_acl_info".
6470df7e8b8STetsuo Handa  *
6480df7e8b8STetsuo Handa  * Returns true if @a == @b except permission bits, false otherwise.
6490df7e8b8STetsuo Handa  */
650237ab459STetsuo Handa static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a,
651237ab459STetsuo Handa 					const struct tomoyo_acl_info *b)
652237ab459STetsuo Handa {
653237ab459STetsuo Handa 	const struct tomoyo_path_number_acl *p1 = container_of(a, typeof(*p1),
654237ab459STetsuo Handa 							       head);
655237ab459STetsuo Handa 	const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2),
656237ab459STetsuo Handa 							       head);
6570df7e8b8STetsuo Handa 	return tomoyo_same_name_union(&p1->name, &p2->name) &&
6580df7e8b8STetsuo Handa 		tomoyo_same_number_union(&p1->number, &p2->number);
659237ab459STetsuo Handa }
660237ab459STetsuo Handa 
6610df7e8b8STetsuo Handa /**
6620df7e8b8STetsuo Handa  * tomoyo_merge_path_number_acl - Merge duplicated "struct tomoyo_path_number_acl" entry.
6630df7e8b8STetsuo Handa  *
6640df7e8b8STetsuo Handa  * @a:         Pointer to "struct tomoyo_acl_info".
6650df7e8b8STetsuo Handa  * @b:         Pointer to "struct tomoyo_acl_info".
6660df7e8b8STetsuo Handa  * @is_delete: True for @a &= ~@b, false for @a |= @b.
6670df7e8b8STetsuo Handa  *
6680df7e8b8STetsuo Handa  * Returns true if @a is empty, false otherwise.
6690df7e8b8STetsuo Handa  */
670237ab459STetsuo Handa static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a,
671237ab459STetsuo Handa 					 struct tomoyo_acl_info *b,
672237ab459STetsuo Handa 					 const bool is_delete)
673237ab459STetsuo Handa {
674237ab459STetsuo Handa 	u8 * const a_perm = &container_of(a, struct tomoyo_path_number_acl,
675237ab459STetsuo Handa 					  head)->perm;
676237ab459STetsuo Handa 	u8 perm = *a_perm;
677237ab459STetsuo Handa 	const u8 b_perm = container_of(b, struct tomoyo_path_number_acl, head)
678237ab459STetsuo Handa 		->perm;
679237ab459STetsuo Handa 	if (is_delete)
680237ab459STetsuo Handa 		perm &= ~b_perm;
681237ab459STetsuo Handa 	else
682237ab459STetsuo Handa 		perm |= b_perm;
683237ab459STetsuo Handa 	*a_perm = perm;
684237ab459STetsuo Handa 	return !perm;
685237ab459STetsuo Handa }
686237ab459STetsuo Handa 
687a1f9bb6aSTetsuo Handa /**
688a1f9bb6aSTetsuo Handa  * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL.
689a1f9bb6aSTetsuo Handa  *
690a238cf5bSTetsuo Handa  * @perm:  Permission.
691a238cf5bSTetsuo Handa  * @param: Pointer to "struct tomoyo_acl_param".
692a1f9bb6aSTetsuo Handa  *
693a1f9bb6aSTetsuo Handa  * Returns 0 on success, negative value otherwise.
694a1f9bb6aSTetsuo Handa  */
695a238cf5bSTetsuo Handa static int tomoyo_update_path_number_acl(const u8 perm,
696a238cf5bSTetsuo Handa 					 struct tomoyo_acl_param *param)
697a1f9bb6aSTetsuo Handa {
698a1f9bb6aSTetsuo Handa 	struct tomoyo_path_number_acl e = {
699a1f9bb6aSTetsuo Handa 		.head.type = TOMOYO_TYPE_PATH_NUMBER_ACL,
700a238cf5bSTetsuo Handa 		.perm = perm
701a1f9bb6aSTetsuo Handa 	};
702a238cf5bSTetsuo Handa 	int error;
703a238cf5bSTetsuo Handa 	if (!tomoyo_parse_name_union(param, &e.name) ||
704a238cf5bSTetsuo Handa 	    !tomoyo_parse_number_union(param, &e.number))
705a238cf5bSTetsuo Handa 		error = -EINVAL;
706a238cf5bSTetsuo Handa 	else
707a238cf5bSTetsuo Handa 		error = tomoyo_update_domain(&e.head, sizeof(e), param,
708237ab459STetsuo Handa 					     tomoyo_same_path_number_acl,
709237ab459STetsuo Handa 					     tomoyo_merge_path_number_acl);
710a1f9bb6aSTetsuo Handa 	tomoyo_put_name_union(&e.name);
711a1f9bb6aSTetsuo Handa 	tomoyo_put_number_union(&e.number);
712a1f9bb6aSTetsuo Handa 	return error;
713a1f9bb6aSTetsuo Handa }
714a1f9bb6aSTetsuo Handa 
715a1f9bb6aSTetsuo Handa /**
716a1f9bb6aSTetsuo Handa  * tomoyo_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp".
717a1f9bb6aSTetsuo Handa  *
718a1f9bb6aSTetsuo Handa  * @type:   Type of operation.
719a1f9bb6aSTetsuo Handa  * @path:   Pointer to "struct path".
720a1f9bb6aSTetsuo Handa  * @number: Number.
721a1f9bb6aSTetsuo Handa  *
722a1f9bb6aSTetsuo Handa  * Returns 0 on success, negative value otherwise.
723a1f9bb6aSTetsuo Handa  */
724a1f9bb6aSTetsuo Handa int tomoyo_path_number_perm(const u8 type, struct path *path,
725a1f9bb6aSTetsuo Handa 			    unsigned long number)
726a1f9bb6aSTetsuo Handa {
727a1f9bb6aSTetsuo Handa 	struct tomoyo_request_info r;
728a1f9bb6aSTetsuo Handa 	int error = -ENOMEM;
729c8c57e84STetsuo Handa 	struct tomoyo_path_info buf;
730a1f9bb6aSTetsuo Handa 	int idx;
731a1f9bb6aSTetsuo Handa 
73257c2590fSTetsuo Handa 	if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type])
73357c2590fSTetsuo Handa 	    == TOMOYO_CONFIG_DISABLED || !path->mnt || !path->dentry)
734a1f9bb6aSTetsuo Handa 		return 0;
735a1f9bb6aSTetsuo Handa 	idx = tomoyo_read_lock();
736c8c57e84STetsuo Handa 	if (!tomoyo_get_realpath(&buf, path))
737a1f9bb6aSTetsuo Handa 		goto out;
738c8c57e84STetsuo Handa 	if (type == TOMOYO_TYPE_MKDIR)
739c8c57e84STetsuo Handa 		tomoyo_add_slash(&buf);
740cb917cf5STetsuo Handa 	r.param_type = TOMOYO_TYPE_PATH_NUMBER_ACL;
741cb917cf5STetsuo Handa 	r.param.path_number.operation = type;
742cb917cf5STetsuo Handa 	r.param.path_number.filename = &buf;
743cb917cf5STetsuo Handa 	r.param.path_number.number = number;
744cb917cf5STetsuo Handa 	do {
745cb917cf5STetsuo Handa 		tomoyo_check_acl(&r, tomoyo_check_path_number_acl);
746cb917cf5STetsuo Handa 		error = tomoyo_audit_path_number_log(&r);
747cb917cf5STetsuo Handa 	} while (error == TOMOYO_RETRY_REQUEST);
748c8c57e84STetsuo Handa 	kfree(buf.name);
749cb917cf5STetsuo Handa  out:
750a1f9bb6aSTetsuo Handa 	tomoyo_read_unlock(idx);
751a1f9bb6aSTetsuo Handa 	if (r.mode != TOMOYO_CONFIG_ENFORCING)
752a1f9bb6aSTetsuo Handa 		error = 0;
753a1f9bb6aSTetsuo Handa 	return error;
754a1f9bb6aSTetsuo Handa }
755a1f9bb6aSTetsuo Handa 
756a1f9bb6aSTetsuo Handa /**
757b69a54eeSKentaro Takeda  * tomoyo_check_open_permission - Check permission for "read" and "write".
758b69a54eeSKentaro Takeda  *
759b69a54eeSKentaro Takeda  * @domain: Pointer to "struct tomoyo_domain_info".
760b69a54eeSKentaro Takeda  * @path:   Pointer to "struct path".
761b69a54eeSKentaro Takeda  * @flag:   Flags for open().
762b69a54eeSKentaro Takeda  *
763b69a54eeSKentaro Takeda  * Returns 0 on success, negative value otherwise.
764b69a54eeSKentaro Takeda  */
765b69a54eeSKentaro Takeda int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
766b69a54eeSKentaro Takeda 				 struct path *path, const int flag)
767b69a54eeSKentaro Takeda {
768b69a54eeSKentaro Takeda 	const u8 acc_mode = ACC_MODE(flag);
769eae61f3cSTetsuo Handa 	int error = 0;
770c8c57e84STetsuo Handa 	struct tomoyo_path_info buf;
771cb0abe6aSTetsuo Handa 	struct tomoyo_request_info r;
772fdb8ebb7STetsuo Handa 	int idx;
773b69a54eeSKentaro Takeda 
7747c75964fSTetsuo Handa 	if (!path->mnt)
775b69a54eeSKentaro Takeda 		return 0;
77657c2590fSTetsuo Handa 	buf.name = NULL;
77757c2590fSTetsuo Handa 	r.mode = TOMOYO_CONFIG_DISABLED;
778fdb8ebb7STetsuo Handa 	idx = tomoyo_read_lock();
7797c75964fSTetsuo Handa 	if (acc_mode &&
7807c75964fSTetsuo Handa 	    tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN)
78157c2590fSTetsuo Handa 	    != TOMOYO_CONFIG_DISABLED) {
78257c2590fSTetsuo Handa 		if (!tomoyo_get_realpath(&buf, path)) {
78357c2590fSTetsuo Handa 			error = -ENOMEM;
78457c2590fSTetsuo Handa 			goto out;
785b69a54eeSKentaro Takeda 		}
7867c75964fSTetsuo Handa 		if (acc_mode & MAY_READ)
7877c75964fSTetsuo Handa 			error = tomoyo_path_permission(&r, TOMOYO_TYPE_READ,
78857c2590fSTetsuo Handa 						       &buf);
7897c75964fSTetsuo Handa 		if (!error && (acc_mode & MAY_WRITE))
7907c75964fSTetsuo Handa 			error = tomoyo_path_permission(&r, (flag & O_APPEND) ?
7917c75964fSTetsuo Handa 						       TOMOYO_TYPE_APPEND :
7927c75964fSTetsuo Handa 						       TOMOYO_TYPE_WRITE,
7937c75964fSTetsuo Handa 						       &buf);
79457c2590fSTetsuo Handa 	}
795b69a54eeSKentaro Takeda  out:
796c8c57e84STetsuo Handa 	kfree(buf.name);
797fdb8ebb7STetsuo Handa 	tomoyo_read_unlock(idx);
798cb0abe6aSTetsuo Handa 	if (r.mode != TOMOYO_CONFIG_ENFORCING)
799b69a54eeSKentaro Takeda 		error = 0;
800b69a54eeSKentaro Takeda 	return error;
801b69a54eeSKentaro Takeda }
802b69a54eeSKentaro Takeda 
803b69a54eeSKentaro Takeda /**
8047c75964fSTetsuo Handa  * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "append", "chroot" and "unmount".
805b69a54eeSKentaro Takeda  *
806b69a54eeSKentaro Takeda  * @operation: Type of operation.
807b69a54eeSKentaro Takeda  * @path:      Pointer to "struct path".
808b69a54eeSKentaro Takeda  *
809b69a54eeSKentaro Takeda  * Returns 0 on success, negative value otherwise.
810b69a54eeSKentaro Takeda  */
81197d6931eSTetsuo Handa int tomoyo_path_perm(const u8 operation, struct path *path)
812b69a54eeSKentaro Takeda {
813cb0abe6aSTetsuo Handa 	struct tomoyo_request_info r;
8147c75964fSTetsuo Handa 	int error;
8157c75964fSTetsuo Handa 	struct tomoyo_path_info buf;
8167c75964fSTetsuo Handa 	bool is_enforce;
817fdb8ebb7STetsuo Handa 	int idx;
818b69a54eeSKentaro Takeda 
81957c2590fSTetsuo Handa 	if (!path->mnt)
820b69a54eeSKentaro Takeda 		return 0;
82157c2590fSTetsuo Handa 	if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation])
82257c2590fSTetsuo Handa 	    == TOMOYO_CONFIG_DISABLED)
82357c2590fSTetsuo Handa 		return 0;
8247c75964fSTetsuo Handa 	is_enforce = (r.mode == TOMOYO_CONFIG_ENFORCING);
8257c75964fSTetsuo Handa 	error = -ENOMEM;
82657c2590fSTetsuo Handa 	buf.name = NULL;
827fdb8ebb7STetsuo Handa 	idx = tomoyo_read_lock();
828c8c57e84STetsuo Handa 	if (!tomoyo_get_realpath(&buf, path))
829b69a54eeSKentaro Takeda 		goto out;
830b69a54eeSKentaro Takeda 	switch (operation) {
8317ef61233STetsuo Handa 	case TOMOYO_TYPE_RMDIR:
8327ef61233STetsuo Handa 	case TOMOYO_TYPE_CHROOT:
833c8c57e84STetsuo Handa 		tomoyo_add_slash(&buf);
834c8c57e84STetsuo Handa 		break;
835b69a54eeSKentaro Takeda 	}
836c8c57e84STetsuo Handa 	error = tomoyo_path_permission(&r, operation, &buf);
837b69a54eeSKentaro Takeda  out:
838c8c57e84STetsuo Handa 	kfree(buf.name);
839fdb8ebb7STetsuo Handa 	tomoyo_read_unlock(idx);
8407c75964fSTetsuo Handa 	if (!is_enforce)
841b69a54eeSKentaro Takeda 		error = 0;
842b69a54eeSKentaro Takeda 	return error;
843b69a54eeSKentaro Takeda }
844b69a54eeSKentaro Takeda 
845b69a54eeSKentaro Takeda /**
84675093152STetsuo Handa  * tomoyo_mkdev_perm - Check permission for "mkblock" and "mkchar".
847a1f9bb6aSTetsuo Handa  *
848a1f9bb6aSTetsuo Handa  * @operation: Type of operation. (TOMOYO_TYPE_MKCHAR or TOMOYO_TYPE_MKBLOCK)
849a1f9bb6aSTetsuo Handa  * @path:      Pointer to "struct path".
850a1f9bb6aSTetsuo Handa  * @mode:      Create mode.
851a1f9bb6aSTetsuo Handa  * @dev:       Device number.
852a1f9bb6aSTetsuo Handa  *
853a1f9bb6aSTetsuo Handa  * Returns 0 on success, negative value otherwise.
854a1f9bb6aSTetsuo Handa  */
85575093152STetsuo Handa int tomoyo_mkdev_perm(const u8 operation, struct path *path,
856a1f9bb6aSTetsuo Handa 		      const unsigned int mode, unsigned int dev)
857a1f9bb6aSTetsuo Handa {
858a1f9bb6aSTetsuo Handa 	struct tomoyo_request_info r;
859a1f9bb6aSTetsuo Handa 	int error = -ENOMEM;
860c8c57e84STetsuo Handa 	struct tomoyo_path_info buf;
861a1f9bb6aSTetsuo Handa 	int idx;
862a1f9bb6aSTetsuo Handa 
86357c2590fSTetsuo Handa 	if (!path->mnt ||
86457c2590fSTetsuo Handa 	    tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation])
86557c2590fSTetsuo Handa 	    == TOMOYO_CONFIG_DISABLED)
866a1f9bb6aSTetsuo Handa 		return 0;
867a1f9bb6aSTetsuo Handa 	idx = tomoyo_read_lock();
868a1f9bb6aSTetsuo Handa 	error = -ENOMEM;
869c8c57e84STetsuo Handa 	if (tomoyo_get_realpath(&buf, path)) {
870cf6e9a64STetsuo Handa 		dev = new_decode_dev(dev);
87175093152STetsuo Handa 		r.param_type = TOMOYO_TYPE_MKDEV_ACL;
872cf6e9a64STetsuo Handa 		r.param.mkdev.filename = &buf;
873cf6e9a64STetsuo Handa 		r.param.mkdev.operation = operation;
874cf6e9a64STetsuo Handa 		r.param.mkdev.mode = mode;
875cf6e9a64STetsuo Handa 		r.param.mkdev.major = MAJOR(dev);
876cf6e9a64STetsuo Handa 		r.param.mkdev.minor = MINOR(dev);
87799a85259STetsuo Handa 		tomoyo_check_acl(&r, tomoyo_check_mkdev_acl);
87899a85259STetsuo Handa 		error = tomoyo_audit_mkdev_log(&r);
879c8c57e84STetsuo Handa 		kfree(buf.name);
880a1f9bb6aSTetsuo Handa 	}
881a1f9bb6aSTetsuo Handa 	tomoyo_read_unlock(idx);
882a1f9bb6aSTetsuo Handa 	if (r.mode != TOMOYO_CONFIG_ENFORCING)
883a1f9bb6aSTetsuo Handa 		error = 0;
884a1f9bb6aSTetsuo Handa 	return error;
885a1f9bb6aSTetsuo Handa }
886a1f9bb6aSTetsuo Handa 
887a1f9bb6aSTetsuo Handa /**
8887ef61233STetsuo Handa  * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root".
889b69a54eeSKentaro Takeda  *
890b69a54eeSKentaro Takeda  * @operation: Type of operation.
891b69a54eeSKentaro Takeda  * @path1:      Pointer to "struct path".
892b69a54eeSKentaro Takeda  * @path2:      Pointer to "struct path".
893b69a54eeSKentaro Takeda  *
894b69a54eeSKentaro Takeda  * Returns 0 on success, negative value otherwise.
895b69a54eeSKentaro Takeda  */
89697d6931eSTetsuo Handa int tomoyo_path2_perm(const u8 operation, struct path *path1,
897b69a54eeSKentaro Takeda 		      struct path *path2)
898b69a54eeSKentaro Takeda {
899b69a54eeSKentaro Takeda 	int error = -ENOMEM;
900c8c57e84STetsuo Handa 	struct tomoyo_path_info buf1;
901c8c57e84STetsuo Handa 	struct tomoyo_path_info buf2;
902cb0abe6aSTetsuo Handa 	struct tomoyo_request_info r;
903fdb8ebb7STetsuo Handa 	int idx;
904b69a54eeSKentaro Takeda 
90557c2590fSTetsuo Handa 	if (!path1->mnt || !path2->mnt ||
90657c2590fSTetsuo Handa 	    tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation])
90757c2590fSTetsuo Handa 	    == TOMOYO_CONFIG_DISABLED)
908b69a54eeSKentaro Takeda 		return 0;
909c8c57e84STetsuo Handa 	buf1.name = NULL;
910c8c57e84STetsuo Handa 	buf2.name = NULL;
911fdb8ebb7STetsuo Handa 	idx = tomoyo_read_lock();
912c8c57e84STetsuo Handa 	if (!tomoyo_get_realpath(&buf1, path1) ||
913c8c57e84STetsuo Handa 	    !tomoyo_get_realpath(&buf2, path2))
914b69a54eeSKentaro Takeda 		goto out;
91557c2590fSTetsuo Handa 	switch (operation) {
91657c2590fSTetsuo Handa 		struct dentry *dentry;
91757c2590fSTetsuo Handa 	case TOMOYO_TYPE_RENAME:
91857c2590fSTetsuo Handa         case TOMOYO_TYPE_LINK:
91957c2590fSTetsuo Handa 		dentry = path1->dentry;
92057c2590fSTetsuo Handa 	        if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode))
92157c2590fSTetsuo Handa                         break;
92257c2590fSTetsuo Handa                 /* fall through */
92357c2590fSTetsuo Handa         case TOMOYO_TYPE_PIVOT_ROOT:
924c8c57e84STetsuo Handa                 tomoyo_add_slash(&buf1);
925c8c57e84STetsuo Handa                 tomoyo_add_slash(&buf2);
92657c2590fSTetsuo Handa 		break;
927b69a54eeSKentaro Takeda         }
928cf6e9a64STetsuo Handa 	r.param_type = TOMOYO_TYPE_PATH2_ACL;
929cf6e9a64STetsuo Handa 	r.param.path2.operation = operation;
930cf6e9a64STetsuo Handa 	r.param.path2.filename1 = &buf1;
931cf6e9a64STetsuo Handa 	r.param.path2.filename2 = &buf2;
93217fcfbd9STetsuo Handa 	do {
93399a85259STetsuo Handa 		tomoyo_check_acl(&r, tomoyo_check_path2_acl);
93499a85259STetsuo Handa 		error = tomoyo_audit_path2_log(&r);
93517fcfbd9STetsuo Handa 	} while (error == TOMOYO_RETRY_REQUEST);
936b69a54eeSKentaro Takeda  out:
937c8c57e84STetsuo Handa 	kfree(buf1.name);
938c8c57e84STetsuo Handa 	kfree(buf2.name);
939fdb8ebb7STetsuo Handa 	tomoyo_read_unlock(idx);
940cb0abe6aSTetsuo Handa 	if (r.mode != TOMOYO_CONFIG_ENFORCING)
941b69a54eeSKentaro Takeda 		error = 0;
942b69a54eeSKentaro Takeda 	return error;
943b69a54eeSKentaro Takeda }
944a1f9bb6aSTetsuo Handa 
945a1f9bb6aSTetsuo Handa /**
946a238cf5bSTetsuo Handa  * tomoyo_same_mount_acl - Check for duplicated "struct tomoyo_mount_acl" entry.
947a1f9bb6aSTetsuo Handa  *
948a238cf5bSTetsuo Handa  * @a: Pointer to "struct tomoyo_acl_info".
949a238cf5bSTetsuo Handa  * @b: Pointer to "struct tomoyo_acl_info".
950a238cf5bSTetsuo Handa  *
951a238cf5bSTetsuo Handa  * Returns true if @a == @b, false otherwise.
952a238cf5bSTetsuo Handa  */
953a238cf5bSTetsuo Handa static bool tomoyo_same_mount_acl(const struct tomoyo_acl_info *a,
954a238cf5bSTetsuo Handa 				  const struct tomoyo_acl_info *b)
955a238cf5bSTetsuo Handa {
956a238cf5bSTetsuo Handa 	const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head);
957a238cf5bSTetsuo Handa 	const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head);
958a238cf5bSTetsuo Handa 	return tomoyo_same_name_union(&p1->dev_name, &p2->dev_name) &&
959a238cf5bSTetsuo Handa 		tomoyo_same_name_union(&p1->dir_name, &p2->dir_name) &&
960a238cf5bSTetsuo Handa 		tomoyo_same_name_union(&p1->fs_type, &p2->fs_type) &&
961a238cf5bSTetsuo Handa 		tomoyo_same_number_union(&p1->flags, &p2->flags);
962a238cf5bSTetsuo Handa }
963a238cf5bSTetsuo Handa 
964a238cf5bSTetsuo Handa /**
965a238cf5bSTetsuo Handa  * tomoyo_update_mount_acl - Write "struct tomoyo_mount_acl" list.
966a238cf5bSTetsuo Handa  *
967a238cf5bSTetsuo Handa  * @param: Pointer to "struct tomoyo_acl_param".
968a1f9bb6aSTetsuo Handa  *
969a1f9bb6aSTetsuo Handa  * Returns 0 on success, negative value otherwise.
970a1f9bb6aSTetsuo Handa  *
971a1f9bb6aSTetsuo Handa  * Caller holds tomoyo_read_lock().
972a1f9bb6aSTetsuo Handa  */
973a238cf5bSTetsuo Handa static int tomoyo_update_mount_acl(struct tomoyo_acl_param *param)
974a1f9bb6aSTetsuo Handa {
975a238cf5bSTetsuo Handa 	struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL };
976a238cf5bSTetsuo Handa 	int error;
977a238cf5bSTetsuo Handa 	if (!tomoyo_parse_name_union(param, &e.dev_name) ||
978a238cf5bSTetsuo Handa 	    !tomoyo_parse_name_union(param, &e.dir_name) ||
979a238cf5bSTetsuo Handa 	    !tomoyo_parse_name_union(param, &e.fs_type) ||
980a238cf5bSTetsuo Handa 	    !tomoyo_parse_number_union(param, &e.flags))
981a238cf5bSTetsuo Handa 		error = -EINVAL;
982a238cf5bSTetsuo Handa 	else
983a238cf5bSTetsuo Handa 		error = tomoyo_update_domain(&e.head, sizeof(e), param,
984a238cf5bSTetsuo Handa 					     tomoyo_same_mount_acl, NULL);
985a238cf5bSTetsuo Handa 	tomoyo_put_name_union(&e.dev_name);
986a238cf5bSTetsuo Handa 	tomoyo_put_name_union(&e.dir_name);
987a238cf5bSTetsuo Handa 	tomoyo_put_name_union(&e.fs_type);
988a238cf5bSTetsuo Handa 	tomoyo_put_number_union(&e.flags);
989a238cf5bSTetsuo Handa 	return error;
990a238cf5bSTetsuo Handa }
991a238cf5bSTetsuo Handa 
992a238cf5bSTetsuo Handa /**
993a238cf5bSTetsuo Handa  * tomoyo_write_file - Update file related list.
994a238cf5bSTetsuo Handa  *
995a238cf5bSTetsuo Handa  * @param: Pointer to "struct tomoyo_acl_param".
996a238cf5bSTetsuo Handa  *
997a238cf5bSTetsuo Handa  * Returns 0 on success, negative value otherwise.
998a238cf5bSTetsuo Handa  *
999a238cf5bSTetsuo Handa  * Caller holds tomoyo_read_lock().
1000a238cf5bSTetsuo Handa  */
1001a238cf5bSTetsuo Handa int tomoyo_write_file(struct tomoyo_acl_param *param)
1002a238cf5bSTetsuo Handa {
1003a238cf5bSTetsuo Handa 	u16 perm = 0;
1004a1f9bb6aSTetsuo Handa 	u8 type;
1005a238cf5bSTetsuo Handa 	const char *operation = tomoyo_read_token(param);
1006a238cf5bSTetsuo Handa 	for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++)
1007a238cf5bSTetsuo Handa 		if (tomoyo_permstr(operation, tomoyo_path_keyword[type]))
1008a238cf5bSTetsuo Handa 			perm |= 1 << type;
1009a238cf5bSTetsuo Handa 	if (perm)
1010a238cf5bSTetsuo Handa 		return tomoyo_update_path_acl(perm, param);
1011a238cf5bSTetsuo Handa 	for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++)
1012a238cf5bSTetsuo Handa 		if (tomoyo_permstr(operation, tomoyo_path2_keyword[type]))
1013a238cf5bSTetsuo Handa 			perm |= 1 << type;
1014a238cf5bSTetsuo Handa 	if (perm)
1015a238cf5bSTetsuo Handa 		return tomoyo_update_path2_acl(perm, param);
1016a238cf5bSTetsuo Handa 	for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++)
1017a238cf5bSTetsuo Handa 		if (tomoyo_permstr(operation,
1018a238cf5bSTetsuo Handa 				   tomoyo_path_number_keyword[type]))
1019a238cf5bSTetsuo Handa 			perm |= 1 << type;
1020a238cf5bSTetsuo Handa 	if (perm)
1021a238cf5bSTetsuo Handa 		return tomoyo_update_path_number_acl(perm, param);
1022a238cf5bSTetsuo Handa 	for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++)
1023a238cf5bSTetsuo Handa 		if (tomoyo_permstr(operation, tomoyo_mkdev_keyword[type]))
1024a238cf5bSTetsuo Handa 			perm |= 1 << type;
1025a238cf5bSTetsuo Handa 	if (perm)
1026a238cf5bSTetsuo Handa 		return tomoyo_update_mkdev_acl(perm, param);
1027a238cf5bSTetsuo Handa 	if (tomoyo_permstr(operation, "mount"))
1028a238cf5bSTetsuo Handa 		return tomoyo_update_mount_acl(param);
1029a1f9bb6aSTetsuo Handa 	return -EINVAL;
1030a1f9bb6aSTetsuo Handa }
1031