X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/666095c852d32df65b5982fcc8c85332979b7fc1..adb354dd1e00aa6b8bd674f0e1f70008badded0f:/hw/9pfs/9p-local.c diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c index f22a3c3654..a2486566af 100644 --- a/hw/9pfs/9p-local.c +++ b/hw/9pfs/9p-local.c @@ -349,7 +349,7 @@ static int local_set_cred_passthrough(FsContext *fs_ctx, int dirfd, const char *name, FsCred *credp) { if (fchownat(dirfd, name, credp->fc_uid, credp->fc_gid, - AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH) < 0) { + AT_SYMLINK_NOFOLLOW) < 0) { /* * If we fail to change ownership and if we are * using security model none. Ignore the error @@ -435,6 +435,7 @@ static int local_opendir(FsContext *ctx, stream = fdopendir(dirfd); if (!stream) { + close(dirfd); return -1; } fs->dir.stream = stream; @@ -451,6 +452,11 @@ static off_t local_telldir(FsContext *ctx, V9fsFidOpenState *fs) return telldir(fs->dir.stream); } +static bool local_is_mapped_file_metadata(FsContext *fs_ctx, const char *name) +{ + return !strcmp(name, VIRTFS_META_DIR); +} + static struct dirent *local_readdir(FsContext *ctx, V9fsFidOpenState *fs) { struct dirent *entry; @@ -464,8 +470,8 @@ again: if (ctx->export_flags & V9FS_SM_MAPPED) { entry->d_type = DT_UNKNOWN; } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { - if (!strcmp(entry->d_name, VIRTFS_META_DIR)) { - /* skp the meta data directory */ + if (local_is_mapped_file_metadata(ctx, entry->d_name)) { + /* skip the meta data directory */ goto again; } entry->d_type = DT_UNKNOWN; @@ -558,6 +564,12 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path, int err = -1; int dirfd; + if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE && + local_is_mapped_file_metadata(fs_ctx, name)) { + errno = EINVAL; + return -1; + } + dirfd = local_opendir_nofollow(fs_ctx, dir_path->data); if (dirfd == -1) { return -1; @@ -604,6 +616,12 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, int err = -1; int dirfd; + if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE && + local_is_mapped_file_metadata(fs_ctx, name)) { + errno = EINVAL; + return -1; + } + dirfd = local_opendir_nofollow(fs_ctx, dir_path->data); if (dirfd == -1) { return -1; @@ -693,6 +711,12 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, int err = -1; int dirfd; + if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE && + local_is_mapped_file_metadata(fs_ctx, name)) { + errno = EINVAL; + return -1; + } + /* * Mark all the open to not follow symlinks */ @@ -751,6 +775,12 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath, int err = -1; int dirfd; + if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE && + local_is_mapped_file_metadata(fs_ctx, name)) { + errno = EINVAL; + return -1; + } + dirfd = local_opendir_nofollow(fs_ctx, dir_path->data); if (dirfd == -1) { return -1; @@ -825,6 +855,12 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath, int ret = -1; int odirfd, ndirfd; + if (ctx->export_flags & V9FS_SM_MAPPED_FILE && + local_is_mapped_file_metadata(ctx, name)) { + errno = EINVAL; + return -1; + } + odirfd = local_opendir_nofollow(ctx, odirpath); if (odirfd == -1) { goto out; @@ -959,7 +995,7 @@ static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name, if (flags == AT_REMOVEDIR) { int fd; - fd = openat(dirfd, name, O_RDONLY | O_DIRECTORY | O_PATH); + fd = openat_dir(dirfd, name); if (fd == -1) { goto err_out; } @@ -1008,7 +1044,7 @@ static int local_remove(FsContext *ctx, const char *path) int err = -1; dirfd = local_opendir_nofollow(ctx, dirpath); - if (dirfd) { + if (dirfd == -1) { goto out; } @@ -1052,6 +1088,9 @@ static int local_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf) int fd, ret; fd = local_open_nofollow(s, fs_path->data, O_RDONLY, 0); + if (fd == -1) { + return -1; + } ret = fstatfs(fd, stbuf); close_preserve_errno(fd); return ret; @@ -1092,10 +1131,21 @@ static int local_lremovexattr(FsContext *ctx, V9fsPath *fs_path, static int local_name_to_path(FsContext *ctx, V9fsPath *dir_path, const char *name, V9fsPath *target) { + if (ctx->export_flags & V9FS_SM_MAPPED_FILE && + local_is_mapped_file_metadata(ctx, name)) { + errno = EINVAL; + return -1; + } + if (dir_path) { v9fs_path_sprintf(target, "%s/%s", dir_path->data, name); - } else { + } else if (strcmp(name, "/")) { v9fs_path_sprintf(target, "%s", name); + } else { + /* We want the path of the export root to be relative, otherwise + * "*at()" syscalls would treat it as "/" in the host. + */ + v9fs_path_sprintf(target, "%s", "."); } return 0; } @@ -1107,6 +1157,13 @@ static int local_renameat(FsContext *ctx, V9fsPath *olddir, int ret; int odirfd, ndirfd; + if (ctx->export_flags & V9FS_SM_MAPPED_FILE && + (local_is_mapped_file_metadata(ctx, old_name) || + local_is_mapped_file_metadata(ctx, new_name))) { + errno = EINVAL; + return -1; + } + odirfd = local_opendir_nofollow(ctx, olddir->data); if (odirfd == -1) { return -1; @@ -1197,6 +1254,12 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir, int ret; int dirfd; + if (ctx->export_flags & V9FS_SM_MAPPED_FILE && + local_is_mapped_file_metadata(ctx, name)) { + errno = EINVAL; + return -1; + } + dirfd = local_opendir_nofollow(ctx, dir->data); if (dirfd == -1) { return -1;