aboutsummaryrefslogtreecommitdiffstats
path: root/security/integrity/ima/ima_policy.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/integrity/ima/ima_policy.c')
-rw-r--r--security/integrity/ima/ima_policy.c107
1 files changed, 79 insertions, 28 deletions
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 8643a93c5963..aef8c0a923ab 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -246,6 +246,9 @@ static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry,
246{ 246{
247 int result; 247 int result;
248 248
249 if (entry->lsm[lsm_rule].rule)
250 return -EINVAL;
251
249 entry->lsm[lsm_rule].type = audit_type; 252 entry->lsm[lsm_rule].type = audit_type;
250 result = security_filter_rule_init(entry->lsm[lsm_rule].type, 253 result = security_filter_rule_init(entry->lsm[lsm_rule].type,
251 Audit_equal, args, 254 Audit_equal, args,
@@ -253,6 +256,13 @@ static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry,
253 return result; 256 return result;
254} 257}
255 258
259static void ima_log_string(struct audit_buffer *ab, char *key, char *value)
260{
261 audit_log_format(ab, "%s=", key);
262 audit_log_untrustedstring(ab, value);
263 audit_log_format(ab, " ");
264}
265
256static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) 266static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
257{ 267{
258 struct audit_buffer *ab; 268 struct audit_buffer *ab;
@@ -261,28 +271,41 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
261 271
262 ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE); 272 ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE);
263 273
264 entry->action = -1; 274 entry->uid = -1;
265 while ((p = strsep(&rule, " \n")) != NULL) { 275 entry->action = UNKNOWN;
276 while ((p = strsep(&rule, " \t")) != NULL) {
266 substring_t args[MAX_OPT_ARGS]; 277 substring_t args[MAX_OPT_ARGS];
267 int token; 278 int token;
268 unsigned long lnum; 279 unsigned long lnum;
269 280
270 if (result < 0) 281 if (result < 0)
271 break; 282 break;
272 if (!*p) 283 if ((*p == '\0') || (*p == ' ') || (*p == '\t'))
273 continue; 284 continue;
274 token = match_token(p, policy_tokens, args); 285 token = match_token(p, policy_tokens, args);
275 switch (token) { 286 switch (token) {
276 case Opt_measure: 287 case Opt_measure:
277 audit_log_format(ab, "%s ", "measure"); 288 ima_log_string(ab, "action", "measure");
289
290 if (entry->action != UNKNOWN)
291 result = -EINVAL;
292
278 entry->action = MEASURE; 293 entry->action = MEASURE;
279 break; 294 break;
280 case Opt_dont_measure: 295 case Opt_dont_measure:
281 audit_log_format(ab, "%s ", "dont_measure"); 296 ima_log_string(ab, "action", "dont_measure");
297
298 if (entry->action != UNKNOWN)
299 result = -EINVAL;
300
282 entry->action = DONT_MEASURE; 301 entry->action = DONT_MEASURE;
283 break; 302 break;
284 case Opt_func: 303 case Opt_func:
285 audit_log_format(ab, "func=%s ", args[0].from); 304 ima_log_string(ab, "func", args[0].from);
305
306 if (entry->func)
307 result = -EINVAL;
308
286 if (strcmp(args[0].from, "FILE_CHECK") == 0) 309 if (strcmp(args[0].from, "FILE_CHECK") == 0)
287 entry->func = FILE_CHECK; 310 entry->func = FILE_CHECK;
288 /* PATH_CHECK is for backwards compat */ 311 /* PATH_CHECK is for backwards compat */
@@ -298,7 +321,11 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
298 entry->flags |= IMA_FUNC; 321 entry->flags |= IMA_FUNC;
299 break; 322 break;
300 case Opt_mask: 323 case Opt_mask:
301 audit_log_format(ab, "mask=%s ", args[0].from); 324 ima_log_string(ab, "mask", args[0].from);
325
326 if (entry->mask)
327 result = -EINVAL;
328
302 if ((strcmp(args[0].from, "MAY_EXEC")) == 0) 329 if ((strcmp(args[0].from, "MAY_EXEC")) == 0)
303 entry->mask = MAY_EXEC; 330 entry->mask = MAY_EXEC;
304 else if (strcmp(args[0].from, "MAY_WRITE") == 0) 331 else if (strcmp(args[0].from, "MAY_WRITE") == 0)
@@ -313,14 +340,26 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
313 entry->flags |= IMA_MASK; 340 entry->flags |= IMA_MASK;
314 break; 341 break;
315 case Opt_fsmagic: 342 case Opt_fsmagic:
316 audit_log_format(ab, "fsmagic=%s ", args[0].from); 343 ima_log_string(ab, "fsmagic", args[0].from);
344
345 if (entry->fsmagic) {
346 result = -EINVAL;
347 break;
348 }
349
317 result = strict_strtoul(args[0].from, 16, 350 result = strict_strtoul(args[0].from, 16,
318 &entry->fsmagic); 351 &entry->fsmagic);
319 if (!result) 352 if (!result)
320 entry->flags |= IMA_FSMAGIC; 353 entry->flags |= IMA_FSMAGIC;
321 break; 354 break;
322 case Opt_uid: 355 case Opt_uid:
323 audit_log_format(ab, "uid=%s ", args[0].from); 356 ima_log_string(ab, "uid", args[0].from);
357
358 if (entry->uid != -1) {
359 result = -EINVAL;
360 break;
361 }
362
324 result = strict_strtoul(args[0].from, 10, &lnum); 363 result = strict_strtoul(args[0].from, 10, &lnum);
325 if (!result) { 364 if (!result) {
326 entry->uid = (uid_t) lnum; 365 entry->uid = (uid_t) lnum;
@@ -331,50 +370,51 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
331 } 370 }
332 break; 371 break;
333 case Opt_obj_user: 372 case Opt_obj_user:
334 audit_log_format(ab, "obj_user=%s ", args[0].from); 373 ima_log_string(ab, "obj_user", args[0].from);
335 result = ima_lsm_rule_init(entry, args[0].from, 374 result = ima_lsm_rule_init(entry, args[0].from,
336 LSM_OBJ_USER, 375 LSM_OBJ_USER,
337 AUDIT_OBJ_USER); 376 AUDIT_OBJ_USER);
338 break; 377 break;
339 case Opt_obj_role: 378 case Opt_obj_role:
340 audit_log_format(ab, "obj_role=%s ", args[0].from); 379 ima_log_string(ab, "obj_role", args[0].from);
341 result = ima_lsm_rule_init(entry, args[0].from, 380 result = ima_lsm_rule_init(entry, args[0].from,
342 LSM_OBJ_ROLE, 381 LSM_OBJ_ROLE,
343 AUDIT_OBJ_ROLE); 382 AUDIT_OBJ_ROLE);
344 break; 383 break;
345 case Opt_obj_type: 384 case Opt_obj_type:
346 audit_log_format(ab, "obj_type=%s ", args[0].from); 385 ima_log_string(ab, "obj_type", args[0].from);
347 result = ima_lsm_rule_init(entry, args[0].from, 386 result = ima_lsm_rule_init(entry, args[0].from,
348 LSM_OBJ_TYPE, 387 LSM_OBJ_TYPE,
349 AUDIT_OBJ_TYPE); 388 AUDIT_OBJ_TYPE);
350 break; 389 break;
351 case Opt_subj_user: 390 case Opt_subj_user:
352 audit_log_format(ab, "subj_user=%s ", args[0].from); 391 ima_log_string(ab, "subj_user", args[0].from);
353 result = ima_lsm_rule_init(entry, args[0].from, 392 result = ima_lsm_rule_init(entry, args[0].from,
354 LSM_SUBJ_USER, 393 LSM_SUBJ_USER,
355 AUDIT_SUBJ_USER); 394 AUDIT_SUBJ_USER);
356 break; 395 break;
357 case Opt_subj_role: 396 case Opt_subj_role:
358 audit_log_format(ab, "subj_role=%s ", args[0].from); 397 ima_log_string(ab, "subj_role", args[0].from);
359 result = ima_lsm_rule_init(entry, args[0].from, 398 result = ima_lsm_rule_init(entry, args[0].from,
360 LSM_SUBJ_ROLE, 399 LSM_SUBJ_ROLE,
361 AUDIT_SUBJ_ROLE); 400 AUDIT_SUBJ_ROLE);
362 break; 401 break;
363 case Opt_subj_type: 402 case Opt_subj_type:
364 audit_log_format(ab, "subj_type=%s ", args[0].from); 403 ima_log_string(ab, "subj_type", args[0].from);
365 result = ima_lsm_rule_init(entry, args[0].from, 404 result = ima_lsm_rule_init(entry, args[0].from,
366 LSM_SUBJ_TYPE, 405 LSM_SUBJ_TYPE,
367 AUDIT_SUBJ_TYPE); 406 AUDIT_SUBJ_TYPE);
368 break; 407 break;
369 case Opt_err: 408 case Opt_err:
370 audit_log_format(ab, "UNKNOWN=%s ", p); 409 ima_log_string(ab, "UNKNOWN", p);
410 result = -EINVAL;
371 break; 411 break;
372 } 412 }
373 } 413 }
374 if (entry->action == UNKNOWN) 414 if (!result && (entry->action == UNKNOWN))
375 result = -EINVAL; 415 result = -EINVAL;
376 416
377 audit_log_format(ab, "res=%d", !result ? 0 : 1); 417 audit_log_format(ab, "res=%d", !!result);
378 audit_log_end(ab); 418 audit_log_end(ab);
379 return result; 419 return result;
380} 420}
@@ -384,13 +424,14 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
384 * @rule - ima measurement policy rule 424 * @rule - ima measurement policy rule
385 * 425 *
386 * Uses a mutex to protect the policy list from multiple concurrent writers. 426 * Uses a mutex to protect the policy list from multiple concurrent writers.
387 * Returns 0 on success, an error code on failure. 427 * Returns the length of the rule parsed, an error code on failure
388 */ 428 */
389int ima_parse_add_rule(char *rule) 429ssize_t ima_parse_add_rule(char *rule)
390{ 430{
391 const char *op = "update_policy"; 431 const char *op = "update_policy";
432 char *p;
392 struct ima_measure_rule_entry *entry; 433 struct ima_measure_rule_entry *entry;
393 int result = 0; 434 ssize_t result, len;
394 int audit_info = 0; 435 int audit_info = 0;
395 436
396 /* Prevent installed policy from changing */ 437 /* Prevent installed policy from changing */
@@ -410,18 +451,28 @@ int ima_parse_add_rule(char *rule)
410 451
411 INIT_LIST_HEAD(&entry->list); 452 INIT_LIST_HEAD(&entry->list);
412 453
413 result = ima_parse_rule(rule, entry); 454 p = strsep(&rule, "\n");
414 if (!result) { 455 len = strlen(p) + 1;
415 mutex_lock(&ima_measure_mutex); 456
416 list_add_tail(&entry->list, &measure_policy_rules); 457 if (*p == '#') {
417 mutex_unlock(&ima_measure_mutex); 458 kfree(entry);
418 } else { 459 return len;
460 }
461
462 result = ima_parse_rule(p, entry);
463 if (result) {
419 kfree(entry); 464 kfree(entry);
420 integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, 465 integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
421 NULL, op, "invalid policy", result, 466 NULL, op, "invalid policy", result,
422 audit_info); 467 audit_info);
468 return result;
423 } 469 }
424 return result; 470
471 mutex_lock(&ima_measure_mutex);
472 list_add_tail(&entry->list, &measure_policy_rules);
473 mutex_unlock(&ima_measure_mutex);
474
475 return len;
425} 476}
426 477
427/* ima_delete_rules called to cleanup invalid policy */ 478/* ima_delete_rules called to cleanup invalid policy */