aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorSteve Grubb <sgrubb@redhat.com>2005-05-19 05:24:22 -0400
committerDavid Woodhouse <dwmw2@shinybook.infradead.org>2005-05-19 05:24:22 -0400
commit168b7173959f80d20720dd1f7ec909a88ef2689d (patch)
treedc197062e11c003b330b5302535fd74407c2138b /kernel
parent209aba03243ee42a22f8df8d08aa9963f62aec64 (diff)
AUDIT: Clean up logging of untrusted strings
* If vsnprintf returns -1, it will mess up the sk buffer space accounting. This is fixed by not calling skb_put with bogus len values. * audit_log_hex was a loop that called audit_log_vformat with %02X for each character. This is very inefficient since conversion from unsigned character to Ascii representation is essentially masking, shifting, and byte lookups. Also, the length of the converted string is well known - it's twice the original. Fixed by rewriting the function. * audit_log_untrustedstring had no comments. This makes it hard for someone to understand what the string format will be. * audit_log_d_path was never fixed to use untrustedstring. This could mess up user space parsers. This was fixed to make a temp buffer, call d_path, and log temp buffer using untrustedstring. From: Steve Grubb <sgrubb@redhat.com> Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/audit.c71
1 files changed, 48 insertions, 23 deletions
diff --git a/kernel/audit.c b/kernel/audit.c
index e6d88635032c..dae3570b3a3b 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -692,7 +692,8 @@ static void audit_log_vformat(struct audit_buffer *ab, const char *fmt,
692 goto out; 692 goto out;
693 len = vsnprintf(skb->tail, avail, fmt, args2); 693 len = vsnprintf(skb->tail, avail, fmt, args2);
694 } 694 }
695 skb_put(skb, (len < avail) ? len : avail); 695 if (len > 0)
696 skb_put(skb, len);
696out: 697out:
697 return; 698 return;
698} 699}
@@ -710,20 +711,47 @@ void audit_log_format(struct audit_buffer *ab, const char *fmt, ...)
710 va_end(args); 711 va_end(args);
711} 712}
712 713
713void audit_log_hex(struct audit_buffer *ab, const unsigned char *buf, size_t len) 714/* This function will take the passed buf and convert it into a string of
715 * ascii hex digits. The new string is placed onto the skb. */
716void audit_log_hex(struct audit_buffer *ab, const unsigned char *buf,
717 size_t len)
714{ 718{
715 int i; 719 int i, avail, new_len;
720 unsigned char *ptr;
721 struct sk_buff *skb;
722 static const unsigned char *hex = "0123456789ABCDEF";
723
724 BUG_ON(!ab->skb);
725 skb = ab->skb;
726 avail = skb_tailroom(skb);
727 new_len = len<<1;
728 if (new_len >= avail) {
729 /* Round the buffer request up to the next multiple */
730 new_len = AUDIT_BUFSIZ*(((new_len-avail)/AUDIT_BUFSIZ) + 1);
731 avail = audit_expand(ab, new_len);
732 if (!avail)
733 return;
734 }
716 735
717 for (i=0; i<len; i++) 736 ptr = skb->tail;
718 audit_log_format(ab, "%02x", buf[i]); 737 for (i=0; i<len; i++) {
738 *ptr++ = hex[(buf[i] & 0xF0)>>4]; /* Upper nibble */
739 *ptr++ = hex[buf[i] & 0x0F]; /* Lower nibble */
740 }
741 *ptr = 0;
742 skb_put(skb, len << 1); /* new string is twice the old string */
719} 743}
720 744
745/* This code will escape a string that is passed to it if the string
746 * contains a control character, unprintable character, double quote mark,
747 * or a space. Unescaped strings will start and end with a double quote mark.
748 * Strings that are escaped are printed in hex (2 digits per char). */
721void audit_log_untrustedstring(struct audit_buffer *ab, const char *string) 749void audit_log_untrustedstring(struct audit_buffer *ab, const char *string)
722{ 750{
723 const unsigned char *p = string; 751 const unsigned char *p = string;
724 752
725 while (*p) { 753 while (*p) {
726 if (*p == '"' || *p == ' ' || *p < 0x20 || *p > 0x7f) { 754 if (*p == '"' || *p < 0x21 || *p > 0x7f) {
727 audit_log_hex(ab, string, strlen(string)); 755 audit_log_hex(ab, string, strlen(string));
728 return; 756 return;
729 } 757 }
@@ -732,31 +760,28 @@ void audit_log_untrustedstring(struct audit_buffer *ab, const char *string)
732 audit_log_format(ab, "\"%s\"", string); 760 audit_log_format(ab, "\"%s\"", string);
733} 761}
734 762
735 763/* This is a helper-function to print the escaped d_path */
736/* This is a helper-function to print the d_path without using a static
737 * buffer or allocating another buffer in addition to the one in
738 * audit_buffer. */
739void audit_log_d_path(struct audit_buffer *ab, const char *prefix, 764void audit_log_d_path(struct audit_buffer *ab, const char *prefix,
740 struct dentry *dentry, struct vfsmount *vfsmnt) 765 struct dentry *dentry, struct vfsmount *vfsmnt)
741{ 766{
742 char *p; 767 char *p, *path;
743 struct sk_buff *skb = ab->skb;
744 int len, avail;
745 768
746 if (prefix) 769 if (prefix)
747 audit_log_format(ab, " %s", prefix); 770 audit_log_format(ab, " %s", prefix);
748 771
749 avail = skb_tailroom(skb); 772 /* We will allow 11 spaces for ' (deleted)' to be appended */
750 p = d_path(dentry, vfsmnt, skb->tail, avail); 773 path = kmalloc(PATH_MAX+11, GFP_KERNEL);
751 if (IS_ERR(p)) { 774 if (!path) {
752 /* FIXME: can we save some information here? */ 775 audit_log_format(ab, "<no memory>");
753 audit_log_format(ab, "<toolong>"); 776 return;
754 } else {
755 /* path isn't at start of buffer */
756 len = ((char *)skb->tail + avail - 1) - p;
757 memmove(skb->tail, p, len);
758 skb_put(skb, len);
759 } 777 }
778 p = d_path(dentry, vfsmnt, path, PATH_MAX+11);
779 if (IS_ERR(p)) { /* Should never happen since we send PATH_MAX */
780 /* FIXME: can we save some information here? */
781 audit_log_format(ab, "<too long>");
782 } else
783 audit_log_untrustedstring(ab, p);
784 kfree(path);
760} 785}
761 786
762/* Remove queued messages from the audit_txlist and send them to user space. */ 787/* Remove queued messages from the audit_txlist and send them to user space. */