]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - kernel/auditsc.c
OMAP: dmtimer: enable all timers to be wakeup events
[linux-2.6-omap-h63xx.git] / kernel / auditsc.c
index 327e65d50674af3ee9a5db037895cefd562b3d76..8cbddff6c283a569acb2b1c707b2448f67771e44 100644 (file)
@@ -165,14 +165,14 @@ struct audit_tree_refs {
 struct audit_context {
        int                 dummy;      /* must be the first element */
        int                 in_syscall; /* 1 if task is in a syscall */
-       enum audit_state    state;
+       enum audit_state    state, current_state;
        unsigned int        serial;     /* serial number for record */
        struct timespec     ctime;      /* time of syscall entry */
        int                 major;      /* syscall number */
        unsigned long       argv[4];    /* syscall arguments */
        int                 return_valid; /* return code is valid */
        long                return_code;/* syscall return code */
-       int                 auditable;  /* 1 if record should be written */
+       u64                 prio;
        int                 name_count;
        struct audit_names  names[AUDIT_NAMES];
        char *              filterkey;  /* key for rule that triggered record */
@@ -235,6 +235,10 @@ struct audit_context {
                        mode_t                  mode;
                        struct mq_attr          attr;
                } mq_open;
+               struct {
+                       pid_t                   pid;
+                       struct audit_cap_data   cap;
+               } capset;
        };
        int fds[2];
 
@@ -626,8 +630,16 @@ static int audit_filter_rules(struct task_struct *tsk,
                        return 0;
                }
        }
-       if (rule->filterkey && ctx)
-               ctx->filterkey = kstrdup(rule->filterkey, GFP_ATOMIC);
+
+       if (ctx) {
+               if (rule->prio <= ctx->prio)
+                       return 0;
+               if (rule->filterkey) {
+                       kfree(ctx->filterkey);
+                       ctx->filterkey = kstrdup(rule->filterkey, GFP_ATOMIC);
+               }
+               ctx->prio = rule->prio;
+       }
        switch (rule->action) {
        case AUDIT_NEVER:    *state = AUDIT_DISABLED;       break;
        case AUDIT_ALWAYS:   *state = AUDIT_RECORD_CONTEXT; break;
@@ -640,7 +652,7 @@ static int audit_filter_rules(struct task_struct *tsk,
  * completely disabled for this task.  Since we only have the task
  * structure at this point, we can only check uid and gid.
  */
-static enum audit_state audit_filter_task(struct task_struct *tsk)
+static enum audit_state audit_filter_task(struct task_struct *tsk, char **key)
 {
        struct audit_entry *e;
        enum audit_state   state;
@@ -648,6 +660,8 @@ static enum audit_state audit_filter_task(struct task_struct *tsk)
        rcu_read_lock();
        list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_TASK], list) {
                if (audit_filter_rules(tsk, &e->rule, NULL, NULL, &state)) {
+                       if (state == AUDIT_RECORD_CONTEXT)
+                               *key = kstrdup(e->rule.filterkey, GFP_ATOMIC);
                        rcu_read_unlock();
                        return state;
                }
@@ -681,6 +695,7 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk,
                            audit_filter_rules(tsk, &e->rule, ctx, NULL,
                                               &state)) {
                                rcu_read_unlock();
+                               ctx->current_state = state;
                                return state;
                        }
                }
@@ -694,15 +709,14 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk,
  * buckets applicable to the inode numbers in audit_names[].
  * Regarding audit_state, same rules apply as for audit_filter_syscall().
  */
-enum audit_state audit_filter_inodes(struct task_struct *tsk,
-                                    struct audit_context *ctx)
+void audit_filter_inodes(struct task_struct *tsk, struct audit_context *ctx)
 {
        int i;
        struct audit_entry *e;
        enum audit_state state;
 
        if (audit_pid && tsk->tgid == audit_pid)
-               return AUDIT_DISABLED;
+               return;
 
        rcu_read_lock();
        for (i = 0; i < ctx->name_count; i++) {
@@ -719,17 +733,20 @@ enum audit_state audit_filter_inodes(struct task_struct *tsk,
                        if ((e->rule.mask[word] & bit) == bit &&
                            audit_filter_rules(tsk, &e->rule, ctx, n, &state)) {
                                rcu_read_unlock();
-                               return state;
+                               ctx->current_state = state;
+                               return;
                        }
                }
        }
        rcu_read_unlock();
-       return AUDIT_BUILD_CONTEXT;
 }
 
-void audit_set_auditable(struct audit_context *ctx)
+static void audit_set_auditable(struct audit_context *ctx)
 {
-       ctx->auditable = 1;
+       if (!ctx->prio) {
+               ctx->prio = 1;
+               ctx->current_state = AUDIT_RECORD_CONTEXT;
+       }
 }
 
 static inline struct audit_context *audit_get_context(struct task_struct *tsk,
@@ -760,23 +777,11 @@ static inline struct audit_context *audit_get_context(struct task_struct *tsk,
        else
                context->return_code  = return_code;
 
-       if (context->in_syscall && !context->dummy && !context->auditable) {
-               enum audit_state state;
-
-               state = audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_EXIT]);
-               if (state == AUDIT_RECORD_CONTEXT) {
-                       context->auditable = 1;
-                       goto get_context;
-               }
-
-               state = audit_filter_inodes(tsk, context);
-               if (state == AUDIT_RECORD_CONTEXT)
-                       context->auditable = 1;
-
+       if (context->in_syscall && !context->dummy) {
+               audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_EXIT]);
+               audit_filter_inodes(tsk, context);
        }
 
-get_context:
-
        tsk->audit_context = NULL;
        return context;
 }
@@ -786,8 +791,7 @@ static inline void audit_free_names(struct audit_context *context)
        int i;
 
 #if AUDIT_DEBUG == 2
-       if (context->auditable
-           ||context->put_count + context->ino_count != context->name_count) {
+       if (context->put_count + context->ino_count != context->name_count) {
                printk(KERN_ERR "%s:%d(:%d): major=%d in_syscall=%d"
                       " name_count=%d put_count=%d"
                       " ino_count=%d [NOT freeing]\n",
@@ -838,6 +842,7 @@ static inline void audit_zero_context(struct audit_context *context,
 {
        memset(context, 0, sizeof(*context));
        context->state      = state;
+       context->prio = state == AUDIT_RECORD_CONTEXT ? ~0ULL : 0;
 }
 
 static inline struct audit_context *audit_alloc_context(enum audit_state state)
@@ -863,18 +868,21 @@ int audit_alloc(struct task_struct *tsk)
 {
        struct audit_context *context;
        enum audit_state     state;
+       char *key = NULL;
 
        if (likely(!audit_ever_enabled))
                return 0; /* Return if not auditing. */
 
-       state = audit_filter_task(tsk);
+       state = audit_filter_task(tsk, &key);
        if (likely(state == AUDIT_DISABLED))
                return 0;
 
        if (!(context = audit_alloc_context(state))) {
+               kfree(key);
                audit_log_lost("out of memory in audit_alloc");
                return -ENOMEM;
        }
+       context->filterkey = key;
 
        tsk->audit_context  = context;
        set_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);
@@ -1291,6 +1299,12 @@ static void show_special(struct audit_context *context, int *call_panic)
                        attr->mq_flags, attr->mq_maxmsg,
                        attr->mq_msgsize, attr->mq_curmsgs);
                break; }
+       case AUDIT_CAPSET: {
+               audit_log_format(ab, "pid=%d", context->capset.pid);
+               audit_log_cap(ab, "cap_pi", &context->capset.cap.inheritable);
+               audit_log_cap(ab, "cap_pp", &context->capset.cap.permitted);
+               audit_log_cap(ab, "cap_pe", &context->capset.cap.effective);
+               break; }
        }
        audit_log_end(ab);
 }
@@ -1392,14 +1406,6 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
                        audit_log_cap(ab, "new_pe", &axs->new_pcap.effective);
                        break; }
 
-               case AUDIT_CAPSET: {
-                       struct audit_aux_data_capset *axs = (void *)aux;
-                       audit_log_format(ab, "pid=%d", axs->pid);
-                       audit_log_cap(ab, "cap_pi", &axs->cap.inheritable);
-                       audit_log_cap(ab, "cap_pp", &axs->cap.permitted);
-                       audit_log_cap(ab, "cap_pe", &axs->cap.effective);
-                       break; }
-
                }
                audit_log_end(ab);
        }
@@ -1541,7 +1547,7 @@ void audit_free(struct task_struct *tsk)
         * We use GFP_ATOMIC here because we might be doing this
         * in the context of the idle thread */
        /* that can happen only if we are called from do_exit() */
-       if (context->in_syscall && context->auditable)
+       if (context->in_syscall && context->current_state == AUDIT_RECORD_CONTEXT)
                audit_log_exit(context, tsk);
 
        audit_free_context(context);
@@ -1625,15 +1631,17 @@ void audit_syscall_entry(int arch, int major,
 
        state = context->state;
        context->dummy = !audit_n_rules;
-       if (!context->dummy && (state == AUDIT_SETUP_CONTEXT || state == AUDIT_BUILD_CONTEXT))
+       if (!context->dummy && state == AUDIT_BUILD_CONTEXT) {
+               context->prio = 0;
                state = audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_ENTRY]);
+       }
        if (likely(state == AUDIT_DISABLED))
                return;
 
        context->serial     = 0;
        context->ctime      = CURRENT_TIME;
        context->in_syscall = 1;
-       context->auditable  = !!(state == AUDIT_RECORD_CONTEXT);
+       context->current_state  = state;
        context->ppid       = 0;
 }
 
@@ -1641,17 +1649,20 @@ void audit_finish_fork(struct task_struct *child)
 {
        struct audit_context *ctx = current->audit_context;
        struct audit_context *p = child->audit_context;
-       if (!p || !ctx || !ctx->auditable)
+       if (!p || !ctx)
+               return;
+       if (!ctx->in_syscall || ctx->current_state != AUDIT_RECORD_CONTEXT)
                return;
        p->arch = ctx->arch;
        p->major = ctx->major;
        memcpy(p->argv, ctx->argv, sizeof(ctx->argv));
        p->ctime = ctx->ctime;
        p->dummy = ctx->dummy;
-       p->auditable = ctx->auditable;
        p->in_syscall = ctx->in_syscall;
        p->filterkey = kstrdup(ctx->filterkey, GFP_KERNEL);
        p->ppid = current->pid;
+       p->prio = ctx->prio;
+       p->current_state = ctx->current_state;
 }
 
 /**
@@ -1675,11 +1686,11 @@ void audit_syscall_exit(int valid, long return_code)
        if (likely(!context))
                return;
 
-       if (context->in_syscall && context->auditable)
+       if (context->in_syscall && context->current_state == AUDIT_RECORD_CONTEXT)
                audit_log_exit(context, tsk);
 
        context->in_syscall = 0;
-       context->auditable  = 0;
+       context->prio = context->state == AUDIT_RECORD_CONTEXT ? ~0ULL : 0;
 
        if (context->previous) {
                struct audit_context *new_context = context->previous;
@@ -1697,8 +1708,10 @@ void audit_syscall_exit(int valid, long return_code)
                context->sockaddr_len = 0;
                context->type = 0;
                context->fds[0] = -1;
-               kfree(context->filterkey);
-               context->filterkey = NULL;
+               if (context->state != AUDIT_RECORD_CONTEXT) {
+                       kfree(context->filterkey);
+                       context->filterkey = NULL;
+               }
                tsk->audit_context = context;
        }
 }
@@ -2089,7 +2102,10 @@ int auditsc_get_stamp(struct audit_context *ctx,
        t->tv_sec  = ctx->ctime.tv_sec;
        t->tv_nsec = ctx->ctime.tv_nsec;
        *serial    = ctx->serial;
-       ctx->auditable = 1;
+       if (!ctx->prio) {
+               ctx->prio = 1;
+               ctx->current_state = AUDIT_RECORD_CONTEXT;
+       }
        return 1;
 }
 
@@ -2456,29 +2472,15 @@ int __audit_log_bprm_fcaps(struct linux_binprm *bprm,
  * Record the aguments userspace sent to sys_capset for later printing by the
  * audit system if applicable
  */
-int __audit_log_capset(pid_t pid,
+void __audit_log_capset(pid_t pid,
                       const struct cred *new, const struct cred *old)
 {
-       struct audit_aux_data_capset *ax;
        struct audit_context *context = current->audit_context;
-
-       if (likely(!audit_enabled || !context || context->dummy))
-               return 0;
-
-       ax = kmalloc(sizeof(*ax), GFP_KERNEL);
-       if (!ax)
-               return -ENOMEM;
-
-       ax->d.type = AUDIT_CAPSET;
-       ax->d.next = context->aux;
-       context->aux = (void *)ax;
-
-       ax->pid = pid;
-       ax->cap.effective   = new->cap_effective;
-       ax->cap.inheritable = new->cap_effective;
-       ax->cap.permitted   = new->cap_permitted;
-
-       return 0;
+       context->capset.pid = pid;
+       context->capset.cap.effective   = new->cap_effective;
+       context->capset.cap.inheritable = new->cap_effective;
+       context->capset.cap.permitted   = new->cap_permitted;
+       context->type = AUDIT_CAPSET;
 }
 
 /**