diff options
author | Greg Kurz <groug@kaod.org> | 2016-08-30 17:02:27 +0200 |
---|---|---|
committer | Michael Roth <mdroth@linux.vnet.ibm.com> | 2016-09-08 15:47:04 -0500 |
commit | 85d0a53c583656e5e37a8317f9119933c796847f (patch) | |
tree | c005c89bcf51d36e1d2f8562dff3539aa5144219 | |
parent | b5191b2df7dc92a7a4f7fb4d18c37cf8aae38894 (diff) | |
download | qemu-85d0a53c583656e5e37a8317f9119933c796847f.zip qemu-85d0a53c583656e5e37a8317f9119933c796847f.tar.gz qemu-85d0a53c583656e5e37a8317f9119933c796847f.tar.bz2 |
9pfs: handle walk of ".." in the root directory
The 9P spec at http://man.cat-v.org/plan_9/5/intro says:
All directories must support walks to the directory .. (dot-dot) meaning
parent directory, although by convention directories contain no explicit
entry for .. or . (dot). The parent of the root directory of a server's
tree is itself.
This means that a client cannot walk further than the root directory
exported by the server. In other words, if the client wants to walk
"/.." or "/foo/../..", the server should answer like the request was
to walk "/".
This patch just does that:
- we cache the QID of the root directory at attach time
- during the walk we compare the QID of each path component with the root
QID to detect if we're in a "/.." situation
- if so, we skip the current component and go to the next one
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit 56f101ecce0eafd09e2daf1c4eeb1377d6959261)
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
-rw-r--r-- | hw/9pfs/9p.c | 40 | ||||
-rw-r--r-- | hw/9pfs/9p.h | 1 |
2 files changed, 32 insertions, 9 deletions
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 1e96427..1ac05b2 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -1008,6 +1008,7 @@ static void v9fs_attach(void *opaque) goto out; } err += offset; + memcpy(&s->root_qid, &qid, sizeof(qid)); trace_v9fs_attach_return(pdu->tag, pdu->id, qid.type, qid.version, qid.path); /* @@ -1259,6 +1260,14 @@ static bool name_is_illegal(const char *name) return !*name || strchr(name, '/') != NULL; } +static bool not_same_qid(const V9fsQID *qid1, const V9fsQID *qid2) +{ + return + qid1->type != qid2->type || + qid1->version != qid2->version || + qid1->path != qid2->path; +} + static void v9fs_walk(void *opaque) { int name_idx; @@ -1274,6 +1283,7 @@ static void v9fs_walk(void *opaque) V9fsFidState *newfidp = NULL; V9fsPDU *pdu = opaque; V9fsState *s = pdu->s; + V9fsQID qid; err = pdu_unmarshal(pdu, offset, "ddw", &fid, &newfid, &nwnames); if (err < 0) { @@ -1307,6 +1317,12 @@ static void v9fs_walk(void *opaque) err = -ENOENT; goto out_nofid; } + + err = fid_to_qid(pdu, fidp, &qid); + if (err < 0) { + goto out; + } + v9fs_path_init(&dpath); v9fs_path_init(&path); /* @@ -1316,16 +1332,22 @@ static void v9fs_walk(void *opaque) v9fs_path_copy(&dpath, &fidp->path); v9fs_path_copy(&path, &fidp->path); for (name_idx = 0; name_idx < nwnames; name_idx++) { - err = v9fs_co_name_to_path(pdu, &dpath, wnames[name_idx].data, &path); - if (err < 0) { - goto out; - } - err = v9fs_co_lstat(pdu, &path, &stbuf); - if (err < 0) { - goto out; + if (not_same_qid(&pdu->s->root_qid, &qid) || + strcmp("..", wnames[name_idx].data)) { + err = v9fs_co_name_to_path(pdu, &dpath, wnames[name_idx].data, + &path); + if (err < 0) { + goto out; + } + + err = v9fs_co_lstat(pdu, &path, &stbuf); + if (err < 0) { + goto out; + } + stat_to_qid(&stbuf, &qid); + v9fs_path_copy(&dpath, &path); } - stat_to_qid(&stbuf, &qids[name_idx]); - v9fs_path_copy(&dpath, &path); + memcpy(&qids[name_idx], &qid, sizeof(qid)); } if (fid == newfid) { BUG_ON(fidp->fid_type != P9_FID_NONE); diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h index 1a19418..589b3a5 100644 --- a/hw/9pfs/9p.h +++ b/hw/9pfs/9p.h @@ -219,6 +219,7 @@ typedef struct V9fsState int32_t root_fid; Error *migration_blocker; V9fsConf fsconf; + V9fsQID root_qid; } V9fsState; /* 9p2000.L open flags */ |