lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:	Mon,  8 Sep 2014 16:01:56 +0400
From:	Andrey Vagin <avagin@...nvz.org>
To:	linux-fsdevel@...r.kernel.org
Cc:	linux-kernel@...r.kernel.org, Andrey Vagin <avagin@...nvz.org>,
	Alexander Viro <viro@...iv.linux.org.uk>,
	John McCutchan <john@...nmccutchan.com>,
	Robert Love <rlove@...ve.org>,
	Eric Paris <eparis@...isplace.org>,
	Cyrill Gorcunov <gorcunov@...nvz.org>,
	Pavel Emelyanov <xemul@...allels.com>
Subject: [PATCH] fs: don't remove inotify watchers from alive inode-s

Currently watchers are removed in dentry_iput(), if n_link is zero.
But other detries can be linked with this inode. For example if we
create two hard links, open the first one and set a watcher on the
second one. Then if we remove both links, the watcher will be removed.
But we will have the alive file descriptor, which allows us to generate
more events.

With this patch, watchers will be removed, only if nlink is zero and
i_dentry list is empty.

Look at a following example:

	fd = inotify_init1(IN_NONBLOCK);
	deleted = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0666);
	link(path, path_link);

	wd_deleted = inotify_add_watch(fd, path_link, IN_ALL_EVENTS);

	unlink(path);
	unlink(path_link);

	printf(" --- unlink\n");
	read_evetns(fd);

	close(deleted);
	printf(" --- close\n");
	read_evetns(fd);

Without this patch:
 --- unlink
4	(IN_ATTRIB)
400	(IN_DELETE_SELF)
8000	(IN_IGNORED)
 --- close
FAIL

With this patch:
 --- unlink
4	(IN_ATTRIB)
400	(IN_DELETE_SELF)
 --- close
8	(IN_CLOSE_WRITE)
400	(IN_DELETE_SELF)
8000	(IN_IGNORED)
PASS

Cc: Alexander Viro <viro@...iv.linux.org.uk>
Cc: John McCutchan <john@...nmccutchan.com>
Cc: Robert Love <rlove@...ve.org>
Cc: Eric Paris <eparis@...isplace.org>
Cc: Cyrill Gorcunov <gorcunov@...nvz.org>
Cc: Pavel Emelyanov <xemul@...allels.com>
Signed-off-by: Andrey Vagin <avagin@...nvz.org>
---
 fs/dcache.c              | 10 ++++++++--
 include/linux/fsnotify.h |  5 +++--
 2 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/fs/dcache.c b/fs/dcache.c
index d30ce69..fb1ee58 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -279,13 +279,16 @@ static void dentry_iput(struct dentry * dentry)
 	__releases(dentry->d_inode->i_lock)
 {
 	struct inode *inode = dentry->d_inode;
+	bool last_dentry;
+
 	if (inode) {
 		dentry->d_inode = NULL;
 		hlist_del_init(&dentry->d_alias);
+		last_dentry = hlist_empty(&inode->i_dentry);
 		spin_unlock(&dentry->d_lock);
 		spin_unlock(&inode->i_lock);
 		if (!inode->i_nlink)
-			fsnotify_inoderemove(inode);
+			fsnotify_inoderemove(inode, last_dentry);
 		if (dentry->d_op && dentry->d_op->d_iput)
 			dentry->d_op->d_iput(dentry, inode);
 		else
@@ -304,14 +307,17 @@ static void dentry_unlink_inode(struct dentry * dentry)
 	__releases(dentry->d_inode->i_lock)
 {
 	struct inode *inode = dentry->d_inode;
+	bool last_dentry;
+
 	__d_clear_type(dentry);
 	dentry->d_inode = NULL;
 	hlist_del_init(&dentry->d_alias);
 	dentry_rcuwalk_barrier(dentry);
+	last_dentry = hlist_empty(&inode->i_dentry);
 	spin_unlock(&dentry->d_lock);
 	spin_unlock(&inode->i_lock);
 	if (!inode->i_nlink)
-		fsnotify_inoderemove(inode);
+		fsnotify_inoderemove(inode, last_dentry);
 	if (dentry->d_op && dentry->d_op->d_iput)
 		dentry->d_op->d_iput(dentry, inode);
 	else
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h
index 1c804b0..63dae9d 100644
--- a/include/linux/fsnotify.h
+++ b/include/linux/fsnotify.h
@@ -144,10 +144,11 @@ static inline void fsnotify_nameremove(struct dentry *dentry, int isdir)
 /*
  * fsnotify_inoderemove - an inode is going away
  */
-static inline void fsnotify_inoderemove(struct inode *inode)
+static inline void fsnotify_inoderemove(struct inode *inode, bool delete)
 {
 	fsnotify(inode, FS_DELETE_SELF, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
-	__fsnotify_inode_delete(inode);
+	if (delete)
+		__fsnotify_inode_delete(inode);
 }
 
 /*
-- 
1.9.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ