This fixes CVE-2016-9602 for the "passthrough" and "mapped" security models.
Signed-off-by: Greg Kurz <gr...@kaod.org> --- hw/9pfs/9p-local.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c index 364da435350b..573852a55a00 100644 --- a/hw/9pfs/9p-local.c +++ b/hw/9pfs/9p-local.c @@ -1432,8 +1432,17 @@ err_out: static int local_remove(FsContext *ctx, const char *path) { - int err; - char *buffer; + char *dirpath = local_dirname(path); + char *name = local_basename(path); + struct stat stbuf; + int flags = 0; + int err = -1; + int dirfd; + + dirfd = local_opendir_nofollow(ctx, dirpath); + if (dirfd) { + goto out; + } if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { err = local_pre_remove_mapped_file(ctx, path); @@ -1442,10 +1451,19 @@ static int local_remove(FsContext *ctx, const char *path) } } - buffer = rpath(ctx, path); - err = remove(buffer); - g_free(buffer); + if (fstatat(dirfd, path, &stbuf, AT_SYMLINK_NOFOLLOW) < 0) { + goto err_out; + } + if (S_ISDIR(stbuf.st_mode)) { + flags |= AT_REMOVEDIR; + } + + err = unlinkat(dirfd, name, flags); err_out: + close_preserve_errno(dirfd); +out: + g_free(name); + g_free(dirpath); return err; }