linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 2/2] vfs: show unreachable paths in getcwd and proc
  2010-05-27 10:29 Miklos Szeredi
@ 2010-05-27 10:30 ` Miklos Szeredi
  0 siblings, 0 replies; 6+ messages in thread
From: Miklos Szeredi @ 2010-05-27 10:30 UTC (permalink / raw)
  To: Al Viro; +Cc: John Johansen, Tetsuo Handa, linux-fsdevel, linux-kernel

From: Miklos Szeredi <mszeredi@suse.cz>

Prepend "(unreachable)" to path strings if the path is not reachable
from the current root.

Two places updated are
 - the return string from getcwd()
 - and symlinks under /proc/$PID.

Other uses of d_path() are left unchanged (we know that some old
software crashes if /proc/mounts is changed).

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
 fs/dcache.c            |   82 +++++++++++++++++++++++++++++++++++++++++--------
 fs/proc/base.c         |    2 -
 include/linux/dcache.h |    1 
 3 files changed, 72 insertions(+), 13 deletions(-)

Index: linux-2.6/fs/dcache.c
===================================================================
--- linux-2.6.orig/fs/dcache.c	2010-05-27 12:22:21.000000000 +0200
+++ linux-2.6/fs/dcache.c	2010-05-27 12:22:24.000000000 +0200
@@ -1957,6 +1957,33 @@ int __d_path(const struct path *path, st
 	return error;
 }
 
+static void current_root(struct path *root)
+{
+	read_lock(&current->fs->lock);
+	*root = current->fs->root;
+	path_get(root);
+	read_unlock(&current->fs->lock);
+}
+
+static int __d_path_with_deleted(const struct path *path, struct path *root,
+				 char **buffer, int *buflen)
+{
+	int error;
+
+	prepend(buffer, buflen, "\0", 1);
+	if (d_unlinked(path->dentry)) {
+		error = prepend(buffer, buflen, " (deleted)", 10);
+		if (error)
+			return error;
+	}
+	return __d_path(path, root, buffer, buflen);
+}
+
+static int prepend_unreachable(char **buffer, int *buflen)
+{
+	return prepend(buffer, buflen, "(unreachable)", 13);
+}
+
 /**
  * d_path - return the path of a dentry
  * @path: path to report
@@ -1990,27 +2017,51 @@ char *d_path(const struct path *path, ch
 	if (path->dentry->d_op && path->dentry->d_op->d_dname)
 		return path->dentry->d_op->d_dname(path->dentry, buf, buflen);
 
-	read_lock(&current->fs->lock);
-	root = current->fs->root;
-	path_get(&root);
-	read_unlock(&current->fs->lock);
+	current_root(&root);
 	spin_lock(&dcache_lock);
 	ptr = buf + buflen;
-	prepend(&ptr, &buflen, "\0", 1);
-	if (d_unlinked(path->dentry)) {
-		error = prepend(&ptr, &buflen, " (deleted)", 10);
-		if (error)
-			goto out;
-	}
 	tmp = root;
-	error = __d_path(path, &tmp, &ptr, &buflen);
-out:
+	error = __d_path_with_deleted(path, &tmp, &ptr, &buflen);
 	spin_unlock(&dcache_lock);
 	path_put(&root);
 	return error ? ERR_PTR(error) : ptr;
 }
 EXPORT_SYMBOL(d_path);
 
+/**
+ * d_path_with_unreachable - return the path of a dentry
+ * @path: path to report
+ * @buf: buffer to return value in
+ * @buflen: buffer length
+ *
+ * The difference from d_path() is that this prepends "(unreachable)"
+ * to paths which are unreachable from the current process' root.
+ */
+char *d_path_with_unreachable(const struct path *path, char *buf, int buflen)
+{
+	char *ptr;
+	struct path root;
+	struct path tmp;
+	int error;
+
+	if (path->dentry->d_op && path->dentry->d_op->d_dname)
+		return path->dentry->d_op->d_dname(path->dentry, buf, buflen);
+
+	current_root(&root);
+	spin_lock(&dcache_lock);
+	ptr = buf + buflen;
+	tmp = root;
+	error = __d_path_with_deleted(path, &tmp, &ptr, &buflen);
+	if (!error) {
+		if (tmp.dentry != root.dentry || tmp.mnt != root.mnt)
+			error = prepend_unreachable(&ptr, &buflen);
+	}
+
+	spin_unlock(&dcache_lock);
+	path_put(&root);
+	return error ? ERR_PTR(error) : ptr;
+}
+
 /*
  * Helper function for dentry_operations.d_dname() members
  */
@@ -2118,6 +2169,13 @@ SYSCALL_DEFINE2(getcwd, char __user *, b
 		if (error)
 			goto out;
 
+		/* Unreachable from current root */
+		if (tmp.dentry != root.dentry || tmp.mnt != root.mnt) {
+			error = prepend_unreachable(&cwd, &buflen);
+			if (error)
+				goto out;
+		}
+
 		error = -ERANGE;
 		len = PAGE_SIZE + page - cwd;
 		if (len <= size) {
Index: linux-2.6/include/linux/dcache.h
===================================================================
--- linux-2.6.orig/include/linux/dcache.h	2010-05-27 12:13:48.000000000 +0200
+++ linux-2.6/include/linux/dcache.h	2010-05-27 12:22:24.000000000 +0200
@@ -315,6 +315,7 @@ extern char *dynamic_dname(struct dentry
 
 extern int __d_path(const struct path *path, struct path *root, char **, int *);
 extern char *d_path(const struct path *, char *, int);
+extern char *d_path_with_unreachable(const struct path *, char *, int);
 extern char *dentry_path(struct dentry *, char *, int);
 
 /* Allocation counts.. */
Index: linux-2.6/fs/proc/base.c
===================================================================
--- linux-2.6.orig/fs/proc/base.c	2010-05-27 11:53:55.000000000 +0200
+++ linux-2.6/fs/proc/base.c	2010-05-27 12:22:24.000000000 +0200
@@ -1438,7 +1438,7 @@ static int do_proc_readlink(struct path
 	if (!tmp)
 		return -ENOMEM;
 
-	pathname = d_path(path, tmp, PAGE_SIZE);
+	pathname = d_path_with_unreachable(path, tmp, PAGE_SIZE);
 	len = PTR_ERR(pathname);
 	if (IS_ERR(pathname))
 		goto out;

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/2] vfs: sanitize __d_path()
@ 2010-06-04 11:52 Miklos Szeredi
  2010-06-04 11:53 ` [PATCH 2/2] vfs: show unreachable paths in getcwd and proc Miklos Szeredi
  2010-06-04 14:10 ` [PATCH 1/2] vfs: sanitize __d_path() Tetsuo Handa
  0 siblings, 2 replies; 6+ messages in thread
From: Miklos Szeredi @ 2010-06-04 11:52 UTC (permalink / raw)
  To: Al Viro, Andrew Morton
  Cc: John Johansen, Tetsuo Handa, linux-fsdevel, linux-kernel

From: Miklos Szeredi <mszeredi@suse.cz>

__d_path() no longer appends " (deleted)" to unlinked paths.  This is
moved into d_path() which is the only caller that cares.

If a global root is reached then __d_path() no longer prepends the
name of the root dentry.  This was needed by pseudo filesystems, but
the d_dname() method has superseded it.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
 fs/dcache.c                |   99 ++++++++++++++++++++-------------------------
 fs/seq_file.c              |   12 +++--
 include/linux/dcache.h     |    2 
 security/tomoyo/realpath.c |   17 ++++---
 4 files changed, 62 insertions(+), 68 deletions(-)

Index: linux-2.6/fs/dcache.c
===================================================================
--- linux-2.6.orig/fs/dcache.c	2010-05-27 12:13:46.000000000 +0200
+++ linux-2.6/fs/dcache.c	2010-05-27 12:22:21.000000000 +0200
@@ -1904,78 +1904,57 @@ static int prepend_name(char **buffer, i
  * __d_path - return the path of a dentry
  * @path: the dentry/vfsmount to report
  * @root: root vfsmnt/dentry (may be modified by this function)
- * @buffer: buffer to return value in
- * @buflen: buffer length
+ * @buffer: end of free buffer, will point to the result on return
+ * @buflen: pointer to buffer length
  *
- * Convert a dentry into an ASCII path name. If the entry has been deleted
- * the string " (deleted)" is appended. Note that this is ambiguous.
+ * Convert a vfsmount+dentry into an ASCII path name.
  *
- * Returns a pointer into the buffer or an error code if the
- * path was too long.
+ * Returns an error code if the path was too long.
  *
  * "buflen" should be positive. Caller holds the dcache_lock.
  *
  * If path is not reachable from the supplied root, then the value of
  * root is changed (without modifying refcounts).
  */
-char *__d_path(const struct path *path, struct path *root,
-	       char *buffer, int buflen)
+int __d_path(const struct path *path, struct path *root,
+	     char **buffer, int *buflen)
 {
 	struct dentry *dentry = path->dentry;
 	struct vfsmount *vfsmnt = path->mnt;
-	char *end = buffer + buflen;
-	char *retval;
+	bool slash = false;
+	int error = 0;
 
 	spin_lock(&vfsmount_lock);
-	prepend(&end, &buflen, "\0", 1);
-	if (d_unlinked(dentry) &&
-		(prepend(&end, &buflen, " (deleted)", 10) != 0))
-			goto Elong;
-
-	if (buflen < 1)
-		goto Elong;
-	/* Get '/' right */
-	retval = end-1;
-	*retval = '/';
-
-	for (;;) {
-		struct dentry * parent;
-
-		if (dentry == root->dentry && vfsmnt == root->mnt)
-			break;
+	while (dentry != root->dentry || vfsmnt != root->mnt) {
 		if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
 			/* Global root? */
 			if (vfsmnt->mnt_parent == vfsmnt) {
-				goto global_root;
+				root->mnt = vfsmnt;
+				root->dentry = dentry;
+				break;
 			}
 			dentry = vfsmnt->mnt_mountpoint;
 			vfsmnt = vfsmnt->mnt_parent;
-			continue;
+		} else {
+			struct dentry *parent = dentry->d_parent;
+
+			prefetch(parent);
+			error = prepend_name(buffer, buflen, &dentry->d_name);
+			if (!error)
+				error = prepend(buffer, buflen, "/", 1);
+			if (error)
+				break;
+
+			slash = true;
+			dentry = parent;
 		}
-		parent = dentry->d_parent;
-		prefetch(parent);
-		if ((prepend_name(&end, &buflen, &dentry->d_name) != 0) ||
-		    (prepend(&end, &buflen, "/", 1) != 0))
-			goto Elong;
-		retval = end;
-		dentry = parent;
 	}
-
-out:
 	spin_unlock(&vfsmount_lock);
-	return retval;
 
-global_root:
-	retval += 1;	/* hit the slash */
-	if (prepend_name(&retval, &buflen, &dentry->d_name) != 0)
-		goto Elong;
-	root->mnt = vfsmnt;
-	root->dentry = dentry;
-	goto out;
+	if (!error && !slash)
+		error = prepend(buffer, buflen, "/", 1);
 
-Elong:
-	retval = ERR_PTR(-ENAMETOOLONG);
-	goto out;
+	return error;
 }
 
 /**
@@ -1996,9 +1975,10 @@ Elong:
  */
 char *d_path(const struct path *path, char *buf, int buflen)
 {
-	char *res;
+	char *ptr;
 	struct path root;
 	struct path tmp;
+	int error;
 
 	/*
 	 * We have various synthetic filesystems that never get mounted.  On
@@ -2015,11 +1995,19 @@ char *d_path(const struct path *path, ch
 	path_get(&root);
 	read_unlock(&current->fs->lock);
 	spin_lock(&dcache_lock);
+	ptr = buf + buflen;
+	prepend(&ptr, &buflen, "\0", 1);
+	if (d_unlinked(path->dentry)) {
+		error = prepend(&ptr, &buflen, " (deleted)", 10);
+		if (error)
+			goto out;
+	}
 	tmp = root;
-	res = __d_path(path, &tmp, buf, buflen);
+	error = __d_path(path, &tmp, &ptr, &buflen);
+out:
 	spin_unlock(&dcache_lock);
 	path_put(&root);
-	return res;
+	return error ? ERR_PTR(error) : ptr;
 }
 EXPORT_SYMBOL(d_path);
 
@@ -2120,13 +2108,14 @@ SYSCALL_DEFINE2(getcwd, char __user *, b
 	if (!d_unlinked(pwd.dentry)) {
 		unsigned long len;
 		struct path tmp = root;
-		char * cwd;
+		int buflen = PAGE_SIZE;
+		char *cwd = page + buflen;
 
-		cwd = __d_path(&pwd, &tmp, page, PAGE_SIZE);
+		prepend(&cwd, &buflen, "\0", 1);
+		error = __d_path(&pwd, &tmp, &cwd, &buflen);
 		spin_unlock(&dcache_lock);
 
-		error = PTR_ERR(cwd);
-		if (IS_ERR(cwd))
+		if (error)
 			goto out;
 
 		error = -ERANGE;
Index: linux-2.6/fs/seq_file.c
===================================================================
--- linux-2.6.orig/fs/seq_file.c	2010-05-27 12:13:46.000000000 +0200
+++ linux-2.6/fs/seq_file.c	2010-05-27 12:13:48.000000000 +0200
@@ -448,7 +448,8 @@ int seq_path(struct seq_file *m, struct
 EXPORT_SYMBOL(seq_path);
 
 /*
- * Same as seq_path, but relative to supplied root.
+ * Same as seq_path, but relative to supplied root and doesn't append
+ * " (deleted)" for unlinked dentries.
  *
  * root may be changed, see __d_path().
  */
@@ -460,13 +461,14 @@ int seq_path_root(struct seq_file *m, st
 	int res = -ENAMETOOLONG;
 
 	if (size) {
-		char *p;
+		int buflen = size - 1;
+		char *p = buf + buflen;
 
+		*p = '\0';
 		spin_lock(&dcache_lock);
-		p = __d_path(path, root, buf, size);
+		res = __d_path(path, root, &p, &buflen);
 		spin_unlock(&dcache_lock);
-		res = PTR_ERR(p);
-		if (!IS_ERR(p)) {
+		if (!res) {
 			char *end = mangle_path(buf, p, esc);
 			if (end)
 				res = end - buf;
Index: linux-2.6/include/linux/dcache.h
===================================================================
--- linux-2.6.orig/include/linux/dcache.h	2010-05-27 12:13:46.000000000 +0200
+++ linux-2.6/include/linux/dcache.h	2010-05-27 12:13:48.000000000 +0200
@@ -313,7 +313,7 @@ extern int d_validate(struct dentry *, s
  */
 extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...);
 
-extern char *__d_path(const struct path *path, struct path *root, char *, int);
+extern int __d_path(const struct path *path, struct path *root, char **, int *);
 extern char *d_path(const struct path *, char *, int);
 extern char *dentry_path(struct dentry *, char *, int);
 
Index: linux-2.6/security/tomoyo/realpath.c
===================================================================
--- linux-2.6.orig/security/tomoyo/realpath.c	2010-05-27 12:13:46.000000000 +0200
+++ linux-2.6/security/tomoyo/realpath.c	2010-05-27 12:13:48.000000000 +0200
@@ -77,7 +77,7 @@ int tomoyo_encode(char *buffer, int bufl
 int tomoyo_realpath_from_path2(struct path *path, char *newname,
 			       int newname_len)
 {
-	int error = -ENOMEM;
+	int error = 0;
 	struct dentry *dentry = path->dentry;
 	char *sp;
 
@@ -88,26 +88,29 @@ int tomoyo_realpath_from_path2(struct pa
 		static const int offset = 1536;
 		sp = dentry->d_op->d_dname(dentry, newname + offset,
 					   newname_len - offset);
+		if (IS_ERR(sp))
+			error = PTR_ERR(sp);
 	} else {
 		struct path ns_root = {.mnt = NULL, .dentry = NULL};
+		int buflen = newname_len - 1;
 
+		sp = newname + buflen;
+		*sp = '\0';
 		spin_lock(&dcache_lock);
 		/* go to whatever namespace root we are under */
-		sp = __d_path(path, &ns_root, newname, newname_len);
+		error = __d_path(path, &ns_root, &sp, &buflen);
 		spin_unlock(&dcache_lock);
 		/* Prepend "/proc" prefix if using internal proc vfs mount. */
-		if (!IS_ERR(sp) && (path->mnt->mnt_flags & MNT_INTERNAL) &&
+		if (!error && (path->mnt->mnt_flags & MNT_INTERNAL) &&
 		    (path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC)) {
 			sp -= 5;
 			if (sp >= newname)
 				memcpy(sp, "/proc", 5);
 			else
-				sp = ERR_PTR(-ENOMEM);
+				error = -ENOMEM;
 		}
 	}
-	if (IS_ERR(sp))
-		error = PTR_ERR(sp);
-	else
+	if (!error)
 		error = tomoyo_encode(newname, sp - newname, sp);
 	/* Append trailing '/' if dentry is a directory. */
 	if (!error && dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 2/2] vfs: show unreachable paths in getcwd and proc
  2010-06-04 11:52 [PATCH 1/2] vfs: sanitize __d_path() Miklos Szeredi
@ 2010-06-04 11:53 ` Miklos Szeredi
  2010-06-15  7:31   ` Miklos Szeredi
  2010-06-15  8:18   ` Nick Piggin
  2010-06-04 14:10 ` [PATCH 1/2] vfs: sanitize __d_path() Tetsuo Handa
  1 sibling, 2 replies; 6+ messages in thread
From: Miklos Szeredi @ 2010-06-04 11:53 UTC (permalink / raw)
  To: Al Viro, Andrew Morton
  Cc: John Johansen, Tetsuo Handa, linux-fsdevel, linux-kernel

From: Miklos Szeredi <mszeredi@suse.cz>

Prepend "(unreachable)" to path strings if the path is not reachable
from the current root.

Two places updated are
 - the return string from getcwd()
 - and symlinks under /proc/$PID.

Other uses of d_path() are left unchanged (we know that some old
software crashes if /proc/mounts is changed).

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
 fs/dcache.c            |   82 +++++++++++++++++++++++++++++++++++++++++--------
 fs/proc/base.c         |    2 -
 include/linux/dcache.h |    1 
 3 files changed, 72 insertions(+), 13 deletions(-)

Index: linux-2.6/fs/dcache.c
===================================================================
--- linux-2.6.orig/fs/dcache.c	2010-05-27 12:22:21.000000000 +0200
+++ linux-2.6/fs/dcache.c	2010-05-27 12:22:24.000000000 +0200
@@ -1957,6 +1957,33 @@ int __d_path(const struct path *path, st
 	return error;
 }
 
+static void current_root(struct path *root)
+{
+	read_lock(&current->fs->lock);
+	*root = current->fs->root;
+	path_get(root);
+	read_unlock(&current->fs->lock);
+}
+
+static int __d_path_with_deleted(const struct path *path, struct path *root,
+				 char **buffer, int *buflen)
+{
+	int error;
+
+	prepend(buffer, buflen, "\0", 1);
+	if (d_unlinked(path->dentry)) {
+		error = prepend(buffer, buflen, " (deleted)", 10);
+		if (error)
+			return error;
+	}
+	return __d_path(path, root, buffer, buflen);
+}
+
+static int prepend_unreachable(char **buffer, int *buflen)
+{
+	return prepend(buffer, buflen, "(unreachable)", 13);
+}
+
 /**
  * d_path - return the path of a dentry
  * @path: path to report
@@ -1990,27 +2017,51 @@ char *d_path(const struct path *path, ch
 	if (path->dentry->d_op && path->dentry->d_op->d_dname)
 		return path->dentry->d_op->d_dname(path->dentry, buf, buflen);
 
-	read_lock(&current->fs->lock);
-	root = current->fs->root;
-	path_get(&root);
-	read_unlock(&current->fs->lock);
+	current_root(&root);
 	spin_lock(&dcache_lock);
 	ptr = buf + buflen;
-	prepend(&ptr, &buflen, "\0", 1);
-	if (d_unlinked(path->dentry)) {
-		error = prepend(&ptr, &buflen, " (deleted)", 10);
-		if (error)
-			goto out;
-	}
 	tmp = root;
-	error = __d_path(path, &tmp, &ptr, &buflen);
-out:
+	error = __d_path_with_deleted(path, &tmp, &ptr, &buflen);
 	spin_unlock(&dcache_lock);
 	path_put(&root);
 	return error ? ERR_PTR(error) : ptr;
 }
 EXPORT_SYMBOL(d_path);
 
+/**
+ * d_path_with_unreachable - return the path of a dentry
+ * @path: path to report
+ * @buf: buffer to return value in
+ * @buflen: buffer length
+ *
+ * The difference from d_path() is that this prepends "(unreachable)"
+ * to paths which are unreachable from the current process' root.
+ */
+char *d_path_with_unreachable(const struct path *path, char *buf, int buflen)
+{
+	char *ptr;
+	struct path root;
+	struct path tmp;
+	int error;
+
+	if (path->dentry->d_op && path->dentry->d_op->d_dname)
+		return path->dentry->d_op->d_dname(path->dentry, buf, buflen);
+
+	current_root(&root);
+	spin_lock(&dcache_lock);
+	ptr = buf + buflen;
+	tmp = root;
+	error = __d_path_with_deleted(path, &tmp, &ptr, &buflen);
+	if (!error) {
+		if (tmp.dentry != root.dentry || tmp.mnt != root.mnt)
+			error = prepend_unreachable(&ptr, &buflen);
+	}
+
+	spin_unlock(&dcache_lock);
+	path_put(&root);
+	return error ? ERR_PTR(error) : ptr;
+}
+
 /*
  * Helper function for dentry_operations.d_dname() members
  */
@@ -2118,6 +2169,13 @@ SYSCALL_DEFINE2(getcwd, char __user *, b
 		if (error)
 			goto out;
 
+		/* Unreachable from current root */
+		if (tmp.dentry != root.dentry || tmp.mnt != root.mnt) {
+			error = prepend_unreachable(&cwd, &buflen);
+			if (error)
+				goto out;
+		}
+
 		error = -ERANGE;
 		len = PAGE_SIZE + page - cwd;
 		if (len <= size) {
Index: linux-2.6/include/linux/dcache.h
===================================================================
--- linux-2.6.orig/include/linux/dcache.h	2010-05-27 12:13:48.000000000 +0200
+++ linux-2.6/include/linux/dcache.h	2010-05-27 12:22:24.000000000 +0200
@@ -315,6 +315,7 @@ extern char *dynamic_dname(struct dentry
 
 extern int __d_path(const struct path *path, struct path *root, char **, int *);
 extern char *d_path(const struct path *, char *, int);
+extern char *d_path_with_unreachable(const struct path *, char *, int);
 extern char *dentry_path(struct dentry *, char *, int);
 
 /* Allocation counts.. */
Index: linux-2.6/fs/proc/base.c
===================================================================
--- linux-2.6.orig/fs/proc/base.c	2010-05-27 11:53:55.000000000 +0200
+++ linux-2.6/fs/proc/base.c	2010-05-27 12:22:24.000000000 +0200
@@ -1438,7 +1438,7 @@ static int do_proc_readlink(struct path
 	if (!tmp)
 		return -ENOMEM;
 
-	pathname = d_path(path, tmp, PAGE_SIZE);
+	pathname = d_path_with_unreachable(path, tmp, PAGE_SIZE);
 	len = PTR_ERR(pathname);
 	if (IS_ERR(pathname))
 		goto out;

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/2] vfs: sanitize __d_path()
  2010-06-04 11:52 [PATCH 1/2] vfs: sanitize __d_path() Miklos Szeredi
  2010-06-04 11:53 ` [PATCH 2/2] vfs: show unreachable paths in getcwd and proc Miklos Szeredi
@ 2010-06-04 14:10 ` Tetsuo Handa
  1 sibling, 0 replies; 6+ messages in thread
From: Tetsuo Handa @ 2010-06-04 14:10 UTC (permalink / raw)
  To: miklos; +Cc: viro, akpm, john.johansen, linux-fsdevel, linux-kernel

Miklos Szeredi wrote:
> -extern char *__d_path(const struct path *path, struct path *root, char *, int);
> +extern int __d_path(const struct path *path, struct path *root, char **, int *);
Does somebody use buflen after returning from __d_path()?
If nobody uses, we can pass it as "int" rather than "int *".

> --- linux-2.6.orig/security/tomoyo/realpath.c	2010-05-27 12:13:46.000000000 +0200
> +++ linux-2.6/security/tomoyo/realpath.c	2010-05-27 12:13:48.000000000 +0200
Sorry. This hunk will not apply because I modified this part
in order to support longer pathnames.
http://git.kernel.org/?p=linux/kernel/git/next/linux-next.git;a=blob;f=security/tomoyo/realpath.c;h=153fa23a05ccd90a9ff3b90c02cefbd9e0cb9126;hb=006dacc8a64e91f6d47c52aec6a9d894e5f93eba
New hunk will look like below.
---
 security/tomoyo/realpath.c |   15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

--- security-testing-2.6.orig/security/tomoyo/realpath.c
+++ security-testing-2.6/security/tomoyo/realpath.c
@@ -94,6 +94,8 @@ char *tomoyo_realpath_from_path(struct p
 		return NULL;
 	is_dir = dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode);
 	while (1) {
+		int error;
+		int len;
 		struct path ns_root = { .mnt = NULL, .dentry = NULL };
 		char *pos;
 		buf_len <<= 1;
@@ -127,21 +129,24 @@ char *tomoyo_realpath_from_path(struct p
 		/* If we don't have a vfsmount, we can't calculate. */
 		if (!path->mnt)
 			break;
+		len = buflen - 1;
+		pos = buf + len;
+		*pos = '\0';
 		spin_lock(&dcache_lock);
 		/* go to whatever namespace root we are under */
-		pos = __d_path(path, &ns_root, buf, buf_len);
+		error = __d_path(path, &ns_root, &pos, &len);
 		spin_unlock(&dcache_lock);
+		if (error)
+			continue;
 		/* Prepend "/proc" prefix if using internal proc vfs mount. */
-		if (!IS_ERR(pos) && (path->mnt->mnt_flags & MNT_INTERNAL) &&
+		if ((path->mnt->mnt_flags & MNT_INTERNAL) &&
 		    (path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC)) {
 			pos -= 5;
 			if (pos >= buf)
 				memcpy(pos, "/proc", 5);
 			else
-				pos = ERR_PTR(-ENOMEM);
+				continue;
 		}
-		if (IS_ERR(pos))
-			continue;
 		name = tomoyo_encode(pos);
 		break;
 	}

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/2] vfs: show unreachable paths in getcwd and proc
  2010-06-04 11:53 ` [PATCH 2/2] vfs: show unreachable paths in getcwd and proc Miklos Szeredi
@ 2010-06-15  7:31   ` Miklos Szeredi
  2010-06-15  8:18   ` Nick Piggin
  1 sibling, 0 replies; 6+ messages in thread
From: Miklos Szeredi @ 2010-06-15  7:31 UTC (permalink / raw)
  To: viro; +Cc: akpm, john.johansen, penguin-kernel, linux-fsdevel, linux-kernel

Hi Al,

Could you please consider these patches for 2.6.36?

Thanks,
Miklos


On Fri, 04 Jun 2010, Miklos Szeredi wrote:
> From: Miklos Szeredi <mszeredi@suse.cz>
> 
> Prepend "(unreachable)" to path strings if the path is not reachable
> from the current root.
> 
> Two places updated are
>  - the return string from getcwd()
>  - and symlinks under /proc/$PID.
> 
> Other uses of d_path() are left unchanged (we know that some old
> software crashes if /proc/mounts is changed).
> 
> Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
> ---
>  fs/dcache.c            |   82 +++++++++++++++++++++++++++++++++++++++++--------
>  fs/proc/base.c         |    2 -
>  include/linux/dcache.h |    1 
>  3 files changed, 72 insertions(+), 13 deletions(-)
> 
> Index: linux-2.6/fs/dcache.c
> ===================================================================
> --- linux-2.6.orig/fs/dcache.c	2010-05-27 12:22:21.000000000 +0200
> +++ linux-2.6/fs/dcache.c	2010-05-27 12:22:24.000000000 +0200
> @@ -1957,6 +1957,33 @@ int __d_path(const struct path *path, st
>  	return error;
>  }
>  
> +static void current_root(struct path *root)
> +{
> +	read_lock(&current->fs->lock);
> +	*root = current->fs->root;
> +	path_get(root);
> +	read_unlock(&current->fs->lock);
> +}
> +
> +static int __d_path_with_deleted(const struct path *path, struct path *root,
> +				 char **buffer, int *buflen)
> +{
> +	int error;
> +
> +	prepend(buffer, buflen, "\0", 1);
> +	if (d_unlinked(path->dentry)) {
> +		error = prepend(buffer, buflen, " (deleted)", 10);
> +		if (error)
> +			return error;
> +	}
> +	return __d_path(path, root, buffer, buflen);
> +}
> +
> +static int prepend_unreachable(char **buffer, int *buflen)
> +{
> +	return prepend(buffer, buflen, "(unreachable)", 13);
> +}
> +
>  /**
>   * d_path - return the path of a dentry
>   * @path: path to report
> @@ -1990,27 +2017,51 @@ char *d_path(const struct path *path, ch
>  	if (path->dentry->d_op && path->dentry->d_op->d_dname)
>  		return path->dentry->d_op->d_dname(path->dentry, buf, buflen);
>  
> -	read_lock(&current->fs->lock);
> -	root = current->fs->root;
> -	path_get(&root);
> -	read_unlock(&current->fs->lock);
> +	current_root(&root);
>  	spin_lock(&dcache_lock);
>  	ptr = buf + buflen;
> -	prepend(&ptr, &buflen, "\0", 1);
> -	if (d_unlinked(path->dentry)) {
> -		error = prepend(&ptr, &buflen, " (deleted)", 10);
> -		if (error)
> -			goto out;
> -	}
>  	tmp = root;
> -	error = __d_path(path, &tmp, &ptr, &buflen);
> -out:
> +	error = __d_path_with_deleted(path, &tmp, &ptr, &buflen);
>  	spin_unlock(&dcache_lock);
>  	path_put(&root);
>  	return error ? ERR_PTR(error) : ptr;
>  }
>  EXPORT_SYMBOL(d_path);
>  
> +/**
> + * d_path_with_unreachable - return the path of a dentry
> + * @path: path to report
> + * @buf: buffer to return value in
> + * @buflen: buffer length
> + *
> + * The difference from d_path() is that this prepends "(unreachable)"
> + * to paths which are unreachable from the current process' root.
> + */
> +char *d_path_with_unreachable(const struct path *path, char *buf, int buflen)
> +{
> +	char *ptr;
> +	struct path root;
> +	struct path tmp;
> +	int error;
> +
> +	if (path->dentry->d_op && path->dentry->d_op->d_dname)
> +		return path->dentry->d_op->d_dname(path->dentry, buf, buflen);
> +
> +	current_root(&root);
> +	spin_lock(&dcache_lock);
> +	ptr = buf + buflen;
> +	tmp = root;
> +	error = __d_path_with_deleted(path, &tmp, &ptr, &buflen);
> +	if (!error) {
> +		if (tmp.dentry != root.dentry || tmp.mnt != root.mnt)
> +			error = prepend_unreachable(&ptr, &buflen);
> +	}
> +
> +	spin_unlock(&dcache_lock);
> +	path_put(&root);
> +	return error ? ERR_PTR(error) : ptr;
> +}
> +
>  /*
>   * Helper function for dentry_operations.d_dname() members
>   */
> @@ -2118,6 +2169,13 @@ SYSCALL_DEFINE2(getcwd, char __user *, b
>  		if (error)
>  			goto out;
>  
> +		/* Unreachable from current root */
> +		if (tmp.dentry != root.dentry || tmp.mnt != root.mnt) {
> +			error = prepend_unreachable(&cwd, &buflen);
> +			if (error)
> +				goto out;
> +		}
> +
>  		error = -ERANGE;
>  		len = PAGE_SIZE + page - cwd;
>  		if (len <= size) {
> Index: linux-2.6/include/linux/dcache.h
> ===================================================================
> --- linux-2.6.orig/include/linux/dcache.h	2010-05-27 12:13:48.000000000 +0200
> +++ linux-2.6/include/linux/dcache.h	2010-05-27 12:22:24.000000000 +0200
> @@ -315,6 +315,7 @@ extern char *dynamic_dname(struct dentry
>  
>  extern int __d_path(const struct path *path, struct path *root, char **, int *);
>  extern char *d_path(const struct path *, char *, int);
> +extern char *d_path_with_unreachable(const struct path *, char *, int);
>  extern char *dentry_path(struct dentry *, char *, int);
>  
>  /* Allocation counts.. */
> Index: linux-2.6/fs/proc/base.c
> ===================================================================
> --- linux-2.6.orig/fs/proc/base.c	2010-05-27 11:53:55.000000000 +0200
> +++ linux-2.6/fs/proc/base.c	2010-05-27 12:22:24.000000000 +0200
> @@ -1438,7 +1438,7 @@ static int do_proc_readlink(struct path
>  	if (!tmp)
>  		return -ENOMEM;
>  
> -	pathname = d_path(path, tmp, PAGE_SIZE);
> +	pathname = d_path_with_unreachable(path, tmp, PAGE_SIZE);
>  	len = PTR_ERR(pathname);
>  	if (IS_ERR(pathname))
>  		goto out;
> 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/2] vfs: show unreachable paths in getcwd and proc
  2010-06-04 11:53 ` [PATCH 2/2] vfs: show unreachable paths in getcwd and proc Miklos Szeredi
  2010-06-15  7:31   ` Miklos Szeredi
@ 2010-06-15  8:18   ` Nick Piggin
  1 sibling, 0 replies; 6+ messages in thread
From: Nick Piggin @ 2010-06-15  8:18 UTC (permalink / raw)
  To: Miklos Szeredi
  Cc: Al Viro, Andrew Morton, John Johansen, Tetsuo Handa,
	linux-fsdevel, linux-kernel

On Fri, Jun 04, 2010 at 01:53:42PM +0200, Miklos Szeredi wrote:
> From: Miklos Szeredi <mszeredi@suse.cz>
> 
> Prepend "(unreachable)" to path strings if the path is not reachable
> from the current root.
> 
> Two places updated are
>  - the return string from getcwd()
>  - and symlinks under /proc/$PID.
> 
> Other uses of d_path() are left unchanged (we know that some old
> software crashes if /proc/mounts is changed).
> 
> Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
> ---
>  fs/dcache.c            |   82 +++++++++++++++++++++++++++++++++++++++++--------
>  fs/proc/base.c         |    2 -
>  include/linux/dcache.h |    1 
>  3 files changed, 72 insertions(+), 13 deletions(-)
> 
> Index: linux-2.6/fs/dcache.c
> ===================================================================
> --- linux-2.6.orig/fs/dcache.c	2010-05-27 12:22:21.000000000 +0200
> +++ linux-2.6/fs/dcache.c	2010-05-27 12:22:24.000000000 +0200
> @@ -1957,6 +1957,33 @@ int __d_path(const struct path *path, st
>  	return error;
>  }
>  
> +static void current_root(struct path *root)
> +{
> +	read_lock(&current->fs->lock);
> +	*root = current->fs->root;
> +	path_get(root);
> +	read_unlock(&current->fs->lock);
> +}

Does this really need a helper? If yes, then please put matching
get_fs_{root,pwd,both} helpers into fs_struct.c and use them throughout
the tree.

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2010-06-15  8:18 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-06-04 11:52 [PATCH 1/2] vfs: sanitize __d_path() Miklos Szeredi
2010-06-04 11:53 ` [PATCH 2/2] vfs: show unreachable paths in getcwd and proc Miklos Szeredi
2010-06-15  7:31   ` Miklos Szeredi
2010-06-15  8:18   ` Nick Piggin
2010-06-04 14:10 ` [PATCH 1/2] vfs: sanitize __d_path() Tetsuo Handa
  -- strict thread matches above, loose matches on Subject: below --
2010-05-27 10:29 Miklos Szeredi
2010-05-27 10:30 ` [PATCH 2/2] vfs: show unreachable paths in getcwd and proc Miklos Szeredi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).