Duplicate environment variables have been a source of bugs, so perhaps
the kernel should fail an execve with an invalid envp. Diff below checks
that each environment string contains a '=' and that there are no
duplicates up to the equals sign.
So far I haven't noticed any breakage except for a purposefully
misbehaving program to test that execve will fail.
EINVAL gives a somewhat confusing error message, but nothing in intro(2)
looked like a better choice.
Idea from Martin Brandenburg.
- Matthew Martin
diff --git kern_exec.c kern_exec.c
index 7784d5f4165..3c3f0aa6266 100644
--- kern_exec.c
+++ kern_exec.c
@@ -239,10 +239,8 @@ sys_execve(struct proc *p, void *v, register_t *retval)
struct vattr attr;
struct ucred *cred = p->p_ucred;
char *argp;
- char * const *cpp, *dp, *sp;
-#ifdef KTRACE
+ char * const *cpp, *dp, *ep, *op, *sp;
char *env_start;
-#endif
struct process *pr = p->p_p;
long argc, envc;
size_t len, sgap;
@@ -357,9 +355,7 @@ sys_execve(struct proc *p, void *v, register_t *retval)
envc = 0;
/* environment does not need to be there */
if ((cpp = SCARG(uap, envp)) != NULL ) {
-#ifdef KTRACE
env_start = dp;
-#endif
while (1) {
len = argp + ARG_MAX - dp;
if ((error = copyin(cpp, &sp, sizeof(sp))) != 0)
@@ -371,6 +367,19 @@ sys_execve(struct proc *p, void *v, register_t *retval)
error = E2BIG;
goto bad;
}
+
+ /* Check for duplicate environment variables */
+ if ((ep = strchr(dp, '=')) == NULL) {
+ error = EINVAL;
+ goto bad;
+ }
+ for (op = env_start; op != dp; op = strchr(op, '\0') +
1) {
+ if (strncmp(dp, op, (ep - dp + 1)) == 0) {
+ error = EINVAL;
+ goto bad;
+ }
+ }
+
dp += len;
cpp++;
envc++;