Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/gkurz/tags/for-upstream' into s…
Browse files Browse the repository at this point in the history
…taging

- fixes a minor bug that could possibly prevent old guests to remove
  directories
- makes default permissions for new files configurable from the cmdline
  when using mapped security modes
- handle transport errors
- g_malloc()+memcpy() converted to g_memdup()

# gpg: Signature made Thu 29 Jun 2017 14:12:42 BST
# gpg:                using DSA key 0x02FC3AEB0101DBC2
# gpg: Good signature from "Greg Kurz <groug@kaod.org>"
# gpg:                 aka "Greg Kurz <groug@free.fr>"
# gpg:                 aka "Greg Kurz <gkurz@linux.vnet.ibm.com>"
# gpg:                 aka "Gregory Kurz (Groug) <groug@free.fr>"
# gpg:                 aka "[jpeg image of size 3330]"
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 2BD4 3B44 535E C0A7 9894  DBA2 02FC 3AEB 0101 DBC2

* remotes/gkurz/tags/for-upstream:
  9pfs: handle transport errors in pdu_complete()
  xen-9pfs: disconnect if buffers are misconfigured
  virtio-9p: break device if buffers are misconfigured
  virtio-9p: message header is 7-byte long
  virtio-9p: record element after sanity checks
  9pfs: replace g_malloc()+memcpy() with g_memdup()
  9pfs: local: Add support for custom fmode/dmode in 9ps mapped security modes
  9pfs: local: remove: use correct path component

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
  • Loading branch information
pm215 committed Jun 29, 2017
2 parents e720624 + 06a37db commit 454d7dc
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 53 deletions.
4 changes: 4 additions & 0 deletions fsdev/file-op-9p.h
Expand Up @@ -76,6 +76,8 @@ typedef struct FsDriverEntry {
int export_flags;
FileOperations *ops;
FsThrottle fst;
mode_t fmode;
mode_t dmode;
} FsDriverEntry;

typedef struct FsContext
Expand All @@ -88,6 +90,8 @@ typedef struct FsContext
FsThrottle *fst;
/* fs driver specific data */
void *private;
mode_t fmode;
mode_t dmode;
} FsContext;

typedef struct V9fsPath {
Expand Down
12 changes: 12 additions & 0 deletions fsdev/qemu-fsdev-opts.c
Expand Up @@ -38,6 +38,12 @@ static QemuOptsList qemu_fsdev_opts = {
}, {
.name = "sock_fd",
.type = QEMU_OPT_NUMBER,
}, {
.name = "fmode",
.type = QEMU_OPT_NUMBER,
}, {
.name = "dmode",
.type = QEMU_OPT_NUMBER,
},

THROTTLE_OPTS,
Expand Down Expand Up @@ -75,6 +81,12 @@ static QemuOptsList qemu_virtfs_opts = {
}, {
.name = "sock_fd",
.type = QEMU_OPT_NUMBER,
}, {
.name = "fmode",
.type = QEMU_OPT_NUMBER,
}, {
.name = "dmode",
.type = QEMU_OPT_NUMBER,
},

{ /*End of list */ }
Expand Down
27 changes: 22 additions & 5 deletions hw/9pfs/9p-local.c
Expand Up @@ -633,7 +633,7 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,

if (fs_ctx->export_flags & V9FS_SM_MAPPED ||
fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
err = mknodat(dirfd, name, SM_LOCAL_MODE_BITS | S_IFREG, 0);
err = mknodat(dirfd, name, fs_ctx->fmode | S_IFREG, 0);
if (err == -1) {
goto out;
}
Expand Down Expand Up @@ -685,7 +685,7 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,

if (fs_ctx->export_flags & V9FS_SM_MAPPED ||
fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
err = mkdirat(dirfd, name, SM_LOCAL_DIR_MODE_BITS);
err = mkdirat(dirfd, name, fs_ctx->dmode);
if (err == -1) {
goto out;
}
Expand Down Expand Up @@ -786,7 +786,7 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
/* Determine the security model */
if (fs_ctx->export_flags & V9FS_SM_MAPPED ||
fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
fd = openat_file(dirfd, name, flags, SM_LOCAL_MODE_BITS);
fd = openat_file(dirfd, name, flags, fs_ctx->fmode);
if (fd == -1) {
goto out;
}
Expand Down Expand Up @@ -849,7 +849,7 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
ssize_t oldpath_size, write_size;

fd = openat_file(dirfd, name, O_CREAT | O_EXCL | O_RDWR,
SM_LOCAL_MODE_BITS);
fs_ctx->fmode);
if (fd == -1) {
goto out;
}
Expand Down Expand Up @@ -1100,7 +1100,7 @@ static int local_remove(FsContext *ctx, const char *path)
goto out;
}

if (fstatat(dirfd, path, &stbuf, AT_SYMLINK_NOFOLLOW) < 0) {
if (fstatat(dirfd, name, &stbuf, AT_SYMLINK_NOFOLLOW) < 0) {
goto err_out;
}

Expand Down Expand Up @@ -1467,6 +1467,23 @@ static int local_parse_opts(QemuOpts *opts, struct FsDriverEntry *fse)
return -1;
}

if (fse->export_flags & V9FS_SM_MAPPED ||
fse->export_flags & V9FS_SM_MAPPED_FILE) {
fse->fmode =
qemu_opt_get_number(opts, "fmode", SM_LOCAL_MODE_BITS) & 0777;
fse->dmode =
qemu_opt_get_number(opts, "dmode", SM_LOCAL_DIR_MODE_BITS) & 0777;
} else {
if (qemu_opt_find(opts, "fmode")) {
error_report("fmode is only valid for mapped 9p modes");
return -1;
}
if (qemu_opt_find(opts, "dmode")) {
error_report("dmode is only valid for mapped 9p modes");
return -1;
}
}

fse->path = g_strdup(path);

return 0;
Expand Down
3 changes: 1 addition & 2 deletions hw/9pfs/9p-synth.c
Expand Up @@ -494,8 +494,7 @@ static int synth_name_to_path(FsContext *ctx, V9fsPath *dir_path,
}
out:
/* Copy the node pointer to fid */
target->data = g_malloc(sizeof(void *));
memcpy(target->data, &node, sizeof(void *));
target->data = g_memdup(&node, sizeof(void *));
target->size = sizeof(void *);
return 0;
}
Expand Down
28 changes: 19 additions & 9 deletions hw/9pfs/9p.c
Expand Up @@ -624,15 +624,11 @@ void pdu_free(V9fsPDU *pdu)
QLIST_INSERT_HEAD(&s->free_list, pdu, next);
}

/*
* We don't do error checking for pdu_marshal/unmarshal here
* because we always expect to have enough space to encode
* error details
*/
static void coroutine_fn pdu_complete(V9fsPDU *pdu, ssize_t len)
{
int8_t id = pdu->id + 1; /* Response */
V9fsState *s = pdu->s;
int ret;

if (len < 0) {
int err = -len;
Expand All @@ -644,11 +640,19 @@ static void coroutine_fn pdu_complete(V9fsPDU *pdu, ssize_t len)
str.data = strerror(err);
str.size = strlen(str.data);

len += pdu_marshal(pdu, len, "s", &str);
ret = pdu_marshal(pdu, len, "s", &str);
if (ret < 0) {
goto out_notify;
}
len += ret;
id = P9_RERROR;
}

len += pdu_marshal(pdu, len, "d", err);
ret = pdu_marshal(pdu, len, "d", err);
if (ret < 0) {
goto out_notify;
}
len += ret;

if (s->proto_version == V9FS_PROTO_2000L) {
id = P9_RLERROR;
Expand All @@ -657,12 +661,15 @@ static void coroutine_fn pdu_complete(V9fsPDU *pdu, ssize_t len)
}

/* fill out the header */
pdu_marshal(pdu, 0, "dbw", (int32_t)len, id, pdu->tag);
if (pdu_marshal(pdu, 0, "dbw", (int32_t)len, id, pdu->tag) < 0) {
goto out_notify;
}

/* keep these in sync */
pdu->size = len;
pdu->id = id;

out_notify:
pdu->s->transport->push_and_notify(pdu);

/* Now wakeup anybody waiting in flush for this request */
Expand Down Expand Up @@ -1664,7 +1671,7 @@ static void v9fs_init_qiov_from_pdu(QEMUIOVector *qiov, V9fsPDU *pdu,
unsigned int niov;

if (is_write) {
pdu->s->transport->init_out_iov_from_pdu(pdu, &iov, &niov);
pdu->s->transport->init_out_iov_from_pdu(pdu, &iov, &niov, size + skip);
} else {
pdu->s->transport->init_in_iov_from_pdu(pdu, &iov, &niov, size + skip);
}
Expand Down Expand Up @@ -3533,6 +3540,9 @@ int v9fs_device_realize_common(V9fsState *s, Error **errp)

s->ops = fse->ops;

s->ctx.fmode = fse->fmode;
s->ctx.dmode = fse->dmode;

s->fid_list = NULL;
qemu_co_rwlock_init(&s->rename_lock);

Expand Down
7 changes: 6 additions & 1 deletion hw/9pfs/9p.h
Expand Up @@ -124,6 +124,11 @@ typedef struct {
uint8_t id;
uint16_t tag_le;
} QEMU_PACKED P9MsgHeader;
/* According to the specification, 9p messages start with a 7-byte header.
* Since most of the code uses this header size in literal form, we must be
* sure this is indeed the case.
*/
QEMU_BUILD_BUG_ON(sizeof(P9MsgHeader) != 7);

struct V9fsPDU
{
Expand Down Expand Up @@ -358,7 +363,7 @@ struct V9fsTransport {
void (*init_in_iov_from_pdu)(V9fsPDU *pdu, struct iovec **piov,
unsigned int *pniov, size_t size);
void (*init_out_iov_from_pdu)(V9fsPDU *pdu, struct iovec **piov,
unsigned int *pniov);
unsigned int *pniov, size_t size);
void (*push_and_notify)(V9fsPDU *pdu);
};

Expand Down
51 changes: 41 additions & 10 deletions hw/9pfs/virtio-9p-device.c
Expand Up @@ -53,23 +53,22 @@ static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
goto out_free_pdu;
}

if (elem->in_num == 0) {
if (iov_size(elem->in_sg, elem->in_num) < 7) {
virtio_error(vdev,
"The guest sent a VirtFS request without space for "
"the reply");
goto out_free_req;
}
QEMU_BUILD_BUG_ON(sizeof(out) != 7);

v->elems[pdu->idx] = elem;
len = iov_to_buf(elem->out_sg, elem->out_num, 0,
&out, sizeof(out));
if (len != sizeof(out)) {
len = iov_to_buf(elem->out_sg, elem->out_num, 0, &out, 7);
if (len != 7) {
virtio_error(vdev, "The guest sent a malformed VirtFS request: "
"header size is %zd, should be 7", len);
goto out_free_req;
}

v->elems[pdu->idx] = elem;

pdu_submit(pdu, &out);
}

Expand Down Expand Up @@ -147,8 +146,16 @@ static ssize_t virtio_pdu_vmarshal(V9fsPDU *pdu, size_t offset,
V9fsState *s = pdu->s;
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
VirtQueueElement *elem = v->elems[pdu->idx];
ssize_t ret;

ret = v9fs_iov_vmarshal(elem->in_sg, elem->in_num, offset, 1, fmt, ap);
if (ret < 0) {
VirtIODevice *vdev = VIRTIO_DEVICE(v);

return v9fs_iov_vmarshal(elem->in_sg, elem->in_num, offset, 1, fmt, ap);
virtio_error(vdev, "Failed to encode VirtFS reply type %d",
pdu->id + 1);
}
return ret;
}

static ssize_t virtio_pdu_vunmarshal(V9fsPDU *pdu, size_t offset,
Expand All @@ -157,28 +164,52 @@ static ssize_t virtio_pdu_vunmarshal(V9fsPDU *pdu, size_t offset,
V9fsState *s = pdu->s;
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
VirtQueueElement *elem = v->elems[pdu->idx];
ssize_t ret;

ret = v9fs_iov_vunmarshal(elem->out_sg, elem->out_num, offset, 1, fmt, ap);
if (ret < 0) {
VirtIODevice *vdev = VIRTIO_DEVICE(v);

return v9fs_iov_vunmarshal(elem->out_sg, elem->out_num, offset, 1, fmt, ap);
virtio_error(vdev, "Failed to decode VirtFS request type %d", pdu->id);
}
return ret;
}

/* The size parameter is used by other transports. Do not drop it. */
static void virtio_init_in_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov,
unsigned int *pniov, size_t size)
{
V9fsState *s = pdu->s;
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
VirtQueueElement *elem = v->elems[pdu->idx];
size_t buf_size = iov_size(elem->in_sg, elem->in_num);

if (buf_size < size) {
VirtIODevice *vdev = VIRTIO_DEVICE(v);

virtio_error(vdev,
"VirtFS reply type %d needs %zu bytes, buffer has %zu",
pdu->id + 1, size, buf_size);
}

*piov = elem->in_sg;
*pniov = elem->in_num;
}

static void virtio_init_out_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov,
unsigned int *pniov)
unsigned int *pniov, size_t size)
{
V9fsState *s = pdu->s;
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
VirtQueueElement *elem = v->elems[pdu->idx];
size_t buf_size = iov_size(elem->out_sg, elem->out_num);

if (buf_size < size) {
VirtIODevice *vdev = VIRTIO_DEVICE(v);

virtio_error(vdev,
"VirtFS request type %d needs %zu bytes, buffer has %zu",
pdu->id, size, buf_size);
}

*piov = elem->out_sg;
*pniov = elem->out_num;
Expand Down

0 comments on commit 454d7dc

Please sign in to comment.