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;