Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion mk/tests.mk
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
test-matrix test-matrix-elfuse-aarch64 test-matrix-qemu-aarch64 \
test-full test-multi-vcpu test-rwx test-sysroot-rename \
test-sysroot-procfs-exec test-timeout-disable \
test-sysroot-nofollow perf
test-sysroot-nofollow test-sysroot-chdir perf

## Build and run the assembly hello world test
test-hello: $(ELFUSE_BIN) $(TEST_HELLO_DEP)
Expand Down Expand Up @@ -47,6 +47,12 @@ test-sysroot-nofollow: $(ELFUSE_BIN) $(BUILD_DIR)/test-sysroot-nofollow
ln -sf /outside-target "$$tmpdir/tmp/elfuse-sysroot-nofollow-link"; \
$(ELFUSE_BIN) --sysroot "$$tmpdir" $(BUILD_DIR)/test-sysroot-nofollow

test-sysroot-chdir: $(ELFUSE_BIN) $(BUILD_DIR)/test-sysroot-chdir
@tmpdir=$$(mktemp -d); \
trap 'rm -rf "$$tmpdir"' EXIT; \
mkdir -p "$$tmpdir/bin" "$$tmpdir/lib" "$$tmpdir/lib/elfuse-sysroot-shadow"; \
$(ELFUSE_BIN) --sysroot "$$tmpdir" $(BUILD_DIR)/test-sysroot-chdir

test-sysroot-procfs-exec: $(ELFUSE_BIN) $(BUILD_DIR)/test-procfs-exec
@tmpdir=$$(mktemp -d); \
trap 'rm -rf "$$tmpdir"' EXIT; \
Expand Down
4 changes: 1 addition & 3 deletions src/runtime/fork-state.c
Original file line number Diff line number Diff line change
Expand Up @@ -440,9 +440,7 @@ int fork_ipc_send_process_state(int ipc_sock,
return -1;

char sysroot_ipc[LINUX_PATH_MAX] = {0};
const char *sr = proc_get_sysroot();
if (sr)
str_copy_trunc(sysroot_ipc, sr, sizeof(sysroot_ipc));
(void) proc_sysroot_snapshot(sysroot_ipc, sizeof(sysroot_ipc));
if (fork_ipc_write_all(ipc_sock, sysroot_ipc, sizeof(sysroot_ipc)) < 0)
return -1;

Expand Down
23 changes: 22 additions & 1 deletion src/runtime/procemu.c
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,13 @@ static int dev_shm_resolve_path(const char *guest_suffix,
return 0;
}

int proc_dev_shm_resolve(const char *guest_suffix,
char *host_path,
size_t host_path_sz)
{
return dev_shm_resolve_path(guest_suffix, host_path, host_path_sz);
}

/* Give synthetic procfs nodes stable identities so directory walkers do not
* collapse distinct paths into one inode and falsely report filesystem loops.
*/
Expand Down Expand Up @@ -2553,13 +2560,27 @@ int proc_intercept_readlink(const char *path, char *buf, size_t bufsiz)
return proc_intercept_readlink(alias, buf, bufsiz);
}

/* /proc/self/exe -> path of current ELF binary */
/* /proc/self/exe -> path of current ELF binary.
* Strip the sysroot prefix so a guest running under --sysroot=/opt/sr
* sees /bin/ls rather than /opt/sr/bin/ls, matching the chroot-like
* abstraction the rest of the path layer presents.
*/
if (!strcmp(path, "/proc/self/exe")) {
const char *exe = proc_get_elf_path();
if (!exe) {
errno = ENOENT;
return -1;
}
char sysroot_snap[LINUX_PATH_MAX];
if (proc_sysroot_snapshot(sysroot_snap, sizeof(sysroot_snap))) {
size_t sr_len = strlen(sysroot_snap);
if (sr_len > 0 && strncmp(exe, sysroot_snap, sr_len) == 0 &&
(exe[sr_len] == '/' || exe[sr_len] == '\0')) {
exe += sr_len;
if (*exe == '\0')
exe = "/";
}
}
size_t len = strlen(exe);
if (len > bufsiz)
len = bufsiz;
Expand Down
10 changes: 10 additions & 0 deletions src/runtime/procemu.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,13 @@ int proc_intercept_readv(int guest_fd,
* Used by sys_unlinkat to rewrite /dev/shm/<name> paths.
*/
const char *proc_get_shm_dir(void);

/* Resolve a /dev/shm/<suffix> guest-path suffix to a host path inside the
* per-UID /dev/shm emulation directory. Rejects empty, ".."-bearing, or
* compound suffixes with errno = EACCES. Returns 0 on success and writes the
* full host path to host_path; returns -1 with errno set (EACCES on invalid
* suffix, ENAMETOOLONG on overflow, or as set by shm_dir_path()).
*/
int proc_dev_shm_resolve(const char *guest_suffix,
char *host_path,
size_t host_path_sz);
5 changes: 4 additions & 1 deletion src/syscall/exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,10 @@ int64_t sys_execve(hv_vcpu_t vcpu,
interp_resolved[0] = '\0';

if (elf_info.interp_path[0] != '\0') {
elf_resolve_interp(proc_get_sysroot(), elf_info.interp_path,
char sysroot_snap[LINUX_PATH_MAX];
bool have_sr =
proc_sysroot_snapshot(sysroot_snap, sizeof(sysroot_snap));
elf_resolve_interp(have_sr ? sysroot_snap : NULL, elf_info.interp_path,
interp_resolved, sizeof(interp_resolved));

log_debug("execve: pre-validating interpreter: %s", interp_resolved);
Expand Down
45 changes: 39 additions & 6 deletions src/syscall/fs-xattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "syscall/abi.h"
#include "syscall/fs.h"
#include "syscall/internal.h"
#include "syscall/path.h"

/* macOS xattr API has extra position and options parameters vs Linux.
* Linux: getxattr(path, name, value, size)
Expand Down Expand Up @@ -73,15 +74,23 @@ int64_t sys_getxattr(guest_t *g,
int nofollow)
{
char path[LINUX_PATH_MAX], name[LINUX_XATTR_NAME_MAX + 1];
char sysroot_buf[LINUX_PATH_MAX];
if (guest_read_str(g, path_gva, path, sizeof(path)) < 0)
return -LINUX_EFAULT;
if (guest_read_str(g, name_gva, name, sizeof(name)) < 0)
return -LINUX_EFAULT;

const char *target = nofollow ? path_resolve_sysroot_nofollow_path(
path, sysroot_buf, sizeof(sysroot_buf))
: path_resolve_sysroot_path(
path, sysroot_buf, sizeof(sysroot_buf));
if (!target)
return -LINUX_ENAMETOOLONG;

int opts = nofollow ? XATTR_NOFOLLOW : 0;

if (size == 0) {
ssize_t ret = getxattr(path, name, NULL, 0, 0, opts);
ssize_t ret = getxattr(target, name, NULL, 0, 0, opts);
return ret < 0 ? linux_errno() : ret;
}

Expand All @@ -90,7 +99,7 @@ int64_t sys_getxattr(guest_t *g,
if (err < 0)
return err;

ssize_t ret = getxattr(path, name, buf, (size_t) size, 0, opts);
ssize_t ret = getxattr(target, name, buf, (size_t) size, 0, opts);
int64_t result = xattr_copy_out_result(g, value_gva, buf, ret);
free(buf);
return result;
Expand All @@ -105,11 +114,19 @@ int64_t sys_setxattr(guest_t *g,
int nofollow)
{
char path[LINUX_PATH_MAX], name[LINUX_XATTR_NAME_MAX + 1];
char sysroot_buf[LINUX_PATH_MAX];
if (guest_read_str(g, path_gva, path, sizeof(path)) < 0)
return -LINUX_EFAULT;
if (guest_read_str(g, name_gva, name, sizeof(name)) < 0)
return -LINUX_EFAULT;

const char *target = nofollow ? path_resolve_sysroot_nofollow_path(
path, sysroot_buf, sizeof(sysroot_buf))
: path_resolve_sysroot_path(
path, sysroot_buf, sizeof(sysroot_buf));
if (!target)
return -LINUX_ENAMETOOLONG;

void *buf;
int64_t err = xattr_alloc_buf(size, &buf);
if (err < 0)
Expand All @@ -126,7 +143,7 @@ int64_t sys_setxattr(guest_t *g,
return err;
}

int ret = setxattr(path, name, buf, (size_t) size, 0, opts);
int ret = setxattr(target, name, buf, (size_t) size, 0, opts);
free(buf);
return ret < 0 ? linux_errno() : 0;
}
Expand All @@ -138,13 +155,21 @@ int64_t sys_listxattr(guest_t *g,
int nofollow)
{
char path[LINUX_PATH_MAX];
char sysroot_buf[LINUX_PATH_MAX];
if (guest_read_str(g, path_gva, path, sizeof(path)) < 0)
return -LINUX_EFAULT;

const char *target = nofollow ? path_resolve_sysroot_nofollow_path(
path, sysroot_buf, sizeof(sysroot_buf))
: path_resolve_sysroot_path(
path, sysroot_buf, sizeof(sysroot_buf));
if (!target)
return -LINUX_ENAMETOOLONG;

int opts = nofollow ? XATTR_NOFOLLOW : 0;

if (size == 0) {
ssize_t ret = listxattr(path, NULL, 0, opts);
ssize_t ret = listxattr(target, NULL, 0, opts);
return ret < 0 ? linux_errno() : ret;
}

Expand All @@ -153,7 +178,7 @@ int64_t sys_listxattr(guest_t *g,
if (err < 0)
return err;

ssize_t ret = listxattr(path, buf, (size_t) size, opts);
ssize_t ret = listxattr(target, buf, (size_t) size, opts);
int64_t result = xattr_copy_out_result(g, list_gva, buf, ret);
free(buf);
return result;
Expand All @@ -165,13 +190,21 @@ int64_t sys_removexattr(guest_t *g,
int nofollow)
{
char path[LINUX_PATH_MAX], name[LINUX_XATTR_NAME_MAX + 1];
char sysroot_buf[LINUX_PATH_MAX];
if (guest_read_str(g, path_gva, path, sizeof(path)) < 0)
return -LINUX_EFAULT;
if (guest_read_str(g, name_gva, name, sizeof(name)) < 0)
return -LINUX_EFAULT;

const char *target = nofollow ? path_resolve_sysroot_nofollow_path(
path, sysroot_buf, sizeof(sysroot_buf))
: path_resolve_sysroot_path(
path, sysroot_buf, sizeof(sysroot_buf));
if (!target)
return -LINUX_ENAMETOOLONG;

int opts = nofollow ? XATTR_NOFOLLOW : 0;
int ret = removexattr(path, name, opts);
int ret = removexattr(target, name, opts);
return ret < 0 ? linux_errno() : 0;
}

Expand Down
Loading
Loading