Merge master.kernel.org:/home/rmk/linux-2.6-arm
[pandora-kernel.git] / kernel / audit.c
index bbc6f54..7f06997 100644 (file)
@@ -234,7 +234,7 @@ static int audit_set_rate_limit(int limit, uid_t loginuid)
        int old          = audit_rate_limit;
        audit_rate_limit = limit;
        audit_log(NULL, AUDIT_CONFIG_CHANGE, 
-                       "audit_rate_limit=%d old=%d by auid %u",
+                       "audit_rate_limit=%d old=%d by auid=%u",
                        audit_rate_limit, old, loginuid);
        return old;
 }
@@ -244,7 +244,7 @@ static int audit_set_backlog_limit(int limit, uid_t loginuid)
        int old          = audit_backlog_limit;
        audit_backlog_limit = limit;
        audit_log(NULL, AUDIT_CONFIG_CHANGE,
-                       "audit_backlog_limit=%d old=%d by auid %u",
+                       "audit_backlog_limit=%d old=%d by auid=%u",
                        audit_backlog_limit, old, loginuid);
        return old;
 }
@@ -256,7 +256,7 @@ static int audit_set_enabled(int state, uid_t loginuid)
                return -EINVAL;
        audit_enabled = state;
        audit_log(NULL, AUDIT_CONFIG_CHANGE,
-                       "audit_enabled=%d old=%d by auid %u",
+                       "audit_enabled=%d old=%d by auid=%u",
                        audit_enabled, old, loginuid);
        return old;
 }
@@ -270,7 +270,7 @@ static int audit_set_failure(int state, uid_t loginuid)
                return -EINVAL;
        audit_failure = state;
        audit_log(NULL, AUDIT_CONFIG_CHANGE,
-                       "audit_failure=%d old=%d by auid %u",
+                       "audit_failure=%d old=%d by auid=%u",
                        audit_failure, old, loginuid);
        return old;
 }
@@ -354,6 +354,7 @@ static int audit_netlink_ok(kernel_cap_t eff_cap, u16 msg_type)
                if (!cap_raised(eff_cap, CAP_AUDIT_CONTROL))
                        err = -EPERM;
                break;
+       case AUDIT_USER:
        case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG:
                if (!cap_raised(eff_cap, CAP_AUDIT_WRITE))
                        err = -EPERM;
@@ -423,7 +424,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                        int old   = audit_pid;
                        audit_pid = status_get->pid;
                        audit_log(NULL, AUDIT_CONFIG_CHANGE,
-                               "audit_pid=%d old=%d by auid %u",
+                               "audit_pid=%d old=%d by auid=%u",
                                  audit_pid, old, loginuid);
                }
                if (status_get->mask & AUDIT_STATUS_RATE_LIMIT)
@@ -432,17 +433,15 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                        audit_set_backlog_limit(status_get->backlog_limit,
                                                        loginuid);
                break;
+       case AUDIT_USER:
        case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG:
                ab = audit_log_start(NULL, msg_type);
                if (!ab)
                        break;  /* audit_panic has been called */
                audit_log_format(ab,
-                                "user pid=%d uid=%d length=%d loginuid=%u"
+                                "user pid=%d uid=%u auid=%u"
                                 " msg='%.1024s'",
-                                pid, uid,
-                                (int)(nlh->nlmsg_len
-                                      - ((char *)data - (char *)nlh)),
-                                loginuid, (char *)data);
+                                pid, uid, loginuid, (char *)data);
                audit_set_pid(ab, pid);
                audit_log_end(ab);
                break;
@@ -515,7 +514,8 @@ static int __init audit_init(void)
 {
        printk(KERN_INFO "audit: initializing netlink socket (%s)\n",
               audit_default ? "enabled" : "disabled");
-       audit_sock = netlink_kernel_create(NETLINK_AUDIT, audit_receive);
+       audit_sock = netlink_kernel_create(NETLINK_AUDIT, 0, audit_receive,
+                                          THIS_MODULE);
        if (!audit_sock)
                audit_panic("cannot initialize netlink socket");
 
@@ -598,6 +598,47 @@ err:
        return NULL;
 }
 
+/* Compute a serial number for the audit record.  Audit records are
+ * written to user-space as soon as they are generated, so a complete
+ * audit record may be written in several pieces.  The timestamp of the
+ * record and this serial number are used by the user-space tools to
+ * determine which pieces belong to the same audit record.  The
+ * (timestamp,serial) tuple is unique for each syscall and is live from
+ * syscall entry to syscall exit.
+ *
+ * Atomic values are only guaranteed to be 24-bit, so we count down.
+ *
+ * NOTE: Another possibility is to store the formatted records off the
+ * audit context (for those records that have a context), and emit them
+ * all at syscall exit.  However, this could delay the reporting of
+ * significant errors until syscall exit (or never, if the system
+ * halts). */
+unsigned int audit_serial(void)
+{
+       static atomic_t serial = ATOMIC_INIT(0xffffff);
+       unsigned int a, b;
+
+       do {
+               a = atomic_read(&serial);
+               if (atomic_dec_and_test(&serial))
+                       atomic_set(&serial, 0xffffff);
+               b = atomic_read(&serial);
+       } while (b != a - 1);
+
+       return 0xffffff - b;
+}
+
+static inline void audit_get_stamp(struct audit_context *ctx, 
+                                  struct timespec *t, unsigned int *serial)
+{
+       if (ctx)
+               auditsc_get_stamp(ctx, t, serial);
+       else {
+               *t = CURRENT_TIME;
+               *serial = audit_serial();
+       }
+}
+
 /* Obtain an audit buffer.  This routine does locking to obtain the
  * audit buffer, but then no locking is required for calls to
  * audit_log_*format.  If the tsk is a task that is currently in a
@@ -613,16 +654,25 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, int type)
        if (!audit_initialized)
                return NULL;
 
+       if (audit_backlog_limit
+           && skb_queue_len(&audit_skb_queue) > audit_backlog_limit) {
+               if (audit_rate_check())
+                       printk(KERN_WARNING
+                              "audit: audit_backlog=%d > "
+                              "audit_backlog_limit=%d\n",
+                              skb_queue_len(&audit_skb_queue),
+                              audit_backlog_limit);
+               audit_log_lost("backlog limit exceeded");
+               return NULL;
+       }
+
        ab = audit_buffer_alloc(ctx, GFP_ATOMIC, type);
        if (!ab) {
                audit_log_lost("out of memory in audit_log_start");
                return NULL;
        }
 
-       if (!audit_get_stamp(ab->ctx, &t, &serial)) {
-               t = CURRENT_TIME;
-               serial = 0;
-       }
+       audit_get_stamp(ab->ctx, &t, &serial);
 
        audit_log_format(ab, "audit(%lu.%03lu:%u): ",
                         t.tv_sec, t.tv_nsec/1000000, serial);