Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

audit: Add typespecific uid and gid comparators

The audit filter code guarantees that uid are always compared with
uids and gids are always compared with gids, as the comparason
operations are type specific. Take advantage of this proper to define
audit_uid_comparator and audit_gid_comparator which use the type safe
comparasons from uidgid.h.

Build on audit_uid_comparator and audit_gid_comparator and replace
audit_compare_id with audit_compare_uid and audit_compare_gid. This
is one of those odd cases where being type safe and duplicating code
leads to simpler shorter and more concise code.

Don't allow bitmask operations in uid and gid comparisons in
audit_data_to_entry. Bitmask operations are already denined in
audit_rule_to_entry.

Convert constants in audit_rule_to_entry and audit_data_to_entry into
kuids and kgids when appropriate.

Convert the uid and gid field in struct audit_names to be of type
kuid_t and kgid_t respectively, so that the new uid and gid comparators
can be applied in a type safe manner.

Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Eric Paris <eparis@redhat.com>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>

+184 -89
+2
include/linux/audit.h
··· 442 442 struct audit_field { 443 443 u32 type; 444 444 u32 val; 445 + kuid_t uid; 446 + kgid_t gid; 445 447 u32 op; 446 448 char *lsm_str; 447 449 void *lsm_rule;
+2
kernel/audit.h
··· 76 76 77 77 extern int audit_match_class(int class, unsigned syscall); 78 78 extern int audit_comparator(const u32 left, const u32 op, const u32 right); 79 + extern int audit_uid_comparator(kuid_t left, u32 op, kuid_t right); 80 + extern int audit_gid_comparator(kgid_t left, u32 op, kgid_t right); 79 81 extern int audit_compare_dname_path(const char *dname, const char *path, 80 82 int *dirlen); 81 83 extern struct sk_buff * audit_make_reply(int pid, int seq, int type,
+109 -10
kernel/auditfilter.c
··· 342 342 343 343 f->type = rule->fields[i] & ~(AUDIT_NEGATE|AUDIT_OPERATORS); 344 344 f->val = rule->values[i]; 345 + f->uid = INVALID_UID; 346 + f->gid = INVALID_GID; 345 347 346 348 err = -EINVAL; 347 349 if (f->op == Audit_bad) ··· 352 350 switch(f->type) { 353 351 default: 354 352 goto exit_free; 355 - case AUDIT_PID: 356 353 case AUDIT_UID: 357 354 case AUDIT_EUID: 358 355 case AUDIT_SUID: 359 356 case AUDIT_FSUID: 357 + case AUDIT_LOGINUID: 358 + /* bit ops not implemented for uid comparisons */ 359 + if (f->op == Audit_bitmask || f->op == Audit_bittest) 360 + goto exit_free; 361 + 362 + f->uid = make_kuid(current_user_ns(), f->val); 363 + if (!uid_valid(f->uid)) 364 + goto exit_free; 365 + break; 360 366 case AUDIT_GID: 361 367 case AUDIT_EGID: 362 368 case AUDIT_SGID: 363 369 case AUDIT_FSGID: 364 - case AUDIT_LOGINUID: 370 + /* bit ops not implemented for gid comparisons */ 371 + if (f->op == Audit_bitmask || f->op == Audit_bittest) 372 + goto exit_free; 373 + 374 + f->gid = make_kgid(current_user_ns(), f->val); 375 + if (!gid_valid(f->gid)) 376 + goto exit_free; 377 + break; 378 + case AUDIT_PID: 365 379 case AUDIT_PERS: 366 380 case AUDIT_MSGTYPE: 367 381 case AUDIT_PPID: ··· 455 437 456 438 f->type = data->fields[i]; 457 439 f->val = data->values[i]; 440 + f->uid = INVALID_UID; 441 + f->gid = INVALID_GID; 458 442 f->lsm_str = NULL; 459 443 f->lsm_rule = NULL; 460 444 switch(f->type) { 461 - case AUDIT_PID: 462 445 case AUDIT_UID: 463 446 case AUDIT_EUID: 464 447 case AUDIT_SUID: 465 448 case AUDIT_FSUID: 449 + case AUDIT_LOGINUID: 450 + case AUDIT_OBJ_UID: 451 + /* bit ops not implemented for uid comparisons */ 452 + if (f->op == Audit_bitmask || f->op == Audit_bittest) 453 + goto exit_free; 454 + 455 + f->uid = make_kuid(current_user_ns(), f->val); 456 + if (!uid_valid(f->uid)) 457 + goto exit_free; 458 + break; 466 459 case AUDIT_GID: 467 460 case AUDIT_EGID: 468 461 case AUDIT_SGID: 469 462 case AUDIT_FSGID: 470 - case AUDIT_LOGINUID: 463 + case AUDIT_OBJ_GID: 464 + /* bit ops not implemented for gid comparisons */ 465 + if (f->op == Audit_bitmask || f->op == Audit_bittest) 466 + goto exit_free; 467 + 468 + f->gid = make_kgid(current_user_ns(), f->val); 469 + if (!gid_valid(f->gid)) 470 + goto exit_free; 471 + break; 472 + case AUDIT_PID: 471 473 case AUDIT_PERS: 472 474 case AUDIT_MSGTYPE: 473 475 case AUDIT_PPID: ··· 499 461 case AUDIT_ARG1: 500 462 case AUDIT_ARG2: 501 463 case AUDIT_ARG3: 502 - case AUDIT_OBJ_UID: 503 - case AUDIT_OBJ_GID: 504 464 break; 505 465 case AUDIT_ARCH: 506 466 entry->rule.arch_f = f; ··· 741 705 case AUDIT_FILTERKEY: 742 706 /* both filterkeys exist based on above type compare */ 743 707 if (strcmp(a->filterkey, b->filterkey)) 708 + return 1; 709 + break; 710 + case AUDIT_UID: 711 + case AUDIT_EUID: 712 + case AUDIT_SUID: 713 + case AUDIT_FSUID: 714 + case AUDIT_LOGINUID: 715 + case AUDIT_OBJ_UID: 716 + if (!uid_eq(a->fields[i].uid, b->fields[i].uid)) 717 + return 1; 718 + break; 719 + case AUDIT_GID: 720 + case AUDIT_EGID: 721 + case AUDIT_SGID: 722 + case AUDIT_FSGID: 723 + case AUDIT_OBJ_GID: 724 + if (!gid_eq(a->fields[i].gid, b->fields[i].gid)) 744 725 return 1; 745 726 break; 746 727 default: ··· 1251 1198 } 1252 1199 } 1253 1200 1201 + int audit_uid_comparator(kuid_t left, u32 op, kuid_t right) 1202 + { 1203 + switch (op) { 1204 + case Audit_equal: 1205 + return uid_eq(left, right); 1206 + case Audit_not_equal: 1207 + return !uid_eq(left, right); 1208 + case Audit_lt: 1209 + return uid_lt(left, right); 1210 + case Audit_le: 1211 + return uid_lte(left, right); 1212 + case Audit_gt: 1213 + return uid_gt(left, right); 1214 + case Audit_ge: 1215 + return uid_gte(left, right); 1216 + case Audit_bitmask: 1217 + case Audit_bittest: 1218 + default: 1219 + BUG(); 1220 + return 0; 1221 + } 1222 + } 1223 + 1224 + int audit_gid_comparator(kgid_t left, u32 op, kgid_t right) 1225 + { 1226 + switch (op) { 1227 + case Audit_equal: 1228 + return gid_eq(left, right); 1229 + case Audit_not_equal: 1230 + return !gid_eq(left, right); 1231 + case Audit_lt: 1232 + return gid_lt(left, right); 1233 + case Audit_le: 1234 + return gid_lte(left, right); 1235 + case Audit_gt: 1236 + return gid_gt(left, right); 1237 + case Audit_ge: 1238 + return gid_gte(left, right); 1239 + case Audit_bitmask: 1240 + case Audit_bittest: 1241 + default: 1242 + BUG(); 1243 + return 0; 1244 + } 1245 + } 1246 + 1254 1247 /* Compare given dentry name with last component in given path, 1255 1248 * return of 0 indicates a match. */ 1256 1249 int audit_compare_dname_path(const char *dname, const char *path, ··· 1350 1251 result = audit_comparator(task_pid_vnr(current), f->op, f->val); 1351 1252 break; 1352 1253 case AUDIT_UID: 1353 - result = audit_comparator(current_uid(), f->op, f->val); 1254 + result = audit_uid_comparator(current_uid(), f->op, f->uid); 1354 1255 break; 1355 1256 case AUDIT_GID: 1356 - result = audit_comparator(current_gid(), f->op, f->val); 1257 + result = audit_gid_comparator(current_gid(), f->op, f->gid); 1357 1258 break; 1358 1259 case AUDIT_LOGINUID: 1359 - result = audit_comparator(audit_get_loginuid(current), 1360 - f->op, f->val); 1260 + result = audit_uid_comparator(audit_get_loginuid(current), 1261 + f->op, f->uid); 1361 1262 break; 1362 1263 case AUDIT_SUBJ_USER: 1363 1264 case AUDIT_SUBJ_ROLE:
+71 -79
kernel/auditsc.c
··· 113 113 unsigned long ino; 114 114 dev_t dev; 115 115 umode_t mode; 116 - uid_t uid; 117 - gid_t gid; 116 + kuid_t uid; 117 + kgid_t gid; 118 118 dev_t rdev; 119 119 u32 osid; 120 120 struct audit_cap_data fcap; ··· 464 464 return 0; 465 465 } 466 466 467 - static int audit_compare_id(uid_t uid1, 468 - struct audit_names *name, 469 - unsigned long name_offset, 470 - struct audit_field *f, 471 - struct audit_context *ctx) 467 + static int audit_compare_uid(kuid_t uid, 468 + struct audit_names *name, 469 + struct audit_field *f, 470 + struct audit_context *ctx) 472 471 { 473 472 struct audit_names *n; 474 - unsigned long addr; 475 - uid_t uid2; 476 473 int rc; 477 - 478 - BUILD_BUG_ON(sizeof(uid_t) != sizeof(gid_t)); 479 - 474 + 480 475 if (name) { 481 - addr = (unsigned long)name; 482 - addr += name_offset; 483 - 484 - uid2 = *(uid_t *)addr; 485 - rc = audit_comparator(uid1, f->op, uid2); 476 + rc = audit_uid_comparator(uid, f->op, name->uid); 486 477 if (rc) 487 478 return rc; 488 479 } 489 - 480 + 490 481 if (ctx) { 491 482 list_for_each_entry(n, &ctx->names_list, list) { 492 - addr = (unsigned long)n; 493 - addr += name_offset; 483 + rc = audit_uid_comparator(uid, f->op, n->uid); 484 + if (rc) 485 + return rc; 486 + } 487 + } 488 + return 0; 489 + } 494 490 495 - uid2 = *(uid_t *)addr; 496 - 497 - rc = audit_comparator(uid1, f->op, uid2); 491 + static int audit_compare_gid(kgid_t gid, 492 + struct audit_names *name, 493 + struct audit_field *f, 494 + struct audit_context *ctx) 495 + { 496 + struct audit_names *n; 497 + int rc; 498 + 499 + if (name) { 500 + rc = audit_gid_comparator(gid, f->op, name->gid); 501 + if (rc) 502 + return rc; 503 + } 504 + 505 + if (ctx) { 506 + list_for_each_entry(n, &ctx->names_list, list) { 507 + rc = audit_gid_comparator(gid, f->op, n->gid); 498 508 if (rc) 499 509 return rc; 500 510 } ··· 521 511 switch (f->val) { 522 512 /* process to file object comparisons */ 523 513 case AUDIT_COMPARE_UID_TO_OBJ_UID: 524 - return audit_compare_id(cred->uid, 525 - name, offsetof(struct audit_names, uid), 526 - f, ctx); 514 + return audit_compare_uid(cred->uid, name, f, ctx); 527 515 case AUDIT_COMPARE_GID_TO_OBJ_GID: 528 - return audit_compare_id(cred->gid, 529 - name, offsetof(struct audit_names, gid), 530 - f, ctx); 516 + return audit_compare_gid(cred->gid, name, f, ctx); 531 517 case AUDIT_COMPARE_EUID_TO_OBJ_UID: 532 - return audit_compare_id(cred->euid, 533 - name, offsetof(struct audit_names, uid), 534 - f, ctx); 518 + return audit_compare_uid(cred->euid, name, f, ctx); 535 519 case AUDIT_COMPARE_EGID_TO_OBJ_GID: 536 - return audit_compare_id(cred->egid, 537 - name, offsetof(struct audit_names, gid), 538 - f, ctx); 520 + return audit_compare_gid(cred->egid, name, f, ctx); 539 521 case AUDIT_COMPARE_AUID_TO_OBJ_UID: 540 - return audit_compare_id(tsk->loginuid, 541 - name, offsetof(struct audit_names, uid), 542 - f, ctx); 522 + return audit_compare_uid(tsk->loginuid, name, f, ctx); 543 523 case AUDIT_COMPARE_SUID_TO_OBJ_UID: 544 - return audit_compare_id(cred->suid, 545 - name, offsetof(struct audit_names, uid), 546 - f, ctx); 524 + return audit_compare_uid(cred->suid, name, f, ctx); 547 525 case AUDIT_COMPARE_SGID_TO_OBJ_GID: 548 - return audit_compare_id(cred->sgid, 549 - name, offsetof(struct audit_names, gid), 550 - f, ctx); 526 + return audit_compare_gid(cred->sgid, name, f, ctx); 551 527 case AUDIT_COMPARE_FSUID_TO_OBJ_UID: 552 - return audit_compare_id(cred->fsuid, 553 - name, offsetof(struct audit_names, uid), 554 - f, ctx); 528 + return audit_compare_uid(cred->fsuid, name, f, ctx); 555 529 case AUDIT_COMPARE_FSGID_TO_OBJ_GID: 556 - return audit_compare_id(cred->fsgid, 557 - name, offsetof(struct audit_names, gid), 558 - f, ctx); 530 + return audit_compare_gid(cred->fsgid, name, f, ctx); 559 531 /* uid comparisons */ 560 532 case AUDIT_COMPARE_UID_TO_AUID: 561 - return audit_comparator(cred->uid, f->op, tsk->loginuid); 533 + return audit_uid_comparator(cred->uid, f->op, tsk->loginuid); 562 534 case AUDIT_COMPARE_UID_TO_EUID: 563 - return audit_comparator(cred->uid, f->op, cred->euid); 535 + return audit_uid_comparator(cred->uid, f->op, cred->euid); 564 536 case AUDIT_COMPARE_UID_TO_SUID: 565 - return audit_comparator(cred->uid, f->op, cred->suid); 537 + return audit_uid_comparator(cred->uid, f->op, cred->suid); 566 538 case AUDIT_COMPARE_UID_TO_FSUID: 567 - return audit_comparator(cred->uid, f->op, cred->fsuid); 539 + return audit_uid_comparator(cred->uid, f->op, cred->fsuid); 568 540 /* auid comparisons */ 569 541 case AUDIT_COMPARE_AUID_TO_EUID: 570 - return audit_comparator(tsk->loginuid, f->op, cred->euid); 542 + return audit_uid_comparator(tsk->loginuid, f->op, cred->euid); 571 543 case AUDIT_COMPARE_AUID_TO_SUID: 572 - return audit_comparator(tsk->loginuid, f->op, cred->suid); 544 + return audit_uid_comparator(tsk->loginuid, f->op, cred->suid); 573 545 case AUDIT_COMPARE_AUID_TO_FSUID: 574 - return audit_comparator(tsk->loginuid, f->op, cred->fsuid); 546 + return audit_uid_comparator(tsk->loginuid, f->op, cred->fsuid); 575 547 /* euid comparisons */ 576 548 case AUDIT_COMPARE_EUID_TO_SUID: 577 - return audit_comparator(cred->euid, f->op, cred->suid); 549 + return audit_uid_comparator(cred->euid, f->op, cred->suid); 578 550 case AUDIT_COMPARE_EUID_TO_FSUID: 579 - return audit_comparator(cred->euid, f->op, cred->fsuid); 551 + return audit_uid_comparator(cred->euid, f->op, cred->fsuid); 580 552 /* suid comparisons */ 581 553 case AUDIT_COMPARE_SUID_TO_FSUID: 582 - return audit_comparator(cred->suid, f->op, cred->fsuid); 554 + return audit_uid_comparator(cred->suid, f->op, cred->fsuid); 583 555 /* gid comparisons */ 584 556 case AUDIT_COMPARE_GID_TO_EGID: 585 - return audit_comparator(cred->gid, f->op, cred->egid); 557 + return audit_gid_comparator(cred->gid, f->op, cred->egid); 586 558 case AUDIT_COMPARE_GID_TO_SGID: 587 - return audit_comparator(cred->gid, f->op, cred->sgid); 559 + return audit_gid_comparator(cred->gid, f->op, cred->sgid); 588 560 case AUDIT_COMPARE_GID_TO_FSGID: 589 - return audit_comparator(cred->gid, f->op, cred->fsgid); 561 + return audit_gid_comparator(cred->gid, f->op, cred->fsgid); 590 562 /* egid comparisons */ 591 563 case AUDIT_COMPARE_EGID_TO_SGID: 592 - return audit_comparator(cred->egid, f->op, cred->sgid); 564 + return audit_gid_comparator(cred->egid, f->op, cred->sgid); 593 565 case AUDIT_COMPARE_EGID_TO_FSGID: 594 - return audit_comparator(cred->egid, f->op, cred->fsgid); 566 + return audit_gid_comparator(cred->egid, f->op, cred->fsgid); 595 567 /* sgid comparison */ 596 568 case AUDIT_COMPARE_SGID_TO_FSGID: 597 - return audit_comparator(cred->sgid, f->op, cred->fsgid); 569 + return audit_gid_comparator(cred->sgid, f->op, cred->fsgid); 598 570 default: 599 571 WARN(1, "Missing AUDIT_COMPARE define. Report as a bug\n"); 600 572 return 0; ··· 622 630 } 623 631 break; 624 632 case AUDIT_UID: 625 - result = audit_comparator(cred->uid, f->op, f->val); 633 + result = audit_uid_comparator(cred->uid, f->op, f->uid); 626 634 break; 627 635 case AUDIT_EUID: 628 - result = audit_comparator(cred->euid, f->op, f->val); 636 + result = audit_uid_comparator(cred->euid, f->op, f->uid); 629 637 break; 630 638 case AUDIT_SUID: 631 - result = audit_comparator(cred->suid, f->op, f->val); 639 + result = audit_uid_comparator(cred->suid, f->op, f->uid); 632 640 break; 633 641 case AUDIT_FSUID: 634 - result = audit_comparator(cred->fsuid, f->op, f->val); 642 + result = audit_uid_comparator(cred->fsuid, f->op, f->uid); 635 643 break; 636 644 case AUDIT_GID: 637 - result = audit_comparator(cred->gid, f->op, f->val); 645 + result = audit_gid_comparator(cred->gid, f->op, f->gid); 638 646 break; 639 647 case AUDIT_EGID: 640 - result = audit_comparator(cred->egid, f->op, f->val); 648 + result = audit_gid_comparator(cred->egid, f->op, f->gid); 641 649 break; 642 650 case AUDIT_SGID: 643 - result = audit_comparator(cred->sgid, f->op, f->val); 651 + result = audit_gid_comparator(cred->sgid, f->op, f->gid); 644 652 break; 645 653 case AUDIT_FSGID: 646 - result = audit_comparator(cred->fsgid, f->op, f->val); 654 + result = audit_gid_comparator(cred->fsgid, f->op, f->gid); 647 655 break; 648 656 case AUDIT_PERS: 649 657 result = audit_comparator(tsk->personality, f->op, f->val); ··· 709 717 break; 710 718 case AUDIT_OBJ_UID: 711 719 if (name) { 712 - result = audit_comparator(name->uid, f->op, f->val); 720 + result = audit_uid_comparator(name->uid, f->op, f->uid); 713 721 } else if (ctx) { 714 722 list_for_each_entry(n, &ctx->names_list, list) { 715 - if (audit_comparator(n->uid, f->op, f->val)) { 723 + if (audit_uid_comparator(n->uid, f->op, f->uid)) { 716 724 ++result; 717 725 break; 718 726 } ··· 721 729 break; 722 730 case AUDIT_OBJ_GID: 723 731 if (name) { 724 - result = audit_comparator(name->gid, f->op, f->val); 732 + result = audit_gid_comparator(name->gid, f->op, f->gid); 725 733 } else if (ctx) { 726 734 list_for_each_entry(n, &ctx->names_list, list) { 727 - if (audit_comparator(n->gid, f->op, f->val)) { 735 + if (audit_gid_comparator(n->gid, f->op, f->gid)) { 728 736 ++result; 729 737 break; 730 738 } ··· 742 750 case AUDIT_LOGINUID: 743 751 result = 0; 744 752 if (ctx) 745 - result = audit_comparator(tsk->loginuid, f->op, f->val); 753 + result = audit_uid_comparator(tsk->loginuid, f->op, f->uid); 746 754 break; 747 755 case AUDIT_SUBJ_USER: 748 756 case AUDIT_SUBJ_ROLE: