Syscall tests for PATH_MAX
Even though it's possible for the user to build a path longer than
PATH_MAX (e.g. 16 NAME_MAX filenames), we still need a limit. If
anything 4096 seems ridiculously large (and will trigger 2-contig page
allocs...).
diff --git a/kern/src/syscall.c b/kern/src/syscall.c
index 7d2e0d5..9769707 100644
--- a/kern/src/syscall.c
+++ b/kern/src/syscall.c
@@ -313,6 +313,29 @@
return target;
}
+/* Helper, copies a pathname from the process into the kernel. Returns a string
+ * on success, which you must free with free_path. Returns 0 on failure and
+ * sets errno. */
+static char *copy_in_path(struct proc *p, const char *path, size_t path_l)
+{
+ char *t_path;
+ /* PATH_MAX includes the \0 */
+ if (path_l > PATH_MAX) {
+ set_errno(ENAMETOOLONG);
+ return 0;
+ }
+ t_path = user_strdup_errno(p, path, path_l);
+ if (!t_path)
+ return 0;
+ return t_path;
+}
+
+/* Helper, frees a path that was allocated with copy_in_path. */
+static void free_path(struct proc *p, char *t_path)
+{
+ user_memdup_free(p, t_path);
+}
+
/************** Utility Syscalls **************/
static int sys_null(void)
@@ -475,13 +498,12 @@
struct file *program;
struct proc *new_p;
- /* Copy in the path. Consider putting an upper bound on path_l. */
- t_path = user_strdup_errno(p, path, path_l);
+ t_path = copy_in_path(p, path, path_l);
if (!t_path)
return -1;
/* TODO: 9ns support */
program = do_file_open(t_path, 0, 0);
- user_memdup_free(p, t_path);
+ free_path(p, t_path);
if (!program)
return -1; /* presumably, errno is already set */
/* TODO: need to split the proc creation, since you must load after setting
@@ -698,8 +720,7 @@
set_errno(EINVAL);
return -1;
}
- /* Copy in the path. Consider putting an upper bound on path_l. */
- t_path = user_strdup_errno(p, path, path_l);
+ t_path = copy_in_path(p, path, path_l);
if (!t_path)
return -1;
disable_irqsave(&state); /* protect cur_ctx */
@@ -725,7 +746,7 @@
/* This could block: */
/* TODO: 9ns support */
program = do_file_open(t_path, 0, 0);
- user_memdup_free(p, t_path);
+ free_path(p, t_path);
if (!program)
goto early_error;
if (!is_valid_elf(program)) {
@@ -1278,7 +1299,7 @@
struct file *file;
printd("File %s Open attempt oflag %x mode %x\n", path, oflag, mode);
- char *t_path = user_strdup_errno(p, path, path_l);
+ char *t_path = copy_in_path(p, path, path_l);
if (!t_path)
return -1;
if (t) {
@@ -1291,7 +1312,7 @@
((oflag & (O_RDONLY | O_WRONLY | O_RDWR)) != O_WRONLY) &&
((oflag & (O_RDONLY | O_WRONLY | O_RDWR)) != O_RDWR)) {
set_errno(EINVAL);
- user_memdup_free(p, t_path);
+ free_path(p, t_path);
return -1;
}
@@ -1313,7 +1334,7 @@
if ((oflag & O_CREATE) && (oflag & O_EXCL)) {
set_errno(EEXIST);
sysclose(fd);
- user_memdup_free(p, t_path);
+ free_path(p, t_path);
return -1;
}
} else {
@@ -1323,7 +1344,7 @@
}
}
}
- user_memdup_free(p, t_path);
+ free_path(p, t_path);
printd("File %s Open, fd=%d\n", path, fd);
return fd;
}
@@ -1392,7 +1413,7 @@
{
struct kstat *kbuf;
struct dentry *path_d;
- char *t_path = user_strdup_errno(p, path, path_l);
+ char *t_path = copy_in_path(p, path, path_l);
int retval = 0;
if (!t_path)
return -1;
@@ -1423,7 +1444,7 @@
out_with_kbuf:
kfree(kbuf);
out_with_path:
- user_memdup_free(p, t_path);
+ free_path(p, t_path);
return retval;
}
@@ -1507,12 +1528,12 @@
int mode)
{
int retval;
- char *t_path = user_strdup_errno(p, path, path_l);
+ char *t_path = copy_in_path(p, path, path_l);
if (!t_path)
return -1;
/* TODO: 9ns support */
retval = do_access(t_path, mode);
- user_memdup_free(p, t_path);
+ free_path(p, t_path);
printd("Access for path: %s retval: %d\n", path, retval);
if (retval < 0) {
set_errno(-retval);
@@ -1563,24 +1584,24 @@
char *new_path, size_t new_l)
{
int ret;
- char *t_oldpath = user_strdup_errno(p, old_path, old_l);
+ char *t_oldpath = copy_in_path(p, old_path, old_l);
if (t_oldpath == NULL)
return -1;
- char *t_newpath = user_strdup_errno(p, new_path, new_l);
+ char *t_newpath = copy_in_path(p, new_path, new_l);
if (t_newpath == NULL) {
- user_memdup_free(p, t_oldpath);
+ free_path(p, t_oldpath);
return -1;
}
ret = do_link(t_oldpath, t_newpath);
- user_memdup_free(p, t_oldpath);
- user_memdup_free(p, t_newpath);
+ free_path(p, t_oldpath);
+ free_path(p, t_newpath);
return ret;
}
intreg_t sys_unlink(struct proc *p, const char *path, size_t path_l)
{
int retval;
- char *t_path = user_strdup_errno(p, path, path_l);
+ char *t_path = copy_in_path(p, path, path_l);
if (!t_path)
return -1;
retval = do_unlink(t_path);
@@ -1588,7 +1609,7 @@
unset_errno();
retval = sysremove(t_path);
}
- user_memdup_free(p, t_path);
+ free_path(p, t_path);
return retval;
}
@@ -1596,17 +1617,17 @@
char *new_path, size_t new_l)
{
int ret;
- char *t_oldpath = user_strdup_errno(p, old_path, old_l);
+ char *t_oldpath = copy_in_path(p, old_path, old_l);
if (t_oldpath == NULL)
return -1;
- char *t_newpath = user_strdup_errno(p, new_path, new_l);
+ char *t_newpath = copy_in_path(p, new_path, new_l);
if (t_newpath == NULL) {
- user_memdup_free(p, t_oldpath);
+ free_path(p, t_oldpath);
return -1;
}
ret = do_symlink(t_newpath, t_oldpath, S_IRWXU | S_IRWXG | S_IRWXO);
- user_memdup_free(p, t_oldpath);
- user_memdup_free(p, t_newpath);
+ free_path(p, t_oldpath);
+ free_path(p, t_newpath);
return ret;
}
@@ -1618,7 +1639,7 @@
ssize_t copy_amt;
int ret = -1;
struct dentry *path_d;
- char *t_path = user_strdup_errno(p, path, path_l);
+ char *t_path = copy_in_path(p, path, path_l);
if (t_path == NULL)
return -1;
/* TODO: 9ns support */
@@ -1637,7 +1658,7 @@
} else
symname = path_d->d_inode->i_op->readlink(path_d);
- user_memdup_free(p, t_path);
+ free_path(p, t_path);
if (symname){
copy_amt = strnlen(symname, buf_l - 1) + 1;
@@ -1652,21 +1673,22 @@
return ret;
}
-static intreg_t sys_chdir(struct proc *p, pid_t pid, const char *path, size_t path_l)
+static intreg_t sys_chdir(struct proc *p, pid_t pid, const char *path,
+ size_t path_l)
{
int retval;
char *t_path;
struct proc *target = get_controllable_proc(p, pid);
if (!target)
return -1;
- t_path = user_strdup_errno(p, path, path_l);
+ t_path = copy_in_path(p, path, path_l);
if (!t_path) {
proc_decref(target);
return -1;
}
/* TODO: 9ns support */
retval = do_chdir(&target->fs_env, t_path);
- user_memdup_free(p, t_path);
+ free_path(p, t_path);
proc_decref(target);
return retval;
}
@@ -1696,7 +1718,12 @@
{
int retval = 0;
char *kfree_this;
- char *k_cwd = do_getcwd(&p->fs_env, &kfree_this, cwd_l);
+ char *k_cwd;
+ if (cwd_l > PATH_MAX) {
+ set_errno(ENAMETOOLONG);
+ return -1;
+ }
+ k_cwd = do_getcwd(&p->fs_env, &kfree_this, cwd_l);
if (!k_cwd)
return -1; /* errno set by do_getcwd */
if (memcpy_to_user_errno(p, u_cwd, k_cwd, strnlen(k_cwd, cwd_l - 1) + 1))
@@ -1709,7 +1736,7 @@
intreg_t sys_mkdir(struct proc *p, const char *path, size_t path_l, int mode)
{
int retval;
- char *t_path = user_strdup_errno(p, path, path_l);
+ char *t_path = copy_in_path(p, path, path_l);
if (!t_path)
return -1;
mode &= S_PMASK;
@@ -1722,19 +1749,19 @@
static_assert(!(S_PMASK & DMDIR));
retval = syscreate(t_path, O_RDWR, DMDIR | mode);
}
- user_memdup_free(p, t_path);
+ free_path(p, t_path);
return retval;
}
intreg_t sys_rmdir(struct proc *p, const char *path, size_t path_l)
{
int retval;
- char *t_path = user_strdup_errno(p, path, path_l);
+ char *t_path = copy_in_path(p, path, path_l);
if (!t_path)
return -1;
/* TODO: 9ns support */
retval = do_rmdir(t_path);
- user_memdup_free(p, t_path);
+ free_path(p, t_path);
return retval;
}
@@ -1864,21 +1891,21 @@
{
int ret;
- char *t_srcpath = user_strdup_errno(p, src_path, src_l);
+ char *t_srcpath = copy_in_path(p, src_path, src_l);
if (t_srcpath == NULL) {
printd("srcpath dup failed ptr %p size %d\n", src_path, src_l);
return -1;
}
- char *t_ontopath = user_strdup_errno(p, onto_path, onto_l);
+ char *t_ontopath = copy_in_path(p, onto_path, onto_l);
if (t_ontopath == NULL) {
- user_memdup_free(p, t_srcpath);
+ free_path(p, t_srcpath);
printd("ontopath dup failed ptr %p size %d\n", onto_path, onto_l);
return -1;
}
printd("sys_nbind: %s -> %s flag %d\n", t_srcpath, t_ontopath, flag);
ret = sysbind(t_srcpath, t_ontopath, flag);
- user_memdup_free(p, t_srcpath);
- user_memdup_free(p, t_ontopath);
+ free_path(p, t_srcpath);
+ free_path(p, t_ontopath);
return ret;
}
@@ -1896,11 +1923,11 @@
int afd;
afd = -1;
- char *t_ontopath = user_strdup_errno(p, onto_path, onto_l);
+ char *t_ontopath = copy_in_path(p, onto_path, onto_l);
if (t_ontopath == NULL)
return -1;
ret = sysmount(fd, afd, t_ontopath, flag, /* spec or auth */"");
- user_memdup_free(p, t_ontopath);
+ free_path(p, t_ontopath);
return ret;
}
@@ -1908,18 +1935,18 @@
intreg_t sys_nunmount(struct proc *p, char *name, int name_l, char *old_path, int old_l)
{
int ret;
- char *t_oldpath = user_strdup_errno(p, old_path, old_l);
+ char *t_oldpath = copy_in_path(p, old_path, old_l);
if (t_oldpath == NULL)
return -1;
- char *t_name = user_strdup_errno(p, name, name_l);
+ char *t_name = copy_in_path(p, name, name_l);
if (t_name == NULL) {
- user_memdup_free(p, t_oldpath);
+ free_path(p, t_oldpath);
return -1;
}
ret = sysunmount(t_name, t_oldpath);
printd("go do it\n");
- user_memdup_free(p, t_oldpath);
- user_memdup_free(p, t_name);
+ free_path(p, t_oldpath);
+ free_path(p, t_name);
return ret;
}
@@ -1996,19 +2023,19 @@
uint8_t *stat_m, size_t stat_sz, int flags)
{
int retval = 0;
- char *t_path = user_strdup_errno(p, path, path_l);
+ char *t_path = copy_in_path(p, path, path_l);
struct file *file;
if (!t_path)
return -1;
retval = syswstat(t_path, stat_m, stat_sz);
if (retval == stat_sz) {
- user_memdup_free(p, t_path);
+ free_path(p, t_path);
return stat_sz;
}
/* 9ns failed, we'll need to check the VFS */
file = do_file_open(t_path, 0, 0);
- user_memdup_free(p, t_path);
+ free_path(p, t_path);
if (!file)
return -1;
retval = vfs_wstat(file, stat_m, stat_sz, flags);
@@ -2041,8 +2068,8 @@
struct systrace_record *t = pcpui->cur_kthread->trace;
ERRSTACK(1);
int mountpointlen = 0;
- char *from_path = user_strdup_errno(p, old_path, old_path_l);
- char *to_path = user_strdup_errno(p, new_path, new_path_l);
+ char *from_path = copy_in_path(p, old_path, old_path_l);
+ char *to_path = copy_in_path(p, new_path, new_path_l);
struct chan *oldchan = 0, *newchan = NULL;
int retval = -1;
@@ -2063,8 +2090,8 @@
poperror();
if (!oldchan) {
retval = do_rename(from_path, to_path);
- user_memdup_free(p, from_path);
- user_memdup_free(p, to_path);
+ free_path(p, from_path);
+ free_path(p, to_path);
return retval;
}
@@ -2152,8 +2179,8 @@
printk("syswstat returns %d\n", retval);
done:
- user_memdup_free(p, from_path);
- user_memdup_free(p, to_path);
+ free_path(p, from_path);
+ free_path(p, to_path);
cclose(oldchan);
cclose(newchan);
return retval;