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
	else
		tomoyo_put_name(ptr->filename);
}

98 99 100
const struct tomoyo_path_info *
tomoyo_compare_name_union(const struct tomoyo_path_info *name,
			  const struct tomoyo_name_union *ptr)
101 102
{
	if (ptr->is_group)
103
		return tomoyo_path_matches_group(name, ptr->group);
104 105 106
	if (tomoyo_path_matches_pattern(name, ptr->filename))
		return ptr->filename;
	return NULL;
107 108
}

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

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 已提交
123 124 125 126 127 128 129 130 131 132 133
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);
}

134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
/**
 * 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 已提交
153
 * tomoyo_get_realpath - Get realpath.
154
 *
T
Tetsuo Handa 已提交
155
 * @buf:  Pointer to "struct tomoyo_path_info".
156 157
 * @path: Pointer to "struct path".
 *
T
Tetsuo Handa 已提交
158
 * Returns true on success, false otherwise.
159
 */
T
Tetsuo Handa 已提交
160
static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path)
161
{
T
Tetsuo Handa 已提交
162 163 164 165
	buf->name = tomoyo_realpath_from_path(path);
	if (buf->name) {
		tomoyo_fill_path_info(buf);
		return true;
166
	}
T
Tetsuo Handa 已提交
167
        return false;
168 169
}

170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
/**
 * 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 已提交
185
				 tomoyo_pattern(filename));
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
}

/**
 * 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 已提交
205 206
				 tomoyo_pattern(filename1),
				 tomoyo_pattern(filename2));
207 208 209 210 211 212 213 214 215 216 217
}

/**
 * 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)
{
218
	const char *operation = tomoyo_mkdev_keyword[r->param.mkdev.operation];
219 220 221 222 223 224 225 226 227
	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 已提交
228
				 tomoyo_pattern(filename), mode, major, minor);
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 264 265 266
}

/**
 * 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 已提交
267
				 tomoyo_pattern(filename), buffer);
268 269
}

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

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

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

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

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

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

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

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

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

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

398 399
	list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_PATTERN],
				head.list) {
400
		if (ptr->head.is_deleted)
401 402 403 404 405 406 407 408 409 410 411 412 413
			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;
414
	return filename->name;
415 416 417
}

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

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

440
/**
T
Tetsuo Handa 已提交
441
 * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite" list.
442 443 444 445 446
 *
 * @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.
447 448
 *
 * Caller holds tomoyo_read_lock().
449 450 451 452
 */
static int tomoyo_update_no_rewrite_entry(const char *pattern,
					  const bool is_delete)
{
T
Tetsuo Handa 已提交
453
	struct tomoyo_no_rewrite e = { };
454
	int error;
455

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

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

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

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

510
static bool tomoyo_check_path_acl(struct tomoyo_request_info *r,
511
				  const struct tomoyo_acl_info *ptr)
512
{
513 514
	const struct tomoyo_path_acl *acl = container_of(ptr, typeof(*acl),
							 head);
515 516 517 518 519 520 521
	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;
522
}
523

524
static bool tomoyo_check_path_number_acl(struct tomoyo_request_info *r,
525 526 527 528 529 530 531 532 533 534 535
					 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);
}

536
static bool tomoyo_check_path2_acl(struct tomoyo_request_info *r,
537 538 539 540 541 542 543 544 545 546
				   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);
}

547
static bool tomoyo_check_mkdev_acl(struct tomoyo_request_info *r,
548 549
				const struct tomoyo_acl_info *ptr)
{
T
Tetsuo Handa 已提交
550
	const struct tomoyo_mkdev_acl *acl =
551 552 553 554 555 556 557 558 559 560
		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);
561 562
}

563 564 565 566 567
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 已提交
568 569
	return tomoyo_same_acl_head(&p1->head, &p2->head) &&
		tomoyo_same_name_union(&p1->name, &p2->name);
570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596
}

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

597
/**
T
Tetsuo Handa 已提交
598
 * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list.
599 600 601 602 603 604 605
 *
 * @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.
606 607
 *
 * Caller holds tomoyo_read_lock().
608
 */
T
Tetsuo Handa 已提交
609
static int tomoyo_update_path_acl(const u8 type, const char *filename,
610
				  struct tomoyo_domain_info * const domain,
T
Tetsuo Handa 已提交
611
				  const bool is_delete)
612
{
613 614
	struct tomoyo_path_acl e = {
		.head.type = TOMOYO_TYPE_PATH_ACL,
615
		.perm = 1 << type
616
	};
617 618 619
	int error;
	if (e.perm == (1 << TOMOYO_TYPE_READ_WRITE))
		e.perm |= TOMOYO_RW_MASK;
620
	if (!tomoyo_parse_name_union(filename, &e.name))
621
		return -EINVAL;
622 623 624
	error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
				     tomoyo_same_path_acl,
				     tomoyo_merge_path_acl);
625
	tomoyo_put_name_union(&e.name);
626 627 628
	return error;
}

T
Tetsuo Handa 已提交
629
static bool tomoyo_same_mkdev_acl(const struct tomoyo_acl_info *a,
630 631
					 const struct tomoyo_acl_info *b)
{
T
Tetsuo Handa 已提交
632
	const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1),
633
								head);
T
Tetsuo Handa 已提交
634
	const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2),
635
								head);
T
Tetsuo Handa 已提交
636 637 638 639 640
	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);
641 642
}

T
Tetsuo Handa 已提交
643
static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a,
644 645 646
					  struct tomoyo_acl_info *b,
					  const bool is_delete)
{
T
Tetsuo Handa 已提交
647
	u8 *const a_perm = &container_of(a, struct tomoyo_mkdev_acl,
648 649
					 head)->perm;
	u8 perm = *a_perm;
T
Tetsuo Handa 已提交
650
	const u8 b_perm = container_of(b, struct tomoyo_mkdev_acl, head)
651 652 653 654 655 656 657 658 659
		->perm;
	if (is_delete)
		perm &= ~b_perm;
	else
		perm |= b_perm;
	*a_perm = perm;
	return !perm;
}

660
/**
T
Tetsuo Handa 已提交
661
 * tomoyo_update_mkdev_acl - Update "struct tomoyo_mkdev_acl" list.
662 663 664 665 666 667 668 669 670 671
 *
 * @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.
672 673
 *
 * Caller holds tomoyo_read_lock().
674
 */
T
Tetsuo Handa 已提交
675
static int tomoyo_update_mkdev_acl(const u8 type, const char *filename,
676 677 678
					  char *mode, char *major, char *minor,
					  struct tomoyo_domain_info * const
					  domain, const bool is_delete)
679
{
T
Tetsuo Handa 已提交
680 681
	struct tomoyo_mkdev_acl e = {
		.head.type = TOMOYO_TYPE_MKDEV_ACL,
682
		.perm = 1 << type
683 684 685 686 687 688 689
	};
	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;
690
	error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
T
Tetsuo Handa 已提交
691 692
				     tomoyo_same_mkdev_acl,
				     tomoyo_merge_mkdev_acl);
693 694 695 696 697 698 699 700
 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;
}

701 702 703 704 705
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 已提交
706 707 708
	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);
709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726
}

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

727
/**
T
Tetsuo Handa 已提交
728
 * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list.
729 730 731 732 733 734 735 736
 *
 * @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.
737 738
 *
 * Caller holds tomoyo_read_lock().
739
 */
T
Tetsuo Handa 已提交
740 741
static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
				   const char *filename2,
742
				   struct tomoyo_domain_info * const domain,
T
Tetsuo Handa 已提交
743
				   const bool is_delete)
744
{
745 746
	struct tomoyo_path2_acl e = {
		.head.type = TOMOYO_TYPE_PATH2_ACL,
747
		.perm = 1 << type
748
	};
749
	int error = is_delete ? -ENOENT : -ENOMEM;
750 751
	if (!tomoyo_parse_name_union(filename1, &e.name1) ||
	    !tomoyo_parse_name_union(filename2, &e.name2))
752
		goto out;
753 754 755
	error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
				     tomoyo_same_path2_acl,
				     tomoyo_merge_path2_acl);
756
 out:
757 758
	tomoyo_put_name_union(&e.name1);
	tomoyo_put_name_union(&e.name2);
759 760 761 762
	return error;
}

/**
763
 * tomoyo_path_permission - Check permission for single path operation.
764
 *
765
 * @r:         Pointer to "struct tomoyo_request_info".
766 767 768 769
 * @operation: Type of operation.
 * @filename:  Filename to check.
 *
 * Returns 0 on success, negative value otherwise.
770 771
 *
 * Caller holds tomoyo_read_lock().
772
 */
773 774
int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
			   const struct tomoyo_path_info *filename)
775 776 777 778
{
	int error;

 next:
T
Tetsuo Handa 已提交
779 780 781 782
	r->type = tomoyo_p2mac[operation];
	r->mode = tomoyo_get_mode(r->profile, r->type);
	if (r->mode == TOMOYO_CONFIG_DISABLED)
		return 0;
783 784 785
	r->param_type = TOMOYO_TYPE_PATH_ACL;
	r->param.path.filename = filename;
	r->param.path.operation = operation;
786
	do {
787 788
		tomoyo_check_acl(r, tomoyo_check_path_acl);
		if (!r->granted && operation == TOMOYO_TYPE_READ &&
789
		    !r->domain->ignore_global_allow_read &&
T
Tetsuo Handa 已提交
790
		    tomoyo_globally_readable_file(filename))
791 792
			r->granted = true;
		error = tomoyo_audit_path_log(r);
793 794 795 796 797 798
		/*
		 * Do not retry for execute request, for alias may have
		 * changed.
		 */
	} while (error == TOMOYO_RETRY_REQUEST &&
		 operation != TOMOYO_TYPE_EXECUTE);
799 800 801 802 803
	/*
	 * 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 已提交
804
	if (!error && operation == TOMOYO_TYPE_TRUNCATE &&
T
Tetsuo Handa 已提交
805
	    tomoyo_no_rewrite_file(filename)) {
T
Tetsuo Handa 已提交
806
		operation = TOMOYO_TYPE_REWRITE;
807 808 809 810 811
		goto next;
	}
	return error;
}

812 813 814 815 816 817 818
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 已提交
819 820 821
	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);
822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840
}

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

841 842 843 844 845 846 847 848 849 850 851
/**
 * 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.
 */
852 853 854 855 856
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)
857 858 859
{
	struct tomoyo_path_number_acl e = {
		.head.type = TOMOYO_TYPE_PATH_NUMBER_ACL,
860
		.perm = 1 << type
861 862 863 864 865 866
	};
	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;
867 868 869
	error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
				     tomoyo_same_path_number_acl,
				     tomoyo_merge_path_number_acl);
870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889
 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 已提交
890
	struct tomoyo_path_info buf;
891 892
	int idx;

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

917 918 919 920 921 922 923 924 925 926 927 928 929
/**
 * 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);
930
	int error = 0;
T
Tetsuo Handa 已提交
931
	struct tomoyo_path_info buf;
932
	struct tomoyo_request_info r;
933
	int idx;
934

T
Tetsuo Handa 已提交
935 936
	if (!path->mnt ||
	    (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode)))
937
		return 0;
T
Tetsuo Handa 已提交
938 939
	buf.name = NULL;
	r.mode = TOMOYO_CONFIG_DISABLED;
940
	idx = tomoyo_read_lock();
941 942 943 944 945
	/*
	 * 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 已提交
946 947 948 949 950 951 952
	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 已提交
953
		if (tomoyo_no_rewrite_file(&buf))
T
Tetsuo Handa 已提交
954 955
			error = tomoyo_path_permission(&r, TOMOYO_TYPE_REWRITE,
						       &buf);
956
	}
T
Tetsuo Handa 已提交
957 958 959
	if (!error && acc_mode &&
	    tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN)
	    != TOMOYO_CONFIG_DISABLED) {
960
		u8 operation;
T
Tetsuo Handa 已提交
961 962 963 964
		if (!buf.name && !tomoyo_get_realpath(&buf, path)) {
			error = -ENOMEM;
			goto out;
		}
965 966 967 968 969 970 971
		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 已提交
972
	}
973
 out:
T
Tetsuo Handa 已提交
974
	kfree(buf.name);
975
	tomoyo_read_unlock(idx);
976
	if (r.mode != TOMOYO_CONFIG_ENFORCING)
977 978 979 980 981
		error = 0;
	return error;
}

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

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

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

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

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

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

/**
T
Tetsuo Handa 已提交
1127
 * tomoyo_write_file - Update file related list.
1128 1129 1130 1131 1132 1133 1134 1135 1136
 *
 * @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 已提交
1137 1138
int tomoyo_write_file(char *data, struct tomoyo_domain_info *domain,
		      const bool is_delete)
1139 1140 1141 1142 1143
{
	char *w[5];
	u8 type;
	if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0])
		return -EINVAL;
1144
	if (strncmp(w[0], "allow_", 6))
1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167
		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 已提交
1168 1169
	for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++) {
		if (strcmp(w[0], tomoyo_mkdev_keyword[type]))
1170
			continue;
T
Tetsuo Handa 已提交
1171 1172
		return tomoyo_update_mkdev_acl(type, w[1], w[2], w[3],
					       w[4], domain, is_delete);
1173 1174 1175 1176
	}
 out:
	return -EINVAL;
}