Subject: hashinit()
To: None <tech-kern@NetBSD.org>
From: Christian Biere <christianbiere@gmx.de>
List: tech-kern
Date: 02/01/2007 02:28:37
--3lcZGd9BuhuYXNfi
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline


Are there objections against the attached patch?

 * hashinit(9):
   * Change type of parameter elements from u_int to size_t.
   * Prevent an infinite loop in hashinit() finding the next power of 2.
   * Prevent integer overflow when calculating the memory size in hashinit().
   * Always panic() on errors as no user checks the result.
 * veriexec_table_add(9), fileassoc_table_add(9):
   * Prevent integer overflows caused by implicit casts due to prototypes:
     int64_t -> size_t -> uint_t

-- 
Christian

--3lcZGd9BuhuYXNfi
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="hashinit.udif"

Index: kern_subr.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_subr.c,v
retrieving revision 1.150
diff -u -p -r1.150 kern_subr.c
--- sys/kern/kern_subr.c.orig	1 Nov 2006 10:17:58 -0000	1.150
+++ sys/kern/kern_subr.c	1 Feb 2007 01:03:21 -0000
@@ -382,7 +382,7 @@ ioctl_copyout(int ioctlflags, const void
  * suitable for masking a value to use as an index into the returned array.
  */
 void *
-hashinit(u_int elements, enum hashtype htype, struct malloc_type *mtype,
+hashinit(size_t elements, enum hashtype htype, struct malloc_type *mtype,
     int mflags, u_long *hashmask)
 {
 	u_long hashsize, i;
@@ -390,29 +390,40 @@ hashinit(u_int elements, enum hashtype h
 	TAILQ_HEAD(, generic) *hashtbl_tailq;
 	size_t esize;
 	void *p;
+	const char *msg;
+
+	if (elements == 0 || elements > (size_t)LONG_MAX + 1) {
+		msg = "bad cnt";
+		goto error;
+	}
 
-	if (elements == 0)
-		panic("hashinit: bad cnt");
 	for (hashsize = 1; hashsize < elements; hashsize <<= 1)
 		continue;
 
 	switch (htype) {
 	case HASH_LIST:
+		if (hashsize > SIZE_MAX / sizeof(*hashtbl_list)) {
+			msg = "too many elements";
+			goto error;
+		}
 		esize = sizeof(*hashtbl_list);
 		break;
 	case HASH_TAILQ:
+		if (hashsize > SIZE_MAX / sizeof(*hashtbl_tailq)) {
+			msg = "too many elements";
+			goto error;
+		}
 		esize = sizeof(*hashtbl_tailq);
 		break;
 	default:
-#ifdef DIAGNOSTIC
-		panic("hashinit: invalid table type");
-#else
+		panic("invalid table type");
 		return NULL;
-#endif
 	}
 
-	if ((p = malloc(hashsize * esize, mtype, mflags)) == NULL)
-		return (NULL);
+	if ((p = malloc(hashsize * esize, mtype, mflags)) == NULL) {
+		msg = "out of memory";
+		goto error;
+	}
 
 	switch (htype) {
 	case HASH_LIST:
@@ -428,6 +439,12 @@ hashinit(u_int elements, enum hashtype h
 	}
 	*hashmask = hashsize - 1;
 	return (p);
+
+error:
+	if (!(mflags & M_CANFAIL))
+		panic("hashinit: %s", msg);
+
+	return NULL;
 }
 
 /*
Index: hashinit.9
===================================================================
RCS file: /cvsroot/src/share/man/man9/hashinit.9,v
retrieving revision 1.3
diff -u -p -r1.3 hashinit.9
--- share/man/man9/hashinit.9.orig	23 Dec 2006 06:36:19 -0000	1.3
+++ share/man/man9/hashinit.9	1 Feb 2007 00:59:59 -0000
@@ -42,7 +42,7 @@
 .In sys/systm.h
 .Ft "void *"
 .Fo hashinit
-.Fa "u_int chains"
+.Fa "size_t chains"
 .Fa "enum hashtype htype"
 .Fa "struct malloc_type *mtype"
 .Fa "int mflags"
Index: systm.h
===================================================================
RCS file: /cvsroot/src/sys/sys/systm.h,v
retrieving revision 1.192
diff -u -p -r1.192 systm.h
--- sys/sys/systm.h.orig	10 Jan 2007 11:20:20 -0000	1.192
+++ sys/sys/systm.h	1 Feb 2007 01:02:10 -0000
@@ -152,7 +152,7 @@ enum hashtype {
 };
 
 struct malloc_type;
-void	*hashinit(u_int, enum hashtype, struct malloc_type *, int, u_long *);
+void	*hashinit(size_t, enum hashtype, struct malloc_type *, int, u_long *);
 void	hashdone(void *, struct malloc_type *);
 int	seltrue(dev_t, int, struct lwp *);
 int	sys_nosys(struct lwp *, void *, register_t *);
Index: kern_verifiedexec.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_verifiedexec.c,v
retrieving revision 1.94
diff -u -p -r1.94 kern_verifiedexec.c
--- sys/kern/kern_verifiedexec.c.orig	11 Jan 2007 16:24:48 -0000	1.94
+++ sys/kern/kern_verifiedexec.c	1 Feb 2007 01:25:22 -0000
@@ -1096,6 +1096,7 @@ veriexec_table_add(struct lwp *l, prop_d
 	u_char buf[16];
 	int error;
 	static ONCE_DECL(control);
+	uint64_t count;
 
 	error = RUN_ONCE(&control, veriexec_mountspecific_init);
 	if (error) {
@@ -1108,8 +1109,13 @@ veriexec_table_add(struct lwp *l, prop_d
 	if (error)
 		return (error);
 
-	error = fileassoc_table_add(nid.ni_vp->v_mount,
-	    prop_number_integer_value(prop_dictionary_get(dict, "count")));
+	count = prop_number_integer_value(prop_dictionary_get(dict, "count"));
+	if (count > SIZE_MAX) {
+		error = ERANGE;
+		goto out;
+	}
+
+	error = fileassoc_table_add(nid.ni_vp->v_mount, (size_t)count);
 	if (error && (error != EEXIST))
 		goto out;
 

--3lcZGd9BuhuYXNfi--