All of lore.kernel.org
 help / color / mirror / Atom feed
* [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 1/2] vfs: sanitize __d_path()
@ 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
  0 siblings, 1 reply; 6+ messages in thread
From: Miklos Szeredi @ 2010-05-27 10:29 UTC (permalink / raw)
  To: Al Viro; +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

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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.