ima_policy.c 19.5 KB
Newer Older
1 2 3 4 5 6 7 8 9
/*
 * Copyright (C) 2008 IBM Corporation
 * Author: Mimi Zohar <zohar@us.ibm.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 2 of the License.
 *
 * ima_policy.c
10
 *	- initialize default measure policy rules
11 12 13 14 15 16
 *
 */
#include <linux/module.h>
#include <linux/list.h>
#include <linux/security.h>
#include <linux/magic.h>
M
Mimi Zohar 已提交
17
#include <linux/parser.h>
18
#include <linux/slab.h>
19
#include <linux/genhd.h>
20 21 22 23

#include "ima.h"

/* flags definitions */
24 25
#define IMA_FUNC	0x0001
#define IMA_MASK	0x0002
26 27
#define IMA_FSMAGIC	0x0004
#define IMA_UID		0x0008
28
#define IMA_FOWNER	0x0010
29
#define IMA_FSUUID	0x0020
30

31 32 33 34 35
#define UNKNOWN		0
#define MEASURE		0x0001	/* same as IMA_MEASURE */
#define DONT_MEASURE	0x0002
#define APPRAISE	0x0004	/* same as IMA_APPRAISE */
#define DONT_APPRAISE	0x0008
P
Peter Moody 已提交
36
#define AUDIT		0x0040
M
Mimi Zohar 已提交
37

38 39
int ima_policy_flag;

M
Mimi Zohar 已提交
40 41 42 43
#define MAX_LSM_RULES 6
enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE,
	LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE
};
44

45
struct ima_rule_entry {
46
	struct list_head list;
M
Mimi Zohar 已提交
47
	int action;
48 49 50 51
	unsigned int flags;
	enum ima_hooks func;
	int mask;
	unsigned long fsmagic;
52
	u8 fsuuid[16];
53
	kuid_t uid;
54
	kuid_t fowner;
M
Mimi Zohar 已提交
55 56
	struct {
		void *rule;	/* LSM file metadata specific */
57
		void *args_p;	/* audit value */
M
Mimi Zohar 已提交
58 59
		int type;	/* audit type */
	} lsm[MAX_LSM_RULES];
60 61
};

62 63
/*
 * Without LSM specific knowledge, the default policy can only be
64
 * written in terms of .action, .func, .mask, .fsmagic, .uid, and .fowner
M
Mimi Zohar 已提交
65
 */
66 67 68 69 70 71 72

/*
 * The minimum rule set to allow for full TCB coverage.  Measures all files
 * opened or mmap for exec and everything read by root.  Dangerous because
 * normal users can easily run the machine out of memory simply building
 * and running executables.
 */
73
static struct ima_rule_entry default_rules[] = {
74 75 76 77 78 79 80 81 82
	{.action = DONT_MEASURE, .fsmagic = PROC_SUPER_MAGIC, .flags = IMA_FSMAGIC},
	{.action = DONT_MEASURE, .fsmagic = SYSFS_MAGIC, .flags = IMA_FSMAGIC},
	{.action = DONT_MEASURE, .fsmagic = DEBUGFS_MAGIC, .flags = IMA_FSMAGIC},
	{.action = DONT_MEASURE, .fsmagic = TMPFS_MAGIC, .flags = IMA_FSMAGIC},
	{.action = DONT_MEASURE, .fsmagic = DEVPTS_SUPER_MAGIC, .flags = IMA_FSMAGIC},
	{.action = DONT_MEASURE, .fsmagic = BINFMTFS_MAGIC, .flags = IMA_FSMAGIC},
	{.action = DONT_MEASURE, .fsmagic = SECURITYFS_MAGIC, .flags = IMA_FSMAGIC},
	{.action = DONT_MEASURE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC},
	{.action = MEASURE, .func = MMAP_CHECK, .mask = MAY_EXEC,
83
	 .flags = IMA_FUNC | IMA_MASK},
84
	{.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC,
85
	 .flags = IMA_FUNC | IMA_MASK},
86
	{.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, .uid = GLOBAL_ROOT_UID,
87
	 .flags = IMA_FUNC | IMA_MASK | IMA_UID},
88
	{.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC},
89
	{.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC},
90 91
};

92
static struct ima_rule_entry default_appraise_rules[] = {
93 94 95 96 97 98 99 100 101 102 103
	{.action = DONT_APPRAISE, .fsmagic = PROC_SUPER_MAGIC, .flags = IMA_FSMAGIC},
	{.action = DONT_APPRAISE, .fsmagic = SYSFS_MAGIC, .flags = IMA_FSMAGIC},
	{.action = DONT_APPRAISE, .fsmagic = DEBUGFS_MAGIC, .flags = IMA_FSMAGIC},
	{.action = DONT_APPRAISE, .fsmagic = TMPFS_MAGIC, .flags = IMA_FSMAGIC},
	{.action = DONT_APPRAISE, .fsmagic = RAMFS_MAGIC, .flags = IMA_FSMAGIC},
	{.action = DONT_APPRAISE, .fsmagic = DEVPTS_SUPER_MAGIC, .flags = IMA_FSMAGIC},
	{.action = DONT_APPRAISE, .fsmagic = BINFMTFS_MAGIC, .flags = IMA_FSMAGIC},
	{.action = DONT_APPRAISE, .fsmagic = SECURITYFS_MAGIC, .flags = IMA_FSMAGIC},
	{.action = DONT_APPRAISE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC},
	{.action = DONT_APPRAISE, .fsmagic = CGROUP_SUPER_MAGIC, .flags = IMA_FSMAGIC},
	{.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .flags = IMA_FOWNER},
104 105 106 107 108
};

static LIST_HEAD(ima_default_rules);
static LIST_HEAD(ima_policy_rules);
static struct list_head *ima_rules;
109

110
static DEFINE_MUTEX(ima_rules_mutex);
M
Mimi Zohar 已提交
111

112
static bool ima_use_tcb __initdata;
113
static int __init default_measure_policy_setup(char *str)
114 115 116 117
{
	ima_use_tcb = 1;
	return 1;
}
118 119 120 121 122 123 124 125 126
__setup("ima_tcb", default_measure_policy_setup);

static bool ima_use_appraise_tcb __initdata;
static int __init default_appraise_policy_setup(char *str)
{
	ima_use_appraise_tcb = 1;
	return 1;
}
__setup("ima_appraise_tcb", default_appraise_policy_setup);
127

128
/*
129 130 131 132
 * Although the IMA policy does not change, the LSM policy can be
 * reloaded, leaving the IMA LSM based rules referring to the old,
 * stale LSM policy.
 *
133
 * Update the IMA LSM based rules to reflect the reloaded LSM policy.
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
 * We assume the rules still exist; and BUG_ON() if they don't.
 */
static void ima_lsm_update_rules(void)
{
	struct ima_rule_entry *entry, *tmp;
	int result;
	int i;

	mutex_lock(&ima_rules_mutex);
	list_for_each_entry_safe(entry, tmp, &ima_policy_rules, list) {
		for (i = 0; i < MAX_LSM_RULES; i++) {
			if (!entry->lsm[i].rule)
				continue;
			result = security_filter_rule_init(entry->lsm[i].type,
							   Audit_equal,
							   entry->lsm[i].args_p,
							   &entry->lsm[i].rule);
			BUG_ON(!entry->lsm[i].rule);
		}
	}
	mutex_unlock(&ima_rules_mutex);
}

157 158 159 160 161 162 163 164 165
/**
 * ima_match_rules - determine whether an inode matches the measure rule.
 * @rule: a pointer to a rule
 * @inode: a pointer to an inode
 * @func: LIM hook identifier
 * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
 *
 * Returns true on rule match, false on failure.
 */
166
static bool ima_match_rules(struct ima_rule_entry *rule,
167 168 169
			    struct inode *inode, enum ima_hooks func, int mask)
{
	struct task_struct *tsk = current;
M
Mimi Zohar 已提交
170
	const struct cred *cred = current_cred();
M
Mimi Zohar 已提交
171
	int i;
172

173 174
	if ((rule->flags & IMA_FUNC) &&
	    (rule->func != func && func != POST_SETATTR))
175
		return false;
176 177
	if ((rule->flags & IMA_MASK) &&
	    (rule->mask != mask && func != POST_SETATTR))
178 179 180 181
		return false;
	if ((rule->flags & IMA_FSMAGIC)
	    && rule->fsmagic != inode->i_sb->s_magic)
		return false;
182
	if ((rule->flags & IMA_FSUUID) &&
183
	    memcmp(rule->fsuuid, inode->i_sb->s_uuid, sizeof(rule->fsuuid)))
184
		return false;
185
	if ((rule->flags & IMA_UID) && !uid_eq(rule->uid, cred->uid))
186
		return false;
187
	if ((rule->flags & IMA_FOWNER) && !uid_eq(rule->fowner, inode->i_uid))
188
		return false;
M
Mimi Zohar 已提交
189
	for (i = 0; i < MAX_LSM_RULES; i++) {
190
		int rc = 0;
M
Mimi Zohar 已提交
191
		u32 osid, sid;
192
		int retried = 0;
M
Mimi Zohar 已提交
193 194 195

		if (!rule->lsm[i].rule)
			continue;
196
retry:
M
Mimi Zohar 已提交
197 198 199 200 201 202 203
		switch (i) {
		case LSM_OBJ_USER:
		case LSM_OBJ_ROLE:
		case LSM_OBJ_TYPE:
			security_inode_getsecid(inode, &osid);
			rc = security_filter_rule_match(osid,
							rule->lsm[i].type,
204
							Audit_equal,
M
Mimi Zohar 已提交
205 206 207 208 209 210 211 212 213
							rule->lsm[i].rule,
							NULL);
			break;
		case LSM_SUBJ_USER:
		case LSM_SUBJ_ROLE:
		case LSM_SUBJ_TYPE:
			security_task_getsecid(tsk, &sid);
			rc = security_filter_rule_match(sid,
							rule->lsm[i].type,
214
							Audit_equal,
M
Mimi Zohar 已提交
215 216 217 218 219
							rule->lsm[i].rule,
							NULL);
		default:
			break;
		}
220 221 222 223
		if ((rc < 0) && (!retried)) {
			retried = 1;
			ima_lsm_update_rules();
			goto retry;
224
		}
M
Mimi Zohar 已提交
225 226 227
		if (!rc)
			return false;
	}
228 229 230
	return true;
}

231 232
/*
 * In addition to knowing that we need to appraise the file in general,
233
 * we need to differentiate between calling hooks, for hook specific rules.
234
 */
235
static int get_subaction(struct ima_rule_entry *rule, int func)
236
{
237 238 239
	if (!(rule->flags & IMA_FUNC))
		return IMA_FILE_APPRAISE;

240
	switch (func) {
241 242 243 244 245 246
	case MMAP_CHECK:
		return IMA_MMAP_APPRAISE;
	case BPRM_CHECK:
		return IMA_BPRM_APPRAISE;
	case MODULE_CHECK:
		return IMA_MODULE_APPRAISE;
247 248
	case FIRMWARE_CHECK:
		return IMA_FIRMWARE_APPRAISE;
249 250 251 252 253 254
	case FILE_CHECK:
	default:
		return IMA_FILE_APPRAISE;
	}
}

255 256 257 258 259 260 261 262 263 264 265 266 267
/**
 * ima_match_policy - decision based on LSM and other conditions
 * @inode: pointer to an inode for which the policy decision is being made
 * @func: IMA hook identifier
 * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
 *
 * Measure decision based on func/mask/fsmagic and LSM(subj/obj/type)
 * conditions.
 *
 * (There is no need for locking when walking the policy list,
 * as elements in the list are never deleted, nor does the list
 * change.)
 */
M
Mimi Zohar 已提交
268 269
int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
		     int flags)
270
{
271
	struct ima_rule_entry *entry;
M
Mimi Zohar 已提交
272
	int action = 0, actmask = flags | (flags << 1);
273

274
	list_for_each_entry(entry, ima_rules, list) {
275

M
Mimi Zohar 已提交
276 277 278 279 280
		if (!(entry->action & actmask))
			continue;

		if (!ima_match_rules(entry, inode, func, mask))
			continue;
281

282 283
		action |= entry->flags & IMA_ACTION_FLAGS;

284
		action |= entry->action & IMA_DO_MASK;
285
		if (entry->action & IMA_APPRAISE)
286
			action |= get_subaction(entry, func);
287

288 289 290 291
		if (entry->action & IMA_DO_MASK)
			actmask &= ~(entry->action | entry->action << 1);
		else
			actmask &= ~(entry->action | entry->action >> 1);
292

M
Mimi Zohar 已提交
293 294
		if (!actmask)
			break;
295
	}
M
Mimi Zohar 已提交
296 297

	return action;
298 299
}

300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
/*
 * Initialize the ima_policy_flag variable based on the currently
 * loaded policy.  Based on this flag, the decision to short circuit
 * out of a function or not call the function in the first place
 * can be made earlier.
 */
void ima_update_policy_flag(void)
{
	struct ima_rule_entry *entry;

	ima_policy_flag = 0;
	list_for_each_entry(entry, ima_rules, list) {
		if (entry->action & IMA_DO_MASK)
			ima_policy_flag |= entry->action;
	}

	if (!ima_appraise)
		ima_policy_flag &= ~IMA_APPRAISE;
}

320 321 322
/**
 * ima_init_policy - initialize the default measure rules.
 *
323 324
 * ima_rules points to either the ima_default_rules or the
 * the new ima_policy_rules.
325
 */
326
void __init ima_init_policy(void)
327
{
328
	int i, measure_entries, appraise_entries;
329 330

	/* if !ima_use_tcb set entries = 0 so we load NO default rules */
331 332 333
	measure_entries = ima_use_tcb ? ARRAY_SIZE(default_rules) : 0;
	appraise_entries = ima_use_appraise_tcb ?
			 ARRAY_SIZE(default_appraise_rules) : 0;
334

335 336 337 338 339 340 341 342 343 344 345 346 347
	for (i = 0; i < measure_entries + appraise_entries; i++) {
		if (i < measure_entries)
			list_add_tail(&default_rules[i].list,
				      &ima_default_rules);
		else {
			int j = i - measure_entries;

			list_add_tail(&default_appraise_rules[j].list,
				      &ima_default_rules);
		}
	}

	ima_rules = &ima_default_rules;
348
}
M
Mimi Zohar 已提交
349 350 351 352 353 354 355 356 357 358

/**
 * ima_update_policy - update default_rules with new measure rules
 *
 * Called on file .release to update the default rules with a complete new
 * policy.  Once updated, the policy is locked, no additional rules can be
 * added to the policy.
 */
void ima_update_policy(void)
{
359
	static const char op[] = "policy_update";
360
	const char *cause = "already-exists";
M
Mimi Zohar 已提交
361 362 363
	int result = 1;
	int audit_info = 0;

364 365
	if (ima_rules == &ima_default_rules) {
		ima_rules = &ima_policy_rules;
366
		ima_update_policy_flag();
M
Mimi Zohar 已提交
367 368 369 370 371 372 373 374 375 376
		cause = "complete";
		result = 0;
	}
	integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
			    NULL, op, cause, result, audit_info);
}

enum {
	Opt_err = -1,
	Opt_measure = 1, Opt_dont_measure,
377
	Opt_appraise, Opt_dont_appraise,
P
Peter Moody 已提交
378
	Opt_audit,
M
Mimi Zohar 已提交
379 380
	Opt_obj_user, Opt_obj_role, Opt_obj_type,
	Opt_subj_user, Opt_subj_role, Opt_subj_type,
381
	Opt_func, Opt_mask, Opt_fsmagic, Opt_uid, Opt_fowner,
382
	Opt_appraise_type, Opt_fsuuid, Opt_permit_directio
M
Mimi Zohar 已提交
383 384 385 386 387
};

static match_table_t policy_tokens = {
	{Opt_measure, "measure"},
	{Opt_dont_measure, "dont_measure"},
388 389
	{Opt_appraise, "appraise"},
	{Opt_dont_appraise, "dont_appraise"},
P
Peter Moody 已提交
390
	{Opt_audit, "audit"},
M
Mimi Zohar 已提交
391 392 393 394 395 396 397 398 399
	{Opt_obj_user, "obj_user=%s"},
	{Opt_obj_role, "obj_role=%s"},
	{Opt_obj_type, "obj_type=%s"},
	{Opt_subj_user, "subj_user=%s"},
	{Opt_subj_role, "subj_role=%s"},
	{Opt_subj_type, "subj_type=%s"},
	{Opt_func, "func=%s"},
	{Opt_mask, "mask=%s"},
	{Opt_fsmagic, "fsmagic=%s"},
400
	{Opt_fsuuid, "fsuuid=%s"},
M
Mimi Zohar 已提交
401
	{Opt_uid, "uid=%s"},
402
	{Opt_fowner, "fowner=%s"},
403
	{Opt_appraise_type, "appraise_type=%s"},
404
	{Opt_permit_directio, "permit_directio"},
M
Mimi Zohar 已提交
405 406 407
	{Opt_err, NULL}
};

408
static int ima_lsm_rule_init(struct ima_rule_entry *entry,
409
			     substring_t *args, int lsm_rule, int audit_type)
M
Mimi Zohar 已提交
410 411 412
{
	int result;

413 414 415
	if (entry->lsm[lsm_rule].rule)
		return -EINVAL;

416 417 418 419
	entry->lsm[lsm_rule].args_p = match_strdup(args);
	if (!entry->lsm[lsm_rule].args_p)
		return -ENOMEM;

M
Mimi Zohar 已提交
420 421
	entry->lsm[lsm_rule].type = audit_type;
	result = security_filter_rule_init(entry->lsm[lsm_rule].type,
422 423
					   Audit_equal,
					   entry->lsm[lsm_rule].args_p,
M
Mimi Zohar 已提交
424
					   &entry->lsm[lsm_rule].rule);
425 426
	if (!entry->lsm[lsm_rule].rule) {
		kfree(entry->lsm[lsm_rule].args_p);
M
Mimi Zohar 已提交
427
		return -EINVAL;
428 429
	}

M
Mimi Zohar 已提交
430 431 432
	return result;
}

433 434 435 436 437 438 439
static void ima_log_string(struct audit_buffer *ab, char *key, char *value)
{
	audit_log_format(ab, "%s=", key);
	audit_log_untrustedstring(ab, value);
	audit_log_format(ab, " ");
}

440
static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
M
Mimi Zohar 已提交
441 442 443 444 445
{
	struct audit_buffer *ab;
	char *p;
	int result = 0;

M
Mimi Zohar 已提交
446
	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE);
M
Mimi Zohar 已提交
447

448
	entry->uid = INVALID_UID;
449
	entry->fowner = INVALID_UID;
450
	entry->action = UNKNOWN;
E
Eric Paris 已提交
451
	while ((p = strsep(&rule, " \t")) != NULL) {
M
Mimi Zohar 已提交
452 453 454 455 456 457
		substring_t args[MAX_OPT_ARGS];
		int token;
		unsigned long lnum;

		if (result < 0)
			break;
E
Eric Paris 已提交
458 459
		if ((*p == '\0') || (*p == ' ') || (*p == '\t'))
			continue;
M
Mimi Zohar 已提交
460 461 462
		token = match_token(p, policy_tokens, args);
		switch (token) {
		case Opt_measure:
463
			ima_log_string(ab, "action", "measure");
464 465 466 467

			if (entry->action != UNKNOWN)
				result = -EINVAL;

M
Mimi Zohar 已提交
468 469 470
			entry->action = MEASURE;
			break;
		case Opt_dont_measure:
471
			ima_log_string(ab, "action", "dont_measure");
472 473 474 475

			if (entry->action != UNKNOWN)
				result = -EINVAL;

M
Mimi Zohar 已提交
476 477
			entry->action = DONT_MEASURE;
			break;
478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
		case Opt_appraise:
			ima_log_string(ab, "action", "appraise");

			if (entry->action != UNKNOWN)
				result = -EINVAL;

			entry->action = APPRAISE;
			break;
		case Opt_dont_appraise:
			ima_log_string(ab, "action", "dont_appraise");

			if (entry->action != UNKNOWN)
				result = -EINVAL;

			entry->action = DONT_APPRAISE;
			break;
P
Peter Moody 已提交
494 495 496 497 498 499 500 501
		case Opt_audit:
			ima_log_string(ab, "action", "audit");

			if (entry->action != UNKNOWN)
				result = -EINVAL;

			entry->action = AUDIT;
			break;
M
Mimi Zohar 已提交
502
		case Opt_func:
503
			ima_log_string(ab, "func", args[0].from);
504 505

			if (entry->func)
506
				result = -EINVAL;
507

508 509 510 511 512
			if (strcmp(args[0].from, "FILE_CHECK") == 0)
				entry->func = FILE_CHECK;
			/* PATH_CHECK is for backwards compat */
			else if (strcmp(args[0].from, "PATH_CHECK") == 0)
				entry->func = FILE_CHECK;
513 514
			else if (strcmp(args[0].from, "MODULE_CHECK") == 0)
				entry->func = MODULE_CHECK;
515 516
			else if (strcmp(args[0].from, "FIRMWARE_CHECK") == 0)
				entry->func = FIRMWARE_CHECK;
M
Mimi Zohar 已提交
517 518 519
			else if ((strcmp(args[0].from, "FILE_MMAP") == 0)
				|| (strcmp(args[0].from, "MMAP_CHECK") == 0))
				entry->func = MMAP_CHECK;
M
Mimi Zohar 已提交
520 521 522 523 524 525 526 527
			else if (strcmp(args[0].from, "BPRM_CHECK") == 0)
				entry->func = BPRM_CHECK;
			else
				result = -EINVAL;
			if (!result)
				entry->flags |= IMA_FUNC;
			break;
		case Opt_mask:
528
			ima_log_string(ab, "mask", args[0].from);
529 530 531 532

			if (entry->mask)
				result = -EINVAL;

M
Mimi Zohar 已提交
533 534 535 536 537 538 539 540 541 542 543 544 545 546
			if ((strcmp(args[0].from, "MAY_EXEC")) == 0)
				entry->mask = MAY_EXEC;
			else if (strcmp(args[0].from, "MAY_WRITE") == 0)
				entry->mask = MAY_WRITE;
			else if (strcmp(args[0].from, "MAY_READ") == 0)
				entry->mask = MAY_READ;
			else if (strcmp(args[0].from, "MAY_APPEND") == 0)
				entry->mask = MAY_APPEND;
			else
				result = -EINVAL;
			if (!result)
				entry->flags |= IMA_MASK;
			break;
		case Opt_fsmagic:
547
			ima_log_string(ab, "fsmagic", args[0].from);
548 549 550 551 552 553

			if (entry->fsmagic) {
				result = -EINVAL;
				break;
			}

554
			result = kstrtoul(args[0].from, 16, &entry->fsmagic);
M
Mimi Zohar 已提交
555 556 557
			if (!result)
				entry->flags |= IMA_FSMAGIC;
			break;
558 559 560 561
		case Opt_fsuuid:
			ima_log_string(ab, "fsuuid", args[0].from);

			if (memchr_inv(entry->fsuuid, 0x00,
562
				       sizeof(entry->fsuuid))) {
563 564 565 566
				result = -EINVAL;
				break;
			}

567 568 569 570
			result = blk_part_pack_uuid(args[0].from,
						    entry->fsuuid);
			if (!result)
				entry->flags |= IMA_FSUUID;
571
			break;
M
Mimi Zohar 已提交
572
		case Opt_uid:
573
			ima_log_string(ab, "uid", args[0].from);
574

575
			if (uid_valid(entry->uid)) {
576 577 578 579
				result = -EINVAL;
				break;
			}

580
			result = kstrtoul(args[0].from, 10, &lnum);
M
Mimi Zohar 已提交
581
			if (!result) {
582 583
				entry->uid = make_kuid(current_user_ns(), (uid_t)lnum);
				if (!uid_valid(entry->uid) || (((uid_t)lnum) != lnum))
M
Mimi Zohar 已提交
584 585 586 587 588
					result = -EINVAL;
				else
					entry->flags |= IMA_UID;
			}
			break;
589 590 591
		case Opt_fowner:
			ima_log_string(ab, "fowner", args[0].from);

592
			if (uid_valid(entry->fowner)) {
593 594 595 596
				result = -EINVAL;
				break;
			}

597
			result = kstrtoul(args[0].from, 10, &lnum);
598
			if (!result) {
599 600
				entry->fowner = make_kuid(current_user_ns(), (uid_t)lnum);
				if (!uid_valid(entry->fowner) || (((uid_t)lnum) != lnum))
601 602 603 604 605
					result = -EINVAL;
				else
					entry->flags |= IMA_FOWNER;
			}
			break;
M
Mimi Zohar 已提交
606
		case Opt_obj_user:
607
			ima_log_string(ab, "obj_user", args[0].from);
608
			result = ima_lsm_rule_init(entry, args,
M
Mimi Zohar 已提交
609 610 611 612
						   LSM_OBJ_USER,
						   AUDIT_OBJ_USER);
			break;
		case Opt_obj_role:
613
			ima_log_string(ab, "obj_role", args[0].from);
614
			result = ima_lsm_rule_init(entry, args,
M
Mimi Zohar 已提交
615 616 617 618
						   LSM_OBJ_ROLE,
						   AUDIT_OBJ_ROLE);
			break;
		case Opt_obj_type:
619
			ima_log_string(ab, "obj_type", args[0].from);
620
			result = ima_lsm_rule_init(entry, args,
M
Mimi Zohar 已提交
621 622 623 624
						   LSM_OBJ_TYPE,
						   AUDIT_OBJ_TYPE);
			break;
		case Opt_subj_user:
625
			ima_log_string(ab, "subj_user", args[0].from);
626
			result = ima_lsm_rule_init(entry, args,
M
Mimi Zohar 已提交
627 628 629 630
						   LSM_SUBJ_USER,
						   AUDIT_SUBJ_USER);
			break;
		case Opt_subj_role:
631
			ima_log_string(ab, "subj_role", args[0].from);
632
			result = ima_lsm_rule_init(entry, args,
M
Mimi Zohar 已提交
633 634 635 636
						   LSM_SUBJ_ROLE,
						   AUDIT_SUBJ_ROLE);
			break;
		case Opt_subj_type:
637
			ima_log_string(ab, "subj_type", args[0].from);
638
			result = ima_lsm_rule_init(entry, args,
M
Mimi Zohar 已提交
639 640 641
						   LSM_SUBJ_TYPE,
						   AUDIT_SUBJ_TYPE);
			break;
642 643 644 645 646 647 648 649 650 651 652 653
		case Opt_appraise_type:
			if (entry->action != APPRAISE) {
				result = -EINVAL;
				break;
			}

			ima_log_string(ab, "appraise_type", args[0].from);
			if ((strcmp(args[0].from, "imasig")) == 0)
				entry->flags |= IMA_DIGSIG_REQUIRED;
			else
				result = -EINVAL;
			break;
654 655 656
		case Opt_permit_directio:
			entry->flags |= IMA_PERMIT_DIRECTIO;
			break;
M
Mimi Zohar 已提交
657
		case Opt_err:
658
			ima_log_string(ab, "UNKNOWN", p);
659
			result = -EINVAL;
M
Mimi Zohar 已提交
660 661 662
			break;
		}
	}
663
	if (!result && (entry->action == UNKNOWN))
M
Mimi Zohar 已提交
664
		result = -EINVAL;
665 666
	else if (entry->func == MODULE_CHECK)
		ima_appraise |= IMA_APPRAISE_MODULES;
667 668
	else if (entry->func == FIRMWARE_CHECK)
		ima_appraise |= IMA_APPRAISE_FIRMWARE;
669
	audit_log_format(ab, "res=%d", !result);
M
Mimi Zohar 已提交
670 671 672 673 674
	audit_log_end(ab);
	return result;
}

/**
675
 * ima_parse_add_rule - add a rule to ima_policy_rules
M
Mimi Zohar 已提交
676 677 678
 * @rule - ima measurement policy rule
 *
 * Uses a mutex to protect the policy list from multiple concurrent writers.
679
 * Returns the length of the rule parsed, an error code on failure
M
Mimi Zohar 已提交
680
 */
681
ssize_t ima_parse_add_rule(char *rule)
M
Mimi Zohar 已提交
682
{
683
	static const char op[] = "update_policy";
684
	char *p;
685
	struct ima_rule_entry *entry;
686
	ssize_t result, len;
M
Mimi Zohar 已提交
687 688 689
	int audit_info = 0;

	/* Prevent installed policy from changing */
690
	if (ima_rules != &ima_default_rules) {
M
Mimi Zohar 已提交
691
		integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
692
				    NULL, op, "already-exists",
M
Mimi Zohar 已提交
693 694 695 696
				    -EACCES, audit_info);
		return -EACCES;
	}

697 698
	p = strsep(&rule, "\n");
	len = strlen(p) + 1;
699
	p += strspn(p, " \t");
700

701
	if (*p == '#' || *p == '\0')
702 703
		return len;

M
Mimi Zohar 已提交
704 705 706 707 708 709 710 711 712
	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
	if (!entry) {
		integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
				    NULL, op, "-ENOMEM", -ENOMEM, audit_info);
		return -ENOMEM;
	}

	INIT_LIST_HEAD(&entry->list);

713
	result = ima_parse_rule(p, entry);
E
Eric Paris 已提交
714
	if (result) {
M
Mimi Zohar 已提交
715
		kfree(entry);
M
Mimi Zohar 已提交
716
		integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
717
				    NULL, op, "invalid-policy", result,
M
Mimi Zohar 已提交
718
				    audit_info);
E
Eric Paris 已提交
719
		return result;
M
Mimi Zohar 已提交
720
	}
E
Eric Paris 已提交
721

722 723 724
	mutex_lock(&ima_rules_mutex);
	list_add_tail(&entry->list, &ima_policy_rules);
	mutex_unlock(&ima_rules_mutex);
E
Eric Paris 已提交
725 726

	return len;
M
Mimi Zohar 已提交
727 728 729
}

/* ima_delete_rules called to cleanup invalid policy */
730
void ima_delete_rules(void)
M
Mimi Zohar 已提交
731
{
732
	struct ima_rule_entry *entry, *tmp;
733
	int i;
M
Mimi Zohar 已提交
734

735 736
	mutex_lock(&ima_rules_mutex);
	list_for_each_entry_safe(entry, tmp, &ima_policy_rules, list) {
737 738 739
		for (i = 0; i < MAX_LSM_RULES; i++)
			kfree(entry->lsm[i].args_p);

M
Mimi Zohar 已提交
740 741 742
		list_del(&entry->list);
		kfree(entry);
	}
743
	mutex_unlock(&ima_rules_mutex);
M
Mimi Zohar 已提交
744
}