lkml.org 
[lkml]   [2022]   [Jun]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v37 26/33] Audit: Allow multiple records in an audit_buffer
    Date
    Replace the single skb pointer in an audit_buffer with
    a list of skb pointers. Add the audit_stamp information
    to the audit_buffer as there's no guarantee that there
    will be an audit_context containing the stamp associated
    with the event. At audit_log_end() time create auxiliary
    records (none are currently defined) as have been added
    to the list. Functions are created to manage the skb list
    in the audit_buffer.

    Suggested-by: Paul Moore <paul@paul-moore.com>
    Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
    ---
    kernel/audit.c | 111 +++++++++++++++++++++++++++++++++++++++----------
    1 file changed, 89 insertions(+), 22 deletions(-)

    diff --git a/kernel/audit.c b/kernel/audit.c
    index e4ee8ee63484..e4cd2cdda7f5 100644
    --- a/kernel/audit.c
    +++ b/kernel/audit.c
    @@ -197,8 +197,10 @@ static struct audit_ctl_mutex {
    * to place it on a transmit queue. Multiple audit_buffers can be in
    * use simultaneously. */
    struct audit_buffer {
    - struct sk_buff *skb; /* formatted skb ready to send */
    + struct sk_buff *skb; /* the skb for audit_log functions */
    + struct sk_buff_head skb_list; /* formatted skbs, ready to send */
    struct audit_context *ctx; /* NULL or associated context */
    + struct audit_stamp stamp; /* audit stamp for these records */
    gfp_t gfp_mask;
    };

    @@ -1765,10 +1767,13 @@ __setup("audit_backlog_limit=", audit_backlog_limit_set);

    static void audit_buffer_free(struct audit_buffer *ab)
    {
    + struct sk_buff *skb;
    +
    if (!ab)
    return;

    - kfree_skb(ab->skb);
    + while ((skb = skb_dequeue(&ab->skb_list)))
    + kfree_skb(skb);
    kmem_cache_free(audit_buffer_cache, ab);
    }

    @@ -1784,6 +1789,10 @@ static struct audit_buffer *audit_buffer_alloc(struct audit_context *ctx,
    ab->skb = nlmsg_new(AUDIT_BUFSIZ, gfp_mask);
    if (!ab->skb)
    goto err;
    +
    + skb_queue_head_init(&ab->skb_list);
    + skb_queue_tail(&ab->skb_list, ab->skb);
    +
    if (!nlmsg_put(ab->skb, 0, 0, type, 0, 0))
    goto err;

    @@ -1849,7 +1858,6 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
    int type)
    {
    struct audit_buffer *ab;
    - struct audit_stamp stamp;

    if (audit_initialized != AUDIT_INITIALIZED)
    return NULL;
    @@ -1904,14 +1912,14 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
    return NULL;
    }

    - audit_get_stamp(ab->ctx, &stamp);
    + audit_get_stamp(ab->ctx, &ab->stamp);
    /* cancel dummy context to enable supporting records */
    if (ctx)
    ctx->dummy = 0;
    audit_log_format(ab, "audit(%llu.%03lu:%u): ",
    - (unsigned long long)stamp.ctime.tv_sec,
    - stamp.ctime.tv_nsec/1000000,
    - stamp.serial);
    + (unsigned long long)ab->stamp.ctime.tv_sec,
    + ab->stamp.ctime.tv_nsec/1000000,
    + ab->stamp.serial);

    return ab;
    }
    @@ -2167,6 +2175,57 @@ void audit_log_key(struct audit_buffer *ab, char *key)
    audit_log_format(ab, "(null)");
    }

    +/**
    + * audit_buffer_aux_new - Add an aux record buffer to the skb list
    + * @ab: audit_buffer
    + * @type: message type
    + *
    + * Aux records are allocated and added to the skb list of
    + * the "main" record. The ab->skb is reset to point to the
    + * aux record on its creation. When the aux record in complete
    + * ab->skb has to be reset to point to the "main" record.
    + * This allows the audit_log_ functions to be ignorant of
    + * which kind of record it is logging to. It also avoids adding
    + * special data for aux records.
    + *
    + * On success ab->skb will point to the new aux record.
    + * Returns 0 on success, -ENOMEM should allocation fail.
    + */
    +static int audit_buffer_aux_new(struct audit_buffer *ab, int type)
    +{
    + WARN_ON(ab->skb != skb_peek(&ab->skb_list));
    +
    + ab->skb = nlmsg_new(AUDIT_BUFSIZ, ab->gfp_mask);
    + if (!ab->skb)
    + goto err;
    + if (!nlmsg_put(ab->skb, 0, 0, type, 0, 0))
    + goto err;
    + skb_queue_tail(&ab->skb_list, ab->skb);
    +
    + audit_log_format(ab, "audit(%llu.%03lu:%u): ",
    + (unsigned long long)ab->stamp.ctime.tv_sec,
    + ab->stamp.ctime.tv_nsec/1000000,
    + ab->stamp.serial);
    +
    + return 0;
    +
    +err:
    + kfree_skb(ab->skb);
    + ab->skb = skb_peek(&ab->skb_list);
    + return -ENOMEM;
    +}
    +
    +/**
    + * audit_buffer_aux_end - Switch back to the "main" record from an aux record
    + * @ab: audit_buffer
    + *
    + * Restores the "main" audit record to ab->skb.
    + */
    +static void audit_buffer_aux_end(struct audit_buffer *ab)
    +{
    + ab->skb = skb_peek(&ab->skb_list);
    +}
    +
    int audit_log_task_context(struct audit_buffer *ab)
    {
    int error;
    @@ -2402,26 +2461,14 @@ int audit_signal_info(int sig, struct task_struct *t)
    }

    /**
    - * audit_log_end - end one audit record
    - * @ab: the audit_buffer
    - *
    - * We can not do a netlink send inside an irq context because it blocks (last
    - * arg, flags, is not set to MSG_DONTWAIT), so the audit buffer is placed on a
    - * queue and a kthread is scheduled to remove them from the queue outside the
    - * irq context. May be called in any context.
    + * __audit_log_end - enqueue one audit record
    + * @skb: the buffer to send
    */
    -void audit_log_end(struct audit_buffer *ab)
    +static void __audit_log_end(struct sk_buff *skb)
    {
    - struct sk_buff *skb;
    struct nlmsghdr *nlh;

    - if (!ab)
    - return;
    -
    if (audit_rate_check()) {
    - skb = ab->skb;
    - ab->skb = NULL;
    -
    /* setup the netlink header, see the comments in
    * kauditd_send_multicast_skb() for length quirks */
    nlh = nlmsg_hdr(skb);
    @@ -2432,6 +2479,26 @@ void audit_log_end(struct audit_buffer *ab)
    wake_up_interruptible(&kauditd_wait);
    } else
    audit_log_lost("rate limit exceeded");
    +}
    +
    +/**
    + * audit_log_end - end one audit record
    + * @ab: the audit_buffer
    + *
    + * We can not do a netlink send inside an irq context because it blocks (last
    + * arg, flags, is not set to MSG_DONTWAIT), so the audit buffer is placed on a
    + * queue and a kthread is scheduled to remove them from the queue outside the
    + * irq context. May be called in any context.
    + */
    +void audit_log_end(struct audit_buffer *ab)
    +{
    + struct sk_buff *skb;
    +
    + if (!ab)
    + return;
    +
    + while ((skb = skb_dequeue(&ab->skb_list)))
    + __audit_log_end(skb);

    audit_buffer_free(ab);
    }
    --
    2.36.1
    \
     
     \ /
      Last update: 2022-06-28 03:13    [W:3.342 / U:0.188 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site