[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

patch update to ~51



Hello,

David and I have been working on ~51 and this patch reflects changes that we've both committed.

* Compaction of struct audit_watch and struct audit_wentry to struct audit_watch (David)
* Compaction of struct audit_create_wentry and audit_create_watch (David / Tim)
* The removal of the "drain watchlist on rename()"
* Corrected argument net/socket.c:audit_socketcall() to prevent Oopsing
* Added proper error handling in fs/namei.c (I think ;-))
* Fixed up spaces
* Removed audit_drain_watch

Two things left that I can think of:
* Getting rid of blanket allocations of audit_inode_data
* Allowing a _list_ of watches on a watched inode
  -> If the same inode is watched from multiple locations (or name spaces)
* Removal of local reader-writer locks on audit_inode_data?
  -> I'm not sure that this lock is needed any longer now that there's only
      two ways we can remove from a watchlist and neither will contend with
      the other.

     (1) explicit administrative action, no other administrative action can
           occur at the same time
     (2) audit_inode_data is being freed, inode is no longer reachable for
          administrative action
   
What do you all think?

-tim

diff -Nurp linux-2.6.9/fs/namei.c linux-2.6.9~working/fs/namei.c
--- linux-2.6.9/fs/namei.c	2005-06-01 14:39:56.702915384 -0500
+++ linux-2.6.9~working/fs/namei.c	2005-06-01 13:16:11.000000000 -0500
@@ -213,7 +213,8 @@ int permission(struct inode * inode,int 
 	int retval;
 	int submask;
 
-	audit_notify_watch(inode, mask);
+	if (audit_notify_watch(inode, mask))
+		return -ENOMEM;
 
 	/* Ordinary permission routines do not understand MAY_APPEND. */
 	submask = mask & ~MAY_APPEND;
@@ -331,7 +332,8 @@ static inline int exec_permission_lite(s
 	if (inode->i_op && inode->i_op->permission)
 		return -EAGAIN;
 
-	audit_notify_watch(inode, MAY_EXEC);
+	if (audit_notify_watch(inode, MAY_EXEC))
+		return -ENOMEM;
 
 	if (current->fsuid == inode->i_uid)
 		mode >>= 6;
@@ -1113,7 +1115,9 @@ static inline int may_delete(struct inod
 
 	BUG_ON(victim->d_parent->d_inode != dir);
 
-	audit_notify_watch(victim->d_inode, MAY_WRITE);
+	error = audit_notify_watch(victim->d_inode, MAY_WRITE);
+	if (error)
+		return error;
 
 	error = permission(dir,MAY_WRITE | MAY_EXEC, NULL);
 	if (error)
@@ -1240,8 +1244,9 @@ int vfs_create(struct inode *dir, struct
 		return error;
 	DQUOT_INIT(dir);
 	error = dir->i_op->create(dir, dentry, mode, nd);
+	if (!error)
+		error =	audit_notify_watch(dentry->d_inode, MAY_WRITE);
 	if (!error) {
-		audit_notify_watch(dentry->d_inode, MAY_WRITE);
 		inode_dir_notify(dir, DN_CREATE);
 		security_inode_post_create(dir, dentry, mode);
 	}
@@ -1555,8 +1560,9 @@ int vfs_mknod(struct inode *dir, struct 
 
 	DQUOT_INIT(dir);
 	error = dir->i_op->mknod(dir, dentry, mode, dev);
+	if (!error)
+		error = audit_notify_watch(dentry->d_inode, MAY_WRITE);
 	if (!error) {
-		audit_notify_watch(dentry->d_inode, MAY_WRITE);
 		inode_dir_notify(dir, DN_CREATE);
 		security_inode_post_mknod(dir, dentry, mode, dev);
 	}
@@ -1629,8 +1635,9 @@ int vfs_mkdir(struct inode *dir, struct 
 
 	DQUOT_INIT(dir);
 	error = dir->i_op->mkdir(dir, dentry, mode);
+	if (!error)
+		error = audit_notify_watch(dentry->d_inode, MAY_WRITE);
 	if (!error) {
-		audit_notify_watch(dentry->d_inode, MAY_WRITE);
 		inode_dir_notify(dir, DN_CREATE);
 		security_inode_post_mkdir(dir,dentry, mode);
 	}
@@ -1874,8 +1881,9 @@ int vfs_symlink(struct inode *dir, struc
 
 	DQUOT_INIT(dir);
 	error = dir->i_op->symlink(dir, dentry, oldname);
+	if (!error)
+		error = audit_notify_watch(dentry->d_inode, MAY_WRITE);
 	if (!error) {
-		audit_notify_watch(dentry->d_inode, MAY_WRITE);
 		inode_dir_notify(dir, DN_CREATE);
 		security_inode_post_symlink(dir, dentry, oldname);
 	}
@@ -1948,8 +1956,9 @@ int vfs_link(struct dentry *old_dentry, 
 	DQUOT_INIT(dir);
 	error = dir->i_op->link(old_dentry, dir, new_dentry);
 	up(&old_dentry->d_inode->i_sem);
+	if (!error)
+		error = audit_notify_watch(new_dentry->d_inode, MAY_WRITE);
 	if (!error) {
-		audit_notify_watch(new_dentry->d_inode, MAY_WRITE);
 		inode_dir_notify(dir, DN_CREATE);
 		security_inode_post_link(old_dentry, dir, new_dentry);
 	}
@@ -2071,12 +2080,13 @@ int vfs_rename_dir(struct inode *old_dir
 			d_rehash(new_dentry);
 		dput(new_dentry);
 	}
-	if (!error) {
+	if (!error)
 		d_move(old_dentry,new_dentry);
-		audit_notify_watch(old_dentry->d_inode, MAY_WRITE);
+	
+	error =	audit_notify_watch(old_dentry->d_inode, MAY_WRITE);
+	if (!error)
 		security_inode_post_rename(old_dir, old_dentry,
 					   new_dir, new_dentry);
-	}
 	return error;
 }
 
@@ -2102,9 +2112,12 @@ int vfs_rename_other(struct inode *old_d
 		/* The following d_move() should become unconditional */
 		if (!(old_dir->i_sb->s_type->fs_flags & FS_ODD_RENAME))
 			d_move(old_dentry, new_dentry);
-		audit_notify_watch(old_dentry->d_inode, MAY_WRITE);
-		security_inode_post_rename(old_dir, old_dentry, new_dir, new_dentry);
 	}
+
+	error = audit_notify_watch(old_dentry->d_inode, MAY_WRITE);
+	if (!error)
+		security_inode_post_rename(old_dir, old_dentry, new_dir, new_dentry);
+	
 	if (target)
 		up(&target->i_sem);
 	dput(new_dentry);
diff -Nurp linux-2.6.9/include/linux/audit.h linux-2.6.9~working/include/linux/audit.h
--- linux-2.6.9/include/linux/audit.h	2005-06-01 14:39:56.727911584 -0500
+++ linux-2.6.9~working/include/linux/audit.h	2005-06-01 14:18:08.000000000 -0500
@@ -215,32 +215,28 @@ struct watch_transport {
 #ifdef __KERNEL__
 /* Structure associated with inode->i_audit */
 
-struct audit_inode_data {
-	struct audit_inode_data *next_hash;
-	struct inode		*inode;
-	struct audit_wentry	*wentry;
-	struct hlist_head 	watchlist;
-	rwlock_t		lock;
-};
-
 struct audit_watch {
-	dev_t	dev;		/* Superblock device	      */
-	__u32	perms;		/* Permissions filtering      */
-	char	*name;		/* Watch point beneath parent */
-	char 	*path;		/* Insertion path             */
-	char	*filterkey;	/* An arbitrary filtering key */
-};
-
-struct audit_wentry {
-	struct rcu_head		w_rcu;
-	struct hlist_node 	w_node;
-	struct hlist_node	w_master;
-	struct audit_watch	*w_watch;
-	struct dentry		*w_dentry;
 	atomic_t		w_count;
+	struct hlist_node 	w_node;		/* per-directory list	      */
+	struct hlist_node	w_master;	/* Master watch list	      */
+	struct dentry		*w_dentry;	/* Watched inode	      */
+	dev_t			w_dev;		/* Superblock device	      */
+	__u32			w_perms;	/* Permissions filtering      */
+	char			*w_name;	/* Watch point beneath parent */
+	char			*w_path;	/* Insertion path             */
+	char			*w_filterkey;	/* An arbitrary filtering key */
+	struct audit_inode_data *w_iaudit;	/* Preallocated inode data    */
+};
 
+struct audit_inode_data {
+	struct audit_inode_data *next_hash;	/* Watch data hash table      */
+	struct inode		*inode;		/* Inode to which it belongs  */
+	struct audit_watch	*watch;		/* Watch for this inode	      */
+	struct hlist_head 	watchlist;	/* Watches for children       */
+	rwlock_t		lock;
 };
 
+
 struct audit_sig_info {
 	uid_t		uid;
 	pid_t		pid;
@@ -306,11 +302,11 @@ extern int audit_receive_watch(int type,
 extern int audit_inode_alloc(struct inode *inode);
 extern void audit_inode_free(struct inode *inode);
 extern void audit_update_watch(struct dentry *dentry, int remove);
-extern void audit_wentry_put(struct audit_wentry *wentry);
+extern void audit_watch_put(struct audit_watch *watch);
 extern void audit_dentry_unpin(struct dentry *dentry);
-extern struct audit_wentry *audit_wentry_get(struct audit_wentry *wentry);
+extern struct audit_watch *audit_watch_get(struct audit_watch *watch);
 extern int audit_notify_watch(struct inode *inode, int mask);
-extern int auditfs_attach_wdata(struct inode *inode, struct audit_wentry *wentry,
+extern int auditfs_attach_wdata(struct inode *inode, struct audit_watch *watch,
 				int mask);
 #else
 #define audit_filesystem_init() ({ 0; })
@@ -319,8 +315,8 @@ extern int auditfs_attach_wdata(struct i
 #define audit_inode_alloc(i) ({ 0; })
 #define audit_inode_free(i) do { ; } while(0)
 #define audit_update_watch(d,r) do { ; } while (0)
-#define audit_wentry_put(w) do { ; } while(0)
-#define audit_wentry_get(w) ({ 0; })
+#define audit_watch_put(w) do { ; } while(0)
+#define audit_watch_get(w) ({ 0; })
 #define audit_notify_watch(i,m) ({ 0; })
 #endif
 
diff -Nurp linux-2.6.9/init/Kconfig linux-2.6.9~working/init/Kconfig
--- linux-2.6.9/init/Kconfig	2005-06-01 14:39:56.710914168 -0500
+++ linux-2.6.9~working/init/Kconfig	2005-06-01 15:02:04.703028680 -0500
@@ -169,6 +169,16 @@ config AUDITSYSCALL
 	  can be used independently or with another kernel subsystem,
 	  such as SELinux.
 
+config AUDITFILESYSTEM
+	bool "Enable file system auditing support"
+	depends on AUDITSYSCALL
+	default n
+	help
+	  Enable file system auditing for regular files and directories.
+	  When a targeted file or directory is accessed, an audit record
+	  is generated describing the inode accessed, how it was accessed,
+	  and by whom (ie: pid and system call).
+
 config LOG_BUF_SHIFT
 	int "Kernel log buffer size (16 => 64KB, 17 => 128KB)" if DEBUG_KERNEL
 	range 12 20
@@ -186,16 +196,6 @@ config LOG_BUF_SHIFT
 		     13 =>  8 KB
 		     12 =>  4 KB
 
-config AUDITFILESYSTEM
-	bool "Enable file system auditing support"
-	depends on AUDITSYSCALL
-	default n
-	help
-	  Enable file system auditing for regular files and directories.
-	  When a targeted file or directory is accessed, an audit record
-	  is generated describing the inode accessed, how it was accessed,
-	  and by whom (ie: pid and system call).
-
 config HOTPLUG
 	bool "Support for hot-pluggable devices" if !ARCH_S390
 	default ARCH_S390
diff -Nurp linux-2.6.9/kernel/auditfs.c linux-2.6.9~working/kernel/auditfs.c
--- linux-2.6.9/kernel/auditfs.c	2005-06-01 14:39:56.755907328 -0500
+++ linux-2.6.9~working/kernel/auditfs.c	2005-06-01 14:22:46.000000000 -0500
@@ -40,16 +40,15 @@
 extern int audit_enabled;
 
 static kmem_cache_t *audit_watch_cache;
-static kmem_cache_t *audit_wentry_cache;
 
 /* Read-heavy list */
-HLIST_HEAD(master_watchlist);
+static 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;
+	struct hlist_node list;
+	void *memblk;
+	size_t size;
 };
 
 
@@ -91,46 +90,46 @@ struct audit_inode_data *inode_audit_dat
 
 /* Private Interface */
 
-/* Unpin the dentry stored at wentry->w_dentry. */
-static inline void audit_unpin(struct audit_wentry *wentry)
+/* Unpin the dentry stored at watch->w_dentry. */
+static inline void audit_unpin(struct audit_watch *watch)
 {
-	if (wentry && wentry->w_dentry) {
-		dput(wentry->w_dentry);
-		wentry->w_dentry = NULL;
+	if (watch && watch->w_dentry) {
+		dput(watch->w_dentry);
+		watch->w_dentry = NULL;
 	}
 }
 
-/* Pin the dentry and store it at wentry->w_dentry. */
-static inline void audit_pin(struct audit_wentry *wentry,
+/* Pin the dentry and store it at watch->w_dentry. */
+static inline void audit_pin(struct audit_watch *watch,
 			     struct dentry *dentry)
 {
-	if (wentry && !wentry->w_dentry)
-		wentry->w_dentry = dget(dentry);
+	if (watch && !watch->w_dentry)
+		watch->w_dentry = dget(dentry);
 }
 
-static inline struct audit_wentry *audit_wentry_fetch(const char *name,
-                                                     struct audit_inode_data *data)
+static inline struct audit_watch *audit_watch_fetch(const char *name,
+						    struct audit_inode_data *data)
 {
-	struct audit_wentry *wentry, *ret = NULL;
+	struct audit_watch *watch, *ret = NULL;
 	struct hlist_node *pos;
 
-	hlist_for_each_entry(wentry, pos, &data->watchlist, w_node)
-		if(!strcmp(wentry->w_watch->name, name)) {
-			ret = audit_wentry_get(wentry);
+	hlist_for_each_entry(watch, pos, &data->watchlist, w_node)
+		if(!strcmp(watch->w_name, name)) {
+			ret = audit_watch_get(watch);
 			break;
 		}
 
 	return ret;
 }
 
-static inline struct audit_wentry *audit_wentry_fetch_lock(const char *name,
+static inline struct audit_watch *audit_watch_fetch_lock(const char *name,
 						struct audit_inode_data *data)
 {
-	struct audit_wentry *ret = NULL;
+	struct audit_watch *ret = NULL;
 
 	if (name && data) {
 		read_lock(&data->lock);
-		ret = audit_wentry_fetch(name, data);
+		ret = audit_watch_fetch(name, data);
 		read_unlock(&data->lock);
 	}
 
@@ -143,25 +142,37 @@ static inline struct audit_watch *audit_
 
 	watch = kmem_cache_alloc(audit_watch_cache, GFP_KERNEL);
 	if (watch) {
-		watch->name = NULL;
-		watch->path = NULL;
-		watch->filterkey = NULL;
-		watch->perms = 0;
+		memset(watch, 0, sizeof(*watch));
+		atomic_set(&watch->w_count, 1);
 	}
 
 	return watch;
 }
 
+/*
+ * If a watch has been removed from a watchlist, we promptly unpin the
+ * dentry that was being watched, as it is no longer important to us.
+ */
 static inline void audit_watch_free(struct audit_watch *watch)
 {
 	if (watch) {
-		kfree(watch->name);
-		kfree(watch->path);
-		kfree(watch->filterkey);
+		audit_unpin(watch);
+		kfree(watch->w_name);
+		kfree(watch->w_path);
+		kfree(watch->w_filterkey);
+		BUG_ON(watch->w_dentry);
+		BUG_ON(!hlist_unhashed(&watch->w_node));
+		BUG_ON(!hlist_unhashed(&watch->w_master));
+		if (watch->w_iaudit) {
+			BUG_ON(watch->w_iaudit->inode);
+			BUG_ON(!hlist_empty(&watch->w_iaudit->watchlist));
+			kfree(watch->w_iaudit);
+		}
 		kmem_cache_free(audit_watch_cache, watch);
 	}
 }
 
+
 /* Convert a watch_transport structure into a kernel audit_watch structure. */
 static inline struct audit_watch *audit_to_watch(void *memblk)
 {
@@ -173,23 +184,23 @@ static inline struct audit_watch *audit_
 	if (!watch)
 		goto audit_to_watch_exit;
 
-	t = (struct watch_transport *)memblk;
+	t = memblk;
 
-	watch->perms = t->perms;
+	watch->w_perms = t->perms;
 
 	offset = sizeof(struct watch_transport);
-	watch->filterkey = kmalloc(t->fklen+1, GFP_KERNEL);
-	if (!watch->filterkey)
+	watch->w_filterkey = kmalloc(t->fklen+1, GFP_KERNEL);
+	if (!watch->w_filterkey)
 		goto audit_to_watch_fail;
-	watch->filterkey[t->fklen] = 0;
-	memcpy(watch->filterkey, memblk + offset, t->fklen);
+	watch->w_filterkey[t->fklen] = 0;
+	memcpy(watch->w_filterkey, memblk + offset, t->fklen);
 
 	offset += t->fklen;
-	watch->path = kmalloc(t->pathlen+1, GFP_KERNEL);
-	if (!watch->path)
+	watch->w_path = kmalloc(t->pathlen+1, GFP_KERNEL);
+	if (!watch->w_path)
 		goto audit_to_watch_fail;
-	watch->path[t->pathlen] = 0;
-	memcpy(watch->path, memblk + offset, t->pathlen);
+	watch->w_path[t->pathlen] = 0;
+	memcpy(watch->w_path, memblk + offset, t->pathlen);
 
 	goto audit_to_watch_exit;
 
@@ -206,99 +217,31 @@ audit_to_watch_exit:
  */
 static inline void *audit_to_transport(struct audit_watch *watch, size_t size)
 {
-	unsigned int offset;
-	struct watch_transport t;
-	void *memblk;
+	struct watch_transport *t;
+	char *p;
 
-        memblk = kmalloc(size, GFP_ATOMIC);
-        if (!memblk)
+        t = kmalloc(size, GFP_KERNEL);
+        if (!t)
                 goto audit_to_transport_exit;
 
-	memset(&t, 0, sizeof(t));
-
-	t.dev_major = MAJOR(watch->dev);
-	t.dev_minor = MINOR(watch->dev);
-	t.perms = watch->perms;
-	t.pathlen = strlen(watch->path) + 1;
-	if (watch->filterkey)
-		t.fklen = strlen(watch->filterkey) + 1;
-
-	memcpy(memblk, &t, sizeof(t));
-	offset = sizeof(t);
-	memcpy(memblk + offset, watch->filterkey, t.fklen);
-	offset += t.fklen;
-	memcpy(memblk + offset, watch->path, t.pathlen);
-
-audit_to_transport_exit:
-	return memblk;
-}
-
-static inline struct audit_watch *audit_create_watch(const char *path,
-						     const char *name,
-						     const char *filterkey,
-						     __u32 perms, dev_t dev)
-{
-	struct audit_watch *err = NULL;
-	struct audit_watch *watch = NULL;
-
-	err = ERR_PTR(-ENOMEM);
-	watch = audit_watch_alloc();
-	if (watch) {
-		watch->path = kmalloc(strlen(path)+1, GFP_KERNEL);
-		if (!watch->path)
-			goto audit_create_watch_fail;
-		strcpy(watch->path, path);
-
-		watch->name = kmalloc(strlen(name)+1, GFP_KERNEL);
-		if (!watch->name)
-			goto audit_create_watch_fail;
-		strcpy(watch->name, name);
-
-		if (filterkey) {
-			watch->filterkey = kmalloc(strlen(filterkey)+1,
-						   GFP_KERNEL);
-			if (!watch->filterkey)
-				goto audit_create_watch_fail;
-			strcpy(watch->filterkey, filterkey);
-		}
-
-		watch->dev = dev;
-		watch->perms = perms;
-
-		goto audit_create_watch_exit;
-	}
+	memset(t, 0, sizeof(*t));
 
-audit_create_watch_fail:
-	audit_watch_free(watch);
-	watch = err;
-audit_create_watch_exit:
-	return watch;
-}
+	t->dev_major = MAJOR(watch->w_dev);
+	t->dev_minor = MINOR(watch->w_dev);
+	t->perms = watch->w_perms;
+	t->pathlen = strlen(watch->w_path) + 1;
 
-static inline struct audit_wentry *audit_wentry_alloc(void)
-{
-	struct audit_wentry *wentry;
+	p = (char *)&t[1];
 
-	wentry = kmem_cache_alloc(audit_wentry_cache, GFP_KERNEL);
-	if (wentry) {
-		atomic_set(&wentry->w_count, 1);
-		wentry->w_watch = NULL;
-		wentry->w_dentry = NULL;
+	if (watch->w_filterkey) {
+		t->fklen = strlen(watch->w_filterkey) + 1;
+		memcpy(p, watch->w_filterkey, t->fklen);
+		p += t->fklen;
 	}
+	memcpy(p, watch->w_path, t->pathlen);
 
-	return wentry;
-}
-/*
- * If a watch has been removed from a watchlist, we promptly unpin the
- * dentry that was being watched, as it is no longer important to us.
- */
-static inline void audit_wentry_free(struct audit_wentry *wentry)
-{
-	if (wentry) {
-		audit_unpin(wentry);
-		audit_watch_free(wentry->w_watch);
-		kmem_cache_free(audit_wentry_cache, wentry);
-	}
+audit_to_transport_exit:
+	return t;
 }
 
 /*
@@ -307,114 +250,92 @@ static inline void audit_wentry_free(str
  * watchlist and the local watchlist to ensure that insertions and removals of
  * watches are seralized.
  */
-static inline int audit_create_wentry(const char *path,
-				      const char *name,
-				      const char *filterkey,
-				      __u32 perms, dev_t dev,
-				      struct audit_inode_data *data)
+static inline int audit_create_watch(const struct audit_watch *tmp,
+				     struct audit_inode_data *data)
 {
 	int ret;
-	struct audit_wentry *wentry = NULL;
-	struct audit_wentry *new = NULL;
 	struct audit_watch *watch;
 
 	ret = -EEXIST;
-	wentry = audit_wentry_fetch_lock(name, data);
-	if (wentry) {
-		audit_wentry_put(wentry);
-		goto audit_create_wentry_exit;
+	watch = audit_watch_fetch_lock(tmp->w_name, data);
+	if (watch) {
+		audit_watch_put(watch);
+		goto audit_create_watch_exit;
 	}
 
 	ret = -ENOMEM;
-	new = audit_wentry_alloc();
-	if (!new)
-		goto audit_create_wentry_exit;
-
-	watch = audit_create_watch(path, name, filterkey, perms, dev);
-	if (IS_ERR(watch)) {
-		ret = PTR_ERR(watch);
-		audit_wentry_put(new);
-		goto audit_create_wentry_exit;
+	watch = audit_watch_alloc();
+	if (!watch)
+		goto audit_create_watch_exit;
+
+	watch->w_path = kmalloc(strlen(tmp->w_path)+1, GFP_KERNEL);
+	if (!watch->w_path)
+		goto audit_create_watch_fail;
+	strcpy(watch->w_path, tmp->w_path);
+
+	watch->w_name = kmalloc(strlen(tmp->w_name)+1, GFP_KERNEL);
+	if (!watch->w_name)
+		goto audit_create_watch_fail;
+	strcpy(watch->w_name, tmp->w_name);
+
+	if (tmp->w_filterkey) {
+		watch->w_filterkey = kmalloc(strlen(tmp->w_filterkey)+1, GFP_KERNEL);
+		if (!watch->w_filterkey)
+			goto audit_create_watch_fail;
+		strcpy(watch->w_filterkey, tmp->w_filterkey);
 	}
 
-	ret = 0;
+	watch->w_dev = tmp->w_dev;
+	watch->w_perms = tmp->w_perms;
 
-	new->w_watch = watch;
-	audit_wentry_get(new);
+	audit_watch_get(watch);
 
 	write_lock(&data->lock);
-	hlist_add_head(&new->w_node, &data->watchlist);
-       spin_lock(&master_watchlist_lock);
-       hlist_add_head_rcu(&new->w_master, &master_watchlist);
-       spin_unlock(&master_watchlist_lock);
+	hlist_add_head(&watch->w_node, &data->watchlist);
+	spin_lock(&master_watchlist_lock);
+	hlist_add_head(&watch->w_master, &master_watchlist);
+	spin_unlock(&master_watchlist_lock);
 	write_unlock(&data->lock);
+	return 0;
 
-audit_create_wentry_exit:
-	return ret;
-}
-
-static inline void audit_wentry_rcu_put(struct rcu_head *head)
-{
-	struct audit_wentry *wentry;
+ audit_create_watch_fail:
+	audit_watch_put(watch);
 
-	wentry = container_of(head, struct audit_wentry, w_rcu);
-	audit_wentry_put(wentry);
+ audit_create_watch_exit:
+	return ret;
 }
 
-/*
- * There's three ways we can arrive at audit_destroy_wentry.  Two of the ways
- * may cause contention with one another, while the third may not.  They are:
- *
- * 1)  An administrator has explicitly requested a watch removal
- * 2)  A directory with an "active" watchlist is rename()'ed
- * 3)  The inode is in the process of being destroyed
- *
- * In ways 1) and 2) the data->lock must be held to safely enter.  We use
- * the audit_master_watchlist spinlock to protect against removal of two
- * consecutive entries concurrently in the master watchlist.
- *
- * If way 3) occurs there will no longer be any reachable references to the
- * inode, thus there is only one way to remove this wentry, and no need to
- * hold the data->lock.
- */
-static inline void audit_destroy_wentry(struct audit_wentry *wentry)
+static inline void audit_destroy_watch(struct audit_watch *watch)
 {
-	if (wentry) {
-		hlist_del_init(&wentry->w_node);
-		audit_wentry_put(wentry);
-               spin_lock(&master_watchlist_lock);
-		hlist_del_rcu(&wentry->w_master);
-		call_rcu(&wentry->w_rcu, audit_wentry_rcu_put);
-               spin_unlock(&master_watchlist_lock);
+	if (watch) {
+		hlist_del_init(&watch->w_node);
+		spin_lock(&master_watchlist_lock);
+		hlist_del_init(&watch->w_master);
+		spin_unlock(&master_watchlist_lock);
+		audit_watch_put(watch);
+		audit_watch_put(watch);
 	}
 }
 
-
-/*
- * We only drain the watchlist in two ways.  They are:
- *
- * 1)  Upon deletion of the inode (no contention)
- * 2)  Upon rename()'ing a directory with an "active" watchlist (contention)
- *
- * Caller should hold data->lock where contention is possible.
- */
-static inline void audit_drain_watchlist(struct audit_inode_data *data)
+static inline void audit_data_free(struct audit_inode_data *data)
 {
-	struct audit_wentry *wentry;
+	struct audit_watch *watch;
+	struct audit_inode_data *wdata = NULL;
 	struct hlist_node *pos, *tmp;
 
-	hlist_for_each_entry_safe(wentry, pos, tmp, &data->watchlist, w_node)
-		audit_destroy_wentry(wentry);
-}
-
+	hlist_for_each_entry_safe(watch, pos, tmp, &data->watchlist, w_node)
+		audit_destroy_watch(watch);
 
-static inline void audit_data_free(struct audit_inode_data *data)
-{
-	if (data) {
-		audit_drain_watchlist(data);
-		audit_wentry_put(data->wentry);
-		kfree(data);
+	/* If this inode was watched itself, we may have been using
+	   the preallocated inode audit data. So don't free it */
+	if (data->watch) {
+		wdata = data->watch->w_iaudit;
+		audit_watch_put(data->watch);
 	}
+	if (data != wdata)
+		kfree(data);
+	else
+		memset(data, 0, sizeof(*data));
 }
 
 static inline int audit_insert_watch(struct audit_watch *watch, uid_t loginuid)
@@ -422,20 +343,25 @@ static inline int audit_insert_watch(str
 	int ret;
 	struct nameidata nd;
 
-	ret = path_lookup(watch->path, LOOKUP_PARENT, &nd);
+	ret = path_lookup(watch->w_path, LOOKUP_PARENT, &nd);
 	if (ret < 0)
 		goto audit_insert_watch_exit;
 
+	/* FIXME: Allocate w_iaudit */
+
 	ret = -EPERM;
 	if (nd.last_type != LAST_NORM || !nd.last.name)
 		goto audit_insert_watch_release;
 
-	ret = audit_create_wentry(watch->path,
-				  nd.last.name,
-				  watch->filterkey,
-				  watch->perms,
-				  nd.dentry->d_inode->i_sb->s_dev,
-				  inode_audit_data(nd.dentry->d_inode));
+	ret = -ENOMEM;
+	watch->w_name = kmalloc(strlen(nd.last.name)+1, GFP_KERNEL);
+	if (!watch->w_name)
+		goto audit_insert_watch_release;
+	strcpy(watch->w_name, nd.last.name);	
+	
+	watch->w_dev = nd.dentry->d_inode->i_sb->s_dev;
+
+	ret = audit_create_watch(watch, inode_audit_data(nd.dentry->d_inode));
 	if (ret < 0)
 		goto audit_insert_watch_release;
 
@@ -449,20 +375,14 @@ audit_insert_watch_exit:
 	return ret;
 }
 
-/*
- * We hold the data->lock here to eliminate contention between this user space
- * request and an action taken by audit_update_watch() in which watch removal
- * is also possible when a directory with an "active" watchlist is rename()'ed.
- *
- */
 static inline int audit_remove_watch(struct audit_watch *watch, uid_t loginuid)
 {
 	int ret;
 	struct nameidata nd;
 	struct audit_inode_data *data;
-	struct audit_wentry *wentry;
+	struct audit_watch *real;
 
-	ret = path_lookup(watch->path, LOOKUP_PARENT, &nd);
+	ret = path_lookup(watch->w_path, LOOKUP_PARENT, &nd);
 	if (ret < 0)
 		goto audit_remove_watch_exit;
 
@@ -473,13 +393,13 @@ static inline int audit_remove_watch(str
 	data = inode_audit_data(nd.dentry->d_inode);
 
 	write_lock(&data->lock);
-	wentry = audit_wentry_fetch(nd.last.name, data);
-	if (!wentry) {
+	real = audit_watch_fetch(nd.last.name, data);
+	if (!real) {
 		write_unlock(&data->lock);
 		goto audit_remove_watch_release;
 	}
-	audit_destroy_wentry(wentry);
-	audit_wentry_put(wentry);
+	audit_destroy_watch(real);
+	audit_watch_put(real);
 	audit_log(NULL, AUDIT_CONFIG_CHANGE, "auid=%u removed watch\n", loginuid);
 	write_unlock(&data->lock);
 
@@ -491,20 +411,20 @@ audit_remove_watch_exit:
 	return ret;
 }
 
-struct audit_wentry *audit_wentry_get(struct audit_wentry *wentry)
+struct audit_watch *audit_watch_get(struct audit_watch *watch)
 {
-	if (wentry) {
-		BUG_ON(!atomic_read(&wentry->w_count));
-		atomic_inc(&wentry->w_count);
+	if (watch) {
+		BUG_ON(!atomic_read(&watch->w_count));
+		atomic_inc(&watch->w_count);
 	}
 
-	return wentry;
+	return watch;
 }
 
-void audit_wentry_put(struct audit_wentry *wentry)
+void audit_watch_put(struct audit_watch *watch)
 {
-	if (wentry && atomic_dec_and_test(&wentry->w_count))
-		audit_wentry_free(wentry);
+	if (watch && atomic_dec_and_test(&watch->w_count))
+		audit_watch_free(watch);
 }
 
 /*
@@ -522,7 +442,7 @@ void audit_wentry_put(struct audit_wentr
  */
 void audit_update_watch(struct dentry *dentry, int remove)
 {
-	struct audit_wentry *wentry;
+	struct audit_watch *watch;
 	struct audit_inode_data *data, *parent;
 
 	if (likely(!audit_enabled))
@@ -542,29 +462,32 @@ void audit_update_watch(struct dentry *d
 	}
 	parent = inode_audit_data(dentry->d_parent->d_inode);
 
-	wentry = audit_wentry_fetch_lock(dentry->d_name.name, parent);
+	watch = audit_watch_fetch_lock(dentry->d_name.name, parent);
 
 	write_lock(&data->lock);
 	/* FIXME: long watchlist == too much spinning? */
 	if (remove) {
-		audit_drain_watchlist(data);
-		if ((wentry && data->wentry))
-			if (!strcmp(wentry->w_watch->name,
-			            data->wentry->w_watch->name)) {
-			audit_wentry_put(data->wentry);
-			data->wentry = NULL;
+		/* If the inode was being watched for _this_ pathname, clear the watch */
+		/* FIXME: If there was _another_ path to the same inode which was 
+		   supposed to be watched, we ought to continue watching. */
+		if (watch && data->watch && 
+		    !strcmp(watch->w_name, data->watch->w_name)) {
+			audit_watch_put(data->watch);
+			data->watch = NULL;
 		}
-	} else if (!data->wentry) {
-		data->wentry = audit_wentry_get(wentry);
-		audit_pin(data->wentry, dentry);
-	} else if (hlist_unhashed(&data->wentry->w_node)) {
-		audit_wentry_put(data->wentry);
-		data->wentry = audit_wentry_get(wentry);
-		audit_pin(data->wentry, dentry);
+	} else if (!data->watch) {
+		/* Inode wasn't watched before. Maybe it is now */
+		data->watch = audit_watch_get(watch);
+		audit_pin(data->watch, dentry);
+	} else if (hlist_unhashed(&data->watch->w_node)) {
+		/* Old watch is dead now. Drop it and add new one .*/
+		audit_watch_put(data->watch);
+		data->watch = audit_watch_get(watch);
+		audit_pin(data->watch, dentry);
 	}
 	write_unlock(&data->lock);
 
-	audit_wentry_put(wentry);
+	audit_watch_put(watch);
 }
 
 /* Convert a watch to a audit_skb_list */
@@ -575,15 +498,15 @@ struct audit_skb_list *audit_to_skb(stru
 	struct audit_skb_list *entry;
 
 	/* We must include space for both "\0" */
-	size = sizeof(struct watch_transport) + strlen(watch->path) +
-	       strlen(watch->filterkey) + 2;
+	size = sizeof(struct watch_transport) + strlen(watch->w_path) +
+	       strlen(watch->w_filterkey) + 2;
 
 	entry = ERR_PTR(-ENOMEM);
 	memblk = audit_to_transport(watch, size);
 	if (!memblk)
 		goto audit_queue_watch_exit;
 
-	entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
 	if (!entry) {
 		entry = ERR_PTR(-ENOMEM);
 		goto audit_queue_watch_exit;
@@ -601,7 +524,7 @@ audit_queue_watch_exit:
  * file system and send it to user space.  There will never be concurrent
  * readers of this list.
  *
- * The reference to wentry will not be put back during a read upon a
+ * The reference to watch will not be put back during a read upon a
  * watch removal, until after we're done reading.  So, the potential
  * for the rug being pulled out from under us is NIL.
  *
@@ -613,21 +536,42 @@ int audit_list_watches(int pid, int seq)
 	struct hlist_head skb_list;
 	struct hlist_node *tmp, *pos;
 	struct audit_skb_list *entry;
-	struct audit_wentry *wentry;
+	struct audit_watch *watch;
 
+ restart:
 	INIT_HLIST_HEAD(&skb_list);
+	spin_lock(&master_watchlist_lock);
 
-	rcu_read_lock();
-	hlist_for_each_entry_rcu(wentry, pos, &master_watchlist, w_master) {
-		entry = audit_to_skb(wentry->w_watch);
+	hlist_for_each_entry(watch, pos, &master_watchlist, w_master) {
+		audit_watch_get(watch);
+		spin_unlock(&master_watchlist_lock);
+		entry = audit_to_skb(watch);
 		if (IS_ERR(entry)) {
 			ret = PTR_ERR(entry);
-			rcu_read_unlock();
+			spin_unlock(&master_watchlist_lock);
 			goto audit_list_watches_fail;
 		}
 		hlist_add_head(&entry->list, &skb_list);
+		spin_lock(&master_watchlist_lock);
+		if (hlist_unhashed(&watch->w_master)) {
+			/* This watch was removed from the list while we 
+			   pondered it. We could play tricks to find how far
+			   we'd got, but we might as well just start again
+			   from scratch. There's no real chance of livelock,
+			   as the number of watches in the system has 
+			   decreased, and the netlink sem prevents new watches
+			   from being added while we're looping */
+			audit_watch_put(watch);
+			hlist_for_each_entry_safe(entry, pos, tmp, &skb_list, list) {
+				hlist_del(&entry->list);
+				kfree(entry->memblk);
+				kfree(entry);
+			}
+			goto restart;
+		}
+		audit_watch_put(watch);
 	}
-	rcu_read_unlock();
+	spin_unlock(&master_watchlist_lock);
 
 	hlist_for_each_entry_safe(entry, pos, tmp, &skb_list, list) {
 		audit_send_reply(pid, seq, AUDIT_WATCH_LIST, 0, 1, 
@@ -655,6 +599,7 @@ int audit_receive_watch(int type, int pi
 {
 	int ret = 0;
 	struct audit_watch *watch = NULL;
+	char *payload = (char *)&req[1];
 
 	ret = -EINVAL;
 	if (req->pathlen > PATH_MAX || req->pathlen == 0)
@@ -663,6 +608,9 @@ int audit_receive_watch(int type, int pi
 	if (req->fklen > AUDIT_FILTERKEY_MAX)
 		goto audit_receive_watch_exit;
 
+	if ( payload[req->fklen] != '/')
+		goto audit_receive_watch_exit;
+
 	if (req->perms > (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND))
 		goto audit_receive_watch_exit;
 
@@ -698,7 +646,7 @@ int audit_inode_alloc(struct inode *inod
 		return -ENOMEM;
 
 	INIT_HLIST_HEAD(&data->watchlist);
-	data->wentry = NULL;
+	data->watch = NULL;
 	data->lock = RW_LOCK_UNLOCKED;
 	data->inode = inode;
 	data->next_hash = NULL;
@@ -751,15 +699,15 @@ void audit_inode_free(struct inode *inod
 void audit_dentry_unpin(struct dentry *dentry)
 {
 	struct audit_inode_data *parent;
-	struct audit_wentry *wentry;
+	struct audit_watch *watch;
 
 	parent = inode_audit_data(dentry->d_parent->d_inode);
-	wentry = audit_wentry_fetch_lock(dentry->d_name.name, parent);
-	if (wentry) {
+	watch = audit_watch_fetch_lock(dentry->d_name.name, parent);
+	if (watch) {
 		struct audit_inode_data *data = inode_audit_data(dentry->d_inode);
 
-		audit_unpin(data->wentry);
-		audit_wentry_put(wentry);
+		audit_unpin(data->watch);
+		audit_watch_put(watch);
 	}
 }
 
@@ -774,12 +722,6 @@ int audit_filesystem_init(void)
 	if (!audit_watch_cache)
 		goto audit_filesystem_init_fail;
 
-	audit_wentry_cache =
-	    kmem_cache_create("audit_wentry_cache",
-			      sizeof(struct audit_wentry), 0, 0, NULL, NULL);
-	if (!audit_wentry_cache)
-		goto audit_filesystem_init_fail;
-
 	/* Set up hash table for inode objects */
 	auditfs_hash_bits = long_log2(auditfs_cache_buckets);
 	if (auditfs_cache_buckets != (1 << auditfs_hash_bits)) {
@@ -804,7 +746,6 @@ int audit_filesystem_init(void)
 
 audit_filesystem_init_fail:
 	kmem_cache_destroy(audit_watch_cache);
-	kmem_cache_destroy(audit_wentry_cache);
 audit_filesystem_init_exit:
 	return ret;
 }
@@ -814,7 +755,7 @@ int audit_notify_watch(struct inode *ino
 {
 	int ret = 0;
 	struct audit_inode_data *data;
-	struct audit_wentry *wentry = NULL;
+	struct audit_watch *watch = NULL;
 
 	if (likely(!audit_enabled))
 		return 0;
@@ -827,24 +768,24 @@ int audit_notify_watch(struct inode *ino
 		return 0;
 
 	/* 
-	 * Won't be able to drop i_audit->wentry reference
+	 * Won't be able to drop i_audit->watch reference
 	 * before we obtain our own reference
 	 */
 	read_lock(&data->lock);
-	wentry = audit_wentry_get(data->wentry);
+	watch = audit_watch_get(data->watch);
 	read_unlock(&data->lock);
-	if (!wentry)
+	if (!watch)
 		return 0;
 
-	if (mask && (wentry->w_watch->perms && !(wentry->w_watch->perms&mask)))
+	if (mask && (watch->w_perms && !(watch->w_perms & mask)))
 		goto audit_notify_watch_fail;
 
-	ret = auditfs_attach_wdata(inode, wentry, mask);
+	ret = auditfs_attach_wdata(inode, watch, mask);
 	if (!ret)
 		return 0;
 
  audit_notify_watch_fail:
-	audit_wentry_put(wentry);
+	audit_watch_put(watch);
 
 	return ret;
 }
diff -Nurp linux-2.6.9/kernel/auditsc.c linux-2.6.9~working/kernel/auditsc.c
--- linux-2.6.9/kernel/auditsc.c	2005-06-01 14:39:56.721912496 -0500
+++ linux-2.6.9~working/kernel/auditsc.c	2005-06-01 09:33:06.000000000 -0500
@@ -131,7 +131,7 @@ struct audit_aux_data_path {
 
 struct audit_aux_data_watched {
 	struct audit_aux_data	link;
-	struct audit_wentry	*wentry;
+	struct audit_watch	*watch;
 	unsigned long		ino;
 	int			mask;
 	uid_t			uid;
@@ -586,7 +586,7 @@ static inline void audit_free_aux(struct
 			break; }
 		case AUDIT_FS_WATCH: {
 			struct audit_aux_data_watched *axi = (void *)aux;
-			audit_wentry_put(axi->wentry);
+			audit_watch_put(axi->watch);
 			break; }
 		}
 		
@@ -769,13 +769,13 @@ static void audit_log_exit(struct audit_
 		case AUDIT_FS_WATCH: {
 			struct audit_aux_data_watched *axi = (void *)aux;
 			audit_log_format(ab, " watch=");
-			audit_log_untrustedstring(ab, axi->wentry->w_watch->name);
+			audit_log_untrustedstring(ab, axi->watch->w_name);
 			audit_log_format(ab,
 					 " filterkey=%s perm=%u perm_mask=%d"
 					 " inode=%lu inode_uid=%u inode_gid=%u"
 					 " inode_dev=%02x:%02x inode_rdev=%02x:%02x",
-					 axi->wentry->w_watch->filterkey,
-					 axi->wentry->w_watch->perms,
+					 axi->watch->w_filterkey,
+					 axi->watch->w_perms,
 					 axi->mask, axi->ino, axi->uid, axi->gid,
 					 MAJOR(axi->dev), MINOR(axi->dev),
 					 MAJOR(axi->rdev), MINOR(axi->rdev));
@@ -1198,7 +1198,7 @@ void audit_signal_info(int sig, struct t
 #ifdef CONFIG_AUDITFILESYSTEM
 /* This has to be here instead of in auditfs.c, because it needs to
    see the audit context */
-int auditfs_attach_wdata(struct inode *inode, struct audit_wentry *wentry,
+int auditfs_attach_wdata(struct inode *inode, struct audit_watch *watch,
 			 int mask)
 {
 	struct audit_context *context = current->audit_context;
@@ -1211,7 +1211,7 @@ int auditfs_attach_wdata(struct inode *i
 	if (context->in_syscall && !context->auditable)
 		context->auditable = 1;
 
-	ax->wentry = wentry;
+	ax->watch = watch;
 	ax->mask = mask;
 	ax->ino = inode->i_ino;
 	ax->uid = inode->i_uid;
diff -Nurp linux-2.6.9/net/socket.c linux-2.6.9~working/net/socket.c
--- linux-2.6.9/net/socket.c	2005-06-01 14:39:56.606929976 -0500
+++ linux-2.6.9~working/net/socket.c	2005-06-01 09:33:22.000000000 -0500
@@ -1929,7 +1929,7 @@ asmlinkage long sys_socketcall(int call,
 	if (copy_from_user(a, args, nargs[call]))
 		return -EFAULT;
 
-	err = audit_socketcall(nargs[call]/sizeof(unsigned long), args);
+	err = audit_socketcall(nargs[call]/sizeof(unsigned long), a);
 	if (err)
 		return err;
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]