lkml.org 
[lkml]   [2010]   [Jun]   [4]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Subject[PATCH 1/2] vfs: sanitize __d_path()
From
Date
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)

\
 
 \ /
  Last update: 2010-06-04 13:55    [from the cache]
©2003-2011 Jasper Spaans