file.c 28.9 KB
Newer Older
1 2 3
/*
 * security/tomoyo/file.c
 *
T
Tetsuo Handa 已提交
4
 * Copyright (C) 2005-2011  NTT DATA CORPORATION
5 6 7
 */

#include "common.h"
8
#include <linux/slab.h>
9

T
Tetsuo Handa 已提交
10 11 12
/*
 * Mapping table from "enum tomoyo_path_acl_index" to "enum tomoyo_mac_index".
 */
T
Tetsuo Handa 已提交
13 14 15 16
static const u8 tomoyo_p2mac[TOMOYO_MAX_PATH_OPERATION] = {
	[TOMOYO_TYPE_EXECUTE]    = TOMOYO_MAC_FILE_EXECUTE,
	[TOMOYO_TYPE_READ]       = TOMOYO_MAC_FILE_OPEN,
	[TOMOYO_TYPE_WRITE]      = TOMOYO_MAC_FILE_OPEN,
T
Tetsuo Handa 已提交
17
	[TOMOYO_TYPE_APPEND]     = TOMOYO_MAC_FILE_OPEN,
T
Tetsuo Handa 已提交
18
	[TOMOYO_TYPE_UNLINK]     = TOMOYO_MAC_FILE_UNLINK,
T
Tetsuo Handa 已提交
19
	[TOMOYO_TYPE_GETATTR]    = TOMOYO_MAC_FILE_GETATTR,
T
Tetsuo Handa 已提交
20 21 22 23 24 25 26
	[TOMOYO_TYPE_RMDIR]      = TOMOYO_MAC_FILE_RMDIR,
	[TOMOYO_TYPE_TRUNCATE]   = TOMOYO_MAC_FILE_TRUNCATE,
	[TOMOYO_TYPE_SYMLINK]    = TOMOYO_MAC_FILE_SYMLINK,
	[TOMOYO_TYPE_CHROOT]     = TOMOYO_MAC_FILE_CHROOT,
	[TOMOYO_TYPE_UMOUNT]     = TOMOYO_MAC_FILE_UMOUNT,
};

T
Tetsuo Handa 已提交
27 28 29
/*
 * Mapping table from "enum tomoyo_mkdev_acl_index" to "enum tomoyo_mac_index".
 */
T
Tetsuo Handa 已提交
30
const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION] = {
T
Tetsuo Handa 已提交
31 32 33 34
	[TOMOYO_TYPE_MKBLOCK] = TOMOYO_MAC_FILE_MKBLOCK,
	[TOMOYO_TYPE_MKCHAR]  = TOMOYO_MAC_FILE_MKCHAR,
};

T
Tetsuo Handa 已提交
35 36 37
/*
 * Mapping table from "enum tomoyo_path2_acl_index" to "enum tomoyo_mac_index".
 */
T
Tetsuo Handa 已提交
38
const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION] = {
T
Tetsuo Handa 已提交
39 40 41 42 43
	[TOMOYO_TYPE_LINK]       = TOMOYO_MAC_FILE_LINK,
	[TOMOYO_TYPE_RENAME]     = TOMOYO_MAC_FILE_RENAME,
	[TOMOYO_TYPE_PIVOT_ROOT] = TOMOYO_MAC_FILE_PIVOT_ROOT,
};

T
Tetsuo Handa 已提交
44 45 46 47
/*
 * Mapping table from "enum tomoyo_path_number_acl_index" to
 * "enum tomoyo_mac_index".
 */
T
Tetsuo Handa 已提交
48
const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = {
T
Tetsuo Handa 已提交
49 50 51 52 53 54 55 56 57 58
	[TOMOYO_TYPE_CREATE] = TOMOYO_MAC_FILE_CREATE,
	[TOMOYO_TYPE_MKDIR]  = TOMOYO_MAC_FILE_MKDIR,
	[TOMOYO_TYPE_MKFIFO] = TOMOYO_MAC_FILE_MKFIFO,
	[TOMOYO_TYPE_MKSOCK] = TOMOYO_MAC_FILE_MKSOCK,
	[TOMOYO_TYPE_IOCTL]  = TOMOYO_MAC_FILE_IOCTL,
	[TOMOYO_TYPE_CHMOD]  = TOMOYO_MAC_FILE_CHMOD,
	[TOMOYO_TYPE_CHOWN]  = TOMOYO_MAC_FILE_CHOWN,
	[TOMOYO_TYPE_CHGRP]  = TOMOYO_MAC_FILE_CHGRP,
};

T
Tetsuo Handa 已提交
59 60 61 62 63 64 65
/**
 * tomoyo_put_name_union - Drop reference on "struct tomoyo_name_union".
 *
 * @ptr: Pointer to "struct tomoyo_name_union".
 *
 * Returns nothing.
 */
66 67
void tomoyo_put_name_union(struct tomoyo_name_union *ptr)
{
T
Tetsuo Handa 已提交
68 69
	tomoyo_put_group(ptr->group);
	tomoyo_put_name(ptr->filename);
70 71
}

T
Tetsuo Handa 已提交
72 73 74 75 76 77 78 79
/**
 * tomoyo_compare_name_union - Check whether a name matches "struct tomoyo_name_union" or not.
 *
 * @name: Pointer to "struct tomoyo_path_info".
 * @ptr:  Pointer to "struct tomoyo_name_union".
 *
 * Returns "struct tomoyo_path_info" if @name matches @ptr, NULL otherwise.
 */
80 81 82
const struct tomoyo_path_info *
tomoyo_compare_name_union(const struct tomoyo_path_info *name,
			  const struct tomoyo_name_union *ptr)
83
{
T
Tetsuo Handa 已提交
84
	if (ptr->group)
85
		return tomoyo_path_matches_group(name, ptr->group);
86 87 88
	if (tomoyo_path_matches_pattern(name, ptr->filename))
		return ptr->filename;
	return NULL;
89 90
}

T
Tetsuo Handa 已提交
91 92 93 94 95 96 97
/**
 * tomoyo_put_number_union - Drop reference on "struct tomoyo_number_union".
 *
 * @ptr: Pointer to "struct tomoyo_number_union".
 *
 * Returns nothing.
 */
98 99
void tomoyo_put_number_union(struct tomoyo_number_union *ptr)
{
T
Tetsuo Handa 已提交
100
	tomoyo_put_group(ptr->group);
101 102
}

T
Tetsuo Handa 已提交
103 104 105 106 107 108 109 110
/**
 * tomoyo_compare_number_union - Check whether a value matches "struct tomoyo_number_union" or not.
 *
 * @value: Number to check.
 * @ptr:   Pointer to "struct tomoyo_number_union".
 *
 * Returns true if @value matches @ptr, false otherwise.
 */
111 112 113
bool tomoyo_compare_number_union(const unsigned long value,
				 const struct tomoyo_number_union *ptr)
{
T
Tetsuo Handa 已提交
114
	if (ptr->group)
115 116 117 118
		return tomoyo_number_matches_group(value, value, ptr->group);
	return value >= ptr->values[0] && value <= ptr->values[1];
}

T
Tetsuo Handa 已提交
119 120 121 122 123 124 125 126 127 128
/**
 * tomoyo_add_slash - Add trailing '/' if needed.
 *
 * @buf: Pointer to "struct tomoyo_path_info".
 *
 * Returns nothing.
 *
 * @buf must be generated by tomoyo_encode() because this function does not
 * allocate memory for adding '/'.
 */
T
Tetsuo Handa 已提交
129 130 131 132 133 134 135 136 137 138 139
static void tomoyo_add_slash(struct tomoyo_path_info *buf)
{
	if (buf->is_dir)
		return;
	/*
	 * This is OK because tomoyo_encode() reserves space for appending "/".
	 */
	strcat((char *) buf->name, "/");
	tomoyo_fill_path_info(buf);
}

140
/**
T
Tetsuo Handa 已提交
141
 * tomoyo_get_realpath - Get realpath.
142
 *
T
Tetsuo Handa 已提交
143
 * @buf:  Pointer to "struct tomoyo_path_info".
144 145
 * @path: Pointer to "struct path".
 *
T
Tetsuo Handa 已提交
146
 * Returns true on success, false otherwise.
147
 */
T
Tetsuo Handa 已提交
148
static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path)
149
{
T
Tetsuo Handa 已提交
150 151 152 153
	buf->name = tomoyo_realpath_from_path(path);
	if (buf->name) {
		tomoyo_fill_path_info(buf);
		return true;
154
	}
T
Tetsuo Handa 已提交
155
	return false;
156 157
}

158 159 160 161 162 163 164 165 166
/**
 * tomoyo_audit_path_log - Audit path request log.
 *
 * @r: Pointer to "struct tomoyo_request_info".
 *
 * Returns 0 on success, negative value otherwise.
 */
static int tomoyo_audit_path_log(struct tomoyo_request_info *r)
{
T
Tetsuo Handa 已提交
167 168 169
	return tomoyo_supervisor(r, "file %s %s\n", tomoyo_path_keyword
				 [r->param.path.operation],
				 r->param.path.filename->name);
170 171 172 173 174 175 176 177 178 179 180
}

/**
 * tomoyo_audit_path2_log - Audit path/path request log.
 *
 * @r: Pointer to "struct tomoyo_request_info".
 *
 * Returns 0 on success, negative value otherwise.
 */
static int tomoyo_audit_path2_log(struct tomoyo_request_info *r)
{
T
Tetsuo Handa 已提交
181 182
	return tomoyo_supervisor(r, "file %s %s %s\n", tomoyo_mac_keywords
				 [tomoyo_pp2mac[r->param.path2.operation]],
T
Tetsuo Handa 已提交
183 184
				 r->param.path2.filename1->name,
				 r->param.path2.filename2->name);
185 186 187 188 189 190 191 192 193 194 195
}

/**
 * tomoyo_audit_mkdev_log - Audit path/number/number/number request log.
 *
 * @r: Pointer to "struct tomoyo_request_info".
 *
 * Returns 0 on success, negative value otherwise.
 */
static int tomoyo_audit_mkdev_log(struct tomoyo_request_info *r)
{
T
Tetsuo Handa 已提交
196
	return tomoyo_supervisor(r, "file %s %s 0%o %u %u\n",
T
Tetsuo Handa 已提交
197 198
				 tomoyo_mac_keywords
				 [tomoyo_pnnn2mac[r->param.mkdev.operation]],
T
Tetsuo Handa 已提交
199 200 201
				 r->param.mkdev.filename->name,
				 r->param.mkdev.mode, r->param.mkdev.major,
				 r->param.mkdev.minor);
202 203 204 205 206
}

/**
 * tomoyo_audit_path_number_log - Audit path/number request log.
 *
T
Tetsuo Handa 已提交
207
 * @r: Pointer to "struct tomoyo_request_info".
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
 *
 * Returns 0 on success, negative value otherwise.
 */
static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r)
{
	const u8 type = r->param.path_number.operation;
	u8 radix;
	char buffer[64];
	switch (type) {
	case TOMOYO_TYPE_CREATE:
	case TOMOYO_TYPE_MKDIR:
	case TOMOYO_TYPE_MKFIFO:
	case TOMOYO_TYPE_MKSOCK:
	case TOMOYO_TYPE_CHMOD:
		radix = TOMOYO_VALUE_TYPE_OCTAL;
		break;
	case TOMOYO_TYPE_IOCTL:
		radix = TOMOYO_VALUE_TYPE_HEXADECIMAL;
		break;
	default:
		radix = TOMOYO_VALUE_TYPE_DECIMAL;
		break;
	}
	tomoyo_print_ulong(buffer, sizeof(buffer), r->param.path_number.number,
			   radix);
T
Tetsuo Handa 已提交
233 234
	return tomoyo_supervisor(r, "file %s %s %s\n", tomoyo_mac_keywords
				 [tomoyo_pn2mac[type]],
T
Tetsuo Handa 已提交
235
				 r->param.path_number.filename->name, buffer);
236 237
}

T
Tetsuo Handa 已提交
238 239 240 241 242 243 244 245 246 247 248 249
/**
 * tomoyo_check_path_acl - Check permission for path operation.
 *
 * @r:   Pointer to "struct tomoyo_request_info".
 * @ptr: Pointer to "struct tomoyo_acl_info".
 *
 * Returns true if granted, false otherwise.
 *
 * To be able to use wildcard for domain transition, this function sets
 * matching entry on success. Since the caller holds tomoyo_read_lock(),
 * it is safe to set matching entry.
 */
250
static bool tomoyo_check_path_acl(struct tomoyo_request_info *r,
251
				  const struct tomoyo_acl_info *ptr)
252
{
253 254
	const struct tomoyo_path_acl *acl = container_of(ptr, typeof(*acl),
							 head);
255 256 257 258 259 260 261
	if (acl->perm & (1 << r->param.path.operation)) {
		r->param.path.matched_path =
			tomoyo_compare_name_union(r->param.path.filename,
						  &acl->name);
		return r->param.path.matched_path != NULL;
	}
	return false;
262
}
263

T
Tetsuo Handa 已提交
264 265 266 267 268 269 270 271
/**
 * tomoyo_check_path_number_acl - Check permission for path number operation.
 *
 * @r:   Pointer to "struct tomoyo_request_info".
 * @ptr: Pointer to "struct tomoyo_acl_info".
 *
 * Returns true if granted, false otherwise.
 */
272
static bool tomoyo_check_path_number_acl(struct tomoyo_request_info *r,
273 274 275 276 277 278 279 280 281 282 283
					 const struct tomoyo_acl_info *ptr)
{
	const struct tomoyo_path_number_acl *acl =
		container_of(ptr, typeof(*acl), head);
	return (acl->perm & (1 << r->param.path_number.operation)) &&
		tomoyo_compare_number_union(r->param.path_number.number,
					    &acl->number) &&
		tomoyo_compare_name_union(r->param.path_number.filename,
					  &acl->name);
}

T
Tetsuo Handa 已提交
284 285 286 287 288 289 290 291
/**
 * tomoyo_check_path2_acl - Check permission for path path operation.
 *
 * @r:   Pointer to "struct tomoyo_request_info".
 * @ptr: Pointer to "struct tomoyo_acl_info".
 *
 * Returns true if granted, false otherwise.
 */
292
static bool tomoyo_check_path2_acl(struct tomoyo_request_info *r,
293 294 295 296 297 298 299 300 301 302
				   const struct tomoyo_acl_info *ptr)
{
	const struct tomoyo_path2_acl *acl =
		container_of(ptr, typeof(*acl), head);
	return (acl->perm & (1 << r->param.path2.operation)) &&
		tomoyo_compare_name_union(r->param.path2.filename1, &acl->name1)
		&& tomoyo_compare_name_union(r->param.path2.filename2,
					     &acl->name2);
}

T
Tetsuo Handa 已提交
303 304 305 306 307 308 309 310
/**
 * tomoyo_check_mkdev_acl - Check permission for path number number number operation.
 *
 * @r:   Pointer to "struct tomoyo_request_info".
 * @ptr: Pointer to "struct tomoyo_acl_info".
 *
 * Returns true if granted, false otherwise.
 */
311
static bool tomoyo_check_mkdev_acl(struct tomoyo_request_info *r,
T
Tetsuo Handa 已提交
312
				   const struct tomoyo_acl_info *ptr)
313
{
T
Tetsuo Handa 已提交
314
	const struct tomoyo_mkdev_acl *acl =
315 316 317 318 319 320 321 322 323 324
		container_of(ptr, typeof(*acl), head);
	return (acl->perm & (1 << r->param.mkdev.operation)) &&
		tomoyo_compare_number_union(r->param.mkdev.mode,
					    &acl->mode) &&
		tomoyo_compare_number_union(r->param.mkdev.major,
					    &acl->major) &&
		tomoyo_compare_number_union(r->param.mkdev.minor,
					    &acl->minor) &&
		tomoyo_compare_name_union(r->param.mkdev.filename,
					  &acl->name);
325 326
}

T
Tetsuo Handa 已提交
327 328 329 330 331 332 333 334
/**
 * tomoyo_same_path_acl - Check for duplicated "struct tomoyo_path_acl" entry.
 *
 * @a: Pointer to "struct tomoyo_acl_info".
 * @b: Pointer to "struct tomoyo_acl_info".
 *
 * Returns true if @a == @b except permission bits, false otherwise.
 */
335 336 337 338 339
static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a,
				 const struct tomoyo_acl_info *b)
{
	const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head);
	const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head);
T
Tetsuo Handa 已提交
340
	return tomoyo_same_name_union(&p1->name, &p2->name);
341 342
}

T
Tetsuo Handa 已提交
343 344 345 346 347 348 349 350 351
/**
 * tomoyo_merge_path_acl - Merge duplicated "struct tomoyo_path_acl" entry.
 *
 * @a:         Pointer to "struct tomoyo_acl_info".
 * @b:         Pointer to "struct tomoyo_acl_info".
 * @is_delete: True for @a &= ~@b, false for @a |= @b.
 *
 * Returns true if @a is empty, false otherwise.
 */
352 353 354 355 356 357 358 359
static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a,
				  struct tomoyo_acl_info *b,
				  const bool is_delete)
{
	u16 * const a_perm = &container_of(a, struct tomoyo_path_acl, head)
		->perm;
	u16 perm = *a_perm;
	const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm;
T
Tetsuo Handa 已提交
360
	if (is_delete)
361
		perm &= ~b_perm;
T
Tetsuo Handa 已提交
362
	else
363 364 365 366 367
		perm |= b_perm;
	*a_perm = perm;
	return !perm;
}

368
/**
T
Tetsuo Handa 已提交
369
 * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list.
370
 *
371 372
 * @perm:  Permission.
 * @param: Pointer to "struct tomoyo_acl_param".
373 374
 *
 * Returns 0 on success, negative value otherwise.
375 376
 *
 * Caller holds tomoyo_read_lock().
377
 */
378 379
static int tomoyo_update_path_acl(const u16 perm,
				  struct tomoyo_acl_param *param)
380
{
381 382
	struct tomoyo_path_acl e = {
		.head.type = TOMOYO_TYPE_PATH_ACL,
383
		.perm = perm
384
	};
385
	int error;
386 387 388 389 390 391
	if (!tomoyo_parse_name_union(param, &e.name))
		error = -EINVAL;
	else
		error = tomoyo_update_domain(&e.head, sizeof(e), param,
					     tomoyo_same_path_acl,
					     tomoyo_merge_path_acl);
392
	tomoyo_put_name_union(&e.name);
393 394 395
	return error;
}

T
Tetsuo Handa 已提交
396 397 398 399 400 401 402 403
/**
 * tomoyo_same_mkdev_acl - Check for duplicated "struct tomoyo_mkdev_acl" entry.
 *
 * @a: Pointer to "struct tomoyo_acl_info".
 * @b: Pointer to "struct tomoyo_acl_info".
 *
 * Returns true if @a == @b except permission bits, false otherwise.
 */
T
Tetsuo Handa 已提交
404
static bool tomoyo_same_mkdev_acl(const struct tomoyo_acl_info *a,
405 406
					 const struct tomoyo_acl_info *b)
{
T
Tetsuo Handa 已提交
407 408 409 410 411 412
	const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1), head);
	const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2), head);
	return tomoyo_same_name_union(&p1->name, &p2->name) &&
		tomoyo_same_number_union(&p1->mode, &p2->mode) &&
		tomoyo_same_number_union(&p1->major, &p2->major) &&
		tomoyo_same_number_union(&p1->minor, &p2->minor);
413 414
}

T
Tetsuo Handa 已提交
415 416 417 418 419 420 421 422 423
/**
 * tomoyo_merge_mkdev_acl - Merge duplicated "struct tomoyo_mkdev_acl" entry.
 *
 * @a:         Pointer to "struct tomoyo_acl_info".
 * @b:         Pointer to "struct tomoyo_acl_info".
 * @is_delete: True for @a &= ~@b, false for @a |= @b.
 *
 * Returns true if @a is empty, false otherwise.
 */
T
Tetsuo Handa 已提交
424
static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a,
T
Tetsuo Handa 已提交
425 426
				   struct tomoyo_acl_info *b,
				   const bool is_delete)
427
{
T
Tetsuo Handa 已提交
428
	u8 *const a_perm = &container_of(a, struct tomoyo_mkdev_acl,
429 430
					 head)->perm;
	u8 perm = *a_perm;
T
Tetsuo Handa 已提交
431
	const u8 b_perm = container_of(b, struct tomoyo_mkdev_acl, head)
432 433 434 435 436 437 438 439 440
		->perm;
	if (is_delete)
		perm &= ~b_perm;
	else
		perm |= b_perm;
	*a_perm = perm;
	return !perm;
}

441
/**
T
Tetsuo Handa 已提交
442
 * tomoyo_update_mkdev_acl - Update "struct tomoyo_mkdev_acl" list.
443
 *
444 445
 * @perm:  Permission.
 * @param: Pointer to "struct tomoyo_acl_param".
446 447
 *
 * Returns 0 on success, negative value otherwise.
448 449
 *
 * Caller holds tomoyo_read_lock().
450
 */
451 452
static int tomoyo_update_mkdev_acl(const u8 perm,
				   struct tomoyo_acl_param *param)
453
{
T
Tetsuo Handa 已提交
454 455
	struct tomoyo_mkdev_acl e = {
		.head.type = TOMOYO_TYPE_MKDEV_ACL,
456
		.perm = perm
457
	};
458 459 460 461 462 463 464 465 466 467
	int error;
	if (!tomoyo_parse_name_union(param, &e.name) ||
	    !tomoyo_parse_number_union(param, &e.mode) ||
	    !tomoyo_parse_number_union(param, &e.major) ||
	    !tomoyo_parse_number_union(param, &e.minor))
		error = -EINVAL;
	else
		error = tomoyo_update_domain(&e.head, sizeof(e), param,
					     tomoyo_same_mkdev_acl,
					     tomoyo_merge_mkdev_acl);
468 469 470 471 472 473 474
	tomoyo_put_name_union(&e.name);
	tomoyo_put_number_union(&e.mode);
	tomoyo_put_number_union(&e.major);
	tomoyo_put_number_union(&e.minor);
	return error;
}

T
Tetsuo Handa 已提交
475 476 477 478 479 480 481 482
/**
 * tomoyo_same_path2_acl - Check for duplicated "struct tomoyo_path2_acl" entry.
 *
 * @a: Pointer to "struct tomoyo_acl_info".
 * @b: Pointer to "struct tomoyo_acl_info".
 *
 * Returns true if @a == @b except permission bits, false otherwise.
 */
483 484 485 486 487
static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a,
				  const struct tomoyo_acl_info *b)
{
	const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head);
	const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head);
T
Tetsuo Handa 已提交
488 489
	return tomoyo_same_name_union(&p1->name1, &p2->name1) &&
		tomoyo_same_name_union(&p1->name2, &p2->name2);
490 491
}

T
Tetsuo Handa 已提交
492 493 494 495 496 497 498 499 500
/**
 * tomoyo_merge_path2_acl - Merge duplicated "struct tomoyo_path2_acl" entry.
 *
 * @a:         Pointer to "struct tomoyo_acl_info".
 * @b:         Pointer to "struct tomoyo_acl_info".
 * @is_delete: True for @a &= ~@b, false for @a |= @b.
 *
 * Returns true if @a is empty, false otherwise.
 */
501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516
static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a,
				   struct tomoyo_acl_info *b,
				   const bool is_delete)
{
	u8 * const a_perm = &container_of(a, struct tomoyo_path2_acl, head)
		->perm;
	u8 perm = *a_perm;
	const u8 b_perm = container_of(b, struct tomoyo_path2_acl, head)->perm;
	if (is_delete)
		perm &= ~b_perm;
	else
		perm |= b_perm;
	*a_perm = perm;
	return !perm;
}

517
/**
T
Tetsuo Handa 已提交
518
 * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list.
519
 *
520 521
 * @perm:  Permission.
 * @param: Pointer to "struct tomoyo_acl_param".
522 523
 *
 * Returns 0 on success, negative value otherwise.
524 525
 *
 * Caller holds tomoyo_read_lock().
526
 */
527 528
static int tomoyo_update_path2_acl(const u8 perm,
				   struct tomoyo_acl_param *param)
529
{
530 531
	struct tomoyo_path2_acl e = {
		.head.type = TOMOYO_TYPE_PATH2_ACL,
532
		.perm = perm
533
	};
534 535 536 537 538 539 540 541
	int error;
	if (!tomoyo_parse_name_union(param, &e.name1) ||
	    !tomoyo_parse_name_union(param, &e.name2))
		error = -EINVAL;
	else
		error = tomoyo_update_domain(&e.head, sizeof(e), param,
					     tomoyo_same_path2_acl,
					     tomoyo_merge_path2_acl);
542 543
	tomoyo_put_name_union(&e.name1);
	tomoyo_put_name_union(&e.name2);
544 545 546 547
	return error;
}

/**
548
 * tomoyo_path_permission - Check permission for single path operation.
549
 *
550
 * @r:         Pointer to "struct tomoyo_request_info".
551 552 553 554
 * @operation: Type of operation.
 * @filename:  Filename to check.
 *
 * Returns 0 on success, negative value otherwise.
555 556
 *
 * Caller holds tomoyo_read_lock().
557
 */
558 559
int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
			   const struct tomoyo_path_info *filename)
560 561 562
{
	int error;

T
Tetsuo Handa 已提交
563
	r->type = tomoyo_p2mac[operation];
564
	r->mode = tomoyo_get_mode(r->domain->ns, r->profile, r->type);
T
Tetsuo Handa 已提交
565 566
	if (r->mode == TOMOYO_CONFIG_DISABLED)
		return 0;
567 568 569
	r->param_type = TOMOYO_TYPE_PATH_ACL;
	r->param.path.filename = filename;
	r->param.path.operation = operation;
570
	do {
571 572
		tomoyo_check_acl(r, tomoyo_check_path_acl);
		error = tomoyo_audit_path_log(r);
573
	} while (error == TOMOYO_RETRY_REQUEST);
574 575 576
	return error;
}

577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607
/**
 * tomoyo_execute_permission - Check permission for execute operation.
 *
 * @r:         Pointer to "struct tomoyo_request_info".
 * @filename:  Filename to check.
 *
 * Returns 0 on success, negative value otherwise.
 *
 * Caller holds tomoyo_read_lock().
 */
int tomoyo_execute_permission(struct tomoyo_request_info *r,
			      const struct tomoyo_path_info *filename)
{
	/*
	 * Unlike other permission checks, this check is done regardless of
	 * profile mode settings in order to check for domain transition
	 * preference.
	 */
	r->type = TOMOYO_MAC_FILE_EXECUTE;
	r->mode = tomoyo_get_mode(r->domain->ns, r->profile, r->type);
	r->param_type = TOMOYO_TYPE_PATH_ACL;
	r->param.path.filename = filename;
	r->param.path.operation = TOMOYO_TYPE_EXECUTE;
	tomoyo_check_acl(r, tomoyo_check_path_acl);
	r->ee->transition = r->matched_acl && r->matched_acl->cond ?
		r->matched_acl->cond->transit : NULL;
	if (r->mode != TOMOYO_CONFIG_DISABLED)
		return tomoyo_audit_path_log(r);
	return 0;
}

T
Tetsuo Handa 已提交
608 609 610 611 612 613 614 615
/**
 * tomoyo_same_path_number_acl - Check for duplicated "struct tomoyo_path_number_acl" entry.
 *
 * @a: Pointer to "struct tomoyo_acl_info".
 * @b: Pointer to "struct tomoyo_acl_info".
 *
 * Returns true if @a == @b except permission bits, false otherwise.
 */
616 617 618 619 620 621 622
static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a,
					const struct tomoyo_acl_info *b)
{
	const struct tomoyo_path_number_acl *p1 = container_of(a, typeof(*p1),
							       head);
	const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2),
							       head);
T
Tetsuo Handa 已提交
623 624
	return tomoyo_same_name_union(&p1->name, &p2->name) &&
		tomoyo_same_number_union(&p1->number, &p2->number);
625 626
}

T
Tetsuo Handa 已提交
627 628 629 630 631 632 633 634 635
/**
 * tomoyo_merge_path_number_acl - Merge duplicated "struct tomoyo_path_number_acl" entry.
 *
 * @a:         Pointer to "struct tomoyo_acl_info".
 * @b:         Pointer to "struct tomoyo_acl_info".
 * @is_delete: True for @a &= ~@b, false for @a |= @b.
 *
 * Returns true if @a is empty, false otherwise.
 */
636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652
static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a,
					 struct tomoyo_acl_info *b,
					 const bool is_delete)
{
	u8 * const a_perm = &container_of(a, struct tomoyo_path_number_acl,
					  head)->perm;
	u8 perm = *a_perm;
	const u8 b_perm = container_of(b, struct tomoyo_path_number_acl, head)
		->perm;
	if (is_delete)
		perm &= ~b_perm;
	else
		perm |= b_perm;
	*a_perm = perm;
	return !perm;
}

653 654 655
/**
 * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL.
 *
656 657
 * @perm:  Permission.
 * @param: Pointer to "struct tomoyo_acl_param".
658 659 660
 *
 * Returns 0 on success, negative value otherwise.
 */
661 662
static int tomoyo_update_path_number_acl(const u8 perm,
					 struct tomoyo_acl_param *param)
663 664 665
{
	struct tomoyo_path_number_acl e = {
		.head.type = TOMOYO_TYPE_PATH_NUMBER_ACL,
666
		.perm = perm
667
	};
668 669 670 671 672 673 674 675
	int error;
	if (!tomoyo_parse_name_union(param, &e.name) ||
	    !tomoyo_parse_number_union(param, &e.number))
		error = -EINVAL;
	else
		error = tomoyo_update_domain(&e.head, sizeof(e), param,
					     tomoyo_same_path_number_acl,
					     tomoyo_merge_path_number_acl);
676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693
	tomoyo_put_name_union(&e.name);
	tomoyo_put_number_union(&e.number);
	return error;
}

/**
 * tomoyo_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp".
 *
 * @type:   Type of operation.
 * @path:   Pointer to "struct path".
 * @number: Number.
 *
 * Returns 0 on success, negative value otherwise.
 */
int tomoyo_path_number_perm(const u8 type, struct path *path,
			    unsigned long number)
{
	struct tomoyo_request_info r;
T
Tetsuo Handa 已提交
694 695 696
	struct tomoyo_obj_info obj = {
		.path1 = *path,
	};
697
	int error = -ENOMEM;
T
Tetsuo Handa 已提交
698
	struct tomoyo_path_info buf;
699 700
	int idx;

T
Tetsuo Handa 已提交
701
	if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type])
702
	    == TOMOYO_CONFIG_DISABLED || !path->dentry)
703 704
		return 0;
	idx = tomoyo_read_lock();
T
Tetsuo Handa 已提交
705
	if (!tomoyo_get_realpath(&buf, path))
706
		goto out;
T
Tetsuo Handa 已提交
707
	r.obj = &obj;
T
Tetsuo Handa 已提交
708 709
	if (type == TOMOYO_TYPE_MKDIR)
		tomoyo_add_slash(&buf);
T
Tetsuo Handa 已提交
710 711 712 713 714 715 716 717
	r.param_type = TOMOYO_TYPE_PATH_NUMBER_ACL;
	r.param.path_number.operation = type;
	r.param.path_number.filename = &buf;
	r.param.path_number.number = number;
	do {
		tomoyo_check_acl(&r, tomoyo_check_path_number_acl);
		error = tomoyo_audit_path_number_log(&r);
	} while (error == TOMOYO_RETRY_REQUEST);
T
Tetsuo Handa 已提交
718
	kfree(buf.name);
T
Tetsuo Handa 已提交
719
 out:
720 721 722 723 724 725
	tomoyo_read_unlock(idx);
	if (r.mode != TOMOYO_CONFIG_ENFORCING)
		error = 0;
	return error;
}

726 727 728 729 730 731 732 733 734 735 736 737 738
/**
 * tomoyo_check_open_permission - Check permission for "read" and "write".
 *
 * @domain: Pointer to "struct tomoyo_domain_info".
 * @path:   Pointer to "struct path".
 * @flag:   Flags for open().
 *
 * Returns 0 on success, negative value otherwise.
 */
int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
				 struct path *path, const int flag)
{
	const u8 acc_mode = ACC_MODE(flag);
739
	int error = 0;
T
Tetsuo Handa 已提交
740
	struct tomoyo_path_info buf;
741
	struct tomoyo_request_info r;
T
Tetsuo Handa 已提交
742 743 744
	struct tomoyo_obj_info obj = {
		.path1 = *path,
	};
745
	int idx;
746

T
Tetsuo Handa 已提交
747 748
	buf.name = NULL;
	r.mode = TOMOYO_CONFIG_DISABLED;
749
	idx = tomoyo_read_lock();
T
Tetsuo Handa 已提交
750 751
	if (acc_mode &&
	    tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN)
T
Tetsuo Handa 已提交
752 753 754 755 756
	    != TOMOYO_CONFIG_DISABLED) {
		if (!tomoyo_get_realpath(&buf, path)) {
			error = -ENOMEM;
			goto out;
		}
T
Tetsuo Handa 已提交
757
		r.obj = &obj;
T
Tetsuo Handa 已提交
758 759 760 761 762 763 764
		if (acc_mode & MAY_READ)
			error = tomoyo_path_permission(&r, TOMOYO_TYPE_READ,
						       &buf);
		if (!error && (acc_mode & MAY_WRITE))
			error = tomoyo_path_permission(&r, (flag & O_APPEND) ?
						       TOMOYO_TYPE_APPEND :
						       TOMOYO_TYPE_WRITE,
T
Tetsuo Handa 已提交
765 766
						       &buf);
	}
767
 out:
T
Tetsuo Handa 已提交
768
	kfree(buf.name);
769
	tomoyo_read_unlock(idx);
770
	if (r.mode != TOMOYO_CONFIG_ENFORCING)
771 772 773 774 775
		error = 0;
	return error;
}

/**
T
Tetsuo Handa 已提交
776
 * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "append", "chroot" and "unmount".
777 778 779
 *
 * @operation: Type of operation.
 * @path:      Pointer to "struct path".
T
Tetsuo Handa 已提交
780 781
 * @target:    Symlink's target if @operation is TOMOYO_TYPE_SYMLINK,
 *             NULL otherwise.
782 783 784
 *
 * Returns 0 on success, negative value otherwise.
 */
T
Tetsuo Handa 已提交
785
int tomoyo_path_perm(const u8 operation, struct path *path, const char *target)
786
{
787
	struct tomoyo_request_info r;
T
Tetsuo Handa 已提交
788 789 790
	struct tomoyo_obj_info obj = {
		.path1 = *path,
	};
T
Tetsuo Handa 已提交
791 792 793
	int error;
	struct tomoyo_path_info buf;
	bool is_enforce;
T
Tetsuo Handa 已提交
794
	struct tomoyo_path_info symlink_target;
795
	int idx;
796

T
Tetsuo Handa 已提交
797 798
	if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation])
	    == TOMOYO_CONFIG_DISABLED)
799
		return 0;
T
Tetsuo Handa 已提交
800 801
	is_enforce = (r.mode == TOMOYO_CONFIG_ENFORCING);
	error = -ENOMEM;
T
Tetsuo Handa 已提交
802
	buf.name = NULL;
803
	idx = tomoyo_read_lock();
T
Tetsuo Handa 已提交
804
	if (!tomoyo_get_realpath(&buf, path))
805
		goto out;
T
Tetsuo Handa 已提交
806
	r.obj = &obj;
807
	switch (operation) {
T
Tetsuo Handa 已提交
808 809
	case TOMOYO_TYPE_RMDIR:
	case TOMOYO_TYPE_CHROOT:
T
Tetsuo Handa 已提交
810 811
		tomoyo_add_slash(&buf);
		break;
T
Tetsuo Handa 已提交
812 813 814 815 816 817 818
	case TOMOYO_TYPE_SYMLINK:
		symlink_target.name = tomoyo_encode(target);
		if (!symlink_target.name)
			goto out;
		tomoyo_fill_path_info(&symlink_target);
		obj.symlink_target = &symlink_target;
		break;
819
	}
T
Tetsuo Handa 已提交
820
	error = tomoyo_path_permission(&r, operation, &buf);
T
Tetsuo Handa 已提交
821 822
	if (operation == TOMOYO_TYPE_SYMLINK)
		kfree(symlink_target.name);
823
 out:
T
Tetsuo Handa 已提交
824
	kfree(buf.name);
825
	tomoyo_read_unlock(idx);
T
Tetsuo Handa 已提交
826
	if (!is_enforce)
827 828 829 830
		error = 0;
	return error;
}

831
/**
T
Tetsuo Handa 已提交
832
 * tomoyo_mkdev_perm - Check permission for "mkblock" and "mkchar".
833 834 835 836 837 838 839 840
 *
 * @operation: Type of operation. (TOMOYO_TYPE_MKCHAR or TOMOYO_TYPE_MKBLOCK)
 * @path:      Pointer to "struct path".
 * @mode:      Create mode.
 * @dev:       Device number.
 *
 * Returns 0 on success, negative value otherwise.
 */
T
Tetsuo Handa 已提交
841
int tomoyo_mkdev_perm(const u8 operation, struct path *path,
T
Tetsuo Handa 已提交
842
		      const unsigned int mode, unsigned int dev)
843 844
{
	struct tomoyo_request_info r;
T
Tetsuo Handa 已提交
845 846 847
	struct tomoyo_obj_info obj = {
		.path1 = *path,
	};
848
	int error = -ENOMEM;
T
Tetsuo Handa 已提交
849
	struct tomoyo_path_info buf;
850 851
	int idx;

852
	if (tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation])
T
Tetsuo Handa 已提交
853
	    == TOMOYO_CONFIG_DISABLED)
854 855 856
		return 0;
	idx = tomoyo_read_lock();
	error = -ENOMEM;
T
Tetsuo Handa 已提交
857
	if (tomoyo_get_realpath(&buf, path)) {
T
Tetsuo Handa 已提交
858
		r.obj = &obj;
859
		dev = new_decode_dev(dev);
T
Tetsuo Handa 已提交
860
		r.param_type = TOMOYO_TYPE_MKDEV_ACL;
861 862 863 864 865
		r.param.mkdev.filename = &buf;
		r.param.mkdev.operation = operation;
		r.param.mkdev.mode = mode;
		r.param.mkdev.major = MAJOR(dev);
		r.param.mkdev.minor = MINOR(dev);
866 867
		tomoyo_check_acl(&r, tomoyo_check_mkdev_acl);
		error = tomoyo_audit_mkdev_log(&r);
T
Tetsuo Handa 已提交
868
		kfree(buf.name);
869 870 871 872 873 874 875
	}
	tomoyo_read_unlock(idx);
	if (r.mode != TOMOYO_CONFIG_ENFORCING)
		error = 0;
	return error;
}

876
/**
T
Tetsuo Handa 已提交
877
 * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root".
878 879 880 881 882 883 884
 *
 * @operation: Type of operation.
 * @path1:      Pointer to "struct path".
 * @path2:      Pointer to "struct path".
 *
 * Returns 0 on success, negative value otherwise.
 */
885
int tomoyo_path2_perm(const u8 operation, struct path *path1,
T
Tetsuo Handa 已提交
886
		      struct path *path2)
887 888
{
	int error = -ENOMEM;
T
Tetsuo Handa 已提交
889 890
	struct tomoyo_path_info buf1;
	struct tomoyo_path_info buf2;
891
	struct tomoyo_request_info r;
T
Tetsuo Handa 已提交
892 893 894 895
	struct tomoyo_obj_info obj = {
		.path1 = *path1,
		.path2 = *path2,
	};
896
	int idx;
897

898
	if (tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation])
T
Tetsuo Handa 已提交
899
	    == TOMOYO_CONFIG_DISABLED)
900
		return 0;
T
Tetsuo Handa 已提交
901 902
	buf1.name = NULL;
	buf2.name = NULL;
903
	idx = tomoyo_read_lock();
T
Tetsuo Handa 已提交
904 905
	if (!tomoyo_get_realpath(&buf1, path1) ||
	    !tomoyo_get_realpath(&buf2, path2))
906
		goto out;
T
Tetsuo Handa 已提交
907 908 909
	switch (operation) {
		struct dentry *dentry;
	case TOMOYO_TYPE_RENAME:
T
Tetsuo Handa 已提交
910
	case TOMOYO_TYPE_LINK:
T
Tetsuo Handa 已提交
911
		dentry = path1->dentry;
T
Tetsuo Handa 已提交
912 913 914 915 916 917
		if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode))
			break;
		/* fall through */
	case TOMOYO_TYPE_PIVOT_ROOT:
		tomoyo_add_slash(&buf1);
		tomoyo_add_slash(&buf2);
T
Tetsuo Handa 已提交
918
		break;
T
Tetsuo Handa 已提交
919
	}
T
Tetsuo Handa 已提交
920
	r.obj = &obj;
921 922 923 924
	r.param_type = TOMOYO_TYPE_PATH2_ACL;
	r.param.path2.operation = operation;
	r.param.path2.filename1 = &buf1;
	r.param.path2.filename2 = &buf2;
925
	do {
926 927 928
		tomoyo_check_acl(&r, tomoyo_check_path2_acl);
		error = tomoyo_audit_path2_log(&r);
	} while (error == TOMOYO_RETRY_REQUEST);
929
 out:
T
Tetsuo Handa 已提交
930 931
	kfree(buf1.name);
	kfree(buf2.name);
932
	tomoyo_read_unlock(idx);
933
	if (r.mode != TOMOYO_CONFIG_ENFORCING)
934 935 936
		error = 0;
	return error;
}
937

938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984
/**
 * tomoyo_same_mount_acl - Check for duplicated "struct tomoyo_mount_acl" entry.
 *
 * @a: Pointer to "struct tomoyo_acl_info".
 * @b: Pointer to "struct tomoyo_acl_info".
 *
 * Returns true if @a == @b, false otherwise.
 */
static bool tomoyo_same_mount_acl(const struct tomoyo_acl_info *a,
				  const struct tomoyo_acl_info *b)
{
	const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head);
	const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head);
	return tomoyo_same_name_union(&p1->dev_name, &p2->dev_name) &&
		tomoyo_same_name_union(&p1->dir_name, &p2->dir_name) &&
		tomoyo_same_name_union(&p1->fs_type, &p2->fs_type) &&
		tomoyo_same_number_union(&p1->flags, &p2->flags);
}

/**
 * tomoyo_update_mount_acl - Write "struct tomoyo_mount_acl" list.
 *
 * @param: Pointer to "struct tomoyo_acl_param".
 *
 * Returns 0 on success, negative value otherwise.
 *
 * Caller holds tomoyo_read_lock().
 */
static int tomoyo_update_mount_acl(struct tomoyo_acl_param *param)
{
	struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL };
	int error;
	if (!tomoyo_parse_name_union(param, &e.dev_name) ||
	    !tomoyo_parse_name_union(param, &e.dir_name) ||
	    !tomoyo_parse_name_union(param, &e.fs_type) ||
	    !tomoyo_parse_number_union(param, &e.flags))
		error = -EINVAL;
	else
		error = tomoyo_update_domain(&e.head, sizeof(e), param,
					     tomoyo_same_mount_acl, NULL);
	tomoyo_put_name_union(&e.dev_name);
	tomoyo_put_name_union(&e.dir_name);
	tomoyo_put_name_union(&e.fs_type);
	tomoyo_put_number_union(&e.flags);
	return error;
}

985
/**
T
Tetsuo Handa 已提交
986
 * tomoyo_write_file - Update file related list.
987
 *
988
 * @param: Pointer to "struct tomoyo_acl_param".
989 990 991 992 993
 *
 * Returns 0 on success, negative value otherwise.
 *
 * Caller holds tomoyo_read_lock().
 */
994
int tomoyo_write_file(struct tomoyo_acl_param *param)
995
{
996
	u16 perm = 0;
997
	u8 type;
998 999 1000 1001 1002 1003 1004
	const char *operation = tomoyo_read_token(param);
	for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++)
		if (tomoyo_permstr(operation, tomoyo_path_keyword[type]))
			perm |= 1 << type;
	if (perm)
		return tomoyo_update_path_acl(perm, param);
	for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++)
T
Tetsuo Handa 已提交
1005 1006
		if (tomoyo_permstr(operation,
				   tomoyo_mac_keywords[tomoyo_pp2mac[type]]))
1007 1008 1009 1010 1011
			perm |= 1 << type;
	if (perm)
		return tomoyo_update_path2_acl(perm, param);
	for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++)
		if (tomoyo_permstr(operation,
T
Tetsuo Handa 已提交
1012
				   tomoyo_mac_keywords[tomoyo_pn2mac[type]]))
1013 1014 1015 1016
			perm |= 1 << type;
	if (perm)
		return tomoyo_update_path_number_acl(perm, param);
	for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++)
T
Tetsuo Handa 已提交
1017 1018
		if (tomoyo_permstr(operation,
				   tomoyo_mac_keywords[tomoyo_pnnn2mac[type]]))
1019 1020 1021
			perm |= 1 << type;
	if (perm)
		return tomoyo_update_mkdev_acl(perm, param);
T
Tetsuo Handa 已提交
1022 1023
	if (tomoyo_permstr(operation,
			   tomoyo_mac_keywords[TOMOYO_MAC_FILE_MOUNT]))
1024
		return tomoyo_update_mount_acl(param);
1025 1026
	return -EINVAL;
}