aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorChris Wright <chrisw@osdl.org>2005-05-06 10:54:53 -0400
committerDavid Woodhouse <dwmw2@shinybook.infradead.org>2005-05-06 10:54:53 -0400
commit5ac52f33b6f05fcb91a97124155183b779a4efdf (patch)
tree9987d074c840a7afa731660400f4d5a8a8bad973 /kernel
parent8fc6115c2a04099a6e846dc0b2d85cba43821b54 (diff)
AUDIT: buffer audit msgs directly to skb
Drop the use of a tmp buffer in the audit_buffer, and just buffer directly to the skb. All header data that was temporarily stored in the audit_buffer can now be stored directly in the netlink header in the skb. Resize skb as needed. This eliminates the extra copy (and the audit_log_move function which was responsible for copying). Signed-off-by: Chris Wright <chrisw@osdl.org> Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/audit.c122
1 files changed, 46 insertions, 76 deletions
diff --git a/kernel/audit.c b/kernel/audit.c
index c6e31d209c41..993e445418a7 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -138,16 +138,18 @@ struct audit_buffer {
138 struct list_head list; 138 struct list_head list;
139 struct sk_buff *skb; /* formatted skb ready to send */ 139 struct sk_buff *skb; /* formatted skb ready to send */
140 struct audit_context *ctx; /* NULL or associated context */ 140 struct audit_context *ctx; /* NULL or associated context */
141 int len; /* used area of tmp */
142 int size; /* size of tmp */
143 char *tmp;
144 int type;
145 int pid;
146}; 141};
147 142
148void audit_set_type(struct audit_buffer *ab, int type) 143void audit_set_type(struct audit_buffer *ab, int type)
149{ 144{
150 ab->type = type; 145 struct nlmsghdr *nlh = (struct nlmsghdr *)ab->skb->data;
146 nlh->nlmsg_type = type;
147}
148
149static void audit_set_pid(struct audit_buffer *ab, pid_t pid)
150{
151 struct nlmsghdr *nlh = (struct nlmsghdr *)ab->skb->data;
152 nlh->nlmsg_pid = pid;
151} 153}
152 154
153struct audit_entry { 155struct audit_entry {
@@ -405,8 +407,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
405 (int)(nlh->nlmsg_len 407 (int)(nlh->nlmsg_len
406 - ((char *)data - (char *)nlh)), 408 - ((char *)data - (char *)nlh)),
407 loginuid, (char *)data); 409 loginuid, (char *)data);
408 ab->type = AUDIT_USER; 410 audit_set_type(ab, AUDIT_USER);
409 ab->pid = pid; 411 audit_set_pid(ab, pid);
410 audit_log_end(ab); 412 audit_log_end(ab);
411 break; 413 break;
412 case AUDIT_ADD: 414 case AUDIT_ADD:
@@ -476,42 +478,7 @@ static void audit_receive(struct sock *sk, int length)
476 up(&audit_netlink_sem); 478 up(&audit_netlink_sem);
477} 479}
478 480
479/* Move data from tmp buffer into an skb. This is an extra copy, and 481/* Grab skbuff from the audit_buffer and send to user space. */
480 * that is unfortunate. However, the copy will only occur when a record
481 * is being written to user space, which is already a high-overhead
482 * operation. (Elimination of the copy is possible, for example, by
483 * writing directly into a pre-allocated skb, at the cost of wasting
484 * memory. */
485static void audit_log_move(struct audit_buffer *ab)
486{
487 struct sk_buff *skb;
488 struct nlmsghdr *nlh;
489 char *start;
490 int len = NLMSG_SPACE(0) + ab->len + 1;
491
492 /* possible resubmission */
493 if (ab->skb)
494 return;
495
496 skb = alloc_skb(len, GFP_ATOMIC);
497 if (!skb) {
498 /* Lose information in ab->tmp */
499 audit_log_lost("out of memory in audit_log_move");
500 return;
501 }
502 ab->skb = skb;
503 nlh = (struct nlmsghdr *)skb_put(skb, NLMSG_SPACE(0));
504 nlh->nlmsg_type = ab->type;
505 nlh->nlmsg_len = ab->len;
506 nlh->nlmsg_flags = 0;
507 nlh->nlmsg_pid = ab->pid;
508 nlh->nlmsg_seq = 0;
509 start = skb_put(skb, ab->len);
510 memcpy(start, ab->tmp, ab->len);
511}
512
513/* Iterate over the skbuff in the audit_buffer, sending their contents
514 * to user space. */
515static inline int audit_log_drain(struct audit_buffer *ab) 482static inline int audit_log_drain(struct audit_buffer *ab)
516{ 483{
517 struct sk_buff *skb = ab->skb; 484 struct sk_buff *skb = ab->skb;
@@ -520,6 +487,8 @@ static inline int audit_log_drain(struct audit_buffer *ab)
520 int retval = 0; 487 int retval = 0;
521 488
522 if (audit_pid) { 489 if (audit_pid) {
490 struct nlmsghdr *nlh = (struct nlmsghdr *)skb->data;
491 nlh->nlmsg_len = skb->len;
523 skb_get(skb); /* because netlink_* frees */ 492 skb_get(skb); /* because netlink_* frees */
524 retval = netlink_unicast(audit_sock, skb, audit_pid, 493 retval = netlink_unicast(audit_sock, skb, audit_pid,
525 MSG_DONTWAIT); 494 MSG_DONTWAIT);
@@ -544,7 +513,6 @@ static inline int audit_log_drain(struct audit_buffer *ab)
544 skb->data[offset + len] = '\0'; 513 skb->data[offset + len] = '\0';
545 printk(KERN_ERR "%s\n", skb->data + offset); 514 printk(KERN_ERR "%s\n", skb->data + offset);
546 } 515 }
547 kfree_skb(skb);
548 } 516 }
549 return 0; 517 return 0;
550} 518}
@@ -615,7 +583,8 @@ static void audit_buffer_free(struct audit_buffer *ab)
615 if (!ab) 583 if (!ab)
616 return; 584 return;
617 585
618 kfree(ab->tmp); 586 if (ab->skb)
587 kfree_skb(ab->skb);
619 atomic_dec(&audit_backlog); 588 atomic_dec(&audit_backlog);
620 spin_lock_irqsave(&audit_freelist_lock, flags); 589 spin_lock_irqsave(&audit_freelist_lock, flags);
621 if (++audit_freelist_count > AUDIT_MAXFREE) 590 if (++audit_freelist_count > AUDIT_MAXFREE)
@@ -630,6 +599,7 @@ static struct audit_buffer * audit_buffer_alloc(struct audit_context *ctx,
630{ 599{
631 unsigned long flags; 600 unsigned long flags;
632 struct audit_buffer *ab = NULL; 601 struct audit_buffer *ab = NULL;
602 struct nlmsghdr *nlh;
633 603
634 spin_lock_irqsave(&audit_freelist_lock, flags); 604 spin_lock_irqsave(&audit_freelist_lock, flags);
635 if (!list_empty(&audit_freelist)) { 605 if (!list_empty(&audit_freelist)) {
@@ -647,16 +617,16 @@ static struct audit_buffer * audit_buffer_alloc(struct audit_context *ctx,
647 } 617 }
648 atomic_inc(&audit_backlog); 618 atomic_inc(&audit_backlog);
649 619
650 ab->tmp = kmalloc(AUDIT_BUFSIZ, GFP_ATOMIC); 620 ab->skb = alloc_skb(AUDIT_BUFSIZ, GFP_ATOMIC);
651 if (!ab->tmp) 621 if (!ab->skb)
652 goto err; 622 goto err;
653 623
654 ab->skb = NULL;
655 ab->ctx = ctx; 624 ab->ctx = ctx;
656 ab->len = 0; 625 nlh = (struct nlmsghdr *)skb_put(ab->skb, NLMSG_SPACE(0));
657 ab->size = AUDIT_BUFSIZ; 626 nlh->nlmsg_type = AUDIT_KERNEL;
658 ab->type = AUDIT_KERNEL; 627 nlh->nlmsg_flags = 0;
659 ab->pid = 0; 628 nlh->nlmsg_pid = 0;
629 nlh->nlmsg_seq = 0;
660 return ab; 630 return ab;
661err: 631err:
662 audit_buffer_free(ab); 632 audit_buffer_free(ab);
@@ -711,7 +681,7 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx)
711} 681}
712 682
713/** 683/**
714 * audit_expand - expand tmp buffer in the audit buffer 684 * audit_expand - expand skb in the audit buffer
715 * @ab: audit_buffer 685 * @ab: audit_buffer
716 * 686 *
717 * Returns 0 (no space) on failed expansion, or available space if 687 * Returns 0 (no space) on failed expansion, or available space if
@@ -719,17 +689,14 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx)
719 */ 689 */
720static inline int audit_expand(struct audit_buffer *ab) 690static inline int audit_expand(struct audit_buffer *ab)
721{ 691{
722 char *tmp; 692 struct sk_buff *skb = ab->skb;
723 int len = ab->size + AUDIT_BUFSIZ; 693 int ret = pskb_expand_head(skb, skb_headroom(skb), AUDIT_BUFSIZ,
724 694 GFP_ATOMIC);
725 tmp = kmalloc(len, GFP_ATOMIC); 695 if (ret < 0) {
726 if (!tmp) 696 audit_log_lost("out of memory in audit_expand");
727 return 0; 697 return 0;
728 memcpy(tmp, ab->tmp, ab->len); 698 }
729 kfree(ab->tmp); 699 return skb_tailroom(skb);
730 ab->tmp = tmp;
731 ab->size = len;
732 return ab->size - ab->len;
733} 700}
734 701
735/* Format an audit message into the audit buffer. If there isn't enough 702/* Format an audit message into the audit buffer. If there isn't enough
@@ -740,17 +707,20 @@ static void audit_log_vformat(struct audit_buffer *ab, const char *fmt,
740 va_list args) 707 va_list args)
741{ 708{
742 int len, avail; 709 int len, avail;
710 struct sk_buff *skb;
743 711
744 if (!ab) 712 if (!ab)
745 return; 713 return;
746 714
747 avail = ab->size - ab->len; 715 BUG_ON(!ab->skb);
748 if (avail <= 0) { 716 skb = ab->skb;
717 avail = skb_tailroom(skb);
718 if (avail == 0) {
749 avail = audit_expand(ab); 719 avail = audit_expand(ab);
750 if (!avail) 720 if (!avail)
751 goto out; 721 goto out;
752 } 722 }
753 len = vsnprintf(ab->tmp + ab->len, avail, fmt, args); 723 len = vsnprintf(skb->tail, avail, fmt, args);
754 if (len >= avail) { 724 if (len >= avail) {
755 /* The printk buffer is 1024 bytes long, so if we get 725 /* The printk buffer is 1024 bytes long, so if we get
756 * here and AUDIT_BUFSIZ is at least 1024, then we can 726 * here and AUDIT_BUFSIZ is at least 1024, then we can
@@ -758,9 +728,9 @@ static void audit_log_vformat(struct audit_buffer *ab, const char *fmt,
758 avail = audit_expand(ab); 728 avail = audit_expand(ab);
759 if (!avail) 729 if (!avail)
760 goto out; 730 goto out;
761 len = vsnprintf(ab->tmp + ab->len, avail, fmt, args); 731 len = vsnprintf(skb->tail, avail, fmt, args);
762 } 732 }
763 ab->len += (len < avail) ? len : avail; 733 skb_put(skb, (len < avail) ? len : avail);
764out: 734out:
765 return; 735 return;
766} 736}
@@ -808,21 +778,22 @@ void audit_log_d_path(struct audit_buffer *ab, const char *prefix,
808 struct dentry *dentry, struct vfsmount *vfsmnt) 778 struct dentry *dentry, struct vfsmount *vfsmnt)
809{ 779{
810 char *p; 780 char *p;
781 struct sk_buff *skb = ab->skb;
811 int len, avail; 782 int len, avail;
812 783
813 if (prefix) 784 if (prefix)
814 audit_log_format(ab, " %s", prefix); 785 audit_log_format(ab, " %s", prefix);
815 786
816 avail = ab->size - ab->len; 787 avail = skb_tailroom(skb);
817 p = d_path(dentry, vfsmnt, ab->tmp + ab->len, avail); 788 p = d_path(dentry, vfsmnt, skb->tail, avail);
818 if (IS_ERR(p)) { 789 if (IS_ERR(p)) {
819 /* FIXME: can we save some information here? */ 790 /* FIXME: can we save some information here? */
820 audit_log_format(ab, "<toolong>"); 791 audit_log_format(ab, "<toolong>");
821 } else { 792 } else {
822 /* path isn't at start of buffer */ 793 /* path isn't at start of buffer */
823 len = (ab->tmp + ab->size - 1) - p; 794 len = ((char *)skb->tail + avail - 1) - p;
824 memmove(ab->tmp + ab->len, p, len); 795 memmove(skb->tail, p, len);
825 ab->len += len; 796 skb_put(skb, len);
826 } 797 }
827} 798}
828 799
@@ -873,7 +844,6 @@ static void audit_log_end_fast(struct audit_buffer *ab)
873 if (!audit_rate_check()) { 844 if (!audit_rate_check()) {
874 audit_log_lost("rate limit exceeded"); 845 audit_log_lost("rate limit exceeded");
875 } else { 846 } else {
876 audit_log_move(ab);
877 if (audit_log_drain(ab)) 847 if (audit_log_drain(ab))
878 return; 848 return;
879 } 849 }