file.c revision 2c47ab9353242b0f061959318f83c55360b88fa4
1/*
2 * security/tomoyo/file.c
3 *
4 * Pathname restriction functions.
5 *
6 * Copyright (C) 2005-2010  NTT DATA CORPORATION
7 */
8
9#include "common.h"
10#include <linux/slab.h>
11
12/*
13 * Mapping table from "enum tomoyo_path_acl_index" to "enum tomoyo_mac_index".
14 */
15static const u8 tomoyo_p2mac[TOMOYO_MAX_PATH_OPERATION] = {
16	[TOMOYO_TYPE_EXECUTE]    = TOMOYO_MAC_FILE_EXECUTE,
17	[TOMOYO_TYPE_READ]       = TOMOYO_MAC_FILE_OPEN,
18	[TOMOYO_TYPE_WRITE]      = TOMOYO_MAC_FILE_OPEN,
19	[TOMOYO_TYPE_APPEND]     = TOMOYO_MAC_FILE_OPEN,
20	[TOMOYO_TYPE_UNLINK]     = TOMOYO_MAC_FILE_UNLINK,
21	[TOMOYO_TYPE_GETATTR]    = TOMOYO_MAC_FILE_GETATTR,
22	[TOMOYO_TYPE_RMDIR]      = TOMOYO_MAC_FILE_RMDIR,
23	[TOMOYO_TYPE_TRUNCATE]   = TOMOYO_MAC_FILE_TRUNCATE,
24	[TOMOYO_TYPE_SYMLINK]    = TOMOYO_MAC_FILE_SYMLINK,
25	[TOMOYO_TYPE_CHROOT]     = TOMOYO_MAC_FILE_CHROOT,
26	[TOMOYO_TYPE_UMOUNT]     = TOMOYO_MAC_FILE_UMOUNT,
27};
28
29/*
30 * Mapping table from "enum tomoyo_mkdev_acl_index" to "enum tomoyo_mac_index".
31 */
32const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION] = {
33	[TOMOYO_TYPE_MKBLOCK] = TOMOYO_MAC_FILE_MKBLOCK,
34	[TOMOYO_TYPE_MKCHAR]  = TOMOYO_MAC_FILE_MKCHAR,
35};
36
37/*
38 * Mapping table from "enum tomoyo_path2_acl_index" to "enum tomoyo_mac_index".
39 */
40const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION] = {
41	[TOMOYO_TYPE_LINK]       = TOMOYO_MAC_FILE_LINK,
42	[TOMOYO_TYPE_RENAME]     = TOMOYO_MAC_FILE_RENAME,
43	[TOMOYO_TYPE_PIVOT_ROOT] = TOMOYO_MAC_FILE_PIVOT_ROOT,
44};
45
46/*
47 * Mapping table from "enum tomoyo_path_number_acl_index" to
48 * "enum tomoyo_mac_index".
49 */
50const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = {
51	[TOMOYO_TYPE_CREATE] = TOMOYO_MAC_FILE_CREATE,
52	[TOMOYO_TYPE_MKDIR]  = TOMOYO_MAC_FILE_MKDIR,
53	[TOMOYO_TYPE_MKFIFO] = TOMOYO_MAC_FILE_MKFIFO,
54	[TOMOYO_TYPE_MKSOCK] = TOMOYO_MAC_FILE_MKSOCK,
55	[TOMOYO_TYPE_IOCTL]  = TOMOYO_MAC_FILE_IOCTL,
56	[TOMOYO_TYPE_CHMOD]  = TOMOYO_MAC_FILE_CHMOD,
57	[TOMOYO_TYPE_CHOWN]  = TOMOYO_MAC_FILE_CHOWN,
58	[TOMOYO_TYPE_CHGRP]  = TOMOYO_MAC_FILE_CHGRP,
59};
60
61/**
62 * tomoyo_put_name_union - Drop reference on "struct tomoyo_name_union".
63 *
64 * @ptr: Pointer to "struct tomoyo_name_union".
65 *
66 * Returns nothing.
67 */
68void tomoyo_put_name_union(struct tomoyo_name_union *ptr)
69{
70	tomoyo_put_group(ptr->group);
71	tomoyo_put_name(ptr->filename);
72}
73
74/**
75 * tomoyo_compare_name_union - Check whether a name matches "struct tomoyo_name_union" or not.
76 *
77 * @name: Pointer to "struct tomoyo_path_info".
78 * @ptr:  Pointer to "struct tomoyo_name_union".
79 *
80 * Returns "struct tomoyo_path_info" if @name matches @ptr, NULL otherwise.
81 */
82const struct tomoyo_path_info *
83tomoyo_compare_name_union(const struct tomoyo_path_info *name,
84			  const struct tomoyo_name_union *ptr)
85{
86	if (ptr->group)
87		return tomoyo_path_matches_group(name, ptr->group);
88	if (tomoyo_path_matches_pattern(name, ptr->filename))
89		return ptr->filename;
90	return NULL;
91}
92
93/**
94 * tomoyo_put_number_union - Drop reference on "struct tomoyo_number_union".
95 *
96 * @ptr: Pointer to "struct tomoyo_number_union".
97 *
98 * Returns nothing.
99 */
100void tomoyo_put_number_union(struct tomoyo_number_union *ptr)
101{
102	tomoyo_put_group(ptr->group);
103}
104
105/**
106 * tomoyo_compare_number_union - Check whether a value matches "struct tomoyo_number_union" or not.
107 *
108 * @value: Number to check.
109 * @ptr:   Pointer to "struct tomoyo_number_union".
110 *
111 * Returns true if @value matches @ptr, false otherwise.
112 */
113bool tomoyo_compare_number_union(const unsigned long value,
114				 const struct tomoyo_number_union *ptr)
115{
116	if (ptr->group)
117		return tomoyo_number_matches_group(value, value, ptr->group);
118	return value >= ptr->values[0] && value <= ptr->values[1];
119}
120
121/**
122 * tomoyo_add_slash - Add trailing '/' if needed.
123 *
124 * @buf: Pointer to "struct tomoyo_path_info".
125 *
126 * Returns nothing.
127 *
128 * @buf must be generated by tomoyo_encode() because this function does not
129 * allocate memory for adding '/'.
130 */
131static void tomoyo_add_slash(struct tomoyo_path_info *buf)
132{
133	if (buf->is_dir)
134		return;
135	/*
136	 * This is OK because tomoyo_encode() reserves space for appending "/".
137	 */
138	strcat((char *) buf->name, "/");
139	tomoyo_fill_path_info(buf);
140}
141
142/**
143 * tomoyo_get_realpath - Get realpath.
144 *
145 * @buf:  Pointer to "struct tomoyo_path_info".
146 * @path: Pointer to "struct path".
147 *
148 * Returns true on success, false otherwise.
149 */
150static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path)
151{
152	buf->name = tomoyo_realpath_from_path(path);
153	if (buf->name) {
154		tomoyo_fill_path_info(buf);
155		return true;
156	}
157        return false;
158}
159
160/**
161 * tomoyo_audit_path_log - Audit path request log.
162 *
163 * @r: Pointer to "struct tomoyo_request_info".
164 *
165 * Returns 0 on success, negative value otherwise.
166 */
167static int tomoyo_audit_path_log(struct tomoyo_request_info *r)
168{
169	return tomoyo_supervisor(r, "file %s %s\n", tomoyo_path_keyword
170				 [r->param.path.operation],
171				 r->param.path.filename->name);
172}
173
174/**
175 * tomoyo_audit_path2_log - Audit path/path request log.
176 *
177 * @r: Pointer to "struct tomoyo_request_info".
178 *
179 * Returns 0 on success, negative value otherwise.
180 */
181static int tomoyo_audit_path2_log(struct tomoyo_request_info *r)
182{
183	return tomoyo_supervisor(r, "file %s %s %s\n", tomoyo_mac_keywords
184				 [tomoyo_pp2mac[r->param.path2.operation]],
185				 r->param.path2.filename1->name,
186				 r->param.path2.filename2->name);
187}
188
189/**
190 * tomoyo_audit_mkdev_log - Audit path/number/number/number request log.
191 *
192 * @r: Pointer to "struct tomoyo_request_info".
193 *
194 * Returns 0 on success, negative value otherwise.
195 */
196static int tomoyo_audit_mkdev_log(struct tomoyo_request_info *r)
197{
198	return tomoyo_supervisor(r, "file %s %s 0%o %u %u\n",
199				 tomoyo_mac_keywords
200				 [tomoyo_pnnn2mac[r->param.mkdev.operation]],
201				 r->param.mkdev.filename->name,
202				 r->param.mkdev.mode, r->param.mkdev.major,
203				 r->param.mkdev.minor);
204}
205
206/**
207 * tomoyo_audit_path_number_log - Audit path/number request log.
208 *
209 * @r: Pointer to "struct tomoyo_request_info".
210 *
211 * Returns 0 on success, negative value otherwise.
212 */
213static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r)
214{
215	const u8 type = r->param.path_number.operation;
216	u8 radix;
217	char buffer[64];
218	switch (type) {
219	case TOMOYO_TYPE_CREATE:
220	case TOMOYO_TYPE_MKDIR:
221	case TOMOYO_TYPE_MKFIFO:
222	case TOMOYO_TYPE_MKSOCK:
223	case TOMOYO_TYPE_CHMOD:
224		radix = TOMOYO_VALUE_TYPE_OCTAL;
225		break;
226	case TOMOYO_TYPE_IOCTL:
227		radix = TOMOYO_VALUE_TYPE_HEXADECIMAL;
228		break;
229	default:
230		radix = TOMOYO_VALUE_TYPE_DECIMAL;
231		break;
232	}
233	tomoyo_print_ulong(buffer, sizeof(buffer), r->param.path_number.number,
234			   radix);
235	return tomoyo_supervisor(r, "file %s %s %s\n", tomoyo_mac_keywords
236				 [tomoyo_pn2mac[type]],
237				 r->param.path_number.filename->name, buffer);
238}
239
240/**
241 * tomoyo_check_path_acl - Check permission for path operation.
242 *
243 * @r:   Pointer to "struct tomoyo_request_info".
244 * @ptr: Pointer to "struct tomoyo_acl_info".
245 *
246 * Returns true if granted, false otherwise.
247 *
248 * To be able to use wildcard for domain transition, this function sets
249 * matching entry on success. Since the caller holds tomoyo_read_lock(),
250 * it is safe to set matching entry.
251 */
252static bool tomoyo_check_path_acl(struct tomoyo_request_info *r,
253				  const struct tomoyo_acl_info *ptr)
254{
255	const struct tomoyo_path_acl *acl = container_of(ptr, typeof(*acl),
256							 head);
257	if (acl->perm & (1 << r->param.path.operation)) {
258		r->param.path.matched_path =
259			tomoyo_compare_name_union(r->param.path.filename,
260						  &acl->name);
261		return r->param.path.matched_path != NULL;
262	}
263	return false;
264}
265
266/**
267 * tomoyo_check_path_number_acl - Check permission for path number operation.
268 *
269 * @r:   Pointer to "struct tomoyo_request_info".
270 * @ptr: Pointer to "struct tomoyo_acl_info".
271 *
272 * Returns true if granted, false otherwise.
273 */
274static bool tomoyo_check_path_number_acl(struct tomoyo_request_info *r,
275					 const struct tomoyo_acl_info *ptr)
276{
277	const struct tomoyo_path_number_acl *acl =
278		container_of(ptr, typeof(*acl), head);
279	return (acl->perm & (1 << r->param.path_number.operation)) &&
280		tomoyo_compare_number_union(r->param.path_number.number,
281					    &acl->number) &&
282		tomoyo_compare_name_union(r->param.path_number.filename,
283					  &acl->name);
284}
285
286/**
287 * tomoyo_check_path2_acl - Check permission for path path operation.
288 *
289 * @r:   Pointer to "struct tomoyo_request_info".
290 * @ptr: Pointer to "struct tomoyo_acl_info".
291 *
292 * Returns true if granted, false otherwise.
293 */
294static bool tomoyo_check_path2_acl(struct tomoyo_request_info *r,
295				   const struct tomoyo_acl_info *ptr)
296{
297	const struct tomoyo_path2_acl *acl =
298		container_of(ptr, typeof(*acl), head);
299	return (acl->perm & (1 << r->param.path2.operation)) &&
300		tomoyo_compare_name_union(r->param.path2.filename1, &acl->name1)
301		&& tomoyo_compare_name_union(r->param.path2.filename2,
302					     &acl->name2);
303}
304
305/**
306 * tomoyo_check_mkdev_acl - Check permission for path number number number operation.
307 *
308 * @r:   Pointer to "struct tomoyo_request_info".
309 * @ptr: Pointer to "struct tomoyo_acl_info".
310 *
311 * Returns true if granted, false otherwise.
312 */
313static bool tomoyo_check_mkdev_acl(struct tomoyo_request_info *r,
314				   const struct tomoyo_acl_info *ptr)
315{
316	const struct tomoyo_mkdev_acl *acl =
317		container_of(ptr, typeof(*acl), head);
318	return (acl->perm & (1 << r->param.mkdev.operation)) &&
319		tomoyo_compare_number_union(r->param.mkdev.mode,
320					    &acl->mode) &&
321		tomoyo_compare_number_union(r->param.mkdev.major,
322					    &acl->major) &&
323		tomoyo_compare_number_union(r->param.mkdev.minor,
324					    &acl->minor) &&
325		tomoyo_compare_name_union(r->param.mkdev.filename,
326					  &acl->name);
327}
328
329/**
330 * tomoyo_same_path_acl - Check for duplicated "struct tomoyo_path_acl" entry.
331 *
332 * @a: Pointer to "struct tomoyo_acl_info".
333 * @b: Pointer to "struct tomoyo_acl_info".
334 *
335 * Returns true if @a == @b except permission bits, false otherwise.
336 */
337static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a,
338				 const struct tomoyo_acl_info *b)
339{
340	const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head);
341	const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head);
342	return tomoyo_same_name_union(&p1->name, &p2->name);
343}
344
345/**
346 * tomoyo_merge_path_acl - Merge duplicated "struct tomoyo_path_acl" entry.
347 *
348 * @a:         Pointer to "struct tomoyo_acl_info".
349 * @b:         Pointer to "struct tomoyo_acl_info".
350 * @is_delete: True for @a &= ~@b, false for @a |= @b.
351 *
352 * Returns true if @a is empty, false otherwise.
353 */
354static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a,
355				  struct tomoyo_acl_info *b,
356				  const bool is_delete)
357{
358	u16 * const a_perm = &container_of(a, struct tomoyo_path_acl, head)
359		->perm;
360	u16 perm = *a_perm;
361	const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm;
362	if (is_delete)
363		perm &= ~b_perm;
364	else
365		perm |= b_perm;
366	*a_perm = perm;
367	return !perm;
368}
369
370/**
371 * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list.
372 *
373 * @perm:  Permission.
374 * @param: Pointer to "struct tomoyo_acl_param".
375 *
376 * Returns 0 on success, negative value otherwise.
377 *
378 * Caller holds tomoyo_read_lock().
379 */
380static int tomoyo_update_path_acl(const u16 perm,
381				  struct tomoyo_acl_param *param)
382{
383	struct tomoyo_path_acl e = {
384		.head.type = TOMOYO_TYPE_PATH_ACL,
385		.perm = perm
386	};
387	int error;
388	if (!tomoyo_parse_name_union(param, &e.name))
389		error = -EINVAL;
390	else
391		error = tomoyo_update_domain(&e.head, sizeof(e), param,
392					     tomoyo_same_path_acl,
393					     tomoyo_merge_path_acl);
394	tomoyo_put_name_union(&e.name);
395	return error;
396}
397
398/**
399 * tomoyo_same_mkdev_acl - Check for duplicated "struct tomoyo_mkdev_acl" entry.
400 *
401 * @a: Pointer to "struct tomoyo_acl_info".
402 * @b: Pointer to "struct tomoyo_acl_info".
403 *
404 * Returns true if @a == @b except permission bits, false otherwise.
405 */
406static bool tomoyo_same_mkdev_acl(const struct tomoyo_acl_info *a,
407					 const struct tomoyo_acl_info *b)
408{
409	const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1), head);
410	const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2), head);
411	return tomoyo_same_name_union(&p1->name, &p2->name) &&
412		tomoyo_same_number_union(&p1->mode, &p2->mode) &&
413		tomoyo_same_number_union(&p1->major, &p2->major) &&
414		tomoyo_same_number_union(&p1->minor, &p2->minor);
415}
416
417/**
418 * tomoyo_merge_mkdev_acl - Merge duplicated "struct tomoyo_mkdev_acl" entry.
419 *
420 * @a:         Pointer to "struct tomoyo_acl_info".
421 * @b:         Pointer to "struct tomoyo_acl_info".
422 * @is_delete: True for @a &= ~@b, false for @a |= @b.
423 *
424 * Returns true if @a is empty, false otherwise.
425 */
426static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a,
427				   struct tomoyo_acl_info *b,
428				   const bool is_delete)
429{
430	u8 *const a_perm = &container_of(a, struct tomoyo_mkdev_acl,
431					 head)->perm;
432	u8 perm = *a_perm;
433	const u8 b_perm = container_of(b, struct tomoyo_mkdev_acl, head)
434		->perm;
435	if (is_delete)
436		perm &= ~b_perm;
437	else
438		perm |= b_perm;
439	*a_perm = perm;
440	return !perm;
441}
442
443/**
444 * tomoyo_update_mkdev_acl - Update "struct tomoyo_mkdev_acl" list.
445 *
446 * @perm:  Permission.
447 * @param: Pointer to "struct tomoyo_acl_param".
448 *
449 * Returns 0 on success, negative value otherwise.
450 *
451 * Caller holds tomoyo_read_lock().
452 */
453static int tomoyo_update_mkdev_acl(const u8 perm,
454				   struct tomoyo_acl_param *param)
455{
456	struct tomoyo_mkdev_acl e = {
457		.head.type = TOMOYO_TYPE_MKDEV_ACL,
458		.perm = perm
459	};
460	int error;
461	if (!tomoyo_parse_name_union(param, &e.name) ||
462	    !tomoyo_parse_number_union(param, &e.mode) ||
463	    !tomoyo_parse_number_union(param, &e.major) ||
464	    !tomoyo_parse_number_union(param, &e.minor))
465		error = -EINVAL;
466	else
467		error = tomoyo_update_domain(&e.head, sizeof(e), param,
468					     tomoyo_same_mkdev_acl,
469					     tomoyo_merge_mkdev_acl);
470	tomoyo_put_name_union(&e.name);
471	tomoyo_put_number_union(&e.mode);
472	tomoyo_put_number_union(&e.major);
473	tomoyo_put_number_union(&e.minor);
474	return error;
475}
476
477/**
478 * tomoyo_same_path2_acl - Check for duplicated "struct tomoyo_path2_acl" entry.
479 *
480 * @a: Pointer to "struct tomoyo_acl_info".
481 * @b: Pointer to "struct tomoyo_acl_info".
482 *
483 * Returns true if @a == @b except permission bits, false otherwise.
484 */
485static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a,
486				  const struct tomoyo_acl_info *b)
487{
488	const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head);
489	const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head);
490	return tomoyo_same_name_union(&p1->name1, &p2->name1) &&
491		tomoyo_same_name_union(&p1->name2, &p2->name2);
492}
493
494/**
495 * tomoyo_merge_path2_acl - Merge duplicated "struct tomoyo_path2_acl" entry.
496 *
497 * @a:         Pointer to "struct tomoyo_acl_info".
498 * @b:         Pointer to "struct tomoyo_acl_info".
499 * @is_delete: True for @a &= ~@b, false for @a |= @b.
500 *
501 * Returns true if @a is empty, false otherwise.
502 */
503static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a,
504				   struct tomoyo_acl_info *b,
505				   const bool is_delete)
506{
507	u8 * const a_perm = &container_of(a, struct tomoyo_path2_acl, head)
508		->perm;
509	u8 perm = *a_perm;
510	const u8 b_perm = container_of(b, struct tomoyo_path2_acl, head)->perm;
511	if (is_delete)
512		perm &= ~b_perm;
513	else
514		perm |= b_perm;
515	*a_perm = perm;
516	return !perm;
517}
518
519/**
520 * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list.
521 *
522 * @perm:  Permission.
523 * @param: Pointer to "struct tomoyo_acl_param".
524 *
525 * Returns 0 on success, negative value otherwise.
526 *
527 * Caller holds tomoyo_read_lock().
528 */
529static int tomoyo_update_path2_acl(const u8 perm,
530				   struct tomoyo_acl_param *param)
531{
532	struct tomoyo_path2_acl e = {
533		.head.type = TOMOYO_TYPE_PATH2_ACL,
534		.perm = perm
535	};
536	int error;
537	if (!tomoyo_parse_name_union(param, &e.name1) ||
538	    !tomoyo_parse_name_union(param, &e.name2))
539		error = -EINVAL;
540	else
541		error = tomoyo_update_domain(&e.head, sizeof(e), param,
542					     tomoyo_same_path2_acl,
543					     tomoyo_merge_path2_acl);
544	tomoyo_put_name_union(&e.name1);
545	tomoyo_put_name_union(&e.name2);
546	return error;
547}
548
549/**
550 * tomoyo_path_permission - Check permission for single path operation.
551 *
552 * @r:         Pointer to "struct tomoyo_request_info".
553 * @operation: Type of operation.
554 * @filename:  Filename to check.
555 *
556 * Returns 0 on success, negative value otherwise.
557 *
558 * Caller holds tomoyo_read_lock().
559 */
560int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
561			   const struct tomoyo_path_info *filename)
562{
563	int error;
564
565	r->type = tomoyo_p2mac[operation];
566	r->mode = tomoyo_get_mode(r->domain->ns, r->profile, r->type);
567	if (r->mode == TOMOYO_CONFIG_DISABLED)
568		return 0;
569	r->param_type = TOMOYO_TYPE_PATH_ACL;
570	r->param.path.filename = filename;
571	r->param.path.operation = operation;
572	do {
573		tomoyo_check_acl(r, tomoyo_check_path_acl);
574		error = tomoyo_audit_path_log(r);
575		/*
576		 * Do not retry for execute request, for alias may have
577		 * changed.
578		 */
579	} while (error == TOMOYO_RETRY_REQUEST &&
580		 operation != TOMOYO_TYPE_EXECUTE);
581	return error;
582}
583
584/**
585 * tomoyo_same_path_number_acl - Check for duplicated "struct tomoyo_path_number_acl" entry.
586 *
587 * @a: Pointer to "struct tomoyo_acl_info".
588 * @b: Pointer to "struct tomoyo_acl_info".
589 *
590 * Returns true if @a == @b except permission bits, false otherwise.
591 */
592static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a,
593					const struct tomoyo_acl_info *b)
594{
595	const struct tomoyo_path_number_acl *p1 = container_of(a, typeof(*p1),
596							       head);
597	const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2),
598							       head);
599	return tomoyo_same_name_union(&p1->name, &p2->name) &&
600		tomoyo_same_number_union(&p1->number, &p2->number);
601}
602
603/**
604 * tomoyo_merge_path_number_acl - Merge duplicated "struct tomoyo_path_number_acl" entry.
605 *
606 * @a:         Pointer to "struct tomoyo_acl_info".
607 * @b:         Pointer to "struct tomoyo_acl_info".
608 * @is_delete: True for @a &= ~@b, false for @a |= @b.
609 *
610 * Returns true if @a is empty, false otherwise.
611 */
612static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a,
613					 struct tomoyo_acl_info *b,
614					 const bool is_delete)
615{
616	u8 * const a_perm = &container_of(a, struct tomoyo_path_number_acl,
617					  head)->perm;
618	u8 perm = *a_perm;
619	const u8 b_perm = container_of(b, struct tomoyo_path_number_acl, head)
620		->perm;
621	if (is_delete)
622		perm &= ~b_perm;
623	else
624		perm |= b_perm;
625	*a_perm = perm;
626	return !perm;
627}
628
629/**
630 * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL.
631 *
632 * @perm:  Permission.
633 * @param: Pointer to "struct tomoyo_acl_param".
634 *
635 * Returns 0 on success, negative value otherwise.
636 */
637static int tomoyo_update_path_number_acl(const u8 perm,
638					 struct tomoyo_acl_param *param)
639{
640	struct tomoyo_path_number_acl e = {
641		.head.type = TOMOYO_TYPE_PATH_NUMBER_ACL,
642		.perm = perm
643	};
644	int error;
645	if (!tomoyo_parse_name_union(param, &e.name) ||
646	    !tomoyo_parse_number_union(param, &e.number))
647		error = -EINVAL;
648	else
649		error = tomoyo_update_domain(&e.head, sizeof(e), param,
650					     tomoyo_same_path_number_acl,
651					     tomoyo_merge_path_number_acl);
652	tomoyo_put_name_union(&e.name);
653	tomoyo_put_number_union(&e.number);
654	return error;
655}
656
657/**
658 * tomoyo_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp".
659 *
660 * @type:   Type of operation.
661 * @path:   Pointer to "struct path".
662 * @number: Number.
663 *
664 * Returns 0 on success, negative value otherwise.
665 */
666int tomoyo_path_number_perm(const u8 type, struct path *path,
667			    unsigned long number)
668{
669	struct tomoyo_request_info r;
670	int error = -ENOMEM;
671	struct tomoyo_path_info buf;
672	int idx;
673
674	if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type])
675	    == TOMOYO_CONFIG_DISABLED || !path->dentry)
676		return 0;
677	idx = tomoyo_read_lock();
678	if (!tomoyo_get_realpath(&buf, path))
679		goto out;
680	if (type == TOMOYO_TYPE_MKDIR)
681		tomoyo_add_slash(&buf);
682	r.param_type = TOMOYO_TYPE_PATH_NUMBER_ACL;
683	r.param.path_number.operation = type;
684	r.param.path_number.filename = &buf;
685	r.param.path_number.number = number;
686	do {
687		tomoyo_check_acl(&r, tomoyo_check_path_number_acl);
688		error = tomoyo_audit_path_number_log(&r);
689	} while (error == TOMOYO_RETRY_REQUEST);
690	kfree(buf.name);
691 out:
692	tomoyo_read_unlock(idx);
693	if (r.mode != TOMOYO_CONFIG_ENFORCING)
694		error = 0;
695	return error;
696}
697
698/**
699 * tomoyo_check_open_permission - Check permission for "read" and "write".
700 *
701 * @domain: Pointer to "struct tomoyo_domain_info".
702 * @path:   Pointer to "struct path".
703 * @flag:   Flags for open().
704 *
705 * Returns 0 on success, negative value otherwise.
706 */
707int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
708				 struct path *path, const int flag)
709{
710	const u8 acc_mode = ACC_MODE(flag);
711	int error = 0;
712	struct tomoyo_path_info buf;
713	struct tomoyo_request_info r;
714	int idx;
715
716	buf.name = NULL;
717	r.mode = TOMOYO_CONFIG_DISABLED;
718	idx = tomoyo_read_lock();
719	if (acc_mode &&
720	    tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN)
721	    != TOMOYO_CONFIG_DISABLED) {
722		if (!tomoyo_get_realpath(&buf, path)) {
723			error = -ENOMEM;
724			goto out;
725		}
726		if (acc_mode & MAY_READ)
727			error = tomoyo_path_permission(&r, TOMOYO_TYPE_READ,
728						       &buf);
729		if (!error && (acc_mode & MAY_WRITE))
730			error = tomoyo_path_permission(&r, (flag & O_APPEND) ?
731						       TOMOYO_TYPE_APPEND :
732						       TOMOYO_TYPE_WRITE,
733						       &buf);
734	}
735 out:
736	kfree(buf.name);
737	tomoyo_read_unlock(idx);
738	if (r.mode != TOMOYO_CONFIG_ENFORCING)
739		error = 0;
740	return error;
741}
742
743/**
744 * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "append", "chroot" and "unmount".
745 *
746 * @operation: Type of operation.
747 * @path:      Pointer to "struct path".
748 *
749 * Returns 0 on success, negative value otherwise.
750 */
751int tomoyo_path_perm(const u8 operation, struct path *path)
752{
753	struct tomoyo_request_info r;
754	int error;
755	struct tomoyo_path_info buf;
756	bool is_enforce;
757	int idx;
758
759	if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation])
760	    == TOMOYO_CONFIG_DISABLED)
761		return 0;
762	is_enforce = (r.mode == TOMOYO_CONFIG_ENFORCING);
763	error = -ENOMEM;
764	buf.name = NULL;
765	idx = tomoyo_read_lock();
766	if (!tomoyo_get_realpath(&buf, path))
767		goto out;
768	switch (operation) {
769	case TOMOYO_TYPE_RMDIR:
770	case TOMOYO_TYPE_CHROOT:
771		tomoyo_add_slash(&buf);
772		break;
773	}
774	error = tomoyo_path_permission(&r, operation, &buf);
775 out:
776	kfree(buf.name);
777	tomoyo_read_unlock(idx);
778	if (!is_enforce)
779		error = 0;
780	return error;
781}
782
783/**
784 * tomoyo_mkdev_perm - Check permission for "mkblock" and "mkchar".
785 *
786 * @operation: Type of operation. (TOMOYO_TYPE_MKCHAR or TOMOYO_TYPE_MKBLOCK)
787 * @path:      Pointer to "struct path".
788 * @mode:      Create mode.
789 * @dev:       Device number.
790 *
791 * Returns 0 on success, negative value otherwise.
792 */
793int tomoyo_mkdev_perm(const u8 operation, struct path *path,
794		      const unsigned int mode, unsigned int dev)
795{
796	struct tomoyo_request_info r;
797	int error = -ENOMEM;
798	struct tomoyo_path_info buf;
799	int idx;
800
801	if (tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation])
802	    == TOMOYO_CONFIG_DISABLED)
803		return 0;
804	idx = tomoyo_read_lock();
805	error = -ENOMEM;
806	if (tomoyo_get_realpath(&buf, path)) {
807		dev = new_decode_dev(dev);
808		r.param_type = TOMOYO_TYPE_MKDEV_ACL;
809		r.param.mkdev.filename = &buf;
810		r.param.mkdev.operation = operation;
811		r.param.mkdev.mode = mode;
812		r.param.mkdev.major = MAJOR(dev);
813		r.param.mkdev.minor = MINOR(dev);
814		tomoyo_check_acl(&r, tomoyo_check_mkdev_acl);
815		error = tomoyo_audit_mkdev_log(&r);
816		kfree(buf.name);
817	}
818	tomoyo_read_unlock(idx);
819	if (r.mode != TOMOYO_CONFIG_ENFORCING)
820		error = 0;
821	return error;
822}
823
824/**
825 * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root".
826 *
827 * @operation: Type of operation.
828 * @path1:      Pointer to "struct path".
829 * @path2:      Pointer to "struct path".
830 *
831 * Returns 0 on success, negative value otherwise.
832 */
833int tomoyo_path2_perm(const u8 operation, struct path *path1,
834		      struct path *path2)
835{
836	int error = -ENOMEM;
837	struct tomoyo_path_info buf1;
838	struct tomoyo_path_info buf2;
839	struct tomoyo_request_info r;
840	int idx;
841
842	if (tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation])
843	    == TOMOYO_CONFIG_DISABLED)
844		return 0;
845	buf1.name = NULL;
846	buf2.name = NULL;
847	idx = tomoyo_read_lock();
848	if (!tomoyo_get_realpath(&buf1, path1) ||
849	    !tomoyo_get_realpath(&buf2, path2))
850		goto out;
851	switch (operation) {
852		struct dentry *dentry;
853	case TOMOYO_TYPE_RENAME:
854        case TOMOYO_TYPE_LINK:
855		dentry = path1->dentry;
856	        if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode))
857                        break;
858                /* fall through */
859        case TOMOYO_TYPE_PIVOT_ROOT:
860                tomoyo_add_slash(&buf1);
861                tomoyo_add_slash(&buf2);
862		break;
863        }
864	r.param_type = TOMOYO_TYPE_PATH2_ACL;
865	r.param.path2.operation = operation;
866	r.param.path2.filename1 = &buf1;
867	r.param.path2.filename2 = &buf2;
868	do {
869		tomoyo_check_acl(&r, tomoyo_check_path2_acl);
870		error = tomoyo_audit_path2_log(&r);
871	} while (error == TOMOYO_RETRY_REQUEST);
872 out:
873	kfree(buf1.name);
874	kfree(buf2.name);
875	tomoyo_read_unlock(idx);
876	if (r.mode != TOMOYO_CONFIG_ENFORCING)
877		error = 0;
878	return error;
879}
880
881/**
882 * tomoyo_same_mount_acl - Check for duplicated "struct tomoyo_mount_acl" entry.
883 *
884 * @a: Pointer to "struct tomoyo_acl_info".
885 * @b: Pointer to "struct tomoyo_acl_info".
886 *
887 * Returns true if @a == @b, false otherwise.
888 */
889static bool tomoyo_same_mount_acl(const struct tomoyo_acl_info *a,
890				  const struct tomoyo_acl_info *b)
891{
892	const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head);
893	const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head);
894	return tomoyo_same_name_union(&p1->dev_name, &p2->dev_name) &&
895		tomoyo_same_name_union(&p1->dir_name, &p2->dir_name) &&
896		tomoyo_same_name_union(&p1->fs_type, &p2->fs_type) &&
897		tomoyo_same_number_union(&p1->flags, &p2->flags);
898}
899
900/**
901 * tomoyo_update_mount_acl - Write "struct tomoyo_mount_acl" list.
902 *
903 * @param: Pointer to "struct tomoyo_acl_param".
904 *
905 * Returns 0 on success, negative value otherwise.
906 *
907 * Caller holds tomoyo_read_lock().
908 */
909static int tomoyo_update_mount_acl(struct tomoyo_acl_param *param)
910{
911	struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL };
912	int error;
913	if (!tomoyo_parse_name_union(param, &e.dev_name) ||
914	    !tomoyo_parse_name_union(param, &e.dir_name) ||
915	    !tomoyo_parse_name_union(param, &e.fs_type) ||
916	    !tomoyo_parse_number_union(param, &e.flags))
917		error = -EINVAL;
918	else
919		error = tomoyo_update_domain(&e.head, sizeof(e), param,
920					     tomoyo_same_mount_acl, NULL);
921	tomoyo_put_name_union(&e.dev_name);
922	tomoyo_put_name_union(&e.dir_name);
923	tomoyo_put_name_union(&e.fs_type);
924	tomoyo_put_number_union(&e.flags);
925	return error;
926}
927
928/**
929 * tomoyo_write_file - Update file related list.
930 *
931 * @param: Pointer to "struct tomoyo_acl_param".
932 *
933 * Returns 0 on success, negative value otherwise.
934 *
935 * Caller holds tomoyo_read_lock().
936 */
937int tomoyo_write_file(struct tomoyo_acl_param *param)
938{
939	u16 perm = 0;
940	u8 type;
941	const char *operation = tomoyo_read_token(param);
942	for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++)
943		if (tomoyo_permstr(operation, tomoyo_path_keyword[type]))
944			perm |= 1 << type;
945	if (perm)
946		return tomoyo_update_path_acl(perm, param);
947	for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++)
948		if (tomoyo_permstr(operation,
949				   tomoyo_mac_keywords[tomoyo_pp2mac[type]]))
950			perm |= 1 << type;
951	if (perm)
952		return tomoyo_update_path2_acl(perm, param);
953	for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++)
954		if (tomoyo_permstr(operation,
955				   tomoyo_mac_keywords[tomoyo_pn2mac[type]]))
956			perm |= 1 << type;
957	if (perm)
958		return tomoyo_update_path_number_acl(perm, param);
959	for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++)
960		if (tomoyo_permstr(operation,
961				   tomoyo_mac_keywords[tomoyo_pnnn2mac[type]]))
962			perm |= 1 << type;
963	if (perm)
964		return tomoyo_update_mkdev_acl(perm, param);
965	if (tomoyo_permstr(operation,
966			   tomoyo_mac_keywords[TOMOYO_MAC_FILE_MOUNT]))
967		return tomoyo_update_mount_acl(param);
968	return -EINVAL;
969}
970