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