Module Name:    src
Committed By:   martin
Date:           Sun Feb  2 14:48:57 UTC 2014

Modified Files:
        src/lib/libc/gen: posix_spawn.3 posix_spawn_file_actions_addopen.3
            posix_spawn_file_actions_init.3 posix_spawn_fileactions.c
        src/sys/compat/netbsd32: netbsd32_execve.c
        src/sys/kern: kern_exec.c

Log Message:
Limit the amount of kernel memory a posix_spawn syscall can use (for handling
the file action list) by limiting the maximum number of file actions to
twice the current file descriptor limit.
Fix a few bugs in the support functions and document the new limit.
>From Maxime Villard.


To generate a diff of this commit:
cvs rdiff -u -r1.4 -r1.5 src/lib/libc/gen/posix_spawn.3
cvs rdiff -u -r1.3 -r1.4 src/lib/libc/gen/posix_spawn_file_actions_addopen.3 \
    src/lib/libc/gen/posix_spawn_file_actions_init.3
cvs rdiff -u -r1.2 -r1.3 src/lib/libc/gen/posix_spawn_fileactions.c
cvs rdiff -u -r1.37 -r1.38 src/sys/compat/netbsd32/netbsd32_execve.c
cvs rdiff -u -r1.372 -r1.373 src/sys/kern/kern_exec.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/lib/libc/gen/posix_spawn.3
diff -u src/lib/libc/gen/posix_spawn.3:1.4 src/lib/libc/gen/posix_spawn.3:1.5
--- src/lib/libc/gen/posix_spawn.3:1.4	Sat Jul 20 21:39:57 2013
+++ src/lib/libc/gen/posix_spawn.3	Sun Feb  2 14:48:57 2014
@@ -1,4 +1,4 @@
-.\" $NetBSD: posix_spawn.3,v 1.4 2013/07/20 21:39:57 wiz Exp $
+.\" $NetBSD: posix_spawn.3,v 1.5 2014/02/02 14:48:57 martin Exp $
 .\"
 .\" Copyright (c) 2008 Ed Schouten <e...@freebsd.org>
 .\" All rights reserved.
@@ -182,6 +182,12 @@ flag set (see
 is closed.
 .El
 .Pp
+The maximum number of
+.Fa file_actions
+objects is limited to the
+.Dv RLIMIT_NOFILE
+rlimit times 2.
+.Pp
 The
 .Vt posix_spawnattr_t
 spawn attributes object type is defined in
@@ -420,6 +426,11 @@ or
 .Fn dup2 ,
 in addition to those described by
 .Fn open .
+Finally, if the number of
+.Fa file_actions
+objects exceeds the allowed limit,
+.Er EINVAL
+is returned.
 .El
 .Sh SEE ALSO
 .Xr close 2 ,

Index: src/lib/libc/gen/posix_spawn_file_actions_addopen.3
diff -u src/lib/libc/gen/posix_spawn_file_actions_addopen.3:1.3 src/lib/libc/gen/posix_spawn_file_actions_addopen.3:1.4
--- src/lib/libc/gen/posix_spawn_file_actions_addopen.3:1.3	Sat Jul 20 21:39:57 2013
+++ src/lib/libc/gen/posix_spawn_file_actions_addopen.3	Sun Feb  2 14:48:57 2014
@@ -1,4 +1,4 @@
-.\" $NetBSD: posix_spawn_file_actions_addopen.3,v 1.3 2013/07/20 21:39:57 wiz Exp $
+.\" $NetBSD: posix_spawn_file_actions_addopen.3,v 1.4 2014/02/02 14:48:57 martin Exp $
 .\"
 .\" Copyright (c) 2008 Ed Schouten <e...@freebsd.org>
 .\" All rights reserved.
@@ -149,6 +149,10 @@ functions fail if:
 .Bl -tag -width Er
 .It Bq Er EINVAL
 The value specified by
+.Fa file_actions
+is invalid.
+.It Bq Er EBADF
+The value specified by
 .Fa fildes
 or
 .Fa newfildes
Index: src/lib/libc/gen/posix_spawn_file_actions_init.3
diff -u src/lib/libc/gen/posix_spawn_file_actions_init.3:1.3 src/lib/libc/gen/posix_spawn_file_actions_init.3:1.4
--- src/lib/libc/gen/posix_spawn_file_actions_init.3:1.3	Sat Jul 20 21:39:57 2013
+++ src/lib/libc/gen/posix_spawn_file_actions_init.3	Sun Feb  2 14:48:57 2014
@@ -1,4 +1,4 @@
-.\" $NetBSD: posix_spawn_file_actions_init.3,v 1.3 2013/07/20 21:39:57 wiz Exp $
+.\" $NetBSD: posix_spawn_file_actions_init.3,v 1.4 2014/02/02 14:48:57 martin Exp $
 .\"
 .\" Copyright (c) 2008 Ed Schouten <e...@freebsd.org>
 .\" All rights reserved.
@@ -81,6 +81,10 @@ function will fail if:
 .Bl -tag -width Er
 .It Bq Er ENOMEM
 Insufficient memory exists to initialize the spawn file actions object.
+.It Bq Er EINVAL
+The value specified by
+.Fa file_actions
+is invalid.
 .El
 .Sh SEE ALSO
 .Xr posix_spawn 3 ,

Index: src/lib/libc/gen/posix_spawn_fileactions.c
diff -u src/lib/libc/gen/posix_spawn_fileactions.c:1.2 src/lib/libc/gen/posix_spawn_fileactions.c:1.3
--- src/lib/libc/gen/posix_spawn_fileactions.c:1.2	Sun Apr  8 11:27:44 2012
+++ src/lib/libc/gen/posix_spawn_fileactions.c	Sun Feb  2 14:48:57 2014
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: posix_spawn_fileactions.c,v 1.2 2012/04/08 11:27:44 martin Exp $");
+__RCSID("$NetBSD: posix_spawn_fileactions.c,v 1.3 2014/02/02 14:48:57 martin Exp $");
 
 #include "namespace.h"
 
@@ -48,11 +48,11 @@ int
 posix_spawn_file_actions_init(posix_spawn_file_actions_t *fa)
 {
 	if (fa == NULL)
-		return (-1);
+		return (EINVAL);
 
 	fa->fae = malloc(MIN_SIZE * sizeof(struct posix_spawn_file_actions_entry));
 	if (fa->fae == NULL)
-		return (-1);
+		return (ENOMEM);
 	fa->size = MIN_SIZE;
 	fa->len = 0;
 
@@ -65,7 +65,7 @@ posix_spawn_file_actions_destroy(posix_s
 	unsigned int i;
 
 	if (fa == NULL)
-		return (-1);
+		return (EINVAL);
 
 	for (i = 0; i < fa->len; i++) {
 		if (fa->fae[i].fae_action == FAE_OPEN)
@@ -77,48 +77,53 @@ posix_spawn_file_actions_destroy(posix_s
 }
 
 static int
-posix_spawn_file_actions_getentry(posix_spawn_file_actions_t *fa)
+posix_spawn_file_actions_getentry(posix_spawn_file_actions_t *fa,
+    unsigned int *i)
 {
+	posix_spawn_file_actions_entry_t *fae;
+
 	if (fa == NULL)
-		return -1;
+		return (EINVAL);
 
 	if (fa->len < fa->size)
-		return fa->len;
-	
-	fa->fae = realloc(fa->fae, (fa->size + MIN_SIZE) * 
-			sizeof(struct posix_spawn_file_actions_entry));
+		goto out;
 
-	if (fa->fae == NULL)
-		return -1;
+	fae = realloc(fa->fae, (fa->size + MIN_SIZE) * sizeof(*fa->fae));
+	if (fae == NULL)
+		return (ENOMEM);
 
+	fa->fae = fae;
 	fa->size += MIN_SIZE;
 
-	return fa->len;
+out:
+	*i = fa->len;
+	return (0);
 }
 
 int
 posix_spawn_file_actions_addopen(posix_spawn_file_actions_t * __restrict fa,
     int fildes, const char * __restrict path, int oflag, mode_t mode)
 {
-	int i, error;
+	char *faepath;
+	unsigned int i;
+	int error;
 
 	if (fildes < 0)
 		return (EBADF);
 
-	i = posix_spawn_file_actions_getentry(fa);
-	if (i < 0)
+	error = posix_spawn_file_actions_getentry(fa, &i);
+	if (error)
+		return (error);
+
+	faepath = strdup(path);
+	if (faepath == NULL)
 		return (ENOMEM);
 
 	fa->fae[i].fae_action = FAE_OPEN;
-	fa->fae[i].fae_path = strdup(path);
-	if (fa->fae[i].fae_path == NULL) {
-		error = errno;
-		return (error);
-	}
+	fa->fae[i].fae_path = faepath;
 	fa->fae[i].fae_fildes = fildes;
 	fa->fae[i].fae_oflag = oflag;
 	fa->fae[i].fae_mode = mode;
-	
 	fa->len++;
 
 	return (0);
@@ -128,14 +133,15 @@ int
 posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *fa,
     int fildes, int newfildes)
 {
-	int i;
+	unsigned int i;
+	int error;
 
 	if (fildes < 0 || newfildes < 0)
 		return (EBADF);
 
-	i = posix_spawn_file_actions_getentry(fa);
-	if (i < 0)
-		return (ENOMEM);
+	error = posix_spawn_file_actions_getentry(fa, &i);
+	if (error)
+		return (error);
 
 	fa->fae[i].fae_action = FAE_DUP2;
 	fa->fae[i].fae_fildes = fildes;
@@ -149,14 +155,15 @@ int
 posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *fa,
     int fildes)
 {
-	int i;
+	unsigned int i;
+	int error;
 
 	if (fildes < 0)
 		return (EBADF);
 
-	i = posix_spawn_file_actions_getentry(fa);
-	if (i < 0)
-		return (ENOMEM);
+	error = posix_spawn_file_actions_getentry(fa, &i);
+	if (error)
+		return (error);
 
 	fa->fae[i].fae_action = FAE_CLOSE;
 	fa->fae[i].fae_fildes = fildes;

Index: src/sys/compat/netbsd32/netbsd32_execve.c
diff -u src/sys/compat/netbsd32/netbsd32_execve.c:1.37 src/sys/compat/netbsd32/netbsd32_execve.c:1.38
--- src/sys/compat/netbsd32/netbsd32_execve.c:1.37	Tue Jan 15 17:14:11 2013
+++ src/sys/compat/netbsd32/netbsd32_execve.c	Sun Feb  2 14:48:57 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: netbsd32_execve.c,v 1.37 2013/01/15 17:14:11 hannken Exp $	*/
+/*	$NetBSD: netbsd32_execve.c,v 1.38 2014/02/02 14:48:57 martin Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Matthew R. Green
@@ -28,7 +28,7 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(0, "$NetBSD: netbsd32_execve.c,v 1.37 2013/01/15 17:14:11 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: netbsd32_execve.c,v 1.38 2014/02/02 14:48:57 martin Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -97,7 +97,7 @@ netbsd32_fexecve(struct lwp *l, const st
 
 static int
 netbsd32_posix_spawn_fa_alloc(struct posix_spawn_file_actions **fap,
-    const struct netbsd32_posix_spawn_file_actions *ufa)
+    const struct netbsd32_posix_spawn_file_actions *ufa, rlim_t lim)
 {
 	struct posix_spawn_file_actions *fa;
 	struct netbsd32_posix_spawn_file_actions fa32;
@@ -117,6 +117,11 @@ netbsd32_posix_spawn_fa_alloc(struct pos
 	fa = kmem_alloc(sizeof(*fa), KM_SLEEP);
 	fa->len = fa->size = fa32.len;
 
+	if (fa->len > lim) {
+		kmem_free(fa, sizeof(*fa));
+		return EINVAL;
+	}
+
 	fal = fa->len * sizeof(*fae);
 	fal32 = fa->len * sizeof(*fae32);
 
@@ -179,6 +184,8 @@ netbsd32_posix_spawn(struct lwp *l,
 	struct posix_spawnattr *sa = NULL;
 	pid_t pid;
 	bool child_ok = false;
+	rlim_t max_fileactions;
+	proc_t *p = l->l_proc;
 
 	error = check_posix_spawn(l);
 	if (error) {
@@ -188,8 +195,10 @@ netbsd32_posix_spawn(struct lwp *l,
 
 	/* copy in file_actions struct */
 	if (SCARG_P32(uap, file_actions) != NULL) {
+		max_fileactions = 2 * min(p->p_rlimit[RLIMIT_NOFILE].rlim_cur,
+		    maxfiles);
 		error = netbsd32_posix_spawn_fa_alloc(&fa,
-		    SCARG_P32(uap, file_actions));
+		    SCARG_P32(uap, file_actions), max_fileactions);
 		if (error)
 			goto error_exit;
 	}

Index: src/sys/kern/kern_exec.c
diff -u src/sys/kern/kern_exec.c:1.372 src/sys/kern/kern_exec.c:1.373
--- src/sys/kern/kern_exec.c:1.372	Sun Feb  2 08:25:23 2014
+++ src/sys/kern/kern_exec.c	Sun Feb  2 14:48:57 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_exec.c,v 1.372 2014/02/02 08:25:23 dogcow Exp $	*/
+/*	$NetBSD: kern_exec.c,v 1.373 2014/02/02 14:48:57 martin Exp $	*/
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -59,7 +59,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.372 2014/02/02 08:25:23 dogcow Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.373 2014/02/02 14:48:57 martin Exp $");
 
 #include "opt_exec.h"
 #include "opt_execfmt.h"
@@ -2065,7 +2065,7 @@ posix_spawn_fa_free(struct posix_spawn_f
 
 static int
 posix_spawn_fa_alloc(struct posix_spawn_file_actions **fap,
-    const struct posix_spawn_file_actions *ufa)
+    const struct posix_spawn_file_actions *ufa, rlim_t lim)
 {
 	struct posix_spawn_file_actions *fa;
 	struct posix_spawn_file_actions_entry *fae;
@@ -2080,6 +2080,11 @@ posix_spawn_fa_alloc(struct posix_spawn_
 		return error;	/* 0 if not an error, and len == 0 */
 	}
 
+	if (fa->len > lim) {
+		kmem_free(fa, sizeof(*fa));
+		return EINVAL;
+	}
+
 	fa->size = fa->len;
 	size_t fal = fa->len * sizeof(*fae);
 	fae = fa->fae;
@@ -2437,6 +2442,8 @@ sys_posix_spawn(struct lwp *l1, const st
 	struct posix_spawnattr *sa = NULL;
 	pid_t pid;
 	bool child_ok = false;
+	rlim_t max_fileactions;
+	proc_t *p = l1->l_proc;
 
 	error = check_posix_spawn(l1);
 	if (error) {
@@ -2446,7 +2453,10 @@ sys_posix_spawn(struct lwp *l1, const st
 
 	/* copy in file_actions struct */
 	if (SCARG(uap, file_actions) != NULL) {
-		error = posix_spawn_fa_alloc(&fa, SCARG(uap, file_actions));
+		max_fileactions = 2 * min(p->p_rlimit[RLIMIT_NOFILE].rlim_cur,
+		    maxfiles);
+		error = posix_spawn_fa_alloc(&fa, SCARG(uap, file_actions),
+		    max_fileactions);
 		if (error)
 			goto error_exit;
 	}

Reply via email to