aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Moore <paul@paul-moore.com>2017-05-02 10:16:05 -0400
committerPaul Moore <paul@paul-moore.com>2017-05-02 10:16:05 -0400
commit8cc96382d9a7fe1746286670dd5140c3b12638ae (patch)
tree22383341416f7ddd97b0f16d259967104ce31739
parent2115bb250f260089743e26decfb5f271ba71ca37 (diff)
audit: use kmem_cache to manage the audit_buffer cache
The audit subsystem implemented its own buffer cache mechanism which is a bit silly these days when we could use the kmem_cache construct. Some credit is due to Florian Westphal for originally proposing that we remove the audit cache implementation in favor of simple kmalloc()/kfree() calls, but I would rather have a dedicated slab cache to ease debugging and future stats/performance work. Cc: Florian Westphal <fw@strlen.de> Reviewed-by: Richard Guy Briggs <rgb@redhat.com> Signed-off-by: Paul Moore <paul@paul-moore.com>
-rw-r--r--kernel/audit.c66
1 files changed, 17 insertions, 49 deletions
diff --git a/kernel/audit.c b/kernel/audit.c
index 41efd2ad1931..10bc2bad2adf 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -59,6 +59,7 @@
59#include <linux/mutex.h> 59#include <linux/mutex.h>
60#include <linux/gfp.h> 60#include <linux/gfp.h>
61#include <linux/pid.h> 61#include <linux/pid.h>
62#include <linux/slab.h>
62 63
63#include <linux/audit.h> 64#include <linux/audit.h>
64 65
@@ -152,12 +153,7 @@ static atomic_t audit_lost = ATOMIC_INIT(0);
152/* Hash for inode-based rules */ 153/* Hash for inode-based rules */
153struct list_head audit_inode_hash[AUDIT_INODE_BUCKETS]; 154struct list_head audit_inode_hash[AUDIT_INODE_BUCKETS];
154 155
155/* The audit_freelist is a list of pre-allocated audit buffers (if more 156static struct kmem_cache *audit_buffer_cache;
156 * than AUDIT_MAXFREE are in use, the audit buffer is freed instead of
157 * being placed on the freelist). */
158static DEFINE_SPINLOCK(audit_freelist_lock);
159static int audit_freelist_count;
160static LIST_HEAD(audit_freelist);
161 157
162/* queue msgs to send via kauditd_task */ 158/* queue msgs to send via kauditd_task */
163static struct sk_buff_head audit_queue; 159static struct sk_buff_head audit_queue;
@@ -192,17 +188,12 @@ DEFINE_MUTEX(audit_cmd_mutex);
192 * should be at least that large. */ 188 * should be at least that large. */
193#define AUDIT_BUFSIZ 1024 189#define AUDIT_BUFSIZ 1024
194 190
195/* AUDIT_MAXFREE is the number of empty audit_buffers we keep on the
196 * audit_freelist. Doing so eliminates many kmalloc/kfree calls. */
197#define AUDIT_MAXFREE (2*NR_CPUS)
198
199/* The audit_buffer is used when formatting an audit record. The caller 191/* The audit_buffer is used when formatting an audit record. The caller
200 * locks briefly to get the record off the freelist or to allocate the 192 * locks briefly to get the record off the freelist or to allocate the
201 * buffer, and locks briefly to send the buffer to the netlink layer or 193 * buffer, and locks briefly to send the buffer to the netlink layer or
202 * to place it on a transmit queue. Multiple audit_buffers can be in 194 * to place it on a transmit queue. Multiple audit_buffers can be in
203 * use simultaneously. */ 195 * use simultaneously. */
204struct audit_buffer { 196struct audit_buffer {
205 struct list_head list;
206 struct sk_buff *skb; /* formatted skb ready to send */ 197 struct sk_buff *skb; /* formatted skb ready to send */
207 struct audit_context *ctx; /* NULL or associated context */ 198 struct audit_context *ctx; /* NULL or associated context */
208 gfp_t gfp_mask; 199 gfp_t gfp_mask;
@@ -1486,6 +1477,10 @@ static int __init audit_init(void)
1486 if (audit_initialized == AUDIT_DISABLED) 1477 if (audit_initialized == AUDIT_DISABLED)
1487 return 0; 1478 return 0;
1488 1479
1480 audit_buffer_cache = kmem_cache_create("audit_buffer",
1481 sizeof(struct audit_buffer),
1482 0, SLAB_PANIC, NULL);
1483
1489 memset(&auditd_conn, 0, sizeof(auditd_conn)); 1484 memset(&auditd_conn, 0, sizeof(auditd_conn));
1490 spin_lock_init(&auditd_conn.lock); 1485 spin_lock_init(&auditd_conn.lock);
1491 1486
@@ -1554,60 +1549,33 @@ __setup("audit_backlog_limit=", audit_backlog_limit_set);
1554 1549
1555static void audit_buffer_free(struct audit_buffer *ab) 1550static void audit_buffer_free(struct audit_buffer *ab)
1556{ 1551{
1557 unsigned long flags;
1558
1559 if (!ab) 1552 if (!ab)
1560 return; 1553 return;
1561 1554
1562 kfree_skb(ab->skb); 1555 kfree_skb(ab->skb);
1563 spin_lock_irqsave(&audit_freelist_lock, flags); 1556 kmem_cache_free(audit_buffer_cache, ab);
1564 if (audit_freelist_count > AUDIT_MAXFREE)
1565 kfree(ab);
1566 else {
1567 audit_freelist_count++;
1568 list_add(&ab->list, &audit_freelist);
1569 }
1570 spin_unlock_irqrestore(&audit_freelist_lock, flags);
1571} 1557}
1572 1558
1573static struct audit_buffer * audit_buffer_alloc(struct audit_context *ctx, 1559static struct audit_buffer *audit_buffer_alloc(struct audit_context *ctx,
1574 gfp_t gfp_mask, int type) 1560 gfp_t gfp_mask, int type)
1575{ 1561{
1576 unsigned long flags; 1562 struct audit_buffer *ab;
1577 struct audit_buffer *ab = NULL;
1578 struct nlmsghdr *nlh;
1579
1580 spin_lock_irqsave(&audit_freelist_lock, flags);
1581 if (!list_empty(&audit_freelist)) {
1582 ab = list_entry(audit_freelist.next,
1583 struct audit_buffer, list);
1584 list_del(&ab->list);
1585 --audit_freelist_count;
1586 }
1587 spin_unlock_irqrestore(&audit_freelist_lock, flags);
1588
1589 if (!ab) {
1590 ab = kmalloc(sizeof(*ab), gfp_mask);
1591 if (!ab)
1592 goto err;
1593 }
1594 1563
1595 ab->ctx = ctx; 1564 ab = kmem_cache_alloc(audit_buffer_cache, gfp_mask);
1596 ab->gfp_mask = gfp_mask; 1565 if (!ab)
1566 return NULL;
1597 1567
1598 ab->skb = nlmsg_new(AUDIT_BUFSIZ, gfp_mask); 1568 ab->skb = nlmsg_new(AUDIT_BUFSIZ, gfp_mask);
1599 if (!ab->skb) 1569 if (!ab->skb)
1600 goto err; 1570 goto err;
1571 if (!nlmsg_put(ab->skb, 0, 0, type, 0, 0))
1572 goto err;
1601 1573
1602 nlh = nlmsg_put(ab->skb, 0, 0, type, 0, 0); 1574 ab->ctx = ctx;
1603 if (!nlh) 1575 ab->gfp_mask = gfp_mask;
1604 goto out_kfree_skb;
1605 1576
1606 return ab; 1577 return ab;
1607 1578
1608out_kfree_skb:
1609 kfree_skb(ab->skb);
1610 ab->skb = NULL;
1611err: 1579err:
1612 audit_buffer_free(ab); 1580 audit_buffer_free(ab);
1613 return NULL; 1581 return NULL;