audit_update_lsm_rules() misses the audit_inode_hash[] ones
[safe/jmp/linux-2.6] / kernel / auditfilter.c
index af3ae91..0febaa0 100644 (file)
@@ -89,14 +89,9 @@ struct list_head audit_filter_list[AUDIT_NR_FILTERS] = {
 
 DEFINE_MUTEX(audit_filter_mutex);
 
-/* Inotify handle */
-extern struct inotify_handle *audit_ih;
-
 /* Inotify events we care about. */
 #define AUDIT_IN_WATCH IN_MOVE|IN_CREATE|IN_DELETE|IN_DELETE_SELF|IN_MOVE_SELF
 
-extern int audit_enabled;
-
 void audit_free_parent(struct inotify_watch *i_watch)
 {
        struct audit_parent *parent;
@@ -272,7 +267,7 @@ static int audit_to_watch(struct audit_krule *krule, char *path, int len,
                return -EINVAL;
 
        watch = audit_init_watch(path);
-       if (unlikely(IS_ERR(watch)))
+       if (IS_ERR(watch))
                return PTR_ERR(watch);
 
        audit_get_watch(watch);
@@ -422,7 +417,7 @@ exit_err:
 static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule)
 {
        struct audit_entry *entry;
-       struct audit_field *f;
+       struct audit_field *ino_f;
        int err = 0;
        int i;
 
@@ -483,6 +478,10 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule)
                        if (f->val & ~15)
                                goto exit_free;
                        break;
+               case AUDIT_FILETYPE:
+                       if ((f->val & ~S_IFMT) > S_IFMT)
+                               goto exit_free;
+                       break;
                case AUDIT_INODE:
                        err = audit_to_inode(&entry->rule, f);
                        if (err)
@@ -504,9 +503,9 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule)
                }
        }
 
-       f = entry->rule.inode_f;
-       if (f) {
-               switch(f->op) {
+       ino_f = entry->rule.inode_f;
+       if (ino_f) {
+               switch(ino_f->op) {
                case AUDIT_NOT_EQUAL:
                        entry->rule.inode_f = NULL;
                case AUDIT_EQUAL:
@@ -531,7 +530,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
 {
        int err = 0;
        struct audit_entry *entry;
-       struct audit_field *f;
+       struct audit_field *ino_f;
        void *bufp;
        size_t remain = datasz - sizeof(struct audit_rule_data);
        int i;
@@ -654,14 +653,18 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
                        if (f->val & ~15)
                                goto exit_free;
                        break;
+               case AUDIT_FILETYPE:
+                       if ((f->val & ~S_IFMT) > S_IFMT)
+                               goto exit_free;
+                       break;
                default:
                        goto exit_free;
                }
        }
 
-       f = entry->rule.inode_f;
-       if (f) {
-               switch(f->op) {
+       ino_f = entry->rule.inode_f;
+       if (ino_f) {
+               switch(ino_f->op) {
                case AUDIT_NOT_EQUAL:
                        entry->rule.inode_f = NULL;
                case AUDIT_EQUAL:
@@ -848,7 +851,7 @@ static struct audit_watch *audit_dupe_watch(struct audit_watch *old)
                return ERR_PTR(-ENOMEM);
 
        new = audit_init_watch(path);
-       if (unlikely(IS_ERR(new))) {
+       if (IS_ERR(new)) {
                kfree(path);
                goto out;
        }
@@ -989,7 +992,7 @@ static void audit_update_watch(struct audit_parent *parent,
                        audit_set_auditable(current->audit_context);
 
                nwatch = audit_dupe_watch(owatch);
-               if (unlikely(IS_ERR(nwatch))) {
+               if (IS_ERR(nwatch)) {
                        mutex_unlock(&audit_filter_mutex);
                        audit_panic("error updating watch, skipping");
                        return;
@@ -1004,7 +1007,7 @@ static void audit_update_watch(struct audit_parent *parent,
                        list_del_rcu(&oentry->list);
 
                        nentry = audit_dupe_rule(&oentry->rule, nwatch);
-                       if (unlikely(IS_ERR(nentry)))
+                       if (IS_ERR(nentry))
                                audit_panic("error updating watch, removing");
                        else {
                                int h = audit_hash_ino((u32)ino);
@@ -1019,8 +1022,11 @@ static void audit_update_watch(struct audit_parent *parent,
                        struct audit_buffer *ab;
                        ab = audit_log_start(NULL, GFP_KERNEL,
                                AUDIT_CONFIG_CHANGE);
+                       audit_log_format(ab, "auid=%u ses=%u",
+                               audit_get_loginuid(current),
+                               audit_get_sessionid(current));
                        audit_log_format(ab,
-                               "op=updated rules specifying path=");
+                               " op=updated rules specifying path=");
                        audit_log_untrustedstring(ab, owatch->path);
                        audit_log_format(ab, " with dev=%u ino=%lu\n",
                                 dev, ino);
@@ -1055,7 +1061,10 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
                                struct audit_buffer *ab;
                                ab = audit_log_start(NULL, GFP_KERNEL,
                                        AUDIT_CONFIG_CHANGE);
-                               audit_log_format(ab, "op=remove rule path=");
+                               audit_log_format(ab, "auid=%u ses=%u",
+                                       audit_get_loginuid(current),
+                                       audit_get_sessionid(current));
+                               audit_log_format(ab, " op=remove rule path=");
                                audit_log_untrustedstring(ab, w->path);
                                if (r->filterkey) {
                                        audit_log_format(ab, " key=");
@@ -1085,8 +1094,8 @@ static void audit_inotify_unregister(struct list_head *in_list)
        list_for_each_entry_safe(p, n, in_list, ilist) {
                list_del(&p->ilist);
                inotify_rm_watch(audit_ih, &p->wdata);
-               /* the put matching the get in audit_do_del_rule() */
-               put_inotify_watch(&p->wdata);
+               /* the unpin matching the pin in audit_do_del_rule() */
+               unpin_inotify_watch(&p->wdata);
        }
 }
 
@@ -1380,9 +1389,13 @@ static inline int audit_del_rule(struct audit_entry *entry,
                                /* Put parent on the inotify un-registration
                                 * list.  Grab a reference before releasing
                                 * audit_filter_mutex, to be released in
-                                * audit_inotify_unregister(). */
-                               list_add(&parent->ilist, &inotify_list);
-                               get_inotify_watch(&parent->wdata);
+                                * audit_inotify_unregister().
+                                * If filesystem is going away, just leave
+                                * the sucker alone, eviction will take
+                                * care of it.
+                                */
+                               if (pin_inotify_watch(&parent->wdata))
+                                       list_add(&parent->ilist, &inotify_list);
                        }
                }
        }
@@ -1541,6 +1554,7 @@ static void audit_log_rule_change(uid_t loginuid, u32 sessionid, u32 sid,
  * @data: payload data
  * @datasz: size of payload data
  * @loginuid: loginuid of sender
+ * @sessionid: sessionid for netlink audit message
  * @sid: SE Linux Security ID of sender
  */
 int audit_receive_filter(int type, int pid, int uid, int seq, void *data,
@@ -1717,7 +1731,7 @@ static int audit_filter_user_rules(struct netlink_skb_parms *cb,
        return 1;
 }
 
-int audit_filter_user(struct netlink_skb_parms *cb, int type)
+int audit_filter_user(struct netlink_skb_parms *cb)
 {
        enum audit_state state = AUDIT_DISABLED;
        struct audit_entry *e;
@@ -1764,6 +1778,41 @@ unlock_and_return:
        return result;
 }
 
+static int update_lsm_rule(struct audit_entry *entry)
+{
+       struct audit_entry *nentry;
+       struct audit_watch *watch;
+       struct audit_tree *tree;
+       int err = 0;
+
+       if (!security_audit_rule_known(&entry->rule))
+               return 0;
+
+       watch = entry->rule.watch;
+       tree = entry->rule.tree;
+       nentry = audit_dupe_rule(&entry->rule, watch);
+       if (IS_ERR(nentry)) {
+               /* save the first error encountered for the
+                * return value */
+               err = PTR_ERR(nentry);
+               audit_panic("error updating LSM filters");
+               if (watch)
+                       list_del(&entry->rule.rlist);
+               list_del_rcu(&entry->list);
+       } else {
+               if (watch) {
+                       list_add(&nentry->rule.rlist, &watch->rules);
+                       list_del(&entry->rule.rlist);
+               } else if (tree)
+                       list_replace_init(&entry->rule.rlist,
+                                    &nentry->rule.rlist);
+               list_replace_rcu(&entry->list, &nentry->list);
+       }
+       call_rcu(&entry->rcu, audit_free_rule_rcu);
+
+       return err;
+}
+
 /* This function will re-initialize the lsm_rule field of all applicable rules.
  * It will traverse the filter lists serarching for rules that contain LSM
  * specific filter fields.  When such a rule is found, it is copied, the
@@ -1771,42 +1820,24 @@ unlock_and_return:
  * updated rule. */
 int audit_update_lsm_rules(void)
 {
-       struct audit_entry *entry, *n, *nentry;
-       struct audit_watch *watch;
-       struct audit_tree *tree;
+       struct audit_entry *e, *n;
        int i, err = 0;
 
        /* audit_filter_mutex synchronizes the writers */
        mutex_lock(&audit_filter_mutex);
 
        for (i = 0; i < AUDIT_NR_FILTERS; i++) {
-               list_for_each_entry_safe(entry, n, &audit_filter_list[i], list) {
-                       if (!security_audit_rule_known(&entry->rule))
-                               continue;
-
-                       watch = entry->rule.watch;
-                       tree = entry->rule.tree;
-                       nentry = audit_dupe_rule(&entry->rule, watch);
-                       if (unlikely(IS_ERR(nentry))) {
-                               /* save the first error encountered for the
-                                * return value */
-                               if (!err)
-                                       err = PTR_ERR(nentry);
-                               audit_panic("error updating LSM filters");
-                               if (watch)
-                                       list_del(&entry->rule.rlist);
-                               list_del_rcu(&entry->list);
-                       } else {
-                               if (watch) {
-                                       list_add(&nentry->rule.rlist,
-                                                &watch->rules);
-                                       list_del(&entry->rule.rlist);
-                               } else if (tree)
-                                       list_replace_init(&entry->rule.rlist,
-                                                    &nentry->rule.rlist);
-                               list_replace_rcu(&entry->list, &nentry->list);
-                       }
-                       call_rcu(&entry->rcu, audit_free_rule_rcu);
+               list_for_each_entry_safe(e, n, &audit_filter_list[i], list) {
+                       int res = update_lsm_rule(e);
+                       if (!err)
+                               err = res;
+               }
+       }
+       for (i=0; i< AUDIT_INODE_BUCKETS; i++) {
+               list_for_each_entry_safe(e, n, &audit_inode_hash[i], list) {
+                       int res = update_lsm_rule(e);
+                       if (!err)
+                               err = res;
                }
        }