A number of routines wasn't checking that the initial call
to prepend "\0" to result buffer doesn't fail.

Coredump code was seeing d_path() with zero-sized buffer
to erroneously return bogus data (non-error pointer
pointing before buffer start).

Users report that this change fixes it.

Cc: Jan Kratochvil <[email protected]>
Cc: Oleg Nesterov <[email protected]>
Cc: [email protected]
Signed-off-by: Denys Vlasenko <[email protected]>
---
 fs/dcache.c | 21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)

diff --git a/fs/dcache.c b/fs/dcache.c
index 24a01fc..93f651b 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -2974,7 +2974,9 @@ char *__d_path(const struct path *path,
        char *res = buf + buflen;
        int error;
 
-       prepend(&res, &buflen, "\0", 1);
+       error = prepend(&res, &buflen, "\0", 1);
+       if (error)
+               return ERR_PTR(error);
        error = prepend_path(path, root, &res, &buflen);
 
        if (error < 0)
@@ -2991,7 +2993,9 @@ char *d_absolute_path(const struct path *path,
        char *res = buf + buflen;
        int error;
 
-       prepend(&res, &buflen, "\0", 1);
+       error = prepend(&res, &buflen, "\0", 1);
+       if (error)
+               return ERR_PTR(error);
        error = prepend_path(path, &root, &res, &buflen);
 
        if (error > 1)
@@ -3008,7 +3012,11 @@ static int path_with_deleted(const struct path *path,
                             const struct path *root,
                             char **buf, int *buflen)
 {
-       prepend(buf, buflen, "\0", 1);
+       int error;
+
+       error = prepend(buf, buflen, "\0", 1);
+       if (error)
+               return error;
        if (d_unlinked(path->dentry)) {
                int error = prepend(buf, buflen, " (deleted)", 10);
                if (error)
@@ -3126,12 +3134,12 @@ static char *__dentry_path(struct dentry *dentry, char 
*buf, int buflen)
 restart:
        end = buf + buflen;
        len = buflen;
-       prepend(&end, &len, "\0", 1);
        if (buflen < 1) {
                if (!(seq & 1))
                        rcu_read_unlock();
                goto Elong;
        }
+       prepend(&end, &len, "\0", 1);
        /* Get '/' right */
        retval = end-1;
        *retval = '/';
@@ -3235,8 +3243,9 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned 
long, size)
                char *cwd = page + PATH_MAX;
                int buflen = PATH_MAX;
 
-               prepend(&cwd, &buflen, "\0", 1);
-               error = prepend_path(&pwd, &root, &cwd, &buflen);
+               error = prepend(&cwd, &buflen, "\0", 1);
+               if (!error)
+                       error = prepend_path(&pwd, &root, &cwd, &buflen);
                rcu_read_unlock();
 
                if (error < 0)
-- 
1.8.1.4

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

Reply via email to