From: Eric W. Biederman Date: Tue, 9 Apr 2013 09:22:10 +0000 (-0700) Subject: audit: Make testing for a valid loginuid explicit. X-Git-Url: http://git.cdn.openwrt.org/?a=commitdiff_plain;h=780a7654cee8;p=openwrt%2Fstaging%2Fblogic.git audit: Make testing for a valid loginuid explicit. 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. Cc: # 3.7 Reported-By: Richard Guy Briggs Signed-off-by: "Eric W. Biederman" Tested-by: Richard Guy Briggs Signed-off-by: Eric Paris --- diff --git a/include/linux/audit.h b/include/linux/audit.h index 469d11755e46..b20b03852f21 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -391,6 +391,11 @@ static inline void audit_ptrace(struct task_struct *t) #define audit_signals 0 #endif /* CONFIG_AUDITSYSCALL */ +static inline bool audit_loginuid_set(struct task_struct *tsk) +{ + return uid_valid(audit_get_loginuid(tsk)); +} + #ifdef CONFIG_AUDIT /* These are defined in audit.c */ /* Public API */ diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h index c058c24b97ac..75cef3fd97ad 100644 --- a/include/uapi/linux/audit.h +++ b/include/uapi/linux/audit.h @@ -246,6 +246,7 @@ #define AUDIT_OBJ_TYPE 21 #define AUDIT_OBJ_LEV_LOW 22 #define AUDIT_OBJ_LEV_HIGH 23 +#define AUDIT_LOGINUID_SET 24 /* These are ONLY useful when checking * at syscall exit time (AUDIT_AT_EXIT). */ diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index 478f4602c96b..bc6595fe952e 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -365,7 +365,10 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f) case AUDIT_DIR: case AUDIT_FILTERKEY: break; - /* arch is only allowed to be = or != */ + case AUDIT_LOGINUID_SET: + if ((f->val != 0) && (f->val != 1)) + return -EINVAL; + /* FALL THROUGH */ case AUDIT_ARCH: if (f->op != Audit_not_equal && f->op != Audit_equal) return -EINVAL; @@ -419,17 +422,23 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, f->lsm_str = NULL; f->lsm_rule = NULL; + /* Support legacy tests for a valid loginuid */ + if ((f->type == AUDIT_LOGINUID) && (f->val == 4294967295)) { + f->type = AUDIT_LOGINUID_SET; + f->val = 0; + } + err = audit_field_valid(entry, f); if (err) goto exit_free; err = -EINVAL; switch (f->type) { + case AUDIT_LOGINUID: case AUDIT_UID: case AUDIT_EUID: case AUDIT_SUID: case AUDIT_FSUID: - case AUDIT_LOGINUID: case AUDIT_OBJ_UID: f->uid = make_kuid(current_user_ns(), f->val); if (!uid_valid(f->uid)) @@ -1222,6 +1231,10 @@ static int audit_filter_user_rules(struct audit_krule *rule, int type, result = audit_uid_comparator(audit_get_loginuid(current), f->op, f->uid); break; + case AUDIT_LOGINUID_SET: + result = audit_comparator(audit_loginuid_set(current), + f->op, f->val); + break; case AUDIT_MSGTYPE: result = audit_comparator(type, f->op, f->val); break; diff --git a/kernel/auditsc.c b/kernel/auditsc.c index add3086bdb02..3c8a601324a2 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -613,6 +613,9 @@ static int audit_filter_rules(struct task_struct *tsk, if (ctx) result = audit_uid_comparator(tsk->loginuid, f->op, f->uid); break; + case AUDIT_LOGINUID_SET: + result = audit_comparator(audit_loginuid_set(tsk), f->op, f->val); + break; case AUDIT_SUBJ_USER: case AUDIT_SUBJ_ROLE: case AUDIT_SUBJ_TYPE: @@ -1970,7 +1973,7 @@ int audit_set_loginuid(kuid_t loginuid) unsigned int sessionid; #ifdef CONFIG_AUDIT_LOGINUID_IMMUTABLE - if (uid_valid(task->loginuid)) + if (audit_loginuid_set(task)) return -EPERM; #else /* CONFIG_AUDIT_LOGINUID_IMMUTABLE */ if (!capable(CAP_AUDIT_CONTROL))