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 <r...@redhat.com>
---
 kernel/audit.c | 75 +++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 62 insertions(+), 13 deletions(-)

diff --git a/kernel/audit.c b/kernel/audit.c
index fcb78a6d8e4a..d2e9d803e5fd 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -231,6 +231,7 @@ struct audit_contobj {
        refcount_t              refcount;
        refcount_t              sigcount;
        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)
        if (refcount_dec_and_test(&cont->sigcount)) {
                if (!refcount_read(&cont->refcount)) {
                        put_task_struct(cont->owner);
+                       _audit_contobj_put(cont->parent);
                        list_del_rcu(&cont->list);
                        kfree_rcu(cont, rcu);
                }
@@ -722,11 +725,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:
@@ -1906,6 +1909,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) {
@@ -1915,13 +1919,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) {
@@ -2608,6 +2626,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
@@ -2627,8 +2662,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;
 }
@@ -2664,7 +2700,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)
@@ -3019,6 +3066,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]);
@@ -3047,9 +3095,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);
@@ -3088,8 +3136,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);
-- 
2.18.4

Reply via email to