瀏覽代碼

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
Linus Torvalds 7 年之前
父節點
當前提交
8c32685030

+ 1 - 1
drivers/tty/tty_audit.c

@@ -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;
 	}
 	}

+ 4 - 1
include/linux/audit.h

@@ -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)
 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

+ 10 - 5
include/linux/cred.h

@@ -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)
 {
 {
         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

+ 1 - 1
include/net/xfrm.h

@@ -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);

+ 2 - 1
include/uapi/linux/audit.h

@@ -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

+ 2 - 5
kernel/audit.c

@@ -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,
 				   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,
 	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:

+ 2 - 0
kernel/audit_tree.c

@@ -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;

+ 26 - 15
kernel/audit_watch.c

@@ -238,20 +238,21 @@ out:
 
 
 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;
-		ab = audit_log_start(NULL, GFP_NOFS, AUDIT_CONFIG_CHANGE);
-		if (unlikely(!ab))
-			return;
-		audit_log_format(ab, "auid=%u ses=%u op=%s",
-				 from_kuid(&init_user_ns, audit_get_loginuid(current)),
-				 audit_get_sessionid(current), op);
-		audit_log_format(ab, " path=");
-		audit_log_untrustedstring(ab, w->path);
-		audit_log_key(ab, r->filterkey);
-		audit_log_format(ab, " list=%d res=1", r->listnr);
-		audit_log_end(ab);
-	}
+	struct audit_buffer *ab;
+
+	if (!audit_enabled)
+		return;
+	ab = audit_log_start(NULL, GFP_NOFS, AUDIT_CONFIG_CHANGE);
+	if (!ab)
+		return;
+	audit_log_format(ab, "auid=%u ses=%u op=%s",
+			 from_kuid(&init_user_ns, audit_get_loginuid(current)),
+			 audit_get_sessionid(current), op);
+	audit_log_format(ab, " path=");
+	audit_log_untrustedstring(ab, w->path);
+	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)
 	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)
 	/* 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)
 	*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;
 }
 }
 
 

+ 10 - 7
kernel/auditfilter.c

@@ -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)
 {
 {
 	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)
 	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)
 	/* 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)
 	/* 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)
 							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)
 				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;
 		}
 		}

+ 7 - 7
kernel/auditsc.c

@@ -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,
 	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)
 	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)
 {
 {
 	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);

+ 1 - 1
net/netfilter/xt_AUDIT.c

@@ -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)

+ 1 - 1
net/netlabel/netlabel_user.c

@@ -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);