Skip to content

Commit

Permalink
Stop mutating the path in real fs functions
Browse files Browse the repository at this point in the history
  • Loading branch information
tbodt committed Nov 16, 2017
1 parent a58f8a8 commit 37aef44
Show file tree
Hide file tree
Showing 10 changed files with 63 additions and 72 deletions.
8 changes: 5 additions & 3 deletions fs/path.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ int path_normalize(struct fd *at, const char *path, char *out, bool follow_links
if (err < 0)
return err;
assert(path_is_normalized(at_path));
strcpy(o, at_path);
n -= strlen(at_path);
o += strlen(at_path);
if (strcmp(at_path, "/") != 0) {
strcpy(o, at_path);
n -= strlen(at_path);
o += strlen(at_path);
}
}
}

Expand Down
90 changes: 39 additions & 51 deletions fs/real.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,28 +28,19 @@ static int getpath(int fd, char *buf) {
#endif
}

char *strnprepend(char *str, const char *prefix, size_t max) {
if (strlen(str) + strlen(prefix) + 1 > max)
return NULL;
const char *src = str + strlen(str) + 1;
char *dst = (char *) src + strlen(prefix);
while (src != str)
*dst-- = *src--;
*dst = *src;
src = prefix;
dst = str;
while (*src != '\0')
*dst++ = *src++;
return str;
const char *fix_path(const char *path) {
if (strcmp(path, "/") == 0)
return ".";
if (path[0] == '/')
path++;
return path;
}

// TODO translate goddamn flags

struct fd *realfs_open(struct mount *mount, char *path, int flags, int mode) {
if (strnprepend(path, mount->source, MAX_PATH) == NULL)
return ERR_PTR(_ENAMETOOLONG);

int fd_no = open(path, flags, mode);
static struct fd *realfs_open(struct mount *mount, char *path, int flags, int mode) {
if (*path == '\0') path = ".";
int fd_no = openat(mount->root_fd, fix_path(path), flags, mode);
if (fd_no < 0)
return ERR_PTR(err_map(errno));
struct fd *fd = fd_create();
Expand Down Expand Up @@ -93,16 +84,9 @@ static void copy_stat(struct statbuf *fake_stat, struct stat *real_stat) {
}

int realfs_stat(struct mount *mount, char *path, struct statbuf *fake_stat, bool follow_links) {
if (strnprepend(path, mount->source, MAX_PATH) == NULL)
return _ENAMETOOLONG;

struct stat real_stat;
int (*stat_fn)(const char *path, struct stat *buf);
if (follow_links)
stat_fn = stat;
else
stat_fn = lstat;
if (stat_fn(path, &real_stat) < 0)
if (*path == '\0') path = ".";
if (fstatat(mount->root_fd, fix_path(path), &real_stat, follow_links ? 0 : AT_SYMLINK_NOFOLLOW) < 0)
return err_map(errno);
copy_stat(fake_stat, &real_stat);
return 0;
Expand All @@ -116,26 +100,22 @@ int realfs_fstat(struct fd *fd, struct statbuf *fake_stat) {
return 0;
}

int realfs_unlink(struct mount *mount, char *path) {
if (strnprepend(path, mount->source, MAX_PATH) == NULL)
return _ENAMETOOLONG;

int res = unlink(path);
static int realfs_unlink(struct mount *mount, char *path) {
if (*path == '\0') path = ".";
int res = unlinkat(mount->root_fd, fix_path(path), 0);
if (res < 0)
return err_map(errno);
return res;
}

int realfs_access(struct mount *mount, char *path, int mode) {
if (strnprepend(path, mount->source, MAX_PATH) == NULL)
return _ENAMETOOLONG;

int real_mode = 0;
if (mode & AC_F) real_mode |= F_OK;
if (mode & AC_R) real_mode |= R_OK;
if (mode & AC_W) real_mode |= W_OK;
if (mode & AC_X) real_mode |= X_OK;
int res = access(path, real_mode);
if (*path == '\0') path = ".";
int res = faccessat(mount->root_fd, fix_path(path), real_mode, 0);
if (res < 0)
return err_map(errno);
return res;
Expand Down Expand Up @@ -201,11 +181,9 @@ int realfs_mmap(struct fd *fd, off_t offset, size_t len, int prot, int flags, vo
return 0;
}

ssize_t realfs_readlink(struct mount *mount, char *path, char *buf, size_t bufsize) {
if (strnprepend(path, mount->source, MAX_PATH) == NULL)
return _ENAMETOOLONG;

ssize_t size = readlink(path, buf, bufsize);
static ssize_t realfs_readlink(struct mount *mount, char *path, char *buf, size_t bufsize) {
if (*path == '\0') path = ".";
ssize_t size = readlinkat(mount->root_fd, fix_path(path), buf, bufsize);
if (size < 0)
return err_map(errno);
return size;
Expand All @@ -215,15 +193,10 @@ int realfs_getpath(struct fd *fd, char *buf) {
int err = getpath(fd->real_fd, buf);
if (err < 0)
return err;
size_t source_len = strlen(fd->mount->source);
memmove(buf, buf + source_len, MAX_PATH - source_len);
return 0;
}

int realfs_statfs(struct mount *mount, struct statfsbuf *stat) {
stat->type = 0x7265616c;
stat->namelen = NAME_MAX;
stat->bsize = PAGE_SIZE;
if (strcmp(fd->mount->source, "/") != 0) {
size_t source_len = strlen(fd->mount->source);
memmove(buf, buf + source_len, MAX_PATH - source_len);
}
return 0;
}

Expand All @@ -236,14 +209,29 @@ int realfs_flock(struct fd *fd, int operation) {
return flock(fd->real_fd, real_op);
}

int realfs_statfs(struct mount *mount, struct statfsbuf *stat) {
stat->type = 0x7265616c;
stat->namelen = NAME_MAX;
stat->bsize = PAGE_SIZE;
return 0;
}

int realfs_mount(struct mount *mount) {
mount->root_fd = open(mount->source, O_DIRECTORY);
if (mount->root_fd < 0)
return err_map(errno);
return 0;
}

const struct fs_ops realfs = {
.mount = realfs_mount,
.statfs = realfs_statfs,
.open = realfs_open,
.unlink = realfs_unlink,
.stat = realfs_stat,
.access = realfs_access,
.readlink = realfs_readlink,
.fstat = realfs_fstat,
.statfs = realfs_statfs,
.flock = realfs_flock,
};

Expand Down
12 changes: 5 additions & 7 deletions kernel/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ struct mount {
const char *source;
const struct fs_ops *fs;
struct mount *next;

int root_fd;
void *data;
};
extern struct mount *mounts;
Expand All @@ -76,6 +78,7 @@ extern struct mount *mounts;
#define O_CREAT_ (1 << 6)

struct fs_ops {
int (*mount)(struct mount *mount);
int (*statfs)(struct mount *mount, struct statfsbuf *stat);
// the path parameter points to MAX_PATH bytes of allocated memory, which
// you can do whatever you want with (but make sure to return _ENAMETOOLONG
Expand Down Expand Up @@ -127,6 +130,7 @@ struct fd_ops {

struct mount *find_mount(char *path);
struct mount *find_mount_and_trim_path(char *path);
const char *fix_path(const char *path); // TODO reconsider

struct pollable {
struct list fds;
Expand Down Expand Up @@ -172,7 +176,7 @@ void poll_destroy(struct poll *poll);
// - resolving . and ..
// - resolving symlinks, skipping the last path component if the follow_links
// argument is true
// The result will always begin with a slash.
// The result will always begin with a slash or be empty.
//
// If the normalized path plus the null terminator would be longer than
// MAX_PATH, _ENAMETOOLONG is returned. The out buffer is expected to be at
Expand All @@ -183,12 +187,9 @@ bool path_is_normalized(const char *path);
// real fs
extern const struct fs_ops realfs;

struct fd *realfs_open(struct mount *mount, char *path, int flags, int mode);
int realfs_stat(struct mount *mount, char *path, struct statbuf *fake_stat, bool follow_links);
int realfs_fstat(struct fd *fd, struct statbuf *fake_stat);
int realfs_unlink(struct mount *mount, char *path);
int realfs_access(struct mount *mount, char *path, int mode);
ssize_t realfs_readlink(struct mount *mount, char *path, char *buf, size_t bufsize);
int realfs_statfs(struct mount *mount, struct statfsbuf *stat);
int realfs_flock(struct fd *fd, int operation);
extern const struct fd_ops realfs_fdops;
Expand All @@ -202,7 +203,4 @@ struct fd *adhoc_fd_create(void);
// fake fs
extern const struct fs_ops fakefs;

// TODO put this somewhere else
char *strnprepend(char *str, const char *prefix, size_t max);

#endif
5 changes: 5 additions & 0 deletions kernel/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ int mount_root(const struct fs_ops *fs, const char *source) {
mounts->fs = fs;
mounts->next = NULL;
mounts->data = NULL;
if (fs->mount) {
int err = fs->mount(mounts);
if (err < 0)
return err;
}
return 0;
}

Expand Down
4 changes: 3 additions & 1 deletion main.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@

int main(int argc, char *const argv[]) {
int err = xX_main_Xx(argc, argv);
if (err < 0)
if (err < 0) {
fprintf(stderr, "%s\n", strerror(-err));
return err;
}
cpu_run(&current->cpu);
}
5 changes: 1 addition & 4 deletions tools/ptraceomatic.c
Original file line number Diff line number Diff line change
Expand Up @@ -442,12 +442,9 @@ int main(int argc, char *const argv[]) {
fprintf(stderr, "enametoolong\n"); exit(1);
}
struct mount *mount = find_mount_and_trim_path(exec_path);
if (strnprepend(exec_path, mount->source, MAX_PATH) == NULL) {
fprintf(stderr, "enametoolong\n"); exit(1);
}
int fds[2];
trycall(socketpair(AF_UNIX, SOCK_DGRAM, 0, fds), "socketpair");
int pid = start_tracee(exec_path, argv + optind, (char *[]) {NULL});
int pid = start_tracee(mount->root_fd, exec_path, argv + optind, (char *[]) {NULL});
int sender = fds[0], receiver = fds[1];
/* close(receiver); // only needed in the child */
prepare_tracee(pid);
Expand Down
4 changes: 2 additions & 2 deletions tools/ptutil.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ static int arch_prctl(int code, unsigned long arg) {
return syscall(SYS_arch_prctl, code, arg);
}

int start_tracee(const char *path, char *const argv[], char *const envp[]) {
int start_tracee(int at, const char *path, char *const argv[], char *const envp[]) {
// shut off aslr
int persona = personality(0xffffffff);
persona |= ADDR_NO_RANDOMIZE;
Expand All @@ -42,7 +42,7 @@ int start_tracee(const char *path, char *const argv[], char *const envp[]) {
trycall(prctl(PR_SET_TSC, PR_TSC_SIGSEGV), "rdtsc faulting");
/* trycall(arch_prctl(ARCH_SET_CPUID, 0), "cpuid faulting"); */
trycall(ptrace(PTRACE_TRACEME, 0, NULL, NULL), "ptrace traceme");
trycall(execve(path, argv, envp), "fexecve");
trycall(syscall(SYS_execveat, at, path, argv, envp, 0), "fexecve");
} else {
// parent, wait for child to stop after exec
int status;
Expand Down
2 changes: 1 addition & 1 deletion tools/ptutil.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "../misc.h"

long trycall(long res, const char *msg);
int start_tracee(const char *path, char *const argv[], char *const envp[]);
int start_tracee(int at, const char *path, char *const argv[], char *const envp[]);
int open_mem(int pid);
dword_t pt_read(int pid, addr_t addr);
void pt_write8(int pid, addr_t addr, byte_t val);
Expand Down
2 changes: 1 addition & 1 deletion tools/vdso-transplant-main.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

int main(int argc, char *const argv[]) {
char *const envp[] = {NULL};
int pid = start_tracee(argv[2], argv + 2, envp);
int pid = start_tracee(AT_FDCWD, argv[2], argv + 2, envp);

int vdso_fd = trycall(open(argv[1], O_RDONLY), "open vdso");
struct stat statbuf;
Expand Down
3 changes: 1 addition & 2 deletions xX_main_Xx.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,7 @@ static inline int xX_main_Xx(int argc, char *const argv[]) {
current->pwd = pwd;
}

char *envp[] = {NULL};
int err = sys_execve(argv[optind], argv + optind, envp);
int err = sys_execve(argv[optind], argv + optind, (char *[]) {NULL});
if (err < 0)
return err;
err = create_stdio(real_tty_driver);
Expand Down

0 comments on commit 37aef44

Please sign in to comment.