AUDIT: Capture sys_socketcall arguments and sockaddrs
[safe/jmp/linux-2.6] / kernel / auditsc.c
index 49ecd70..818778d 100644 (file)
@@ -1,4 +1,4 @@
-/* auditsc.c -- System-call auditing support -*- linux-c -*-
+/* auditsc.c -- System-call auditing support
  * Handles all system-call specific auditing features.
  *
  * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina.
@@ -34,7 +34,7 @@
 #include <asm/types.h>
 #include <linux/mm.h>
 #include <linux/module.h>
-
+#include <linux/socket.h>
 #include <linux/audit.h>
 #include <linux/personality.h>
 #include <linux/time.h>
@@ -112,6 +112,18 @@ struct audit_aux_data_ipcctl {
        mode_t                  mode;
 };
 
+struct audit_aux_data_socketcall {
+       struct audit_aux_data   d;
+       int                     nargs;
+       unsigned long           args[0];
+};
+
+struct audit_aux_data_sockaddr {
+       struct audit_aux_data   d;
+       int                     len;
+       char                    a[0];
+};
+
 
 /* The per-task audit context. */
 struct audit_context {
@@ -226,7 +238,6 @@ static inline int audit_del_rule(struct audit_rule *rule,
        return -EFAULT;         /* No matching rule */
 }
 
-#ifdef CONFIG_NET
 /* Copy rule from user-space to kernel-space.  Called during
  * AUDIT_ADD. */
 static int audit_copy_rule(struct audit_rule *d, struct audit_rule *s)
@@ -251,7 +262,8 @@ static int audit_copy_rule(struct audit_rule *d, struct audit_rule *s)
        return 0;
 }
 
-int audit_receive_filter(int type, int pid, int uid, int seq, void *data)
+int audit_receive_filter(int type, int pid, int uid, int seq, void *data,
+                                                       uid_t loginuid)
 {
        u32                flags;
        struct audit_entry *entry;
@@ -286,6 +298,8 @@ int audit_receive_filter(int type, int pid, int uid, int seq, void *data)
                        err = audit_add_rule(entry, &audit_entlist);
                if (!err && (flags & AUDIT_AT_EXIT))
                        err = audit_add_rule(entry, &audit_extlist);
+               audit_log(NULL, AUDIT_CONFIG_CHANGE, 
+                               "auid %u added an audit rule\n", loginuid);
                break;
        case AUDIT_DEL:
                flags =((struct audit_rule *)data)->flags;
@@ -295,6 +309,8 @@ int audit_receive_filter(int type, int pid, int uid, int seq, void *data)
                        err = audit_del_rule(data, &audit_entlist);
                if (!err && (flags & AUDIT_AT_EXIT))
                        err = audit_del_rule(data, &audit_extlist);
+               audit_log(NULL, AUDIT_CONFIG_CHANGE,
+                               "auid %u removed an audit rule\n", loginuid);
                break;
        default:
                return -EINVAL;
@@ -302,7 +318,6 @@ int audit_receive_filter(int type, int pid, int uid, int seq, void *data)
 
        return err;
 }
-#endif
 
 /* Compare a task_struct with an audit_rule.  Return 1 on match, 0
  * otherwise. */
@@ -441,7 +456,7 @@ static enum audit_state audit_filter_task(struct task_struct *tsk)
 
 /* At syscall entry and exit time, this filter is called if the
  * audit_state is not low enough that auditing cannot take place, but is
- * also not high enough that we already know we have to write and audit
+ * also not high enough that we already know we have to write an audit
  * record (i.e., the state is AUDIT_SETUP_CONTEXT or  AUDIT_BUILD_CONTEXT).
  */
 static enum audit_state audit_filter_syscall(struct task_struct *tsk,
@@ -647,7 +662,7 @@ static void audit_log_exit(struct audit_context *context)
        int i;
        struct audit_buffer *ab;
 
-       ab = audit_log_start(context);
+       ab = audit_log_start(context, AUDIT_SYSCALL);
        if (!ab)
                return;         /* audit_panic has been called */
        audit_log_format(ab, "syscall=%d", context->major);
@@ -679,28 +694,43 @@ static void audit_log_exit(struct audit_context *context)
        while (context->aux) {
                struct audit_aux_data *aux;
 
-               ab = audit_log_start(context);
+               aux = context->aux;
+
+               ab = audit_log_start(context, aux->type);
                if (!ab)
                        continue; /* audit_panic has been called */
 
-               aux = context->aux;
-               context->aux = aux->next;
-
-               audit_log_format(ab, "auxitem=%d", aux->type);
                switch (aux->type) {
-               case AUDIT_AUX_IPCPERM: {
+               case AUDIT_IPC: {
                        struct audit_aux_data_ipcctl *axi = (void *)aux;
                        audit_log_format(ab, 
-                                        " qbytes=%lx uid=%d gid=%d mode=%x",
+                                        " qbytes=%lx iuid=%d igid=%d mode=%x",
                                         axi->qbytes, axi->uid, axi->gid, axi->mode);
-                       }
+                       break; }
+
+               case AUDIT_SOCKETCALL: {
+                       int i;
+                       struct audit_aux_data_socketcall *axs = (void *)aux;
+                       audit_log_format(ab, "nargs=%d", axs->nargs);
+                       for (i=0; i<axs->nargs; i++)
+                               audit_log_format(ab, " a%d=%lx", i, axs->args[i]);
+                       break; }
+
+               case AUDIT_SOCKADDR: {
+                       struct audit_aux_data_sockaddr *axs = (void *)aux;
+
+                       audit_log_format(ab, "saddr=");
+                       audit_log_hex(ab, axs->a, axs->len);
+                       break; }
                }
                audit_log_end(ab);
+
+               context->aux = aux->next;
                kfree(aux);
        }
 
        for (i = 0; i < context->name_count; i++) {
-               ab = audit_log_start(context);
+               ab = audit_log_start(context, AUDIT_PATH);
                if (!ab)
                        continue; /* audit_panic has been called */
                audit_log_format(ab, "item=%d", i);
@@ -710,7 +740,7 @@ static void audit_log_exit(struct audit_context *context)
                }
                if (context->names[i].ino != (unsigned long)-1)
                        audit_log_format(ab, " inode=%lu dev=%02x:%02x mode=%#o"
-                                            " uid=%d gid=%d rdev=%02x:%02x",
+                                            " ouid=%d ogid=%d rdev=%02x:%02x",
                                         context->names[i].ino,
                                         MAJOR(context->names[i].dev),
                                         MINOR(context->names[i].dev),
@@ -747,7 +777,7 @@ void audit_free(struct task_struct *tsk)
 /* 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 daemon to
+ * 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.
@@ -991,7 +1021,7 @@ void audit_inode(const char *name, const struct inode *inode)
        context->names[idx].rdev = inode->i_rdev;
 }
 
-void audit_get_stamp(struct audit_context *ctx,
+int audit_get_stamp(struct audit_context *ctx,
                     struct timespec *t, unsigned int *serial)
 {
        if (ctx) {
@@ -999,28 +1029,25 @@ void audit_get_stamp(struct audit_context *ctx,
                t->tv_nsec = ctx->ctime.tv_nsec;
                *serial    = ctx->serial;
                ctx->auditable = 1;
-       } else {
-               *t      = CURRENT_TIME;
-               *serial = 0;
+               return 1;
        }
+       return 0;
 }
 
-extern int audit_set_type(struct audit_buffer *ab, int type);
-
-int audit_set_loginuid(struct audit_context *ctx, uid_t loginuid)
+int audit_set_loginuid(struct task_struct *task, uid_t loginuid)
 {
-       if (ctx) {
+       if (task->audit_context) {
                struct audit_buffer *ab;
 
-               ab = audit_log_start(NULL);
+               ab = audit_log_start(NULL, AUDIT_LOGIN);
                if (ab) {
                        audit_log_format(ab, "login pid=%d uid=%u "
                                "old loginuid=%u new loginuid=%u",
-                               ctx->pid, ctx->uid, ctx->loginuid, loginuid);
-                       audit_set_type(ab, AUDIT_LOGIN);
+                               task->pid, task->uid, 
+                               task->audit_context->loginuid, loginuid);
                        audit_log_end(ab);
                }
-               ctx->loginuid = loginuid;
+               task->audit_context->loginuid = loginuid;
        }
        return 0;
 }
@@ -1047,8 +1074,69 @@ int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode)
        ax->gid = gid;
        ax->mode = mode;
 
-       ax->d.type = AUDIT_AUX_IPCPERM;
+       ax->d.type = AUDIT_IPC;
+       ax->d.next = context->aux;
+       context->aux = (void *)ax;
+       return 0;
+}
+
+int audit_socketcall(int nargs, unsigned long *args)
+{
+       struct audit_aux_data_socketcall *ax;
+       struct audit_context *context = current->audit_context;
+
+       if (likely(!context))
+               return 0;
+
+       ax = kmalloc(sizeof(*ax) + nargs * sizeof(unsigned long), GFP_KERNEL);
+       if (!ax)
+               return -ENOMEM;
+
+       ax->nargs = nargs;
+       memcpy(ax->args, args, nargs * sizeof(unsigned long));
+
+       ax->d.type = AUDIT_SOCKETCALL;
+       ax->d.next = context->aux;
+       context->aux = (void *)ax;
+       return 0;
+}
+
+int audit_sockaddr(int len, void *a)
+{
+       struct audit_aux_data_sockaddr *ax;
+       struct audit_context *context = current->audit_context;
+
+       if (likely(!context))
+               return 0;
+
+       ax = kmalloc(sizeof(*ax) + len, GFP_KERNEL);
+       if (!ax)
+               return -ENOMEM;
+
+       ax->len = len;
+       memcpy(ax->a, a, len);
+
+       ax->d.type = AUDIT_SOCKADDR;
        ax->d.next = context->aux;
        context->aux = (void *)ax;
        return 0;
 }
+
+void audit_signal_info(int sig, struct task_struct *t)
+{
+       extern pid_t audit_sig_pid;
+       extern uid_t audit_sig_uid;
+       extern int audit_pid;
+
+       if (unlikely(audit_pid && t->pid == audit_pid)) {
+               if (sig == SIGTERM || sig == SIGHUP) {
+                       struct audit_context *ctx = current->audit_context;
+                       audit_sig_pid = current->pid;
+                       if (ctx)
+                               audit_sig_uid = ctx->loginuid;
+                       else
+                               audit_sig_uid = current->uid;
+               }
+       }
+}
+