Commit 8c326850 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'audit-pr-20180814' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/audit

Pull audit patches from Paul Moore:
 "Twelve audit patches for v4.19 and they run the full gamut from fixes
  to features.

  Notable changes include the ability to use the "exe" audit filter
  field in a wider variety of filter types, a fix for our comparison of
  GID/EGID in audit filter rules, better association of related audit
  records (connecting related audit records together into one audit
  event), and a fix for a potential use-after-free in audit_add_watch().

  All the patches pass the audit-testsuite and merge cleanly on your
  current master branch"

* tag 'audit-pr-20180814' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/audit:
  audit: fix use-after-free in audit_add_watch
  audit: use ktime_get_coarse_real_ts64() for timestamps
  audit: use ktime_get_coarse_ts64() for time access
  audit: simplify audit_enabled check in audit_watch_log_rule_change()
  audit: check audit_enabled in audit_tree_log_remove_rule()
  cred: conditionally declare groups-related functions
  audit: eliminate audit_enabled magic number comparison
  audit: rename FILTER_TYPE to FILTER_EXCLUDE
  audit: Fix extended comparison of GID/EGID
  audit: tie ANOM_ABEND records to syscall
  audit: tie SECCOMP records to syscall
  audit: allow other filter list types for AUDIT_EXE
parents 6f7dac11 baa2a4fd
...@@ -92,7 +92,7 @@ static void tty_audit_buf_push(struct tty_audit_buf *buf) ...@@ -92,7 +92,7 @@ static void tty_audit_buf_push(struct tty_audit_buf *buf)
{ {
if (buf->valid == 0) if (buf->valid == 0)
return; return;
if (audit_enabled == 0) { if (audit_enabled == AUDIT_OFF) {
buf->valid = 0; buf->valid = 0;
return; return;
} }
......
...@@ -117,6 +117,9 @@ struct filename; ...@@ -117,6 +117,9 @@ struct filename;
extern void audit_log_session_info(struct audit_buffer *ab); extern void audit_log_session_info(struct audit_buffer *ab);
#define AUDIT_OFF 0
#define AUDIT_ON 1
#define AUDIT_LOCKED 2
#ifdef CONFIG_AUDIT #ifdef CONFIG_AUDIT
/* These are defined in audit.c */ /* These are defined in audit.c */
/* Public API */ /* Public API */
...@@ -202,7 +205,7 @@ static inline int audit_log_task_context(struct audit_buffer *ab) ...@@ -202,7 +205,7 @@ static inline int audit_log_task_context(struct audit_buffer *ab)
static inline void audit_log_task_info(struct audit_buffer *ab, static inline void audit_log_task_info(struct audit_buffer *ab,
struct task_struct *tsk) struct task_struct *tsk)
{ } { }
#define audit_enabled 0 #define audit_enabled AUDIT_OFF
#endif /* CONFIG_AUDIT */ #endif /* CONFIG_AUDIT */
#ifdef CONFIG_AUDIT_COMPAT_GENERIC #ifdef CONFIG_AUDIT_COMPAT_GENERIC
......
...@@ -65,6 +65,12 @@ extern void groups_free(struct group_info *); ...@@ -65,6 +65,12 @@ extern void groups_free(struct group_info *);
extern int in_group_p(kgid_t); extern int in_group_p(kgid_t);
extern int in_egroup_p(kgid_t); extern int in_egroup_p(kgid_t);
extern int groups_search(const struct group_info *, kgid_t);
extern int set_current_groups(struct group_info *);
extern void set_groups(struct cred *, struct group_info *);
extern bool may_setgroups(void);
extern void groups_sort(struct group_info *);
#else #else
static inline void groups_free(struct group_info *group_info) static inline void groups_free(struct group_info *group_info)
{ {
...@@ -78,12 +84,11 @@ static inline int in_egroup_p(kgid_t grp) ...@@ -78,12 +84,11 @@ static inline int in_egroup_p(kgid_t grp)
{ {
return 1; return 1;
} }
static inline int groups_search(const struct group_info *group_info, kgid_t grp)
{
return 1;
}
#endif #endif
extern int set_current_groups(struct group_info *);
extern void set_groups(struct cred *, struct group_info *);
extern int groups_search(const struct group_info *, kgid_t);
extern bool may_setgroups(void);
extern void groups_sort(struct group_info *);
/* /*
* The security context of a task * The security context of a task
......
...@@ -735,7 +735,7 @@ static inline struct audit_buffer *xfrm_audit_start(const char *op) ...@@ -735,7 +735,7 @@ static inline struct audit_buffer *xfrm_audit_start(const char *op)
{ {
struct audit_buffer *audit_buf = NULL; struct audit_buffer *audit_buf = NULL;
if (audit_enabled == 0) if (audit_enabled == AUDIT_OFF)
return NULL; return NULL;
audit_buf = audit_log_start(audit_context(), GFP_ATOMIC, audit_buf = audit_log_start(audit_context(), GFP_ATOMIC,
AUDIT_MAC_IPSEC_EVENT); AUDIT_MAC_IPSEC_EVENT);
......
...@@ -157,7 +157,8 @@ ...@@ -157,7 +157,8 @@
#define AUDIT_FILTER_ENTRY 0x02 /* Apply rule at syscall entry */ #define AUDIT_FILTER_ENTRY 0x02 /* Apply rule at syscall entry */
#define AUDIT_FILTER_WATCH 0x03 /* Apply rule to file system watches */ #define AUDIT_FILTER_WATCH 0x03 /* Apply rule to file system watches */
#define AUDIT_FILTER_EXIT 0x04 /* Apply rule at syscall exit */ #define AUDIT_FILTER_EXIT 0x04 /* Apply rule at syscall exit */
#define AUDIT_FILTER_TYPE 0x05 /* Apply rule at audit_log_start */ #define AUDIT_FILTER_EXCLUDE 0x05 /* Apply rule before record creation */
#define AUDIT_FILTER_TYPE AUDIT_FILTER_EXCLUDE /* obsolete misleading naming */
#define AUDIT_FILTER_FS 0x06 /* Apply rule at __audit_inode_child */ #define AUDIT_FILTER_FS 0x06 /* Apply rule at __audit_inode_child */
#define AUDIT_NR_FILTERS 7 #define AUDIT_NR_FILTERS 7
......
...@@ -83,9 +83,6 @@ ...@@ -83,9 +83,6 @@
#define AUDIT_INITIALIZED 1 #define AUDIT_INITIALIZED 1
static int audit_initialized; static int audit_initialized;
#define AUDIT_OFF 0
#define AUDIT_ON 1
#define AUDIT_LOCKED 2
u32 audit_enabled = AUDIT_OFF; u32 audit_enabled = AUDIT_OFF;
bool audit_ever_enabled = !!AUDIT_OFF; bool audit_ever_enabled = !!AUDIT_OFF;
...@@ -1724,7 +1721,7 @@ static inline void audit_get_stamp(struct audit_context *ctx, ...@@ -1724,7 +1721,7 @@ static inline void audit_get_stamp(struct audit_context *ctx,
struct timespec64 *t, unsigned int *serial) struct timespec64 *t, unsigned int *serial)
{ {
if (!ctx || !auditsc_get_stamp(ctx, t, serial)) { if (!ctx || !auditsc_get_stamp(ctx, t, serial)) {
*t = current_kernel_time64(); ktime_get_coarse_real_ts64(t);
*serial = audit_serial(); *serial = audit_serial();
} }
} }
...@@ -1754,7 +1751,7 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, ...@@ -1754,7 +1751,7 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
if (audit_initialized != AUDIT_INITIALIZED) if (audit_initialized != AUDIT_INITIALIZED)
return NULL; return NULL;
if (unlikely(!audit_filter(type, AUDIT_FILTER_TYPE))) if (unlikely(!audit_filter(type, AUDIT_FILTER_EXCLUDE)))
return NULL; return NULL;
/* NOTE: don't ever fail/sleep on these two conditions: /* NOTE: don't ever fail/sleep on these two conditions:
......
...@@ -497,6 +497,8 @@ static void audit_tree_log_remove_rule(struct audit_krule *rule) ...@@ -497,6 +497,8 @@ static void audit_tree_log_remove_rule(struct audit_krule *rule)
{ {
struct audit_buffer *ab; struct audit_buffer *ab;
if (!audit_enabled)
return;
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
if (unlikely(!ab)) if (unlikely(!ab))
return; return;
......
...@@ -238,20 +238,21 @@ static struct audit_watch *audit_dupe_watch(struct audit_watch *old) ...@@ -238,20 +238,21 @@ static struct audit_watch *audit_dupe_watch(struct audit_watch *old)
static void audit_watch_log_rule_change(struct audit_krule *r, struct audit_watch *w, char *op) static void audit_watch_log_rule_change(struct audit_krule *r, struct audit_watch *w, char *op)
{ {
if (audit_enabled) { struct audit_buffer *ab;
struct audit_buffer *ab;
ab = audit_log_start(NULL, GFP_NOFS, AUDIT_CONFIG_CHANGE); if (!audit_enabled)
if (unlikely(!ab)) return;
return; ab = audit_log_start(NULL, GFP_NOFS, AUDIT_CONFIG_CHANGE);
audit_log_format(ab, "auid=%u ses=%u op=%s", if (!ab)
from_kuid(&init_user_ns, audit_get_loginuid(current)), return;
audit_get_sessionid(current), op); audit_log_format(ab, "auid=%u ses=%u op=%s",
audit_log_format(ab, " path="); from_kuid(&init_user_ns, audit_get_loginuid(current)),
audit_log_untrustedstring(ab, w->path); audit_get_sessionid(current), op);
audit_log_key(ab, r->filterkey); audit_log_format(ab, " path=");
audit_log_format(ab, " list=%d res=1", r->listnr); audit_log_untrustedstring(ab, w->path);
audit_log_end(ab); audit_log_key(ab, r->filterkey);
} audit_log_format(ab, " list=%d res=1", r->listnr);
audit_log_end(ab);
} }
/* Update inode info in audit rules based on filesystem event. */ /* Update inode info in audit rules based on filesystem event. */
...@@ -419,6 +420,13 @@ int audit_add_watch(struct audit_krule *krule, struct list_head **list) ...@@ -419,6 +420,13 @@ int audit_add_watch(struct audit_krule *krule, struct list_head **list)
struct path parent_path; struct path parent_path;
int h, ret = 0; int h, ret = 0;
/*
* When we will be calling audit_add_to_parent, krule->watch might have
* been updated and watch might have been freed.
* So we need to keep a reference of watch.
*/
audit_get_watch(watch);
mutex_unlock(&audit_filter_mutex); mutex_unlock(&audit_filter_mutex);
/* Avoid calling path_lookup under audit_filter_mutex. */ /* Avoid calling path_lookup under audit_filter_mutex. */
...@@ -427,8 +435,10 @@ int audit_add_watch(struct audit_krule *krule, struct list_head **list) ...@@ -427,8 +435,10 @@ int audit_add_watch(struct audit_krule *krule, struct list_head **list)
/* caller expects mutex locked */ /* caller expects mutex locked */
mutex_lock(&audit_filter_mutex); mutex_lock(&audit_filter_mutex);
if (ret) if (ret) {
audit_put_watch(watch);
return ret; return ret;
}
/* either find an old parent or attach a new one */ /* either find an old parent or attach a new one */
parent = audit_find_parent(d_backing_inode(parent_path.dentry)); parent = audit_find_parent(d_backing_inode(parent_path.dentry));
...@@ -446,6 +456,7 @@ int audit_add_watch(struct audit_krule *krule, struct list_head **list) ...@@ -446,6 +456,7 @@ int audit_add_watch(struct audit_krule *krule, struct list_head **list)
*list = &audit_inode_hash[h]; *list = &audit_inode_hash[h];
error: error:
path_put(&parent_path); path_put(&parent_path);
audit_put_watch(watch);
return ret; return ret;
} }
......
...@@ -264,7 +264,7 @@ static inline struct audit_entry *audit_to_entry_common(struct audit_rule_data * ...@@ -264,7 +264,7 @@ static inline struct audit_entry *audit_to_entry_common(struct audit_rule_data *
case AUDIT_FILTER_TASK: case AUDIT_FILTER_TASK:
#endif #endif
case AUDIT_FILTER_USER: case AUDIT_FILTER_USER:
case AUDIT_FILTER_TYPE: case AUDIT_FILTER_EXCLUDE:
case AUDIT_FILTER_FS: case AUDIT_FILTER_FS:
; ;
} }
...@@ -337,7 +337,7 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f) ...@@ -337,7 +337,7 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f)
{ {
switch(f->type) { switch(f->type) {
case AUDIT_MSGTYPE: case AUDIT_MSGTYPE:
if (entry->rule.listnr != AUDIT_FILTER_TYPE && if (entry->rule.listnr != AUDIT_FILTER_EXCLUDE &&
entry->rule.listnr != AUDIT_FILTER_USER) entry->rule.listnr != AUDIT_FILTER_USER)
return -EINVAL; return -EINVAL;
break; break;
...@@ -428,8 +428,6 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f) ...@@ -428,8 +428,6 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f)
case AUDIT_EXE: case AUDIT_EXE:
if (f->op != Audit_not_equal && f->op != Audit_equal) if (f->op != Audit_not_equal && f->op != Audit_equal)
return -EINVAL; return -EINVAL;
if (entry->rule.listnr != AUDIT_FILTER_EXIT)
return -EINVAL;
break; break;
} }
return 0; return 0;
...@@ -931,7 +929,7 @@ static inline int audit_add_rule(struct audit_entry *entry) ...@@ -931,7 +929,7 @@ static inline int audit_add_rule(struct audit_entry *entry)
/* If any of these, don't count towards total */ /* If any of these, don't count towards total */
switch(entry->rule.listnr) { switch(entry->rule.listnr) {
case AUDIT_FILTER_USER: case AUDIT_FILTER_USER:
case AUDIT_FILTER_TYPE: case AUDIT_FILTER_EXCLUDE:
case AUDIT_FILTER_FS: case AUDIT_FILTER_FS:
dont_count = 1; dont_count = 1;
} }
...@@ -1013,7 +1011,7 @@ int audit_del_rule(struct audit_entry *entry) ...@@ -1013,7 +1011,7 @@ int audit_del_rule(struct audit_entry *entry)
/* If any of these, don't count towards total */ /* If any of these, don't count towards total */
switch(entry->rule.listnr) { switch(entry->rule.listnr) {
case AUDIT_FILTER_USER: case AUDIT_FILTER_USER:
case AUDIT_FILTER_TYPE: case AUDIT_FILTER_EXCLUDE:
case AUDIT_FILTER_FS: case AUDIT_FILTER_FS:
dont_count = 1; dont_count = 1;
} }
...@@ -1360,6 +1358,11 @@ int audit_filter(int msgtype, unsigned int listtype) ...@@ -1360,6 +1358,11 @@ int audit_filter(int msgtype, unsigned int listtype)
f->type, f->op, f->lsm_rule, NULL); f->type, f->op, f->lsm_rule, NULL);
} }
break; break;
case AUDIT_EXE:
result = audit_exe_compare(current, e->rule.exe);
if (f->op == Audit_not_equal)
result = !result;
break;
default: default:
goto unlock_and_return; goto unlock_and_return;
} }
...@@ -1369,7 +1372,7 @@ int audit_filter(int msgtype, unsigned int listtype) ...@@ -1369,7 +1372,7 @@ int audit_filter(int msgtype, unsigned int listtype)
break; break;
} }
if (result > 0) { if (result > 0) {
if (e->rule.action == AUDIT_NEVER || listtype == AUDIT_FILTER_TYPE) if (e->rule.action == AUDIT_NEVER || listtype == AUDIT_FILTER_EXCLUDE)
ret = 0; ret = 0;
break; break;
} }
......
...@@ -494,20 +494,20 @@ static int audit_filter_rules(struct task_struct *tsk, ...@@ -494,20 +494,20 @@ static int audit_filter_rules(struct task_struct *tsk,
result = audit_gid_comparator(cred->gid, f->op, f->gid); result = audit_gid_comparator(cred->gid, f->op, f->gid);
if (f->op == Audit_equal) { if (f->op == Audit_equal) {
if (!result) if (!result)
result = in_group_p(f->gid); result = groups_search(cred->group_info, f->gid);
} else if (f->op == Audit_not_equal) { } else if (f->op == Audit_not_equal) {
if (result) if (result)
result = !in_group_p(f->gid); result = !groups_search(cred->group_info, f->gid);
} }
break; break;
case AUDIT_EGID: case AUDIT_EGID:
result = audit_gid_comparator(cred->egid, f->op, f->gid); result = audit_gid_comparator(cred->egid, f->op, f->gid);
if (f->op == Audit_equal) { if (f->op == Audit_equal) {
if (!result) if (!result)
result = in_egroup_p(f->gid); result = groups_search(cred->group_info, f->gid);
} else if (f->op == Audit_not_equal) { } else if (f->op == Audit_not_equal) {
if (result) if (result)
result = !in_egroup_p(f->gid); result = !groups_search(cred->group_info, f->gid);
} }
break; break;
case AUDIT_SGID: case AUDIT_SGID:
...@@ -1544,10 +1544,10 @@ void __audit_syscall_entry(int major, unsigned long a1, unsigned long a2, ...@@ -1544,10 +1544,10 @@ void __audit_syscall_entry(int major, unsigned long a1, unsigned long a2,
context->argv[2] = a3; context->argv[2] = a3;
context->argv[3] = a4; context->argv[3] = a4;
context->serial = 0; context->serial = 0;
context->ctime = current_kernel_time64();
context->in_syscall = 1; context->in_syscall = 1;
context->current_state = state; context->current_state = state;
context->ppid = 0; context->ppid = 0;
ktime_get_coarse_real_ts64(&context->ctime);
} }
/** /**
...@@ -2466,7 +2466,7 @@ void audit_core_dumps(long signr) ...@@ -2466,7 +2466,7 @@ void audit_core_dumps(long signr)
if (signr == SIGQUIT) /* don't care for those */ if (signr == SIGQUIT) /* don't care for those */
return; return;
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND); ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_ANOM_ABEND);
if (unlikely(!ab)) if (unlikely(!ab))
return; return;
audit_log_task(ab); audit_log_task(ab);
...@@ -2490,7 +2490,7 @@ void audit_seccomp(unsigned long syscall, long signr, int code) ...@@ -2490,7 +2490,7 @@ void audit_seccomp(unsigned long syscall, long signr, int code)
{ {
struct audit_buffer *ab; struct audit_buffer *ab;
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_SECCOMP); ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_SECCOMP);
if (unlikely(!ab)) if (unlikely(!ab))
return; return;
audit_log_task(ab); audit_log_task(ab);
......
...@@ -72,7 +72,7 @@ audit_tg(struct sk_buff *skb, const struct xt_action_param *par) ...@@ -72,7 +72,7 @@ audit_tg(struct sk_buff *skb, const struct xt_action_param *par)
struct audit_buffer *ab; struct audit_buffer *ab;
int fam = -1; int fam = -1;
if (audit_enabled == 0) if (audit_enabled == AUDIT_OFF)
goto errout; goto errout;
ab = audit_log_start(NULL, GFP_ATOMIC, AUDIT_NETFILTER_PKT); ab = audit_log_start(NULL, GFP_ATOMIC, AUDIT_NETFILTER_PKT);
if (ab == NULL) if (ab == NULL)
......
...@@ -101,7 +101,7 @@ struct audit_buffer *netlbl_audit_start_common(int type, ...@@ -101,7 +101,7 @@ struct audit_buffer *netlbl_audit_start_common(int type,
char *secctx; char *secctx;
u32 secctx_len; u32 secctx_len;
if (audit_enabled == 0) if (audit_enabled == AUDIT_OFF)
return NULL; return NULL;
audit_buf = audit_log_start(audit_context(), GFP_ATOMIC, type); audit_buf = audit_log_start(audit_context(), GFP_ATOMIC, type);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment