changeset 4142:0d7fa83a8b00 onnv_64

6548196 Multiple memory corruption vulnerabilities in nscd(1M)
author michen
date Mon, 30 Apr 2007 17:48:25 -0700
parents ddd21f3d4066
children e96717d2a371
files usr/src/cmd/nscd/cache.c usr/src/cmd/nscd/nscd_common.h usr/src/cmd/nscd/nscd_door.c usr/src/cmd/nscd/nscd_door.h usr/src/cmd/nscd/nscd_frontend.c usr/src/cmd/nscd/nscd_frontend.h usr/src/lib/libc/port/gen/getxby_door.c usr/src/lib/libc/port/gen/nss_dbdefs.c
diffstat 8 files changed, 377 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/nscd/cache.c	Mon Apr 30 16:52:44 2007 -0700
+++ b/usr/src/cmd/nscd/cache.c	Mon Apr 30 17:48:25 2007 -0700
@@ -1748,7 +1748,13 @@
 		break;
 
 	case SERVERERROR:
-		/* status and errno already set in the phdr */
+		/*
+		 * status and errno should have been set in the phdr,
+		 * if not, set status to NSS_ERROR
+		 */
+		if (NSCD_STATUS_IS_OK(phdr)) {
+			NSCD_SET_STATUS(phdr, NSS_ERROR, 0);
+		}
 		break;
 
 	case NOSERVER:
--- a/usr/src/cmd/nscd/nscd_common.h	Mon Apr 30 16:52:44 2007 -0700
+++ b/usr/src/cmd/nscd/nscd_common.h	Mon Apr 30 17:48:25 2007 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -69,6 +69,7 @@
 	NSCD_CREATE_GETENT_CTX_FAILED,
 	NSCD_NSS_BACKEND_NOT_FOUND,
 	NSCD_DOOR_UCRED_ERROR,
+	NSCD_DOOR_BUFFER_CHECK_FAILED,
 	NSCD_SELF_CRED_NOT_CONFIGURED,
 	NSCD_SELF_CRED_NO_FORKER,
 	NSCD_SELF_CRED_WRONG_NSCD,
--- a/usr/src/cmd/nscd/nscd_door.c	Mon Apr 30 16:52:44 2007 -0700
+++ b/usr/src/cmd/nscd/nscd_door.c	Mon Apr 30 17:48:25 2007 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -105,11 +105,11 @@
 	return (ret);
 }
 
-
 nss_status_t
 _nscd_doorcall(int callnum)
 {
-	nss_pheader_t	phdr;
+	size_t		buflen;
+	nss_pheader_t	*phdr;
 	void		*dptr;
 	size_t		ndata;
 	size_t		adata;
@@ -119,21 +119,24 @@
 	_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
 	(me, "processing door call %d ...\n", callnum);
 
-	phdr.nsc_callnumber = callnum;
-	ndata = sizeof (phdr);
-	adata = sizeof (phdr);
-	dptr = (void *)&phdr;
+	/* allocate door buffer from the stack */
+	NSCD_ALLOC_DOORBUF(callnum, 0, dptr, buflen);
+	ndata = buflen;
+	adata = buflen;
+
 	ret = _nsc_trydoorcall(&dptr, &ndata, &adata);
 
 	if (ret != NSS_SUCCESS) {
+		phdr = (nss_pheader_t *)dptr;
 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
 		(me, "door call (%d) failed (status = %d, error = %s)\n",
-			callnum, ret, strerror(NSCD_GET_ERRNO(&phdr)));
+			callnum, ret, strerror(NSCD_GET_ERRNO(phdr)));
 	}
 
 	return (ret);
 }
 
+
 nss_status_t
 _nscd_doorcall_data(int callnum, void *indata, int indlen,
 	void *outdata, int outdlen, nss_pheader_t *phdr)
--- a/usr/src/cmd/nscd/nscd_door.h	Mon Apr 30 16:52:44 2007 -0700
+++ b/usr/src/cmd/nscd/nscd_door.h	Mon Apr 30 17:48:25 2007 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -70,8 +70,12 @@
 	uptr = alloca(usz); \
 	(void) memset(uptr, 0, usz); \
 	((nss_pheader_t *)uptr)->nsc_callnumber = (cn); \
+	((nss_pheader_t *)uptr)->p_version = NSCD_HEADER_REV; \
 	((nss_pheader_t *)uptr)->pbufsiz = usz; \
-	((nss_pheader_t *)uptr)->data_off = sizeof (nss_pheader_t);
+	((nss_pheader_t *)uptr)->data_off = sizeof (nss_pheader_t); \
+	((nss_pheader_t *)uptr)->key_off = sizeof (nss_pheader_t); \
+	((nss_pheader_t *)uptr)->dbd_off = sizeof (nss_pheader_t); \
+	((nss_pheader_t *)uptr)->data_len = dsz;
 
 #define	NSCD_N2N_DOOR_DATA(type, buf) \
 	(type *)((void *)(((char *)(buf)) + sizeof (nss_pheader_t)))
--- a/usr/src/cmd/nscd/nscd_frontend.c	Mon Apr 30 16:52:44 2007 -0700
+++ b/usr/src/cmd/nscd/nscd_frontend.c	Mon Apr 30 17:48:25 2007 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -377,6 +377,261 @@
 	}
 }
 
+/* log error and return -1 when an invalid packed buffer header is found */
+static int
+pheader_error(nss_pheader_t *phdr, uint32_t call_number)
+{
+	char *call_num_str;
+
+	switch (call_number) {
+	case NSCD_SEARCH:
+		call_num_str = "NSCD_SEARCH";
+		break;
+	case NSCD_SETENT:
+		call_num_str = "NSCD_SETENT";
+		break;
+	case NSCD_GETENT:
+		call_num_str = "NSCD_GETENT";
+		break;
+	case NSCD_ENDENT:
+		call_num_str = "NSCD_ENDENT";
+		break;
+	case NSCD_PUT:
+		call_num_str = "NSCD_PUT";
+		break;
+	case NSCD_GETHINTS:
+		call_num_str = "NSCD_GETHINTS";
+		break;
+	default:
+		call_num_str = "UNKNOWN";
+		break;
+	}
+
+	_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT)
+	("pheader_error", "call number %s: invalid packed buffer header\n",
+		call_num_str);
+
+	NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL);
+	return (-1);
+}
+
+/*
+ * Validate the header of a getXbyY or setent/getent/endent request.
+ * Return 0 if good, -1 otherwise.
+ *
+ * A valid header looks like the following (size is arg_size, does
+ * not include the output area):
+ * +----------------------------------+ --
+ * | nss_pheader_t (header fixed part)| ^
+ * |                                  | |
+ * | pbufsiz, dbd,off, key_off,       | len = sizeof(nss_pheader_t)
+ * | data_off ....                    | |
+ * |                                  | v
+ * +----------------------------------+ <----- dbd_off
+ * | dbd (database description)       | ^
+ * | nss_dbd_t + up to 3 strings      | |
+ * | length = sizeof(nss_dbd_t) +     | len = key_off - dbd_off
+ * |          length of 3 strings +   | |
+ * |          length of padding       | |
+ * | (total length in multiple of 4)  | v
+ * +----------------------------------+ <----- key_off
+ * | lookup key                       | ^
+ * | nss_XbyY_key_t, content varies,  | |
+ * | based on database and lookup op  | len = data_off - key_off
+ * | length = data_off - key_off      | |
+ * | including padding, multiple of 4 | v
+ * +----------------------------------+ <----- data_off (= arg_size)
+ * |                                  | ^
+ * | area to hold results             | |
+ * |                                  | len = data_len (= pbufsiz -
+ * |                                  | |                 data_off)
+ * |                                  | v
+ * +----------------------------------+ <----- pbufsiz
+ */
+static int
+validate_pheader(
+	void		*argp,
+	size_t		arg_size,
+	uint32_t	call_number)
+{
+	nss_pheader_t	*phdr = (nss_pheader_t *)(void *)argp;
+	nssuint_t	l1, l2;
+
+	/*
+	 * current version is NSCD_HEADER_REV, length of the fixed part
+	 * of the header must match the size of nss_pheader_t
+	 */
+	if (phdr->p_version != NSCD_HEADER_REV ||
+			phdr->dbd_off != sizeof (nss_pheader_t))
+		return (pheader_error(phdr, call_number));
+
+	/*
+	 * buffer size and offsets must be in multiple of 4
+	 */
+	if ((arg_size & 3) || (phdr->dbd_off & 3) || (phdr->key_off & 3) ||
+		(phdr->data_off & 3))
+		return (pheader_error(phdr, call_number));
+
+	/*
+	 * the input arg_size is the length of the request header
+	 * and should be less than NSCD_PHDR_MAXLEN
+	 */
+	if (phdr->data_off != arg_size || arg_size > NSCD_PHDR_MAXLEN)
+		return (pheader_error(phdr, call_number));
+
+	/* get length of the dbd area */
+	l1 = phdr->key_off - phdr-> dbd_off;
+
+	/*
+	 * dbd area may contain padding, so length of dbd should
+	 * not be less than the length of the actual data
+	 */
+	if (l1 < phdr->dbd_len)
+		return (pheader_error(phdr, call_number));
+
+	/* get length of the key area */
+	l2 = phdr->data_off - phdr->key_off;
+
+	/*
+	 * key area may contain padding, so length of key area should
+	 * not be less than the length of the actual data
+	 */
+	if (l2 < phdr->key_len)
+		return (pheader_error(phdr, call_number));
+
+	/*
+	 * length of fixed part + lengths of dbd and key area = length of
+	 * the request header
+	 */
+	if (sizeof (nss_pheader_t) + l1 + l2 != phdr->data_off)
+		return (pheader_error(phdr, call_number));
+
+	/* header length + data length = buffer length */
+	if (phdr->data_off + phdr->data_len != phdr->pbufsiz)
+		return (pheader_error(phdr, call_number));
+
+	return (0);
+}
+
+/* log error and return -1 when an invalid nscd to nscd buffer is found */
+static int
+N2Nbuf_error(nss_pheader_t *phdr, uint32_t call_number)
+{
+	char *call_num_str;
+
+	switch (call_number) {
+	case NSCD_PING:
+		call_num_str = "NSCD_PING";
+		break;
+
+	case NSCD_IMHERE:
+		call_num_str = "NSCD_IMHERE";
+		break;
+
+	case NSCD_PULSE:
+		call_num_str = "NSCD_PULSE";
+		break;
+
+	case NSCD_FORK:
+		call_num_str = "NSCD_FORK";
+		break;
+
+	case NSCD_KILL:
+		call_num_str = "NSCD_KILL";
+		break;
+
+	case NSCD_REFRESH:
+		call_num_str = "NSCD_REFRESH";
+		break;
+
+	case NSCD_GETPUADMIN:
+		call_num_str = "NSCD_GETPUADMIN";
+		break;
+
+	case NSCD_GETADMIN:
+		call_num_str = "NSCD_GETADMIN";
+		break;
+
+	case NSCD_SETADMIN:
+		call_num_str = "NSCD_SETADMIN";
+		break;
+
+	case NSCD_KILLSERVER:
+		call_num_str = "NSCD_KILLSERVER";
+		break;
+	default:
+		call_num_str = "UNKNOWN";
+		break;
+	}
+
+	_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT)
+	("N2Nbuf_error", "call number %s: invalid N2N buffer\n",
+		call_num_str);
+
+	NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
+			NSCD_DOOR_BUFFER_CHECK_FAILED);
+
+	return (-1);
+}
+
+/*
+ * Validate the buffer of an nscd to nscd request.
+ * Return 0 if good, -1 otherwise.
+ *
+ * A valid buffer looks like the following (size is arg_size):
+ * +----------------------------------+ --
+ * | nss_pheader_t (header fixed part)| ^
+ * |                                  | |
+ * | pbufsiz, dbd,off, key_off,       | len = sizeof(nss_pheader_t)
+ * | data_off ....                    | |
+ * |                                  | v
+ * +----------------------------------+ <---dbd_off = key_off = data_off
+ * |                                  | ^
+ * | input data/output data           | |
+ * | OR no data                       | len = data_len (= pbufsiz -
+ * |                                  | |                 data_off)
+ * |                                  | | len could be zero
+ * |                                  | v
+ * +----------------------------------+ <--- pbufsiz
+ */
+static int
+validate_N2Nbuf(
+	void		*argp,
+	size_t		arg_size,
+	uint32_t	call_number)
+{
+	nss_pheader_t	*phdr = (nss_pheader_t *)(void *)argp;
+
+	/*
+	 * current version is NSCD_HEADER_REV, length of the fixed part
+	 * of the header must match the size of nss_pheader_t
+	 */
+	if (phdr->p_version != NSCD_HEADER_REV ||
+			phdr->dbd_off != sizeof (nss_pheader_t))
+		return (N2Nbuf_error(phdr, call_number));
+
+	/*
+	 * There are no dbd and key data, so the dbd, key, data
+	 * offsets should be equal
+	 */
+	if (phdr->dbd_off != phdr->key_off ||
+		phdr->dbd_off != phdr->data_off)
+		return (N2Nbuf_error(phdr, call_number));
+
+	/*
+	 * the input arg_size is the buffer length and should
+	 * be less or equal than NSCD_N2NBUF_MAXLEN
+	 */
+	if (phdr->pbufsiz != arg_size || arg_size > NSCD_N2NBUF_MAXLEN)
+		return (N2Nbuf_error(phdr, call_number));
+
+	/* header length + data length = buffer length */
+	if (phdr->data_off + phdr->data_len != phdr->pbufsiz)
+		return (N2Nbuf_error(phdr, call_number));
+
+	return (0);
+}
+
 static void
 lookup(char *argp, size_t arg_size)
 {
@@ -387,6 +642,12 @@
 	NSCD_ALLOC_LOOKUP_BUFFER(argp, arg_size, phdr, space,
 		sizeof (space));
 
+	/*
+	 * make sure the first couple bytes of the data area is null,
+	 * so that bad strings in the packed header stop here
+	 */
+	(void) memset((char *)phdr + phdr->data_off, 0, 16);
+
 	(void) memset(&largs, 0, sizeof (largs));
 	largs.buffer = argp;
 	largs.bufsize = arg_size;
@@ -506,7 +767,8 @@
 	int		door = -1;
 	int		rc = 0;
 	door_desc_t	desc;
-	char		space[1024*4];
+	char		*space;
+	int		len;
 
 	/*
 	 * check to see if self-cred is configured and
@@ -540,17 +802,16 @@
 	}
 
 	/* return the alternate door descriptor */
-	(void) memcpy(space, phdr, NSCD_PHDR_LEN(phdr));
-	argp = space;
-	phdr = (nss_pheader_t *)(void *)space;
+	len = strlen(dblist) + 1;
+	space = alloca(arg_size + len);
+	phdr->data_len = len;
+	(void) memcpy(space, phdr, arg_size);
+	(void) strncpy((char *)space + arg_size, dblist, len);
 	dp = &desc;
 	dp->d_attributes = DOOR_DESCRIPTOR;
 	dp->d_data.d_desc.d_descriptor = door;
-	phdr->data_len = strlen(dblist) + 1;
-	(void) strcpy(((char *)phdr) + NSCD_PHDR_LEN(phdr), dblist);
-
-	arg_size = NSCD_PHDR_LEN(phdr) + NSCD_DATA_LEN(phdr);
-	(void) door_return(argp, arg_size, dp, 1);
+	arg_size += len;
+	(void) door_return(space, arg_size, dp, 1);
 }
 
 /*ARGSUSED*/
@@ -562,7 +823,8 @@
 	pid_t			ent_pid = -1;
 	nss_pheader_t		*phdr = (nss_pheader_t *)((void *)argp);
 	void			*uptr;
-	int			buflen, len;
+	int			len;
+	size_t			buflen;
 	int			callnum;
 	char			*me = "switcher";
 
@@ -585,7 +847,14 @@
 		restart_if_cfgfile_changed();
 
 	if ((phdr->nsc_callnumber & NSCDV2CATMASK) == NSCD_CALLCAT_APP) {
+
+		/* make sure the packed buffer header is good */
+		if (validate_pheader(argp, arg_size,
+				phdr->nsc_callnumber) == -1)
+			(void) door_return(argp, arg_size, NULL, 0);
+
 		switch (phdr->nsc_callnumber) {
+
 		case NSCD_SEARCH:
 
 		/* if a fallback to main nscd, skip per-user setup */
@@ -655,6 +924,11 @@
 		callnum = phdr->nsc_callnumber;
 
 	/* nscd -> nscd v2 calls */
+
+	/* make sure the buffer is good */
+	if (validate_N2Nbuf(argp, arg_size, callnum) == -1)
+		(void) door_return(argp, arg_size, NULL, 0);
+
 	switch (callnum) {
 
 	case NSCD_PING:
@@ -684,9 +958,12 @@
 		break;
 
 	case NSCD_REFRESH:
-		if (_nscd_refresh() != NSCD_SUCCESS)
-			exit(1);
-		NSCD_SET_STATUS_SUCCESS(phdr);
+		N2N_check_priv(argp, "NSCD_REFRESH");
+		if (NSCD_STATUS_IS_OK(phdr)) {
+			if (_nscd_refresh() != NSCD_SUCCESS)
+				exit(1);
+			NSCD_SET_STATUS_SUCCESS(phdr);
+		}
 		break;
 
 	case NSCD_GETPUADMIN:
--- a/usr/src/cmd/nscd/nscd_frontend.h	Mon Apr 30 16:52:44 2007 -0700
+++ b/usr/src/cmd/nscd/nscd_frontend.h	Mon Apr 30 17:48:25 2007 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -34,6 +34,8 @@
 
 #include "cache.h"
 
+#define	NSCD_N2NBUF_MAXLEN	1024 * 8
+#define	NSCD_PHDR_MAXLEN	1024 * 8
 #define	NSCD_LOOKUP_BUFSIZE	1024 * 16
 #define	NSCD_DOORBUF_MAXLEN	1024 * 512
 #define	NSCD_PHDR_LEN(hdrp)	((hdrp)->data_off)
@@ -45,6 +47,8 @@
 		bufp = space; \
 		bufsiz = spsiz; \
 		hdrp = (nss_pheader_t *)(void *)space; \
+		(hdrp)->pbufsiz = bufsiz; \
+		(hdrp)->data_len = bufsiz - (hdrp)->data_off; \
 	} else { \
 		(bufp) = NULL; \
 		bufsiz = (hdrp)->pbufsiz; \
@@ -54,6 +58,8 @@
 		if ((bufp) != NULL) { \
 			(void) memcpy((bufp), (hdrp), NSCD_PHDR_LEN(hdrp)); \
 			(hdrp) = (nss_pheader_t *)(void *)(bufp); \
+			(hdrp)->pbufsiz = bufsiz; \
+			(hdrp)->data_len = bufsiz - (hdrp)->data_off; \
 		} else { \
 			NSCD_SET_STATUS((hdrp), NSS_ERROR, ENOMEM); \
 			(void) door_return((char *)(hdrp), \
--- a/usr/src/lib/libc/port/gen/getxby_door.c	Mon Apr 30 16:52:44 2007 -0700
+++ b/usr/src/lib/libc/port/gen/getxby_door.c	Mon Apr 30 17:48:25 2007 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -43,6 +43,7 @@
 #include <sys/door.h>
 #include <procfs.h>
 #include <door.h>
+#include <sys/mman.h>
 #include "libc.h"
 #include "tsd.h"
 #include "base_conversion.h"
@@ -418,11 +419,20 @@
 	nss_dbd_t	*dbd;
 	int		fb2frontd = 0;
 	int		reset_frontd = 0;
+	size_t		ndata_save = *ndata, adata_save = *adata;
+	void		*dptr_save = *dptr;
 
 	ph = (nss_pheader_t *)*dptr;
 	dbd = (nss_dbd_t *)((void *)((char *)ph + ph->dbd_off));
 	if (dbd->o_name != 0)
 		db = (char *)dbd + dbd->o_name;
+
+	/*
+	 * save away a copy of the header, in case the request needs
+	 * to be sent to nscd more than once. In that case, this
+	 * original header can be copied back to the door buffer
+	 * to replace the possibly changed header
+	 */
 	ph_save = *ph;
 
 	while (ret == NSS_ALTRETRY || ret == NSS_ALTRESET) {
@@ -449,6 +459,18 @@
 				 * fall back and retry on front door
 				 */
 				fb2frontd = 1;
+				if (*dptr != dptr_save)
+					(void) munmap((void *)*dptr, *ndata);
+
+				/*
+				 * restore the buffer size and header
+				 * data so that the front door will
+				 * see the original request
+				 */
+				*ndata = ndata_save;
+				*adata = adata_save;
+				*dptr = dptr_save;
+				ph =  (nss_pheader_t *)*dptr;
 				*ph = ph_save;
 				/*
 				 * tell the front door server, this is
@@ -538,6 +560,18 @@
 		(void) fcntl(backd->doorfd, F_SETFD, FD_CLOEXEC);
 		lmutex_unlock(&backd->door_lock);
 		/* NSS_ALTRETRY new back door */
+		if (*dptr != dptr_save)
+			(void) munmap((void *)*dptr, *ndata);
+
+		/*
+		 * restore the buffer size and header
+		 * data so that the back door will
+		 * see the original request
+		 */
+		*ndata = ndata_save;
+		*adata = adata_save;
+		*dptr = dptr_save;
+		ph =  (nss_pheader_t *)*dptr;
 		*ph = ph_save;
 	}
 	return (ret);
--- a/usr/src/lib/libc/port/gen/nss_dbdefs.c	Mon Apr 30 16:52:44 2007 -0700
+++ b/usr/src/lib/libc/port/gen/nss_dbdefs.c	Mon Apr 30 17:48:25 2007 -0700
@@ -864,7 +864,7 @@
 {
 	nss_pheader_t 			*pbuf = (nss_pheader_t *)buffer;
 	const char			*strtype = NULL;
-	nssuint_t 			off, *uptr;
+	nssuint_t 			off, *uptr, keysize;
 	size_t				len, slop;
 	int				i, j;
 	char				**cv, *bptr;
@@ -874,6 +874,9 @@
 	nss_pnetgr_t			*pptr;
 	_priv_execattr			*pe;
 
+	/* keysize is length of the key area */
+	keysize = pbuf->data_off - pbuf->key_off;
+
 	off = pbuf->key_off;
 	bptr = (char *)buffer + off;
 	uptr = (nssuint_t *)((void *)bptr);
@@ -1014,11 +1017,15 @@
 			for (j = 0; j < NSS_NETGR_N; j++) {
 				ing->arg[j].argv = cv;
 				for (i = 0; i < ing->arg[j].argc; i++) {
+					if (*uptr >= keysize)
+						return (NSS_ERROR);
 					*cv++ = (bptr + *uptr++);
 				}
 			}
 			ing->groups.argv = cv;
 			for (i = 0; i < ing->groups.argc; i++) {
+				if (*uptr >= keysize)
+					return (NSS_ERROR);
 				*cv++ = (bptr + *uptr++);
 			}
 			break;
@@ -1110,7 +1117,7 @@
 {
 	nss_pheader_t 	*pbuf = (nss_pheader_t *)buffer;
 	nss_dbd_t	*pdbd;
-	nssuint_t 	off;
+	nssuint_t 	off, dbdsize;
 	int		index;
 
 	if (buffer == NULL || length == 0 || dbop == NULL ||
@@ -1120,6 +1127,10 @@
 	*dbop = pbuf->nss_dbop;
 	off = pbuf->dbd_off;
 	pdbd = (nss_dbd_t *)((void *)((char *)buffer + off));
+	dbdsize = pbuf->key_off - pbuf->dbd_off;
+	if (pdbd->o_name >= dbdsize || pdbd->o_config_name >= dbdsize ||
+			pdbd->o_default_config >= dbdsize)
+		return (NSS_ERROR);
 	*dbname = (char *)buffer + off + pdbd->o_name;
 	if ((index = nss_dbop_search(*dbname, (uint32_t)*dbop)) < 0)
 		return (NSS_ERROR);
@@ -1169,7 +1180,7 @@
 	nss_str2ent_t		s2e = str2packent;
 	nss_str2ent_t		real_s2e = NULL;
 	nss_dbd_t		*pdbd;
-	nssuint_t 		off;
+	nssuint_t		off, dbdsize;
 	char			*dbname, *bptr;
 	size_t			len;
 	int			index;
@@ -1182,6 +1193,10 @@
 	*dbop = pbuf->nss_dbop;
 	off = pbuf->dbd_off;
 	pdbd = (nss_dbd_t *)((void *)((char *)buffer + off));
+	dbdsize = pbuf->key_off - pbuf->dbd_off;
+	if (pdbd->o_name >= dbdsize || pdbd->o_config_name >= dbdsize ||
+			pdbd->o_default_config >= dbdsize)
+		return (NSS_ERROR);
 	dbname = (char *)buffer + off + pdbd->o_name;
 	if ((index = nss_dbop_search(dbname, (uint32_t)*dbop)) < 0)
 		return (NSS_ERROR);