From: Amir Goldstein <amir73il@gmail.com>
To: Miklos Szeredi <miklos@szeredi.hu>
Cc: linux-unionfs@vger.kernel.org
Subject: [PATCH v2] ovl: fix possible use after free on redirect dir lookup
Date: Wed, 18 Jan 2017 10:15:30 +0200 [thread overview]
Message-ID: <1484727330-7260-1-git-send-email-amir73il@gmail.com> (raw)
In-Reply-To: <1484656498-5265-1-git-send-email-amir73il@gmail.com>
ovl_lookup_layer() iterates on path elements of d->name.name
but also frees and allocates a new pointer for d->name.name.
For the case of lookup in upper layer, the initial d->name.name
pointer is stable (dentry->d_name), but for lower layers, the
initial d->name.name can be d->redirect, which can be freed during
iteration.
Make a copy of initial d->name.name before iterating it and reset
the iteration pointer to point inside the newly allocated d->redirect
path after lookup of every element in the path.
Fixes: 02b69b284cd7 ("ovl: lookup redirects")
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
fs/overlayfs/namei.c | 33 +++++++++++++++++++++++----------
1 file changed, 23 insertions(+), 10 deletions(-)
Miklos,
I was pretty close with the test case yesterday, but got it right this morning:
https://github.com/amir73il/unionmount-testsuite/commit/fac638f1d1d0191ca3590f22519a4715a96d5bf2
'./run --ov=20 rename-move-dir' fails on kernel 4.10-rc1:
...
TEST rename-move-dir.py:123: Rename populated dir and parent and move into another
./run --rename /mnt/a/dir106/pop /mnt/a/dir106/popx #no_recycle
./run --rename /mnt/a/dir106 /mnt/a/dir106x #recycle
./run --rename /mnt/a/dir106x/popx /mnt/a/empty106/popx #recycle
...
./run --open-file /mnt/a/empty106/popx -r -d
/mnt/a/empty106/popx/b: File is missing
I actually wrote the right test description yesterday:
("Rename populated dir and parent and move self into another dir")
but implemented instead:
("Rename populated dir and child and move self into another dir")
Both cases get to a point of iterating over freed memory and that
causes iteration to stop (*s != '/') on my debug kernel.
Latter case would have stopped iterating anyway (postlen == 0),
while Former case would have continued iterating, but does not,
so the test case fails to lookup inside the moved directory.
Amir.
v2:
- Remove stable tag
- Add Fixes tag
v1:
- Initial fix
diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c
index 9ad48d9..9cb589c 100644
--- a/fs/overlayfs/namei.c
+++ b/fs/overlayfs/namei.c
@@ -154,6 +154,7 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
static int ovl_lookup_layer(struct dentry *base, struct ovl_lookup_data *d,
struct dentry **ret)
{
+ struct qstr name = d->name;
const char *s = d->name.name;
struct dentry *dentry = NULL;
int err;
@@ -162,24 +163,36 @@ static int ovl_lookup_layer(struct dentry *base, struct ovl_lookup_data *d,
return ovl_lookup_single(base, d, d->name.name, d->name.len,
0, "", ret);
+ /* ovl_lookup_single() -> ovl_check_redirect() may free d->name.name */
+ s = name.name = kstrdup(d->name.name, GFP_KERNEL);
+ if (!s)
+ return -ENOMEM;
+
while (*s++ == '/' && !IS_ERR_OR_NULL(base) && d_can_lookup(base)) {
- const char *next = strchrnul(s, '/');
+ const char *post = strchrnul(s, '/');
size_t slen = strlen(s);
+ size_t postlen = slen - (post - s);
- if (WARN_ON(slen > d->name.len) ||
- WARN_ON(strcmp(d->name.name + d->name.len - slen, s)))
- return -EIO;
-
- err = ovl_lookup_single(base, d, s, next - s,
- d->name.len - slen, next, &base);
+ err = ovl_lookup_single(base, d, s, post - s,
+ d->name.len - slen, post, &base);
dput(dentry);
if (err)
- return err;
+ goto out_err;
dentry = base;
- s = next;
+
+ /* d->name.name may be a new string with modified prefix */
+ s = d->name.name + d->name.len - postlen;
+ err = -EIO;
+ if (WARN_ON(postlen > name.len) ||
+ WARN_ON(strcmp(name.name + name.len - postlen, s)))
+ goto out_err;
}
+
*ret = dentry;
- return 0;
+ err = 0;
+out_err:
+ kfree(name.name);
+ return err;
}
/*
--
2.7.4
next prev parent reply other threads:[~2017-01-18 8:23 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-01-17 12:34 [PATCH] ovl: fix possible use after free on redirect dir lookup Amir Goldstein
2017-01-17 20:06 ` Amir Goldstein
2017-01-18 4:46 ` Amir Goldstein
2017-01-18 8:15 ` Amir Goldstein [this message]
2017-01-18 10:38 ` [PATCH v2] " Miklos Szeredi
2017-01-18 11:40 ` Amir Goldstein
2017-01-18 14:55 ` Miklos Szeredi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1484727330-7260-1-git-send-email-amir73il@gmail.com \
--to=amir73il@gmail.com \
--cc=linux-unionfs@vger.kernel.org \
--cc=miklos@szeredi.hu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox