file.c 33.2 KB
Newer Older
1 2 3
/*
 * security/tomoyo/file.c
 *
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
/* Keyword array for operations with one pathname. */
13
const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = {
T
Tetsuo Handa 已提交
14 15 16 17 18 19 20 21 22 23 24
	[TOMOYO_TYPE_READ_WRITE] = "read/write",
	[TOMOYO_TYPE_EXECUTE]    = "execute",
	[TOMOYO_TYPE_READ]       = "read",
	[TOMOYO_TYPE_WRITE]      = "write",
	[TOMOYO_TYPE_UNLINK]     = "unlink",
	[TOMOYO_TYPE_RMDIR]      = "rmdir",
	[TOMOYO_TYPE_TRUNCATE]   = "truncate",
	[TOMOYO_TYPE_SYMLINK]    = "symlink",
	[TOMOYO_TYPE_REWRITE]    = "rewrite",
	[TOMOYO_TYPE_CHROOT]     = "chroot",
	[TOMOYO_TYPE_UMOUNT]     = "unmount",
25 26
};

27
/* Keyword array for operations with one pathname and three numbers. */
28
const char *tomoyo_mkdev_keyword[TOMOYO_MAX_MKDEV_OPERATION] = {
29 30 31 32 33
	[TOMOYO_TYPE_MKBLOCK]    = "mkblock",
	[TOMOYO_TYPE_MKCHAR]     = "mkchar",
};

/* Keyword array for operations with two pathnames. */
34
const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = {
35 36
	[TOMOYO_TYPE_LINK]       = "link",
	[TOMOYO_TYPE_RENAME]     = "rename",
T
Tetsuo Handa 已提交
37
	[TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root",
38 39
};

40
/* Keyword array for operations with one pathname and one number. */
41
const char *tomoyo_path_number_keyword[TOMOYO_MAX_PATH_NUMBER_OPERATION] = {
42 43 44 45 46 47 48 49 50 51
	[TOMOYO_TYPE_CREATE]     = "create",
	[TOMOYO_TYPE_MKDIR]      = "mkdir",
	[TOMOYO_TYPE_MKFIFO]     = "mkfifo",
	[TOMOYO_TYPE_MKSOCK]     = "mksock",
	[TOMOYO_TYPE_IOCTL]      = "ioctl",
	[TOMOYO_TYPE_CHMOD]      = "chmod",
	[TOMOYO_TYPE_CHOWN]      = "chown",
	[TOMOYO_TYPE_CHGRP]      = "chgrp",
};

T
Tetsuo Handa 已提交
52 53 54 55 56 57 58 59 60 61 62 63 64 65
static const u8 tomoyo_p2mac[TOMOYO_MAX_PATH_OPERATION] = {
	[TOMOYO_TYPE_READ_WRITE] = TOMOYO_MAC_FILE_OPEN,
	[TOMOYO_TYPE_EXECUTE]    = TOMOYO_MAC_FILE_EXECUTE,
	[TOMOYO_TYPE_READ]       = TOMOYO_MAC_FILE_OPEN,
	[TOMOYO_TYPE_WRITE]      = TOMOYO_MAC_FILE_OPEN,
	[TOMOYO_TYPE_UNLINK]     = TOMOYO_MAC_FILE_UNLINK,
	[TOMOYO_TYPE_RMDIR]      = TOMOYO_MAC_FILE_RMDIR,
	[TOMOYO_TYPE_TRUNCATE]   = TOMOYO_MAC_FILE_TRUNCATE,
	[TOMOYO_TYPE_SYMLINK]    = TOMOYO_MAC_FILE_SYMLINK,
	[TOMOYO_TYPE_REWRITE]    = TOMOYO_MAC_FILE_REWRITE,
	[TOMOYO_TYPE_CHROOT]     = TOMOYO_MAC_FILE_CHROOT,
	[TOMOYO_TYPE_UMOUNT]     = TOMOYO_MAC_FILE_UMOUNT,
};

T
Tetsuo Handa 已提交
66
static const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION] = {
T
Tetsuo Handa 已提交
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
	[TOMOYO_TYPE_MKBLOCK] = TOMOYO_MAC_FILE_MKBLOCK,
	[TOMOYO_TYPE_MKCHAR]  = TOMOYO_MAC_FILE_MKCHAR,
};

static const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION] = {
	[TOMOYO_TYPE_LINK]       = TOMOYO_MAC_FILE_LINK,
	[TOMOYO_TYPE_RENAME]     = TOMOYO_MAC_FILE_RENAME,
	[TOMOYO_TYPE_PIVOT_ROOT] = TOMOYO_MAC_FILE_PIVOT_ROOT,
};

static const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = {
	[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,
};

88 89 90 91 92
void tomoyo_put_name_union(struct tomoyo_name_union *ptr)
{
	if (!ptr)
		return;
	if (ptr->is_group)
93
		tomoyo_put_group(ptr->group);
94 95 96 97 98 99 100 101
	else
		tomoyo_put_name(ptr->filename);
}

bool tomoyo_compare_name_union(const struct tomoyo_path_info *name,
			       const struct tomoyo_name_union *ptr)
{
	if (ptr->is_group)
102
		return tomoyo_path_matches_group(name, ptr->group);
103 104 105
	return tomoyo_path_matches_pattern(name, ptr->filename);
}

106 107 108
void tomoyo_put_number_union(struct tomoyo_number_union *ptr)
{
	if (ptr && ptr->is_group)
109
		tomoyo_put_group(ptr->group);
110 111 112 113 114 115 116 117 118 119
}

bool tomoyo_compare_number_union(const unsigned long value,
				 const struct tomoyo_number_union *ptr)
{
	if (ptr->is_group)
		return tomoyo_number_matches_group(value, value, ptr->group);
	return value >= ptr->values[0] && value <= ptr->values[1];
}

T
Tetsuo Handa 已提交
120 121 122 123 124 125 126 127 128 129 130
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);
}

131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
/**
 * tomoyo_strendswith - Check whether the token ends with the given token.
 *
 * @name: The token to check.
 * @tail: The token to find.
 *
 * Returns true if @name ends with @tail, false otherwise.
 */
static bool tomoyo_strendswith(const char *name, const char *tail)
{
	int len;

	if (!name || !tail)
		return false;
	len = strlen(name) - strlen(tail);
	return len >= 0 && !strcmp(name + len, tail);
}

/**
T
Tetsuo Handa 已提交
150
 * tomoyo_get_realpath - Get realpath.
151
 *
T
Tetsuo Handa 已提交
152
 * @buf:  Pointer to "struct tomoyo_path_info".
153 154
 * @path: Pointer to "struct path".
 *
T
Tetsuo Handa 已提交
155
 * Returns true on success, false otherwise.
156
 */
T
Tetsuo Handa 已提交
157
static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path)
158
{
T
Tetsuo Handa 已提交
159 160 161 162
	buf->name = tomoyo_realpath_from_path(path);
	if (buf->name) {
		tomoyo_fill_path_info(buf);
		return true;
163
	}
T
Tetsuo Handa 已提交
164
        return false;
165 166
}

167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
/**
 * 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)
{
	const char *operation = tomoyo_path_keyword[r->param.path.operation];
	const struct tomoyo_path_info *filename = r->param.path.filename;
	if (r->granted)
		return 0;
	tomoyo_warn_log(r, "%s %s", operation, filename->name);
	return tomoyo_supervisor(r, "allow_%s %s\n", operation,
T
Tetsuo Handa 已提交
182
				 tomoyo_pattern(filename));
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
}

/**
 * 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)
{
	const char *operation = tomoyo_path2_keyword[r->param.path2.operation];
	const struct tomoyo_path_info *filename1 = r->param.path2.filename1;
	const struct tomoyo_path_info *filename2 = r->param.path2.filename2;
	if (r->granted)
		return 0;
	tomoyo_warn_log(r, "%s %s %s", operation, filename1->name,
			filename2->name);
	return tomoyo_supervisor(r, "allow_%s %s %s\n", operation,
T
Tetsuo Handa 已提交
202 203
				 tomoyo_pattern(filename1),
				 tomoyo_pattern(filename2));
204 205 206 207 208 209 210 211 212 213 214
}

/**
 * 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)
{
215
	const char *operation = tomoyo_mkdev_keyword[r->param.mkdev.operation];
216 217 218 219 220 221 222 223 224
	const struct tomoyo_path_info *filename = r->param.mkdev.filename;
	const unsigned int major = r->param.mkdev.major;
	const unsigned int minor = r->param.mkdev.minor;
	const unsigned int mode = r->param.mkdev.mode;
	if (r->granted)
		return 0;
	tomoyo_warn_log(r, "%s %s 0%o %u %u", operation, filename->name, mode,
			major, minor);
	return tomoyo_supervisor(r, "allow_%s %s 0%o %u %u\n", operation,
T
Tetsuo Handa 已提交
225
				 tomoyo_pattern(filename), mode, major, minor);
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
}

/**
 * tomoyo_audit_path_number_log - Audit path/number request log.
 *
 * @r:     Pointer to "struct tomoyo_request_info".
 * @error: Error code.
 *
 * 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;
	const struct tomoyo_path_info *filename = r->param.path_number.filename;
	const char *operation = tomoyo_path_number_keyword[type];
	char buffer[64];
	if (r->granted)
		return 0;
	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);
	tomoyo_warn_log(r, "%s %s %s", operation, filename->name, buffer);
	return tomoyo_supervisor(r, "allow_%s %s %s\n", operation,
T
Tetsuo Handa 已提交
264
				 tomoyo_pattern(filename), buffer);
265 266
}

267 268 269
static bool tomoyo_same_globally_readable(const struct tomoyo_acl_head *a,
					  const struct tomoyo_acl_head *b)
{
T
Tetsuo Handa 已提交
270
	return container_of(a, struct tomoyo_readable_file,
271
			    head)->filename ==
T
Tetsuo Handa 已提交
272
		container_of(b, struct tomoyo_readable_file,
273 274 275
			     head)->filename;
}

276
/**
T
Tetsuo Handa 已提交
277
 * tomoyo_update_globally_readable_entry - Update "struct tomoyo_readable_file" list.
278 279 280 281 282
 *
 * @filename:  Filename unconditionally permitted to open() for reading.
 * @is_delete: True if it is a delete request.
 *
 * Returns 0 on success, negative value otherwise.
283 284
 *
 * Caller holds tomoyo_read_lock().
285 286 287 288
 */
static int tomoyo_update_globally_readable_entry(const char *filename,
						 const bool is_delete)
{
T
Tetsuo Handa 已提交
289
	struct tomoyo_readable_file e = { };
290
	int error;
291

T
Tetsuo Handa 已提交
292
	if (!tomoyo_correct_word(filename))
293
		return -EINVAL;
294 295
	e.filename = tomoyo_get_name(filename);
	if (!e.filename)
296
		return -ENOMEM;
297
	error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
298 299
				     &tomoyo_policy_list
				     [TOMOYO_ID_GLOBALLY_READABLE],
300
				     tomoyo_same_globally_readable);
301
	tomoyo_put_name(e.filename);
302 303 304 305
	return error;
}

/**
T
Tetsuo Handa 已提交
306
 * tomoyo_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading.
307 308 309 310
 *
 * @filename: The filename to check.
 *
 * Returns true if any domain can open @filename for reading, false otherwise.
311 312
 *
 * Caller holds tomoyo_read_lock().
313
 */
T
Tetsuo Handa 已提交
314
static bool tomoyo_globally_readable_file(const struct tomoyo_path_info *
315 316
					     filename)
{
T
Tetsuo Handa 已提交
317
	struct tomoyo_readable_file *ptr;
318
	bool found = false;
319

320 321
	list_for_each_entry_rcu(ptr, &tomoyo_policy_list
				[TOMOYO_ID_GLOBALLY_READABLE], head.list) {
322
		if (!ptr->head.is_deleted &&
323 324 325 326 327 328 329 330 331
		    tomoyo_path_matches_pattern(filename, ptr->filename)) {
			found = true;
			break;
		}
	}
	return found;
}

/**
T
Tetsuo Handa 已提交
332
 * tomoyo_write_globally_readable - Write "struct tomoyo_readable_file" list.
333 334 335 336 337
 *
 * @data:      String to parse.
 * @is_delete: True if it is a delete request.
 *
 * Returns 0 on success, negative value otherwise.
338 339
 *
 * Caller holds tomoyo_read_lock().
340
 */
T
Tetsuo Handa 已提交
341
int tomoyo_write_globally_readable(char *data, const bool is_delete)
342 343 344 345
{
	return tomoyo_update_globally_readable_entry(data, is_delete);
}

346 347 348
static bool tomoyo_same_pattern(const struct tomoyo_acl_head *a,
				const struct tomoyo_acl_head *b)
{
T
Tetsuo Handa 已提交
349 350
	return container_of(a, struct tomoyo_no_pattern, head)->pattern ==
		container_of(b, struct tomoyo_no_pattern, head)->pattern;
351 352
}

353
/**
T
Tetsuo Handa 已提交
354
 * tomoyo_update_file_pattern_entry - Update "struct tomoyo_no_pattern" list.
355 356 357 358 359
 *
 * @pattern:   Pathname pattern.
 * @is_delete: True if it is a delete request.
 *
 * Returns 0 on success, negative value otherwise.
360 361
 *
 * Caller holds tomoyo_read_lock().
362 363 364 365
 */
static int tomoyo_update_file_pattern_entry(const char *pattern,
					    const bool is_delete)
{
T
Tetsuo Handa 已提交
366
	struct tomoyo_no_pattern e = { };
367
	int error;
368

T
Tetsuo Handa 已提交
369
	if (!tomoyo_correct_word(pattern))
370 371
		return -EINVAL;
	e.pattern = tomoyo_get_name(pattern);
372
	if (!e.pattern)
373 374
		return -ENOMEM;
	error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
375
				     &tomoyo_policy_list[TOMOYO_ID_PATTERN],
376
				     tomoyo_same_pattern);
377
	tomoyo_put_name(e.pattern);
378 379 380 381
	return error;
}

/**
T
Tetsuo Handa 已提交
382
 * tomoyo_pattern - Get patterned pathname.
383 384 385 386
 *
 * @filename: The filename to find patterned pathname.
 *
 * Returns pointer to pathname pattern if matched, @filename otherwise.
387 388
 *
 * Caller holds tomoyo_read_lock().
389
 */
T
Tetsuo Handa 已提交
390
const char *tomoyo_pattern(const struct tomoyo_path_info *filename)
391
{
T
Tetsuo Handa 已提交
392
	struct tomoyo_no_pattern *ptr;
393 394
	const struct tomoyo_path_info *pattern = NULL;

395 396
	list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_PATTERN],
				head.list) {
397
		if (ptr->head.is_deleted)
398 399 400 401 402 403 404 405 406 407 408 409 410
			continue;
		if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
			continue;
		pattern = ptr->pattern;
		if (tomoyo_strendswith(pattern->name, "/\\*")) {
			/* Do nothing. Try to find the better match. */
		} else {
			/* This would be the better match. Use this. */
			break;
		}
	}
	if (pattern)
		filename = pattern;
411
	return filename->name;
412 413 414
}

/**
T
Tetsuo Handa 已提交
415
 * tomoyo_write_pattern - Write "struct tomoyo_no_pattern" list.
416 417 418 419 420
 *
 * @data:      String to parse.
 * @is_delete: True if it is a delete request.
 *
 * Returns 0 on success, negative value otherwise.
421 422
 *
 * Caller holds tomoyo_read_lock().
423
 */
T
Tetsuo Handa 已提交
424
int tomoyo_write_pattern(char *data, const bool is_delete)
425 426 427 428
{
	return tomoyo_update_file_pattern_entry(data, is_delete);
}

429 430 431
static bool tomoyo_same_no_rewrite(const struct tomoyo_acl_head *a,
				   const struct tomoyo_acl_head *b)
{
T
Tetsuo Handa 已提交
432 433
	return container_of(a, struct tomoyo_no_rewrite, head)->pattern
		== container_of(b, struct tomoyo_no_rewrite, head)
434 435 436
		->pattern;
}

437
/**
T
Tetsuo Handa 已提交
438
 * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite" list.
439 440 441 442 443
 *
 * @pattern:   Pathname pattern that are not rewritable by default.
 * @is_delete: True if it is a delete request.
 *
 * Returns 0 on success, negative value otherwise.
444 445
 *
 * Caller holds tomoyo_read_lock().
446 447 448 449
 */
static int tomoyo_update_no_rewrite_entry(const char *pattern,
					  const bool is_delete)
{
T
Tetsuo Handa 已提交
450
	struct tomoyo_no_rewrite e = { };
451
	int error;
452

T
Tetsuo Handa 已提交
453
	if (!tomoyo_correct_word(pattern))
454
		return -EINVAL;
455 456
	e.pattern = tomoyo_get_name(pattern);
	if (!e.pattern)
457 458
		return -ENOMEM;
	error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
459
				     &tomoyo_policy_list[TOMOYO_ID_NO_REWRITE],
460
				     tomoyo_same_no_rewrite);
461
	tomoyo_put_name(e.pattern);
462 463 464 465
	return error;
}

/**
T
Tetsuo Handa 已提交
466
 * tomoyo_no_rewrite_file - Check if the given pathname is not permitted to be rewrited.
467 468 469 470 471
 *
 * @filename: Filename to check.
 *
 * Returns true if @filename is specified by "deny_rewrite" directive,
 * false otherwise.
472 473
 *
 * Caller holds tomoyo_read_lock().
474
 */
T
Tetsuo Handa 已提交
475
static bool tomoyo_no_rewrite_file(const struct tomoyo_path_info *filename)
476
{
T
Tetsuo Handa 已提交
477
	struct tomoyo_no_rewrite *ptr;
478 479
	bool found = false;

480 481
	list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_NO_REWRITE],
				head.list) {
482
		if (ptr->head.is_deleted)
483 484 485 486 487 488 489 490 491 492
			continue;
		if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
			continue;
		found = true;
		break;
	}
	return found;
}

/**
T
Tetsuo Handa 已提交
493
 * tomoyo_write_no_rewrite - Write "struct tomoyo_no_rewrite" list.
494 495 496 497 498
 *
 * @data:      String to parse.
 * @is_delete: True if it is a delete request.
 *
 * Returns 0 on success, negative value otherwise.
499 500
 *
 * Caller holds tomoyo_read_lock().
501
 */
T
Tetsuo Handa 已提交
502
int tomoyo_write_no_rewrite(char *data, const bool is_delete)
503 504 505 506
{
	return tomoyo_update_no_rewrite_entry(data, is_delete);
}

507 508
static bool tomoyo_check_path_acl(const struct tomoyo_request_info *r,
				  const struct tomoyo_acl_info *ptr)
509
{
510 511 512 513 514
	const struct tomoyo_path_acl *acl = container_of(ptr, typeof(*acl),
							 head);
	return (acl->perm & (1 << r->param.path.operation)) &&
		tomoyo_compare_name_union(r->param.path.filename, &acl->name);
}
515

516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541
static bool tomoyo_check_path_number_acl(const struct tomoyo_request_info *r,
					 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);
}

static bool tomoyo_check_path2_acl(const struct tomoyo_request_info *r,
				   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);
}

static bool tomoyo_check_mkdev_acl(const struct tomoyo_request_info *r,
				const struct tomoyo_acl_info *ptr)
{
T
Tetsuo Handa 已提交
542
	const struct tomoyo_mkdev_acl *acl =
543 544 545 546 547 548 549 550 551 552
		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);
553 554
}

555 556 557 558 559
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 已提交
560 561
	return tomoyo_same_acl_head(&p1->head, &p2->head) &&
		tomoyo_same_name_union(&p1->name, &p2->name);
562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
}

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;
	if (is_delete) {
		perm &= ~b_perm;
		if ((perm & TOMOYO_RW_MASK) != TOMOYO_RW_MASK)
			perm &= ~(1 << TOMOYO_TYPE_READ_WRITE);
		else if (!(perm & (1 << TOMOYO_TYPE_READ_WRITE)))
			perm &= ~TOMOYO_RW_MASK;
	} else {
		perm |= b_perm;
		if ((perm & TOMOYO_RW_MASK) == TOMOYO_RW_MASK)
			perm |= (1 << TOMOYO_TYPE_READ_WRITE);
		else if (perm & (1 << TOMOYO_TYPE_READ_WRITE))
			perm |= TOMOYO_RW_MASK;
	}
	*a_perm = perm;
	return !perm;
}

589
/**
T
Tetsuo Handa 已提交
590
 * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list.
591 592 593 594 595 596 597
 *
 * @type:      Type of operation.
 * @filename:  Filename.
 * @domain:    Pointer to "struct tomoyo_domain_info".
 * @is_delete: True if it is a delete request.
 *
 * Returns 0 on success, negative value otherwise.
598 599
 *
 * Caller holds tomoyo_read_lock().
600
 */
T
Tetsuo Handa 已提交
601
static int tomoyo_update_path_acl(const u8 type, const char *filename,
602
				  struct tomoyo_domain_info * const domain,
T
Tetsuo Handa 已提交
603
				  const bool is_delete)
604
{
605 606
	struct tomoyo_path_acl e = {
		.head.type = TOMOYO_TYPE_PATH_ACL,
607
		.perm = 1 << type
608
	};
609 610 611
	int error;
	if (e.perm == (1 << TOMOYO_TYPE_READ_WRITE))
		e.perm |= TOMOYO_RW_MASK;
612
	if (!tomoyo_parse_name_union(filename, &e.name))
613
		return -EINVAL;
614 615 616
	error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
				     tomoyo_same_path_acl,
				     tomoyo_merge_path_acl);
617
	tomoyo_put_name_union(&e.name);
618 619 620
	return error;
}

T
Tetsuo Handa 已提交
621
static bool tomoyo_same_mkdev_acl(const struct tomoyo_acl_info *a,
622 623
					 const struct tomoyo_acl_info *b)
{
T
Tetsuo Handa 已提交
624
	const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1),
625
								head);
T
Tetsuo Handa 已提交
626
	const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2),
627
								head);
T
Tetsuo Handa 已提交
628 629 630 631 632
	return tomoyo_same_acl_head(&p1->head, &p2->head)
		&& 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);
633 634
}

T
Tetsuo Handa 已提交
635
static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a,
636 637 638
					  struct tomoyo_acl_info *b,
					  const bool is_delete)
{
T
Tetsuo Handa 已提交
639
	u8 *const a_perm = &container_of(a, struct tomoyo_mkdev_acl,
640 641
					 head)->perm;
	u8 perm = *a_perm;
T
Tetsuo Handa 已提交
642
	const u8 b_perm = container_of(b, struct tomoyo_mkdev_acl, head)
643 644 645 646 647 648 649 650 651
		->perm;
	if (is_delete)
		perm &= ~b_perm;
	else
		perm |= b_perm;
	*a_perm = perm;
	return !perm;
}

652
/**
T
Tetsuo Handa 已提交
653
 * tomoyo_update_mkdev_acl - Update "struct tomoyo_mkdev_acl" list.
654 655 656 657 658 659 660 661 662 663
 *
 * @type:      Type of operation.
 * @filename:  Filename.
 * @mode:      Create mode.
 * @major:     Device major number.
 * @minor:     Device minor number.
 * @domain:    Pointer to "struct tomoyo_domain_info".
 * @is_delete: True if it is a delete request.
 *
 * Returns 0 on success, negative value otherwise.
664 665
 *
 * Caller holds tomoyo_read_lock().
666
 */
T
Tetsuo Handa 已提交
667
static int tomoyo_update_mkdev_acl(const u8 type, const char *filename,
668 669 670
					  char *mode, char *major, char *minor,
					  struct tomoyo_domain_info * const
					  domain, const bool is_delete)
671
{
T
Tetsuo Handa 已提交
672 673
	struct tomoyo_mkdev_acl e = {
		.head.type = TOMOYO_TYPE_MKDEV_ACL,
674
		.perm = 1 << type
675 676 677 678 679 680 681
	};
	int error = is_delete ? -ENOENT : -ENOMEM;
	if (!tomoyo_parse_name_union(filename, &e.name) ||
	    !tomoyo_parse_number_union(mode, &e.mode) ||
	    !tomoyo_parse_number_union(major, &e.major) ||
	    !tomoyo_parse_number_union(minor, &e.minor))
		goto out;
682
	error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
T
Tetsuo Handa 已提交
683 684
				     tomoyo_same_mkdev_acl,
				     tomoyo_merge_mkdev_acl);
685 686 687 688 689 690 691 692
 out:
	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;
}

693 694 695 696 697
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 已提交
698 699 700
	return tomoyo_same_acl_head(&p1->head, &p2->head)
		&& tomoyo_same_name_union(&p1->name1, &p2->name1)
		&& tomoyo_same_name_union(&p1->name2, &p2->name2);
701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718
}

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;
}

719
/**
T
Tetsuo Handa 已提交
720
 * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list.
721 722 723 724 725 726 727 728
 *
 * @type:      Type of operation.
 * @filename1: First filename.
 * @filename2: Second filename.
 * @domain:    Pointer to "struct tomoyo_domain_info".
 * @is_delete: True if it is a delete request.
 *
 * Returns 0 on success, negative value otherwise.
729 730
 *
 * Caller holds tomoyo_read_lock().
731
 */
T
Tetsuo Handa 已提交
732 733
static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
				   const char *filename2,
734
				   struct tomoyo_domain_info * const domain,
T
Tetsuo Handa 已提交
735
				   const bool is_delete)
736
{
737 738
	struct tomoyo_path2_acl e = {
		.head.type = TOMOYO_TYPE_PATH2_ACL,
739
		.perm = 1 << type
740
	};
741
	int error = is_delete ? -ENOENT : -ENOMEM;
742 743
	if (!tomoyo_parse_name_union(filename1, &e.name1) ||
	    !tomoyo_parse_name_union(filename2, &e.name2))
744
		goto out;
745 746 747
	error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
				     tomoyo_same_path2_acl,
				     tomoyo_merge_path2_acl);
748
 out:
749 750
	tomoyo_put_name_union(&e.name1);
	tomoyo_put_name_union(&e.name2);
751 752 753 754
	return error;
}

/**
755
 * tomoyo_path_permission - Check permission for single path operation.
756
 *
757
 * @r:         Pointer to "struct tomoyo_request_info".
758 759 760 761
 * @operation: Type of operation.
 * @filename:  Filename to check.
 *
 * Returns 0 on success, negative value otherwise.
762 763
 *
 * Caller holds tomoyo_read_lock().
764
 */
765 766
int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
			   const struct tomoyo_path_info *filename)
767 768 769 770
{
	int error;

 next:
T
Tetsuo Handa 已提交
771 772 773 774
	r->type = tomoyo_p2mac[operation];
	r->mode = tomoyo_get_mode(r->profile, r->type);
	if (r->mode == TOMOYO_CONFIG_DISABLED)
		return 0;
775 776 777
	r->param_type = TOMOYO_TYPE_PATH_ACL;
	r->param.path.filename = filename;
	r->param.path.operation = operation;
778
	do {
779 780
		tomoyo_check_acl(r, tomoyo_check_path_acl);
		if (!r->granted && operation == TOMOYO_TYPE_READ &&
781
		    !r->domain->ignore_global_allow_read &&
T
Tetsuo Handa 已提交
782
		    tomoyo_globally_readable_file(filename))
783 784
			r->granted = true;
		error = tomoyo_audit_path_log(r);
785 786 787 788 789 790
		/*
		 * Do not retry for execute request, for alias may have
		 * changed.
		 */
	} while (error == TOMOYO_RETRY_REQUEST &&
		 operation != TOMOYO_TYPE_EXECUTE);
791 792 793 794 795
	/*
	 * Since "allow_truncate" doesn't imply "allow_rewrite" permission,
	 * we need to check "allow_rewrite" permission if the filename is
	 * specified by "deny_rewrite" keyword.
	 */
T
Tetsuo Handa 已提交
796
	if (!error && operation == TOMOYO_TYPE_TRUNCATE &&
T
Tetsuo Handa 已提交
797
	    tomoyo_no_rewrite_file(filename)) {
T
Tetsuo Handa 已提交
798
		operation = TOMOYO_TYPE_REWRITE;
799 800 801 802 803
		goto next;
	}
	return error;
}

804 805 806 807 808 809 810
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 已提交
811 812 813
	return tomoyo_same_acl_head(&p1->head, &p2->head)
		&& tomoyo_same_name_union(&p1->name, &p2->name)
		&& tomoyo_same_number_union(&p1->number, &p2->number);
814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832
}

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;
}

833 834 835 836 837 838 839 840 841 842 843
/**
 * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL.
 *
 * @type:      Type of operation.
 * @filename:  Filename.
 * @number:    Number.
 * @domain:    Pointer to "struct tomoyo_domain_info".
 * @is_delete: True if it is a delete request.
 *
 * Returns 0 on success, negative value otherwise.
 */
844 845 846 847 848
static int tomoyo_update_path_number_acl(const u8 type, const char *filename,
					 char *number,
					 struct tomoyo_domain_info * const
					 domain,
					 const bool is_delete)
849 850 851
{
	struct tomoyo_path_number_acl e = {
		.head.type = TOMOYO_TYPE_PATH_NUMBER_ACL,
852
		.perm = 1 << type
853 854 855 856 857 858
	};
	int error = is_delete ? -ENOENT : -ENOMEM;
	if (!tomoyo_parse_name_union(filename, &e.name))
		return -EINVAL;
	if (!tomoyo_parse_number_union(number, &e.number))
		goto out;
859 860 861
	error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
				     tomoyo_same_path_number_acl,
				     tomoyo_merge_path_number_acl);
862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881
 out:
	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;
	int error = -ENOMEM;
T
Tetsuo Handa 已提交
882
	struct tomoyo_path_info buf;
883 884
	int idx;

T
Tetsuo Handa 已提交
885 886
	if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type])
	    == TOMOYO_CONFIG_DISABLED || !path->mnt || !path->dentry)
887 888
		return 0;
	idx = tomoyo_read_lock();
T
Tetsuo Handa 已提交
889
	if (!tomoyo_get_realpath(&buf, path))
890
		goto out;
T
Tetsuo Handa 已提交
891 892
	if (type == TOMOYO_TYPE_MKDIR)
		tomoyo_add_slash(&buf);
T
Tetsuo Handa 已提交
893 894 895 896 897 898 899 900
	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 已提交
901
	kfree(buf.name);
T
Tetsuo Handa 已提交
902
 out:
903 904 905 906 907 908
	tomoyo_read_unlock(idx);
	if (r.mode != TOMOYO_CONFIG_ENFORCING)
		error = 0;
	return error;
}

909 910 911 912 913 914 915 916 917 918 919 920 921 922
/**
 * 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);
	int error = -ENOMEM;
T
Tetsuo Handa 已提交
923
	struct tomoyo_path_info buf;
924
	struct tomoyo_request_info r;
925
	int idx;
926

T
Tetsuo Handa 已提交
927 928
	if (!path->mnt ||
	    (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode)))
929
		return 0;
T
Tetsuo Handa 已提交
930 931
	buf.name = NULL;
	r.mode = TOMOYO_CONFIG_DISABLED;
932
	idx = tomoyo_read_lock();
T
Tetsuo Handa 已提交
933
	if (!tomoyo_get_realpath(&buf, path))
934 935 936 937 938 939 940
		goto out;
	error = 0;
	/*
	 * If the filename is specified by "deny_rewrite" keyword,
	 * we need to check "allow_rewrite" permission when the filename is not
	 * opened for append mode or the filename is truncated at open time.
	 */
T
Tetsuo Handa 已提交
941 942 943 944 945 946 947
	if ((acc_mode & MAY_WRITE) && !(flag & O_APPEND)
	    && tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_REWRITE)
	    != TOMOYO_CONFIG_DISABLED) {
		if (!tomoyo_get_realpath(&buf, path)) {
			error = -ENOMEM;
			goto out;
		}
T
Tetsuo Handa 已提交
948
		if (tomoyo_no_rewrite_file(&buf))
T
Tetsuo Handa 已提交
949 950
			error = tomoyo_path_permission(&r, TOMOYO_TYPE_REWRITE,
						       &buf);
951
	}
T
Tetsuo Handa 已提交
952 953 954
	if (!error && acc_mode &&
	    tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN)
	    != TOMOYO_CONFIG_DISABLED) {
955
		u8 operation;
T
Tetsuo Handa 已提交
956 957 958 959
		if (!buf.name && !tomoyo_get_realpath(&buf, path)) {
			error = -ENOMEM;
			goto out;
		}
960 961 962 963 964 965 966
		if (acc_mode == (MAY_READ | MAY_WRITE))
			operation = TOMOYO_TYPE_READ_WRITE;
		else if (acc_mode == MAY_READ)
			operation = TOMOYO_TYPE_READ;
		else
			operation = TOMOYO_TYPE_WRITE;
		error = tomoyo_path_permission(&r, operation, &buf);
T
Tetsuo Handa 已提交
967
	}
968
 out:
T
Tetsuo Handa 已提交
969
	kfree(buf.name);
970
	tomoyo_read_unlock(idx);
971
	if (r.mode != TOMOYO_CONFIG_ENFORCING)
972 973 974 975 976
		error = 0;
	return error;
}

/**
T
Tetsuo Handa 已提交
977
 * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "rewrite", "chroot" and "unmount".
978 979 980 981 982 983
 *
 * @operation: Type of operation.
 * @path:      Pointer to "struct path".
 *
 * Returns 0 on success, negative value otherwise.
 */
984
int tomoyo_path_perm(const u8 operation, struct path *path)
985 986
{
	int error = -ENOMEM;
T
Tetsuo Handa 已提交
987
	struct tomoyo_path_info buf;
988
	struct tomoyo_request_info r;
989
	int idx;
990

T
Tetsuo Handa 已提交
991 992 993 994
	if (!path->mnt)
		return 0;
	if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation])
	    == TOMOYO_CONFIG_DISABLED)
995
		return 0;
T
Tetsuo Handa 已提交
996
	buf.name = NULL;
997
	idx = tomoyo_read_lock();
T
Tetsuo Handa 已提交
998
	if (!tomoyo_get_realpath(&buf, path))
999 1000
		goto out;
	switch (operation) {
1001
	case TOMOYO_TYPE_REWRITE:
T
Tetsuo Handa 已提交
1002
		if (!tomoyo_no_rewrite_file(&buf)) {
1003 1004 1005 1006
			error = 0;
			goto out;
		}
		break;
T
Tetsuo Handa 已提交
1007 1008
	case TOMOYO_TYPE_RMDIR:
	case TOMOYO_TYPE_CHROOT:
T
Tetsuo Handa 已提交
1009
	case TOMOYO_TYPE_UMOUNT:
T
Tetsuo Handa 已提交
1010 1011
		tomoyo_add_slash(&buf);
		break;
1012
	}
T
Tetsuo Handa 已提交
1013
	error = tomoyo_path_permission(&r, operation, &buf);
1014
 out:
T
Tetsuo Handa 已提交
1015
	kfree(buf.name);
1016
	tomoyo_read_unlock(idx);
1017
	if (r.mode != TOMOYO_CONFIG_ENFORCING)
1018 1019 1020 1021
		error = 0;
	return error;
}

1022
/**
T
Tetsuo Handa 已提交
1023
 * tomoyo_mkdev_perm - Check permission for "mkblock" and "mkchar".
1024 1025 1026 1027 1028 1029 1030 1031
 *
 * @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 已提交
1032
int tomoyo_mkdev_perm(const u8 operation, struct path *path,
1033 1034 1035 1036
			     const unsigned int mode, unsigned int dev)
{
	struct tomoyo_request_info r;
	int error = -ENOMEM;
T
Tetsuo Handa 已提交
1037
	struct tomoyo_path_info buf;
1038 1039
	int idx;

T
Tetsuo Handa 已提交
1040 1041 1042
	if (!path->mnt ||
	    tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation])
	    == TOMOYO_CONFIG_DISABLED)
1043 1044 1045
		return 0;
	idx = tomoyo_read_lock();
	error = -ENOMEM;
T
Tetsuo Handa 已提交
1046
	if (tomoyo_get_realpath(&buf, path)) {
1047
		dev = new_decode_dev(dev);
T
Tetsuo Handa 已提交
1048
		r.param_type = TOMOYO_TYPE_MKDEV_ACL;
1049 1050 1051 1052 1053
		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);
1054 1055
		tomoyo_check_acl(&r, tomoyo_check_mkdev_acl);
		error = tomoyo_audit_mkdev_log(&r);
T
Tetsuo Handa 已提交
1056
		kfree(buf.name);
1057 1058 1059 1060 1061 1062 1063
	}
	tomoyo_read_unlock(idx);
	if (r.mode != TOMOYO_CONFIG_ENFORCING)
		error = 0;
	return error;
}

1064
/**
T
Tetsuo Handa 已提交
1065
 * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root".
1066 1067 1068 1069 1070 1071 1072
 *
 * @operation: Type of operation.
 * @path1:      Pointer to "struct path".
 * @path2:      Pointer to "struct path".
 *
 * Returns 0 on success, negative value otherwise.
 */
1073
int tomoyo_path2_perm(const u8 operation, struct path *path1,
T
Tetsuo Handa 已提交
1074
		      struct path *path2)
1075 1076
{
	int error = -ENOMEM;
T
Tetsuo Handa 已提交
1077 1078
	struct tomoyo_path_info buf1;
	struct tomoyo_path_info buf2;
1079
	struct tomoyo_request_info r;
1080
	int idx;
1081

T
Tetsuo Handa 已提交
1082 1083 1084
	if (!path1->mnt || !path2->mnt ||
	    tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation])
	    == TOMOYO_CONFIG_DISABLED)
1085
		return 0;
T
Tetsuo Handa 已提交
1086 1087
	buf1.name = NULL;
	buf2.name = NULL;
1088
	idx = tomoyo_read_lock();
T
Tetsuo Handa 已提交
1089 1090
	if (!tomoyo_get_realpath(&buf1, path1) ||
	    !tomoyo_get_realpath(&buf2, path2))
1091
		goto out;
T
Tetsuo Handa 已提交
1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104
	switch (operation) {
		struct dentry *dentry;
	case TOMOYO_TYPE_RENAME:
        case TOMOYO_TYPE_LINK:
		dentry = path1->dentry;
	        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);
		break;
        }
1105 1106 1107 1108
	r.param_type = TOMOYO_TYPE_PATH2_ACL;
	r.param.path2.operation = operation;
	r.param.path2.filename1 = &buf1;
	r.param.path2.filename2 = &buf2;
1109
	do {
1110 1111 1112
		tomoyo_check_acl(&r, tomoyo_check_path2_acl);
		error = tomoyo_audit_path2_log(&r);
	} while (error == TOMOYO_RETRY_REQUEST);
1113
 out:
T
Tetsuo Handa 已提交
1114 1115
	kfree(buf1.name);
	kfree(buf2.name);
1116
	tomoyo_read_unlock(idx);
1117
	if (r.mode != TOMOYO_CONFIG_ENFORCING)
1118 1119 1120
		error = 0;
	return error;
}
1121 1122

/**
T
Tetsuo Handa 已提交
1123
 * tomoyo_write_file - Update file related list.
1124 1125 1126 1127 1128 1129 1130 1131 1132
 *
 * @data:      String to parse.
 * @domain:    Pointer to "struct tomoyo_domain_info".
 * @is_delete: True if it is a delete request.
 *
 * Returns 0 on success, negative value otherwise.
 *
 * Caller holds tomoyo_read_lock().
 */
T
Tetsuo Handa 已提交
1133 1134
int tomoyo_write_file(char *data, struct tomoyo_domain_info *domain,
		      const bool is_delete)
1135 1136 1137 1138 1139
{
	char *w[5];
	u8 type;
	if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0])
		return -EINVAL;
1140
	if (strncmp(w[0], "allow_", 6))
1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163
		goto out;
	w[0] += 6;
	for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) {
		if (strcmp(w[0], tomoyo_path_keyword[type]))
			continue;
		return tomoyo_update_path_acl(type, w[1], domain, is_delete);
	}
	if (!w[2][0])
		goto out;
	for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) {
		if (strcmp(w[0], tomoyo_path2_keyword[type]))
			continue;
		return tomoyo_update_path2_acl(type, w[1], w[2], domain,
					       is_delete);
	}
	for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) {
		if (strcmp(w[0], tomoyo_path_number_keyword[type]))
			continue;
		return tomoyo_update_path_number_acl(type, w[1], w[2], domain,
						     is_delete);
	}
	if (!w[3][0] || !w[4][0])
		goto out;
T
Tetsuo Handa 已提交
1164 1165
	for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++) {
		if (strcmp(w[0], tomoyo_mkdev_keyword[type]))
1166
			continue;
T
Tetsuo Handa 已提交
1167 1168
		return tomoyo_update_mkdev_acl(type, w[1], w[2], w[3],
					       w[4], domain, is_delete);
1169 1170 1171 1172
	}
 out:
	return -EINVAL;
}