audit rule additions containing "-F auid!=4294967295" were failing with EINVAL because of a regression caused by e1760bd. Apparently some userland audit rule sets want to know if loginuid uid has been set and are using a test for auid != 4294967295 to determine that. In practice that is a horrible way to ask if a value has been set, because it relies on subtle implementation details and will break every time the uid implementation in the kernel changes. So add a clean way to test if the audit loginuid has been set, and silently convert the old idiom to the cleaner and more comprehensible new idiom.
Unified · Split
| @@ -391,6 +391,11 @@ static inline void audit_ptrace(struct task_struct *t) · 390 unmodified lines | ||
| 391 | 391 | #define audit_signals 0 |
| 392 | 392 | #endif /* CONFIG_AUDITSYSCALL */ |
| 393 | 393 | |
| 394 | +static inline bool audit_loginuid_set(struct task_struct *tsk) | |
| 395 | +{ | |
| 396 | + return uid_valid(audit_get_loginuid(tsk)); | |
| 397 | +} | |
| 398 | + | |
| 394 | 399 | #ifdef CONFIG_AUDIT |
| 395 | 400 | /* These are defined in audit.c */ |
| 396 | 401 | /* Public API */ |
| @@ -246,6 +246,7 @@ · 245 unmodified lines | ||
| 246 | 246 | #define AUDIT_OBJ_TYPE 21 |
| 247 | 247 | #define AUDIT_OBJ_LEV_LOW 22 |
| 248 | 248 | #define AUDIT_OBJ_LEV_HIGH 23 |
| 249 | +#define AUDIT_LOGINUID_SET 24 | |
| 249 | 250 | |
| 250 | 251 | /* These are ONLY useful when checking |
| 251 | 252 | * at syscall exit time (AUDIT_AT_EXIT). */ |
| @@ -365,7 +365,10 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f) · 364 unmodified lines | ||
| 365 | 365 | case AUDIT_DIR: |
| 366 | 366 | case AUDIT_FILTERKEY: |
| 367 | 367 | break; |
| 368 | − /* arch is only allowed to be = or != */ | |
| 368 | + case AUDIT_LOGINUID_SET: | |
| 369 | + if ((f->val != 0) && (f->val != 1)) | |
| 370 | + return -EINVAL; | |
| 371 | + /* FALL THROUGH */ | |
| 369 | 372 | case AUDIT_ARCH: |
| 370 | 373 | if (f->op != Audit_not_equal && f->op != Audit_equal) |
| 371 | 374 | return -EINVAL; |
| @@ -419,17 +422,23 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, · 47 unmodified lines | ||
| 419 | 422 | f->lsm_str = NULL; |
| 420 | 423 | f->lsm_rule = NULL; |
| 421 | 424 | |
| 425 | + /* Support legacy tests for a valid loginuid */ | |
| 426 | + if ((f->type == AUDIT_LOGINUID) && (f->val == 4294967295)) { | |
| 427 | + f->type = AUDIT_LOGINUID_SET; | |
| 428 | + f->val = 0; | |
| 429 | + } | |
| 430 | + | |
| 422 | 431 | err = audit_field_valid(entry, f); |
| 423 | 432 | if (err) |
| 424 | 433 | goto exit_free; |
| 425 | 434 | |
| 426 | 435 | err = -EINVAL; |
| 427 | 436 | switch (f->type) { |
| 437 | + case AUDIT_LOGINUID: | |
| 428 | 438 | case AUDIT_UID: |
| 429 | 439 | case AUDIT_EUID: |
| 430 | 440 | case AUDIT_SUID: |
| 431 | 441 | case AUDIT_FSUID: |
| 432 | − case AUDIT_LOGINUID: | |
| 433 | 442 | case AUDIT_OBJ_UID: |
| 434 | 443 | f->uid = make_kuid(current_user_ns(), f->val); |
| 435 | 444 | if (!uid_valid(f->uid)) |
| @@ -1222,6 +1231,10 @@ static int audit_filter_user_rules(struct audit_krule *rule, int type, · 786 unmodified lines | ||
| 1222 | 1231 | result = audit_uid_comparator(audit_get_loginuid(current), |
| 1223 | 1232 | f->op, f->uid); |
| 1224 | 1233 | break; |
| 1234 | + case AUDIT_LOGINUID_SET: | |
| 1235 | + result = audit_comparator(audit_loginuid_set(current), | |
| 1236 | + f->op, f->val); | |
| 1237 | + break; | |
| 1225 | 1238 | case AUDIT_MSGTYPE: |
| 1226 | 1239 | result = audit_comparator(type, f->op, f->val); |
| 1227 | 1240 | break; |
| @@ -613,6 +613,9 @@ static int audit_filter_rules(struct task_struct *tsk, · 612 unmodified lines | ||
| 613 | 613 | if (ctx) |
| 614 | 614 | result = audit_uid_comparator(tsk->loginuid, f->op, f->uid); |
| 615 | 615 | break; |
| 616 | + case AUDIT_LOGINUID_SET: | |
| 617 | + result = audit_comparator(audit_loginuid_set(tsk), f->op, f->val); | |
| 618 | + break; | |
| 616 | 619 | case AUDIT_SUBJ_USER: |
| 617 | 620 | case AUDIT_SUBJ_ROLE: |
| 618 | 621 | case AUDIT_SUBJ_TYPE: |
| @@ -1970,7 +1973,7 @@ int audit_set_loginuid(kuid_t loginuid) · 1351 unmodified lines | ||
| 1970 | 1973 | unsigned int sessionid; |
| 1971 | 1974 | |
| 1972 | 1975 | #ifdef CONFIG_AUDIT_LOGINUID_IMMUTABLE |
| 1973 | − if (uid_valid(task->loginuid)) | |
| 1976 | + if (audit_loginuid_set(task)) | |
| 1974 | 1977 | return -EPERM; |
| 1975 | 1978 | #else /* CONFIG_AUDIT_LOGINUID_IMMUTABLE */ |
| 1976 | 1979 | if (!capable(CAP_AUDIT_CONTROL)) |