From 446851c8615721294b2265cddc36007ae450e916 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 30 Nov 2016 09:23:52 -0800 Subject: librpc: cab: Fix ndr_size_cab_file() to detect integer wrap. Signed-off-by: Jeremy Allison Reviewed-by: Andreas Schneider Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Thu Dec 1 05:53:43 CET 2016 on sn-devel-144 --- librpc/ndr/ndr_cab.c | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/librpc/ndr/ndr_cab.c b/librpc/ndr/ndr_cab.c index d5ab87fb0af..ae95bf45b3b 100644 --- a/librpc/ndr/ndr_cab.c +++ b/librpc/ndr/ndr_cab.c @@ -116,7 +116,7 @@ uint32_t ndr_cab_generate_checksum(const struct CFDATA *r) csumPartial); } -static uint32_t ndr_size_cab_file(const struct cab_file *r) +static bool ndr_size_cab_file(const struct cab_file *r, uint32_t *psize) { uint32_t size = 0; int i; @@ -126,20 +126,39 @@ static uint32_t ndr_size_cab_file(const struct cab_file *r) /* folder */ for (i = 0; i < r->cfheader.cFolders; i++) { + if (size + 8 < size) { + /* Integer wrap. */ + return false; + } size += 8; } /* files */ for (i = 0; i < r->cfheader.cFiles; i++) { - size += ndr_size_CFFILE(&r->cffiles[i], 0); + uint32_t cfsize = ndr_size_CFFILE(&r->cffiles[i], 0); + if (size + cfsize < size) { + /* Integer wrap. */ + return false; + } + size += cfsize; } /* data */ for (i = 0; i < ndr_count_cfdata(r); i++) { - size += 8 + r->cfdata[i].cbData; + if (size + 8 < size) { + /* Integer wrap. */ + return false; + } + size += 8; + if (size + r->cfdata[i].cbData < size) { + /* Integer wrap. */ + return false; + } + size += r->cfdata[i].cbData; } - return size; + *psize = size; + return true; } enum cf_compress_type ndr_cab_get_compression(const struct cab_file *r) @@ -156,6 +175,7 @@ _PUBLIC_ enum ndr_err_code ndr_push_cab_file(struct ndr_push *ndr, int ndr_flags uint32_t cntr_cffolders_0; uint32_t cntr_cffiles_0; uint32_t cntr_cfdata_0; + uint32_t cab_size = 0; { uint32_t _flags_save_STRUCT = ndr->flags; ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX|LIBNDR_FLAG_LITTLE_ENDIAN|LIBNDR_FLAG_NOALIGN); @@ -188,7 +208,10 @@ _PUBLIC_ enum ndr_err_code ndr_push_cab_file(struct ndr_push *ndr, int ndr_flags ndr->flags = _flags_save_STRUCT; } - SIVAL(ndr->data, 8, ndr_size_cab_file(r)); + if (ndr_size_cab_file(r, &cab_size) == false) { + return NDR_ERR_VALIDATE; + } + SIVAL(ndr->data, 8, cab_size); return NDR_ERR_SUCCESS; } -- cgit v1.2.1