diff mbox series

[ghak90,v10,10/11] audit: track container nesting

Message ID ceca0192c35bde32f1adb5148eca08375edbc116.1608225886.git.rgb@redhat.com (mailing list archive)
State Not Applicable
Headers show
Series audit: implement container identifier | expand

Checks

Context Check Description
netdev/tree_selection success Not a local patch

Commit Message

Richard Guy Briggs Dec. 21, 2020, 4:55 p.m. UTC
Track the parent container of a container to be able to filter and
report nesting.

Now that we have a way to track and check the parent container of a
container, modify the contid field format to be able to report that
nesting using a carrat ("^") modifier to indicate nesting.  The
original field format was "contid=<contid>" for task-associated records
and "contid=<contid>[,<contid>[...]]" for network-namespace-associated
records.  The new field format is
"contid=<contid>[,^<contid>[...]][,<contid>[...]]".

For task event example, an orchestrator in contid 1 spawns tasks in contid
2 and contid 3, then the task in contid 2 spawns a task in contid 4.  An
event happens in the task in contid 4:
    type=SYSCALL ...
    type=CONTAINER_ID msg=audit(<date.time>:<serno>): contid=4,^2,^1

For a network namespace event example, an orchestrator in contid 1 in
network namespace A spawns peer tasks 2 and 3 in network namespace B.  An
event happens in network namespace B:
    type=NETFILTER_PKT ...
    type=CONTAINER_ID msg=audit(<date.time>:<serno>): contid=2,^1,3,^1

Signed-off-by: Richard Guy Briggs <rgb@redhat.com>
---
 kernel/audit.c | 75 +++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 62 insertions(+), 13 deletions(-)
diff mbox series

Patch

diff --git a/kernel/audit.c b/kernel/audit.c
index 6eed8ed0cc8e..46ddf49f731f 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -231,6 +231,7 @@  struct audit_contobj {
 	refcount_t		refcount;
 	refcount_t		sigflag;
 	struct rcu_head         rcu;
+	struct audit_contobj	*parent;
 };
 
 struct audit_task_info {
@@ -253,6 +254,7 @@  struct audit_contobj_netns {
 
 static void audit_netns_contid_add(struct net *net, struct audit_contobj *cont);
 static void audit_netns_contid_del(struct net *net, struct audit_contobj *cont);
+static void audit_log_contid(struct audit_buffer *ab, struct audit_contobj *cont);
 
 void __init audit_task_init(void)
 {
@@ -378,6 +380,7 @@  static void _audit_contobj_put_sig(struct audit_contobj *cont)
 	refcount_set(&cont->sigflag, 0);
 	if (!refcount_read(&cont->refcount)) {
 		put_task_struct(cont->owner);
+		_audit_contobj_put(cont->parent);
 		list_del_rcu(&cont->list);
 		kfree_rcu(cont, rcu);
 	}
@@ -721,11 +724,11 @@  int audit_log_netns_contid_list(struct net *net, struct audit_context *context)
 				audit_log_lost("out of memory in audit_log_netns_contid_list");
 				goto out;
 			}
-			audit_log_format(ab, "record=1 contid=%llu",
-					 cont->obj->id);
+			audit_log_format(ab, "record=1 contid=");
 		} else {
-			audit_log_format(ab, ",%llu", cont->obj->id);
+			audit_log_format(ab, ",");
 		}
+		audit_log_contid(ab, cont->obj);
 	}
 	audit_log_end(ab);
 out:
@@ -1905,6 +1908,7 @@  static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 	case AUDIT_SIGNAL_INFO2: {
 		char *contidstr = NULL;
 		unsigned int contidstrlen = 0;
+		struct audit_contobj *cont = audit_sig_cid;
 
 		len = 0;
 		if (audit_sig_sid) {
@@ -1914,13 +1918,27 @@  static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 				return err;
 		}
 		if (audit_sig_cid) {
-			contidstr = kmalloc(21, GFP_KERNEL);
+			contidstr = kmalloc(AUDIT_MESSAGE_TEXT_MAX, GFP_KERNEL);
 			if (!contidstr) {
 				if (audit_sig_sid)
 					security_release_secctx(ctx, len);
 				return -ENOMEM;
 			}
-			contidstrlen = scnprintf(contidstr, 20, "%llu", audit_sig_cid->id);
+			rcu_read_lock();
+			while (cont) {
+				if (cont->parent)
+					contidstrlen += scnprintf(contidstr,
+								  AUDIT_MESSAGE_TEXT_MAX -
+								  contidstrlen,
+								  "%llu,^", cont->id);
+				else
+					contidstrlen += scnprintf(contidstr,
+								  AUDIT_MESSAGE_TEXT_MAX -
+								  contidstrlen,
+								  "%llu", cont->id);
+				cont = cont->parent;
+			}
+			rcu_read_unlock();
 		}
 		sig_data2 = kmalloc(sizeof(*sig_data2) + contidstrlen + len, GFP_KERNEL);
 		if (!sig_data2) {
@@ -2607,6 +2625,23 @@  void audit_log_session_info(struct audit_buffer *ab)
 	audit_log_format(ab, "auid=%u ses=%u", auid, sessionid);
 }
 
+static void audit_log_contid(struct audit_buffer *ab, struct audit_contobj *cont)
+{
+	if (!cont) {
+		audit_log_format(ab, "-1");
+		return;
+	}
+	rcu_read_lock();
+	while (cont) {
+		if (cont->parent)
+			audit_log_format(ab, "%llu,^", cont->id);
+		else
+			audit_log_format(ab, "%llu", cont->id);
+		cont = cont->parent;
+	}
+	rcu_read_unlock();
+}
+
 /*
  * _audit_log_container_id - report container info
  * @context: task or local context for record
@@ -2626,8 +2661,9 @@  static int _audit_log_container_id(struct audit_context *context,
 	ab = audit_log_start(context, GFP_KERNEL, AUDIT_CONTAINER_ID);
 	if (!ab)
 		return 0;
-	audit_log_format(ab, "record=%d contid=%llu",
-			 record = ++context->contid_records, contobj->id);
+	audit_log_format(ab, "record=%d contid=",
+			 record = ++context->contid_records);
+	audit_log_contid(ab, contobj);
 	audit_log_end(ab);
 	return record;
 }
@@ -2663,7 +2699,18 @@  int audit_log_container_id_ctx(struct audit_context *context)
 
 int audit_contid_comparator(struct task_struct *tsk, u32 op, u64 right)
 {
-	return audit_comparator64(audit_get_contid(tsk), op, right);
+	struct audit_contobj *cont = NULL;
+	int h;
+	int result = 0;
+	u64 left = audit_get_contid(tsk);
+
+	h = audit_hash_contid(left);
+	list_for_each_entry_rcu(cont, &audit_contid_hash[h], list) {
+		result = audit_comparator64(cont->id, op, right);
+		if (result)
+			break;
+	}
+	return result;
 }
 
 void audit_log_key(struct audit_buffer *ab, char *key)
@@ -3018,6 +3065,7 @@  int audit_set_contid(struct task_struct *tsk, u64 contid)
 			INIT_LIST_HEAD(&newcont->list);
 			newcont->id = contid;
 			newcont->owner = get_task_struct(current);
+			newcont->parent = _audit_contobj_get_bytask(newcont->owner);
 			refcount_set(&newcont->refcount, 1);
 			list_add_rcu(&newcont->list,
 				     &audit_contid_hash[h]);
@@ -3046,9 +3094,9 @@  int audit_set_contid(struct task_struct *tsk, u64 contid)
 	if (!ab)
 		return rc;
 
-	audit_log_format(ab,
-			 "op=set opid=%d contid=%llu old-contid=%llu",
-			 task_tgid_nr(tsk), contid, oldcont ? oldcont->id : -1);
+	audit_log_format(ab, "op=set opid=%d contid=%llu old-contid=",
+			 task_tgid_nr(tsk), contid);
+	audit_log_contid(ab, oldcont);
 	spin_lock_irqsave(&_audit_contobj_list_lock, flags);
 	_audit_contobj_put(oldcont);
 	spin_unlock_irqrestore(&_audit_contobj_list_lock, flags);
@@ -3087,8 +3135,9 @@  void audit_log_container_drop(void)
 	ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_CONTAINER_OP);
 	if (!ab)
 		goto out;
-	audit_log_format(ab, "op=drop opid=%d contid=-1 old-contid=%llu",
-			 task_tgid_nr(current), cont->id);
+	audit_log_format(ab, "op=drop opid=%d contid=-1 old-contid=",
+			 task_tgid_nr(current));
+	audit_log_contid(ab, cont);
 	audit_log_end(ab);
 out:
 	spin_lock_irqsave(&_audit_contobj_list_lock, flags);