updated audit.39 with fixes for sleeping, missing watches, and spinlocks

Timothy R. Chavez tinytim at us.ibm.com
Thu May 19 18:29:52 UTC 2005


Hello,

This is the patch I just tested using the audit.39 SRPM on an Opteron.
Everything appears to be in order.  We're going to have the performance
team here run the audit code including auditfs on a PPC 15-way with hopes
of flushing memory errors/corruption, deadlock, etc and to also get some
performance [impact] numbers as a nice "to-have".

Hopefully the patch applies cleanly to audit.39 (I just forwarded it to
myself and stripped the quotations :-))

-tim

diff -Nurp linux-2.6.9/fs/dcache.c /var/log/kernel-2.6.9/linux-2.6.9/fs/dcache.c
--- linux-2.6.9/fs/dcache.c     2005-05-18 15:50:17.182181000 -0500
+++ /var/log/kernel-2.6.9/linux-2.6.9/fs/dcache.c       2005-05-17 16:29:47.000000000 -0500
@@ -1109,14 +1109,14 @@ out:
  
 void d_delete(struct dentry * dentry)
 {
+       audit_dentry_unpin(dentry);
+       
        /*
         * Are we the only user?
         */
        spin_lock(&dcache_lock);
        spin_lock(&dentry->d_lock);
 
-       audit_dentry_unpin(dentry);
-
        if (atomic_read(&dentry->d_count) == 1) {
                dentry_iput(dentry);
                return;
diff -Nurp linux-2.6.9/fs/namei.c /var/log/kernel-2.6.9/linux-2.6.9/fs/namei.c
--- linux-2.6.9/fs/namei.c      2005-05-18 15:50:17.184180696 -0500
+++ /var/log/kernel-2.6.9/linux-2.6.9/fs/namei.c        2005-05-18 15:26:11.000000000 -0500
@@ -163,8 +163,6 @@ int vfs_permission(struct inode * inode,
 {
        umode_t                 mode = inode->i_mode;
 
-       audit_notify_watch(inode, mask);
-
        if (mask & MAY_WRITE) {
                /*
                 * Nobody gets write access to a read-only fs.
@@ -217,6 +215,8 @@ int permission(struct inode * inode,int 
 
        /* Ordinary permission routines do not understand MAY_APPEND. */
        submask = mask & ~MAY_APPEND;
+       
+       audit_notify_watch(inode, mask);
 
        if (inode->i_op && inode->i_op->permission)
                retval = inode->i_op->permission(inode, submask, nd);
diff -Nurp linux-2.6.9/kernel/auditfs.c /var/log/kernel-2.6.9/linux-2.6.9/kernel/auditfs.c
--- linux-2.6.9/kernel/auditfs.c        2005-05-18 15:50:17.186180392 -0500
+++ /var/log/kernel-2.6.9/linux-2.6.9/kernel/auditfs.c  2005-05-18 16:57:43.760007664 -0500
@@ -41,9 +41,14 @@ static kmem_cache_t *audit_watch_cache;
 static kmem_cache_t *audit_wentry_cache;
 
 /* Read-heavy list */
-HLIST_HEAD(audit_master_watchlist);
-static spinlock_t audit_master_watchlist_lock = SPIN_LOCK_UNLOCKED;
+HLIST_HEAD(master_watchlist);
+static spinlock_t master_watchlist_lock = SPIN_LOCK_UNLOCKED;
 
+struct audit_skb_list {
+       struct hlist_node list;
+       void *memblk;
+       size_t size;
+};
 
 /* Private Interface */
 
@@ -65,7 +70,7 @@ static inline void audit_pin(struct audi
 }
 
 static inline struct audit_wentry *audit_wentry_fetch(const char *name,
-                                               struct audit_inode_data *data)
+                                                     struct audit_inode_data *data)
 {
        struct audit_wentry *wentry, *ret = NULL;
        struct hlist_node *pos;
@@ -166,7 +171,7 @@ static inline void *audit_to_transport(s
        struct watch_transport t;
        void *memblk;
 
-        memblk = kmalloc(size, GFP_KERNEL);
+        memblk = kmalloc(size, GFP_ATOMIC);
         if (!memblk)
                 goto audit_to_transport_exit;
 
@@ -300,9 +305,9 @@ static inline int audit_create_wentry(co
 
        write_lock(&data->lock);
        hlist_add_head(&new->w_node, &data->watchlist);
-       spin_lock(&audit_master_watchlist_lock);
-       hlist_add_head_rcu(&new->w_master, &audit_master_watchlist);
-       spin_unlock(&audit_master_watchlist_lock);
+       spin_lock(&master_watchlist_lock);
+       hlist_add_head_rcu(&new->w_master, &master_watchlist);
+       spin_unlock(&master_watchlist_lock);
        write_unlock(&data->lock);
 
 audit_create_wentry_exit:
@@ -338,10 +343,10 @@ static inline void audit_destroy_wentry(
        if (wentry) {
                hlist_del_init(&wentry->w_node);
                audit_wentry_put(wentry);
-               spin_lock(&audit_master_watchlist_lock);
+               spin_lock(&master_watchlist_lock);
                hlist_del_rcu(&wentry->w_master);
                call_rcu(&wentry->w_rcu, audit_wentry_rcu_put);
-               spin_unlock(&audit_master_watchlist_lock);
+               spin_unlock(&master_watchlist_lock);
        }
 }
 
@@ -531,27 +536,33 @@ void audit_update_watch(struct dentry *d
        audit_wentry_put(wentry);
 }
 
-int audit_send_watch(int pid, int seq, struct audit_watch *watch)
+/* Convert a watch to a audit_skb_list */
+struct audit_skb_list *audit_to_skb(struct audit_watch *watch)
 {
-       int ret;
        size_t size;
        void *memblk;
-
+       struct audit_skb_list *entry;
+      
        /* We must include space for both "\0" */
        size = sizeof(struct watch_transport) + strlen(watch->path) +
-              strlen(watch->filterkey) + 2;
-
-       ret = -ENOMEM;
+                     strlen(watch->filterkey) + 2;
+                                                                                                                                                                    
+       entry = ERR_PTR(-ENOMEM);
        memblk = audit_to_transport(watch, size);
        if (!memblk)
-               goto audit_send_watch_exit;
+               goto audit_queue_watch_exit;
 
-       ret = 0;
-       audit_send_reply(pid, seq, AUDIT_WATCH_LIST, 0, 1, memblk, size);
-       kfree(memblk);
+       entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+       if (!entry) {
+               entry = ERR_PTR(-ENOMEM);
+               goto audit_queue_watch_exit;
+       }
+       
+       entry->memblk = memblk;
+       entry->size = size;
 
-audit_send_watch_exit:
-       return ret;
+audit_queue_watch_exit:
+       return entry;
 }
 
 /*
@@ -568,19 +579,40 @@ audit_send_watch_exit:
 int audit_list_watches(int pid, int seq)
 {
        int ret = 0;
+       struct hlist_head skb_list;
+       struct hlist_node *tmp, *pos;
+       struct audit_skb_list *entry;
        struct audit_wentry *wentry;
-       struct hlist_node *pos;
+
+       INIT_HLIST_HEAD(&skb_list);
 
        rcu_read_lock();
-       hlist_for_each_entry_rcu(wentry, pos, &audit_master_watchlist, w_master) {
-               ret = audit_send_watch(pid, seq, wentry->w_watch);
-               if (ret < 0)
-                       break;
+       hlist_for_each_entry_rcu(wentry, pos, &master_watchlist, w_master) {
+               entry = audit_to_skb(wentry->w_watch);
+               if (IS_ERR(entry)) {
+                       ret = PTR_ERR(entry);
+                       goto audit_list_watches_fail;
+               }
+               hlist_add_head(&entry->list, &skb_list);
        }
        rcu_read_unlock();
 
-       audit_send_reply(pid, seq, AUDIT_WATCH_LIST, 1, 1, NULL, 0);
+       hlist_for_each_entry_safe(entry, pos, tmp, &skb_list, list) {
+               audit_send_reply(pid, seq, AUDIT_WATCH_LIST, 0, 1, 
+                                entry->memblk, entry->size);
+               kfree(entry->memblk);
+               kfree(entry);
+       }
 
+       audit_send_reply(pid, seq, AUDIT_WATCH_LIST, 1, 1, NULL, 0);
+       goto audit_list_watches_exit;
+       
+audit_list_watches_fail:
+       hlist_for_each_entry_safe(entry, pos, tmp, &skb_list, list) {
+               kfree(entry->memblk);
+               kfree(entry);
+       }
+audit_list_watches_exit:
        return ret;
 }




More information about the Linux-audit mailing list