aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorChris Wright <chrisw@osdl.org>2005-05-06 10:54:17 -0400
committerDavid Woodhouse <dwmw2@shinybook.infradead.org>2005-05-06 10:54:17 -0400
commit8fc6115c2a04099a6e846dc0b2d85cba43821b54 (patch)
tree6dc6bf0f59f6ada9ed42c79b0e641f8668a9bf0b /kernel
parent16e1904e694d459ec2ca9b33c22b818eaaa4c63f (diff)
AUDIT: expand audit tmp buffer as needed
Introduce audit_expand and make the audit_buffer use a dynamic buffer which can be resized. When audit buffer is moved to skb it will not be fragmented across skb's, so we can eliminate the sklist in the audit_buffer. During audit_log_move, we simply copy the full buffer into a single skb, and then audit_log_drain sends it on. 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.c139
1 files changed, 79 insertions, 60 deletions
diff --git a/kernel/audit.c b/kernel/audit.c
index e5bdba3e3ae1..c6e31d209c41 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -136,14 +136,11 @@ static DECLARE_MUTEX(audit_netlink_sem);
136 * use simultaneously. */ 136 * use simultaneously. */
137struct audit_buffer { 137struct audit_buffer {
138 struct list_head list; 138 struct list_head list;
139 struct sk_buff_head sklist; /* formatted skbs 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 */ 141 int len; /* used area of tmp */
142 char tmp[AUDIT_BUFSIZ]; 142 int size; /* size of tmp */
143 143 char *tmp;
144 /* Pointer to header and contents */
145 struct nlmsghdr *nlh;
146 int total;
147 int type; 144 int type;
148 int pid; 145 int pid;
149}; 146};
@@ -488,55 +485,47 @@ static void audit_receive(struct sock *sk, int length)
488static void audit_log_move(struct audit_buffer *ab) 485static void audit_log_move(struct audit_buffer *ab)
489{ 486{
490 struct sk_buff *skb; 487 struct sk_buff *skb;
488 struct nlmsghdr *nlh;
491 char *start; 489 char *start;
492 int extra = ab->nlh ? 0 : NLMSG_SPACE(0); 490 int len = NLMSG_SPACE(0) + ab->len + 1;
493 491
494 /* possible resubmission */ 492 /* possible resubmission */
495 if (ab->len == 0) 493 if (ab->skb)
496 return; 494 return;
497 495
498 skb = skb_peek_tail(&ab->sklist); 496 skb = alloc_skb(len, GFP_ATOMIC);
499 if (!skb || skb_tailroom(skb) <= ab->len + extra) { 497 if (!skb) {
500 skb = alloc_skb(2 * ab->len + extra, GFP_ATOMIC); 498 /* Lose information in ab->tmp */
501 if (!skb) { 499 audit_log_lost("out of memory in audit_log_move");
502 ab->len = 0; /* Lose information in ab->tmp */ 500 return;
503 audit_log_lost("out of memory in audit_log_move");
504 return;
505 }
506 __skb_queue_tail(&ab->sklist, skb);
507 if (!ab->nlh)
508 ab->nlh = (struct nlmsghdr *)skb_put(skb,
509 NLMSG_SPACE(0));
510 } 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;
511 start = skb_put(skb, ab->len); 509 start = skb_put(skb, ab->len);
512 memcpy(start, ab->tmp, ab->len); 510 memcpy(start, ab->tmp, ab->len);
513 ab->len = 0;
514} 511}
515 512
516/* Iterate over the skbuff in the audit_buffer, sending their contents 513/* Iterate over the skbuff in the audit_buffer, sending their contents
517 * to user space. */ 514 * to user space. */
518static inline int audit_log_drain(struct audit_buffer *ab) 515static inline int audit_log_drain(struct audit_buffer *ab)
519{ 516{
520 struct sk_buff *skb; 517 struct sk_buff *skb = ab->skb;
521 518
522 while ((skb = skb_dequeue(&ab->sklist))) { 519 if (skb) {
523 int retval = 0; 520 int retval = 0;
524 521
525 if (audit_pid) { 522 if (audit_pid) {
526 if (ab->nlh) {
527 ab->nlh->nlmsg_len = ab->total;
528 ab->nlh->nlmsg_type = ab->type;
529 ab->nlh->nlmsg_flags = 0;
530 ab->nlh->nlmsg_seq = 0;
531 ab->nlh->nlmsg_pid = ab->pid;
532 }
533 skb_get(skb); /* because netlink_* frees */ 523 skb_get(skb); /* because netlink_* frees */
534 retval = netlink_unicast(audit_sock, skb, audit_pid, 524 retval = netlink_unicast(audit_sock, skb, audit_pid,
535 MSG_DONTWAIT); 525 MSG_DONTWAIT);
536 } 526 }
537 if (retval == -EAGAIN && 527 if (retval == -EAGAIN &&
538 (atomic_read(&audit_backlog)) < audit_backlog_limit) { 528 (atomic_read(&audit_backlog)) < audit_backlog_limit) {
539 skb_queue_head(&ab->sklist, skb);
540 audit_log_end_irq(ab); 529 audit_log_end_irq(ab);
541 return 1; 530 return 1;
542 } 531 }
@@ -550,13 +539,12 @@ static inline int audit_log_drain(struct audit_buffer *ab)
550 audit_log_lost("netlink socket too busy"); 539 audit_log_lost("netlink socket too busy");
551 } 540 }
552 if (!audit_pid) { /* No daemon */ 541 if (!audit_pid) { /* No daemon */
553 int offset = ab->nlh ? NLMSG_SPACE(0) : 0; 542 int offset = NLMSG_SPACE(0);
554 int len = skb->len - offset; 543 int len = skb->len - offset;
555 skb->data[offset + len] = '\0'; 544 skb->data[offset + len] = '\0';
556 printk(KERN_ERR "%s\n", skb->data + offset); 545 printk(KERN_ERR "%s\n", skb->data + offset);
557 } 546 }
558 kfree_skb(skb); 547 kfree_skb(skb);
559 ab->nlh = NULL;
560 } 548 }
561 return 0; 549 return 0;
562} 550}
@@ -624,6 +612,10 @@ static void audit_buffer_free(struct audit_buffer *ab)
624{ 612{
625 unsigned long flags; 613 unsigned long flags;
626 614
615 if (!ab)
616 return;
617
618 kfree(ab->tmp);
627 atomic_dec(&audit_backlog); 619 atomic_dec(&audit_backlog);
628 spin_lock_irqsave(&audit_freelist_lock, flags); 620 spin_lock_irqsave(&audit_freelist_lock, flags);
629 if (++audit_freelist_count > AUDIT_MAXFREE) 621 if (++audit_freelist_count > AUDIT_MAXFREE)
@@ -633,7 +625,8 @@ static void audit_buffer_free(struct audit_buffer *ab)
633 spin_unlock_irqrestore(&audit_freelist_lock, flags); 625 spin_unlock_irqrestore(&audit_freelist_lock, flags);
634} 626}
635 627
636static struct audit_buffer * audit_buffer_alloc(int gfp_mask) 628static struct audit_buffer * audit_buffer_alloc(struct audit_context *ctx,
629 int gfp_mask)
637{ 630{
638 unsigned long flags; 631 unsigned long flags;
639 struct audit_buffer *ab = NULL; 632 struct audit_buffer *ab = NULL;
@@ -650,11 +643,24 @@ static struct audit_buffer * audit_buffer_alloc(int gfp_mask)
650 if (!ab) { 643 if (!ab) {
651 ab = kmalloc(sizeof(*ab), GFP_ATOMIC); 644 ab = kmalloc(sizeof(*ab), GFP_ATOMIC);
652 if (!ab) 645 if (!ab)
653 goto out; 646 goto err;
654 } 647 }
655 atomic_inc(&audit_backlog); 648 atomic_inc(&audit_backlog);
656out: 649
650 ab->tmp = kmalloc(AUDIT_BUFSIZ, GFP_ATOMIC);
651 if (!ab->tmp)
652 goto err;
653
654 ab->skb = NULL;
655 ab->ctx = ctx;
656 ab->len = 0;
657 ab->size = AUDIT_BUFSIZ;
658 ab->type = AUDIT_KERNEL;
659 ab->pid = 0;
657 return ab; 660 return ab;
661err:
662 audit_buffer_free(ab);
663 return NULL;
658} 664}
659 665
660/* Obtain an audit buffer. This routine does locking to obtain the 666/* Obtain an audit buffer. This routine does locking to obtain the
@@ -684,21 +690,12 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx)
684 return NULL; 690 return NULL;
685 } 691 }
686 692
687 ab = audit_buffer_alloc(GFP_ATOMIC); 693 ab = audit_buffer_alloc(ctx, GFP_ATOMIC);
688 if (!ab) { 694 if (!ab) {
689 audit_log_lost("out of memory in audit_log_start"); 695 audit_log_lost("out of memory in audit_log_start");
690 return NULL; 696 return NULL;
691 } 697 }
692 698
693 skb_queue_head_init(&ab->sklist);
694
695 ab->ctx = ctx;
696 ab->len = 0;
697 ab->nlh = NULL;
698 ab->total = 0;
699 ab->type = AUDIT_KERNEL;
700 ab->pid = 0;
701
702#ifdef CONFIG_AUDITSYSCALL 699#ifdef CONFIG_AUDITSYSCALL
703 if (ab->ctx) 700 if (ab->ctx)
704 audit_get_stamp(ab->ctx, &t, &serial); 701 audit_get_stamp(ab->ctx, &t, &serial);
@@ -713,6 +710,27 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx)
713 return ab; 710 return ab;
714} 711}
715 712
713/**
714 * audit_expand - expand tmp buffer in the audit buffer
715 * @ab: audit_buffer
716 *
717 * Returns 0 (no space) on failed expansion, or available space if
718 * successful.
719 */
720static inline int audit_expand(struct audit_buffer *ab)
721{
722 char *tmp;
723 int len = ab->size + AUDIT_BUFSIZ;
724
725 tmp = kmalloc(len, GFP_ATOMIC);
726 if (!tmp)
727 return 0;
728 memcpy(tmp, ab->tmp, ab->len);
729 kfree(ab->tmp);
730 ab->tmp = tmp;
731 ab->size = len;
732 return ab->size - ab->len;
733}
716 734
717/* Format an audit message into the audit buffer. If there isn't enough 735/* Format an audit message into the audit buffer. If there isn't enough
718 * room in the audit buffer, more room will be allocated and vsnprint 736 * room in the audit buffer, more room will be allocated and vsnprint
@@ -726,22 +744,25 @@ static void audit_log_vformat(struct audit_buffer *ab, const char *fmt,
726 if (!ab) 744 if (!ab)
727 return; 745 return;
728 746
729 avail = sizeof(ab->tmp) - ab->len; 747 avail = ab->size - ab->len;
730 if (avail <= 0) { 748 if (avail <= 0) {
731 audit_log_move(ab); 749 avail = audit_expand(ab);
732 avail = sizeof(ab->tmp) - ab->len; 750 if (!avail)
751 goto out;
733 } 752 }
734 len = vsnprintf(ab->tmp + ab->len, avail, fmt, args); 753 len = vsnprintf(ab->tmp + ab->len, avail, fmt, args);
735 if (len >= avail) { 754 if (len >= avail) {
736 /* The printk buffer is 1024 bytes long, so if we get 755 /* The printk buffer is 1024 bytes long, so if we get
737 * here and AUDIT_BUFSIZ is at least 1024, then we can 756 * here and AUDIT_BUFSIZ is at least 1024, then we can
738 * log everything that printk could have logged. */ 757 * log everything that printk could have logged. */
739 audit_log_move(ab); 758 avail = audit_expand(ab);
740 avail = sizeof(ab->tmp) - ab->len; 759 if (!avail)
741 len = vsnprintf(ab->tmp + ab->len, avail, fmt, args); 760 goto out;
761 len = vsnprintf(ab->tmp + ab->len, avail, fmt, args);
742 } 762 }
743 ab->len += (len < avail) ? len : avail; 763 ab->len += (len < avail) ? len : avail;
744 ab->total += (len < avail) ? len : avail; 764out:
765 return;
745} 766}
746 767
747/* Format a message into the audit buffer. All the work is done in 768/* Format a message into the audit buffer. All the work is done in
@@ -789,21 +810,19 @@ void audit_log_d_path(struct audit_buffer *ab, const char *prefix,
789 char *p; 810 char *p;
790 int len, avail; 811 int len, avail;
791 812
792 if (prefix) audit_log_format(ab, " %s", prefix); 813 if (prefix)
814 audit_log_format(ab, " %s", prefix);
793 815
794 if (ab->len > 128) 816 avail = ab->size - ab->len;
795 audit_log_move(ab);
796 avail = sizeof(ab->tmp) - ab->len;
797 p = d_path(dentry, vfsmnt, ab->tmp + ab->len, avail); 817 p = d_path(dentry, vfsmnt, ab->tmp + ab->len, avail);
798 if (IS_ERR(p)) { 818 if (IS_ERR(p)) {
799 /* FIXME: can we save some information here? */ 819 /* FIXME: can we save some information here? */
800 audit_log_format(ab, "<toolong>"); 820 audit_log_format(ab, "<toolong>");
801 } else { 821 } else {
802 /* path isn't at start of buffer */ 822 /* path isn't at start of buffer */
803 len = (ab->tmp + sizeof(ab->tmp) - 1) - p; 823 len = (ab->tmp + ab->size - 1) - p;
804 memmove(ab->tmp + ab->len, p, len); 824 memmove(ab->tmp + ab->len, p, len);
805 ab->len += len; 825 ab->len += len;
806 ab->total += len;
807 } 826 }
808} 827}
809 828