futex: Fix uninterruptible loop due to gate_area
[linux-2.6.git] / kernel / auditsc.c
index 240063c..ce4b054 100644 (file)
@@ -44,7 +44,7 @@
 
 #include <linux/init.h>
 #include <asm/types.h>
-#include <asm/atomic.h>
+#include <linux/atomic.h>
 #include <linux/fs.h>
 #include <linux/namei.h>
 #include <linux/mm.h>
@@ -65,7 +65,6 @@
 #include <linux/binfmts.h>
 #include <linux/highmem.h>
 #include <linux/syscalls.h>
-#include <linux/inotify.h>
 #include <linux/capability.h>
 #include <linux/fs_struct.h>
 
@@ -242,6 +241,10 @@ struct audit_context {
                        pid_t                   pid;
                        struct audit_cap_data   cap;
                } capset;
+               struct {
+                       int                     fd;
+                       int                     flags;
+               } mmap;
        };
        int fds[2];
 
@@ -440,17 +443,25 @@ static int match_tree_refs(struct audit_context *ctx, struct audit_tree *tree)
 
 /* Determine if any context name data matches a rule's watch data */
 /* Compare a task_struct with an audit_rule.  Return 1 on match, 0
- * otherwise. */
+ * otherwise.
+ *
+ * If task_creation is true, this is an explicit indication that we are
+ * filtering a task rule at task creation time.  This and tsk == current are
+ * the only situations where tsk->cred may be accessed without an rcu read lock.
+ */
 static int audit_filter_rules(struct task_struct *tsk,
                              struct audit_krule *rule,
                              struct audit_context *ctx,
                              struct audit_names *name,
-                             enum audit_state *state)
+                             enum audit_state *state,
+                             bool task_creation)
 {
-       const struct cred *cred = get_task_cred(tsk);
+       const struct cred *cred;
        int i, j, need_sid = 1;
        u32 sid;
 
+       cred = rcu_dereference_check(tsk->cred, tsk == current || task_creation);
+
        for (i = 0; i < rule->field_count; i++) {
                struct audit_field *f = &rule->fields[i];
                int result = 0;
@@ -634,10 +645,8 @@ static int audit_filter_rules(struct task_struct *tsk,
                        break;
                }
 
-               if (!result) {
-                       put_cred(cred);
+               if (!result)
                        return 0;
-               }
        }
 
        if (ctx) {
@@ -653,7 +662,6 @@ static int audit_filter_rules(struct task_struct *tsk,
        case AUDIT_NEVER:    *state = AUDIT_DISABLED;       break;
        case AUDIT_ALWAYS:   *state = AUDIT_RECORD_CONTEXT; break;
        }
-       put_cred(cred);
        return 1;
 }
 
@@ -668,7 +676,8 @@ static enum audit_state audit_filter_task(struct task_struct *tsk, char **key)
 
        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 (audit_filter_rules(tsk, &e->rule, NULL, NULL,
+                                      &state, true)) {
                        if (state == AUDIT_RECORD_CONTEXT)
                                *key = kstrdup(e->rule.filterkey, GFP_ATOMIC);
                        rcu_read_unlock();
@@ -702,7 +711,7 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk,
                list_for_each_entry_rcu(e, list, list) {
                        if ((e->rule.mask[word] & bit) == bit &&
                            audit_filter_rules(tsk, &e->rule, ctx, NULL,
-                                              &state)) {
+                                              &state, false)) {
                                rcu_read_unlock();
                                ctx->current_state = state;
                                return state;
@@ -740,7 +749,8 @@ void audit_filter_inodes(struct task_struct *tsk, struct audit_context *ctx)
 
                list_for_each_entry_rcu(e, list, list) {
                        if ((e->rule.mask[word] & bit) == bit &&
-                           audit_filter_rules(tsk, &e->rule, ctx, n, &state)) {
+                           audit_filter_rules(tsk, &e->rule, ctx, n,
+                                              &state, false)) {
                                rcu_read_unlock();
                                ctx->current_state = state;
                                return;
@@ -1008,7 +1018,7 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
 /*
  * to_send and len_sent accounting are very loose estimates.  We aren't
  * really worried about a hard cap to MAX_EXECVE_AUDIT_LEN so much as being
- * within about 500 bytes (next page boundry)
+ * within about 500 bytes (next page boundary)
  *
  * why snprintf?  an int is up to 12 digits long.  if we just assumed when
  * logging that a[%d]= was going to be 16 characters long we would be wasting
@@ -1306,6 +1316,10 @@ static void show_special(struct audit_context *context, int *call_panic)
                audit_log_cap(ab, "cap_pp", &context->capset.cap.permitted);
                audit_log_cap(ab, "cap_pe", &context->capset.cap.effective);
                break; }
+       case AUDIT_MMAP: {
+               audit_log_format(ab, "fd=%d flags=0x%x", context->mmap.fd,
+                                context->mmap.flags);
+               break; }
        }
        audit_log_end(ab);
 }
@@ -1725,7 +1739,7 @@ static inline void handle_one(const struct inode *inode)
        struct audit_tree_refs *p;
        struct audit_chunk *chunk;
        int count;
-       if (likely(list_empty(&inode->inotify_watches)))
+       if (likely(hlist_empty(&inode->i_fsnotify_marks)))
                return;
        context = current->audit_context;
        p = context->trees;
@@ -1768,7 +1782,7 @@ retry:
        seq = read_seqbegin(&rename_lock);
        for(;;) {
                struct inode *inode = d->d_inode;
-               if (inode && unlikely(!list_empty(&inode->inotify_watches))) {
+               if (inode && unlikely(!hlist_empty(&inode->i_fsnotify_marks))) {
                        struct audit_chunk *chunk;
                        chunk = audit_tree_lookup(inode);
                        if (chunk) {
@@ -1836,13 +1850,8 @@ void __audit_getname(const char *name)
        context->names[context->name_count].ino  = (unsigned long)-1;
        context->names[context->name_count].osid = 0;
        ++context->name_count;
-       if (!context->pwd.dentry) {
-               read_lock(&current->fs->lock);
-               context->pwd = current->fs->pwd;
-               path_get(&current->fs->pwd);
-               read_unlock(&current->fs->lock);
-       }
-
+       if (!context->pwd.dentry)
+               get_fs_pwd(current->fs, &context->pwd);
 }
 
 /* audit_putname - intercept a putname request
@@ -2482,6 +2491,14 @@ void __audit_log_capset(pid_t pid,
        context->type = AUDIT_CAPSET;
 }
 
+void __audit_mmap_fd(int fd, int flags)
+{
+       struct audit_context *context = current->audit_context;
+       context->mmap.fd = fd;
+       context->mmap.flags = flags;
+       context->type = AUDIT_MMAP;
+}
+
 /**
  * audit_core_dumps - record information about processes that end abnormally
  * @signr: signal value