]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - kernel/auditsc.c
[PATCH] execve argument logging
[linux-2.6-omap-h63xx.git] / kernel / auditsc.c
index d3d97d28b69aacb31a78beada6fe7a6e0c5af2a0..114f921979ecb4af75e1b360923de691a1f7a061 100644 (file)
@@ -59,6 +59,7 @@
 #include <linux/list.h>
 #include <linux/tty.h>
 #include <linux/selinux.h>
+#include <linux/binfmts.h>
 
 #include "audit.h"
 
@@ -90,7 +91,7 @@ struct audit_names {
        uid_t           uid;
        gid_t           gid;
        dev_t           rdev;
-       char            *ctx;
+       u32             osid;
 };
 
 struct audit_aux_data {
@@ -107,7 +108,14 @@ struct audit_aux_data_ipcctl {
        uid_t                   uid;
        gid_t                   gid;
        mode_t                  mode;
-       char                    *ctx;
+       u32                     osid;
+};
+
+struct audit_aux_data_execve {
+       struct audit_aux_data   d;
+       int argc;
+       int envc;
+       char mem[0];
 };
 
 struct audit_aux_data_socketcall {
@@ -168,11 +176,9 @@ static int audit_filter_rules(struct task_struct *tsk,
                              struct audit_context *ctx,
                              enum audit_state *state)
 {
-       int i, j;
+       int i, j, need_sid = 1;
        u32 sid;
 
-       selinux_task_ctxid(tsk, &sid);
-
        for (i = 0; i < rule->field_count; i++) {
                struct audit_field *f = &rule->fields[i];
                int result = 0;
@@ -271,11 +277,16 @@ static int audit_filter_rules(struct task_struct *tsk,
                           match for now to avoid losing information that
                           may be wanted.   An error message will also be
                           logged upon error */
-                       if (f->se_rule)
+                       if (f->se_rule) {
+                               if (need_sid) {
+                                       selinux_task_ctxid(tsk, &sid);
+                                       need_sid = 0;
+                               }
                                result = selinux_audit_rule_match(sid, f->type,
                                                                  f->op,
                                                                  f->se_rule,
                                                                  ctx);
+                       }
                        break;
                case AUDIT_ARG0:
                case AUDIT_ARG1:
@@ -410,9 +421,6 @@ static inline void audit_free_names(struct audit_context *context)
 #endif
 
        for (i = 0; i < context->name_count; i++) {
-               char *p = context->names[i].ctx;
-               context->names[i].ctx = NULL;
-               kfree(p);
                if (context->names[i].name)
                        __putname(context->names[i].name);
        }
@@ -435,11 +443,6 @@ static inline void audit_free_aux(struct audit_context *context)
                        dput(axi->dentry);
                        mntput(axi->mnt);
                }
-               if ( aux->type == AUDIT_IPC ) {
-                       struct audit_aux_data_ipcctl *axi = (void *)aux;
-                       if (axi->ctx)
-                               kfree(axi->ctx);
-               }
 
                context->aux = aux->next;
                kfree(aux);
@@ -587,7 +590,7 @@ static void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk
 
 static void audit_log_exit(struct audit_context *context, struct task_struct *tsk)
 {
-       int i;
+       int i, call_panic = 0;
        struct audit_buffer *ab;
        struct audit_aux_data *aux;
        const char *tty;
@@ -638,8 +641,49 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
                case AUDIT_IPC: {
                        struct audit_aux_data_ipcctl *axi = (void *)aux;
                        audit_log_format(ab, 
-                                        " qbytes=%lx iuid=%u igid=%u mode=%x obj=%s",
-                                        axi->qbytes, axi->uid, axi->gid, axi->mode, axi->ctx);
+                                " qbytes=%lx iuid=%u igid=%u mode=%x",
+                                axi->qbytes, axi->uid, axi->gid, axi->mode);
+                       if (axi->osid != 0) {
+                               char *ctx = NULL;
+                               u32 len;
+                               if (selinux_ctxid_to_string(
+                                               axi->osid, &ctx, &len)) {
+                                       audit_log_format(ab, " osid=%u",
+                                                       axi->osid);
+                                       call_panic = 1;
+                               } else
+                                       audit_log_format(ab, " obj=%s", ctx);
+                               kfree(ctx);
+                       }
+                       break; }
+
+               case AUDIT_IPC_SET_PERM: {
+                       struct audit_aux_data_ipcctl *axi = (void *)aux;
+                       audit_log_format(ab,
+                               " new qbytes=%lx new iuid=%u new igid=%u new mode=%x",
+                               axi->qbytes, axi->uid, axi->gid, axi->mode);
+                       if (axi->osid != 0) {
+                               char *ctx = NULL;
+                               u32 len;
+                               if (selinux_ctxid_to_string(
+                                               axi->osid, &ctx, &len)) {
+                                       audit_log_format(ab, " osid=%u",
+                                                       axi->osid);
+                                       call_panic = 1;
+                               } else
+                                       audit_log_format(ab, " obj=%s", ctx);
+                               kfree(ctx);
+                       }
+                       break; }
+               case AUDIT_EXECVE: {
+                       struct audit_aux_data_execve *axi = (void *)aux;
+                       int i;
+                       const char *p;
+                       for (i = 0, p = axi->mem; i < axi->argc; i++) {
+                               audit_log_format(ab, "a%d=", i);
+                               p = audit_log_untrustedstring(ab, p);
+                               audit_log_format(ab, "\n");
+                       }
                        break; }
 
                case AUDIT_SOCKETCALL: {
@@ -703,13 +747,23 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
                                         context->names[i].gid, 
                                         MAJOR(context->names[i].rdev), 
                                         MINOR(context->names[i].rdev));
-               if (context->names[i].ctx) {
-                       audit_log_format(ab, " obj=%s",
-                                       context->names[i].ctx);
+               if (context->names[i].osid != 0) {
+                       char *ctx = NULL;
+                       u32 len;
+                       if (selinux_ctxid_to_string(
+                               context->names[i].osid, &ctx, &len)) {
+                               audit_log_format(ab, " osid=%u",
+                                               context->names[i].osid);
+                               call_panic = 2;
+                       } else
+                               audit_log_format(ab, " obj=%s", ctx);
+                       kfree(ctx);
                }
 
                audit_log_end(ab);
        }
+       if (call_panic)
+               audit_panic("error converting sid to string");
 }
 
 /**
@@ -943,40 +997,11 @@ void audit_putname(const char *name)
 #endif
 }
 
-void audit_inode_context(int idx, const struct inode *inode)
+static void audit_inode_context(int idx, const struct inode *inode)
 {
        struct audit_context *context = current->audit_context;
-       const char *suffix = security_inode_xattr_getsuffix();
-       char *ctx = NULL;
-       int len = 0;
 
-       if (!suffix)
-               goto ret;
-
-       len = security_inode_getsecurity(inode, suffix, NULL, 0, 0);
-       if (len == -EOPNOTSUPP)
-               goto ret;
-       if (len < 0) 
-               goto error_path;
-
-       ctx = kmalloc(len, GFP_KERNEL);
-       if (!ctx) 
-               goto error_path;
-
-       len = security_inode_getsecurity(inode, suffix, ctx, len, 0);
-       if (len < 0)
-               goto error_path;
-
-       kfree(context->names[idx].ctx);
-       context->names[idx].ctx = ctx;
-       goto ret;
-
-error_path:
-       if (ctx)
-               kfree(ctx);
-       audit_panic("error in audit_inode_context");
-ret:
-       return;
+       selinux_get_inode_sid(inode, &context->names[idx].osid);
 }
 
 
@@ -1162,40 +1187,37 @@ uid_t audit_get_loginuid(struct audit_context *ctx)
        return ctx ? ctx->loginuid : -1;
 }
 
-static char *audit_ipc_context(struct kern_ipc_perm *ipcp)
+/**
+ * audit_ipc_obj - record audit data for ipc object
+ * @ipcp: ipc permissions
+ *
+ * Returns 0 for success or NULL context or < 0 on error.
+ */
+int audit_ipc_obj(struct kern_ipc_perm *ipcp)
 {
+       struct audit_aux_data_ipcctl *ax;
        struct audit_context *context = current->audit_context;
-       char *ctx = NULL;
-       int len = 0;
 
        if (likely(!context))
-               return NULL;
-
-       len = security_ipc_getsecurity(ipcp, NULL, 0);
-       if (len == -EOPNOTSUPP)
-               goto ret;
-       if (len < 0)
-               goto error_path;
-
-       ctx = kmalloc(len, GFP_ATOMIC);
-       if (!ctx)
-               goto error_path;
+               return 0;
 
-       len = security_ipc_getsecurity(ipcp, ctx, len);
-       if (len < 0)
-               goto error_path;
+       ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
+       if (!ax)
+               return -ENOMEM;
 
-       return ctx;
+       ax->uid = ipcp->uid;
+       ax->gid = ipcp->gid;
+       ax->mode = ipcp->mode;
+       selinux_get_ipc_sid(ipcp, &ax->osid);
 
-error_path:
-       kfree(ctx);
-       audit_panic("error in audit_ipc_context");
-ret:
-       return NULL;
+       ax->d.type = AUDIT_IPC;
+       ax->d.next = context->aux;
+       context->aux = (void *)ax;
+       return 0;
 }
 
 /**
- * audit_ipc_perms - record audit data for ipc
+ * audit_ipc_set_perm - record audit data for new ipc permissions
  * @qbytes: msgq bytes
  * @uid: msgq user id
  * @gid: msgq group id
@@ -1203,7 +1225,7 @@ ret:
  *
  * Returns 0 for success or NULL context or < 0 on error.
  */
-int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp)
+int audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp)
 {
        struct audit_aux_data_ipcctl *ax;
        struct audit_context *context = current->audit_context;
@@ -1219,14 +1241,47 @@ int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, str
        ax->uid = uid;
        ax->gid = gid;
        ax->mode = mode;
-       ax->ctx = audit_ipc_context(ipcp);
+       selinux_get_ipc_sid(ipcp, &ax->osid);
 
-       ax->d.type = AUDIT_IPC;
+       ax->d.type = AUDIT_IPC_SET_PERM;
        ax->d.next = context->aux;
        context->aux = (void *)ax;
        return 0;
 }
 
+int audit_bprm(struct linux_binprm *bprm)
+{
+       struct audit_aux_data_execve *ax;
+       struct audit_context *context = current->audit_context;
+       unsigned long p, next;
+       void *to;
+
+       if (likely(!audit_enabled || !context))
+               return 0;
+
+       ax = kmalloc(sizeof(*ax) + PAGE_SIZE * MAX_ARG_PAGES - bprm->p,
+                               GFP_KERNEL);
+       if (!ax)
+               return -ENOMEM;
+
+       ax->argc = bprm->argc;
+       ax->envc = bprm->envc;
+       for (p = bprm->p, to = ax->mem; p < MAX_ARG_PAGES*PAGE_SIZE; p = next) {
+               struct page *page = bprm->page[p / PAGE_SIZE];
+               void *kaddr = kmap(page);
+               next = (p + PAGE_SIZE) & ~(PAGE_SIZE - 1);
+               memcpy(to, kaddr + (p & (PAGE_SIZE - 1)), next - p);
+               to += next - p;
+               kunmap(page);
+       }
+
+       ax->d.type = AUDIT_EXECVE;
+       ax->d.next = context->aux;
+       context->aux = (void *)ax;
+       return 0;
+}
+
+
 /**
  * audit_socketcall - record audit data for sys_socketcall
  * @nargs: number of args