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 | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c index 5e320917c484..de860db3d70b 100644 --- a/hw/9pfs/9p-local.c +++ b/hw/9pfs/9p-local.c @@ -1181,21 +1181,23 @@ out: static int local_link(FsContext *ctx, V9fsPath *oldpath, V9fsPath *dirpath, const char *name) { - int ret; - V9fsString newpath; - char *buffer, *buffer1; - int serrno; - - v9fs_string_init(&newpath); - v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name); + char *odirpath = local_dirname(oldpath->data); + char *oname = local_basename(oldpath->data); + int ret = -1; + int odirfd, ndirfd; - buffer = rpath(ctx, oldpath->data); - buffer1 = rpath(ctx, newpath.data); - ret = link(buffer, buffer1); - g_free(buffer); - if (ret < 0) { + odirfd = local_opendir_nofollow(ctx, odirpath); + if (odirfd == -1) { goto out; } + ndirfd = local_opendir_nofollow(ctx, dirpath->data); + if (ndirfd == -1) { + goto out_close_odirfd; + } + ret = linkat(odirfd, oname, ndirfd, name, AT_SYMLINK_FOLLOW); + if (ret < 0) { + goto out_close_ndirfd; + } /* now link the virtfs_metadata files */ if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { @@ -1204,15 +1206,17 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath, goto err_out; } } - goto out; + goto out_close_ndirfd; err_out: - serrno = errno; - remove(buffer1); - errno = serrno; + unlinkat_preserve_errno(ndirfd, name, 0); +out_close_ndirfd: + close_preserve_errno(ndirfd); +out_close_odirfd: + close_preserve_errno(odirfd); out: - g_free(buffer1); - v9fs_string_free(&newpath); + g_free(oname); + g_free(odirpath); return ret; }