diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c index 45e9a1f9b0..494ee00c66 100644 --- a/hw/9pfs/9p-local.c +++ b/hw/9pfs/9p-local.c @@ -84,6 +84,23 @@ static void unlinkat_preserve_errno(int dirfd, const char *path, int flags) #define VIRTFS_META_DIR ".virtfs_metadata" +static int is_in_store_path(const char *path) +{ + static char *store_path = NULL; + int store_path_len = -1; + + if (store_path_len == -1) { + if ((store_path = getenv("NIX_STORE")) != NULL) + store_path_len = strlen(store_path); + else + store_path_len = 0; + } + + if (store_path_len > 0) + return strncmp(path, store_path, strlen(store_path)) == 0; + return 0; +} + static FILE *local_fopenat(int dirfd, const char *name, const char *mode) { int fd, o_mode = 0; @@ -161,6 +178,8 @@ static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf) if (err) { goto err_out; } + stbuf->st_uid = 0; + stbuf->st_gid = 0; if (fs_ctx->export_flags & V9FS_SM_MAPPED) { /* Actual credentials are part of extended attrs */ uid_t tmp_uid; @@ -280,6 +299,9 @@ static int fchmodat_nofollow(int dirfd, const char *name, mode_t mode) { int fd, ret; + if (is_in_store_path(name)) + return 0; + /* FIXME: this should be handled with fchmodat(AT_SYMLINK_NOFOLLOW). * Unfortunately, the linux kernel doesn't implement it yet. As an * alternative, let's open the file and use fchmod() instead. This @@ -661,6 +683,8 @@ static int local_fstat(FsContext *fs_ctx, int fid_type, if (err) { return err; } + stbuf->st_uid = 0; + stbuf->st_gid = 0; if (fs_ctx->export_flags & V9FS_SM_MAPPED) { /* Actual credentials are part of extended attrs */ uid_t tmp_uid; @@ -795,8 +819,11 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath, if (err) { goto out; } - err = fchownat(dirfd, name, credp->fc_uid, credp->fc_gid, - AT_SYMLINK_NOFOLLOW); + if (is_in_store_path(name)) + err = 0; + else + err = fchownat(dirfd, name, credp->fc_uid, credp->fc_gid, + AT_SYMLINK_NOFOLLOW); if (err == -1) { /* * If we fail to change ownership and if we are @@ -911,7 +938,9 @@ static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) goto out; } - if ((credp->fc_uid == -1 && credp->fc_gid == -1) || + if (is_in_store_path(name)) { + ret = 0; + } else if ((credp->fc_uid == -1 && credp->fc_gid == -1) || (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || (fs_ctx->export_flags & V9FS_SM_NONE)) { ret = fchownat(dirfd, name, credp->fc_uid, credp->fc_gid,