summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormichen <none@none>2007-04-30 17:48:25 -0700
committermichen <none@none>2007-04-30 17:48:25 -0700
commit606f6aa3d37f0f8e8282e483c1400bae5275aeeb (patch)
treefc38185db3e98a44b67a3c8753ee0064ed7e5398
parent59f2ff5c96304fcfa3d97e66fbe1c521f42ac103 (diff)
downloadillumos-gate-onnv_64.tar.gz
6548196 Multiple memory corruption vulnerabilities in nscd(1M)onnv_64
-rw-r--r--usr/src/cmd/nscd/cache.c8
-rw-r--r--usr/src/cmd/nscd/nscd_common.h3
-rw-r--r--usr/src/cmd/nscd/nscd_door.c19
-rw-r--r--usr/src/cmd/nscd/nscd_door.h8
-rw-r--r--usr/src/cmd/nscd/nscd_frontend.c305
-rw-r--r--usr/src/cmd/nscd/nscd_frontend.h8
-rw-r--r--usr/src/lib/libc/port/gen/getxby_door.c36
-rw-r--r--usr/src/lib/libc/port/gen/nss_dbdefs.c21
8 files changed, 377 insertions, 31 deletions
diff --git a/usr/src/cmd/nscd/cache.c b/usr/src/cmd/nscd/cache.c
index 65bdd85db3..f7abb08d58 100644
--- a/usr/src/cmd/nscd/cache.c
+++ b/usr/src/cmd/nscd/cache.c
@@ -1748,7 +1748,13 @@ nsc_lookup(nsc_lookup_args_t *largs, int flag) {
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:
diff --git a/usr/src/cmd/nscd/nscd_common.h b/usr/src/cmd/nscd/nscd_common.h
index 8d7de7478c..f45ce07f07 100644
--- a/usr/src/cmd/nscd/nscd_common.h
+++ b/usr/src/cmd/nscd/nscd_common.h
@@ -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 @@ typedef enum {
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,
diff --git a/usr/src/cmd/nscd/nscd_door.c b/usr/src/cmd/nscd/nscd_door.c
index 87640baf02..dc43c9c92f 100644
--- a/usr/src/cmd/nscd/nscd_door.c
+++ b/usr/src/cmd/nscd/nscd_door.c
@@ -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 @@ copy_output(void *outdata, int outdlen,
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_doorcall(int callnum)
_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)
diff --git a/usr/src/cmd/nscd/nscd_door.h b/usr/src/cmd/nscd/nscd_door.h
index 382968f5e1..102cc65f26 100644
--- a/usr/src/cmd/nscd/nscd_door.h
+++ b/usr/src/cmd/nscd/nscd_door.h
@@ -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 @@ extern "C" {
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)))
diff --git a/usr/src/cmd/nscd/nscd_frontend.c b/usr/src/cmd/nscd/nscd_frontend.c
index fe42fecb90..02b081db58 100644
--- a/usr/src/cmd/nscd/nscd_frontend.c
+++ b/usr/src/cmd/nscd/nscd_frontend.c
@@ -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 @@ _nscd_APP_check_cred(
}
}
+/* 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 @@ lookup(char *argp, size_t arg_size)
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 @@ if_selfcred_return_per_user_door(char *argp, size_t arg_size,
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 @@ if_selfcred_return_per_user_door(char *argp, size_t arg_size,
}
/* 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 @@ switcher(void *cookie, char *argp, size_t arg_size,
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 @@ switcher(void *cookie, char *argp, size_t arg_size,
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 @@ switcher(void *cookie, char *argp, size_t arg_size,
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 @@ switcher(void *cookie, char *argp, size_t arg_size,
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:
diff --git a/usr/src/cmd/nscd/nscd_frontend.h b/usr/src/cmd/nscd/nscd_frontend.h
index e917db99bd..48da7c37e3 100644
--- a/usr/src/cmd/nscd/nscd_frontend.h
+++ b/usr/src/cmd/nscd/nscd_frontend.h
@@ -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 @@ extern "C" {
#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 @@ extern "C" {
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 @@ extern "C" {
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), \
diff --git a/usr/src/lib/libc/port/gen/getxby_door.c b/usr/src/lib/libc/port/gen/getxby_door.c
index e659ed9dcb..3d1768baca 100644
--- a/usr/src/lib/libc/port/gen/getxby_door.c
+++ b/usr/src/lib/libc/port/gen/getxby_door.c
@@ -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 @@ _nsc_trydoorcall_ext(void **dptr, size_t *ndata, size_t *adata)
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 @@ _nsc_trydoorcall_ext(void **dptr, size_t *ndata, size_t *adata)
* 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 @@ _nsc_trydoorcall_ext(void **dptr, size_t *ndata, size_t *adata)
(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);
diff --git a/usr/src/lib/libc/port/gen/nss_dbdefs.c b/usr/src/lib/libc/port/gen/nss_dbdefs.c
index 22f8d1bc98..f8ef2e93d1 100644
--- a/usr/src/lib/libc/port/gen/nss_dbdefs.c
+++ b/usr/src/lib/libc/port/gen/nss_dbdefs.c
@@ -864,7 +864,7 @@ nss_upack_key2arg(void *buffer, size_t length, char **dbname,
{
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_upack_key2arg(void *buffer, size_t length, char **dbname,
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 @@ nss_upack_key2arg(void *buffer, size_t length, char **dbname,
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_packed_getkey(void *buffer, size_t length, char **dbname,
{
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 @@ nss_packed_getkey(void *buffer, size_t length, char **dbname,
*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_packed_arg_init(void *buffer, size_t length, nss_db_root_t *db_root,
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 @@ nss_packed_arg_init(void *buffer, size_t length, nss_db_root_t *db_root,
*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);