Re: [PATCH ghak90 V9 10/13] audit: add support for containerid to network namespaces

From: Paul Moore
Date: Sun Jul 05 2020 - 11:11:40 EST


On Sat, Jun 27, 2020 at 9:23 AM Richard Guy Briggs <rgb@xxxxxxxxxx> wrote:
>
> This also adds support to qualify NETFILTER_PKT records.
>
> Audit events could happen in a network namespace outside of a task
> context due to packets received from the net that trigger an auditing
> rule prior to being associated with a running task. The network
> namespace could be in use by multiple containers by association to the
> tasks in that network namespace. We still want a way to attribute
> these events to any potential containers. Keep a list per network
> namespace to track these audit container identifiiers.
>
> Add/increment the audit container identifier on:
> - initial setting of the audit container identifier via /proc
> - clone/fork call that inherits an audit container identifier
> - unshare call that inherits an audit container identifier
> - setns call that inherits an audit container identifier
> Delete/decrement the audit container identifier on:
> - an inherited audit container identifier dropped when child set
> - process exit
> - unshare call that drops a net namespace
> - setns call that drops a net namespace
>
> Add audit container identifier auxiliary record(s) to NETFILTER_PKT
> event standalone records. Iterate through all potential audit container
> identifiers associated with a network namespace.
>
> Please see the github audit kernel issue for contid net support:
> https://github.com/linux-audit/audit-kernel/issues/92
> Please see the github audit testsuiite issue for the test case:
> https://github.com/linux-audit/audit-testsuite/issues/64
> Please see the github audit wiki for the feature overview:
> https://github.com/linux-audit/audit-kernel/wiki/RFE-Audit-Container-ID
> Signed-off-by: Richard Guy Briggs <rgb@xxxxxxxxxx>
> Acked-by: Neil Horman <nhorman@xxxxxxxxxxxxx>
> Reviewed-by: Ondrej Mosnacek <omosnace@xxxxxxxxxx>
> ---
> include/linux/audit.h | 20 ++++++
> kernel/audit.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++-
> kernel/nsproxy.c | 4 ++
> net/netfilter/nft_log.c | 11 +++-
> net/netfilter/xt_AUDIT.c | 11 +++-
> 5 files changed, 195 insertions(+), 7 deletions(-)
>
> diff --git a/include/linux/audit.h b/include/linux/audit.h
> index c4a755ae0d61..304fbb7c3c5b 100644
> --- a/include/linux/audit.h
> +++ b/include/linux/audit.h
> @@ -128,6 +128,13 @@ struct audit_task_info {
>
> extern struct audit_task_info init_struct_audit;
>
> +struct audit_contobj_netns {
> + struct list_head list;
> + struct audit_contobj *obj;
> + int count;

This seems like it might be a good candidate for refcount_t, yes?

> + struct rcu_head rcu;
> +};

...

> diff --git a/kernel/audit.c b/kernel/audit.c
> index 997c34178ee8..a862721dfd9b 100644
> --- a/kernel/audit.c
> +++ b/kernel/audit.c
> @@ -437,6 +452,136 @@ static struct sock *audit_get_sk(const struct net *net)
> return aunet->sk;
> }
>
> +void audit_netns_contid_add(struct net *net, struct audit_contobj *cont)
> +{
> + struct audit_net *aunet;
> + struct list_head *contobj_list;
> + struct audit_contobj_netns *contns;
> +
> + if (!net)
> + return;
> + if (!cont)
> + return;
> + aunet = net_generic(net, audit_net_id);
> + if (!aunet)
> + return;
> + contobj_list = &aunet->contobj_list;
> + rcu_read_lock();
> + spin_lock(&aunet->contobj_list_lock);
> + list_for_each_entry_rcu(contns, contobj_list, list)
> + if (contns->obj == cont) {
> + contns->count++;
> + goto out;
> + }
> + contns = kmalloc(sizeof(*contns), GFP_ATOMIC);
> + if (contns) {
> + INIT_LIST_HEAD(&contns->list);
> + contns->obj = cont;
> + contns->count = 1;
> + list_add_rcu(&contns->list, contobj_list);
> + }
> +out:
> + spin_unlock(&aunet->contobj_list_lock);
> + rcu_read_unlock();
> +}
> +
> +void audit_netns_contid_del(struct net *net, struct audit_contobj *cont)
> +{
> + struct audit_net *aunet;
> + struct list_head *contobj_list;
> + struct audit_contobj_netns *contns = NULL;
> +
> + if (!net)
> + return;
> + if (!cont)
> + return;
> + aunet = net_generic(net, audit_net_id);
> + if (!aunet)
> + return;
> + contobj_list = &aunet->contobj_list;
> + rcu_read_lock();
> + spin_lock(&aunet->contobj_list_lock);
> + list_for_each_entry_rcu(contns, contobj_list, list)
> + if (contns->obj == cont) {
> + contns->count--;
> + if (contns->count < 1) {

One could simplify this with "(--countns->count) < 1", although if it
is changed to a refcount_t (which seems like a smart thing), the
normal decrement/test would be the best choice.


> + list_del_rcu(&contns->list);
> + kfree_rcu(contns, rcu);
> + }
> + break;
> + }
> + spin_unlock(&aunet->contobj_list_lock);
> + rcu_read_unlock();
> +}

--
paul moore
www.paul-moore.com