librpc: cab: Fix ndr_size_cab_file() to detect integer wrap.
authorJeremy Allison <jra@samba.org>
Wed, 30 Nov 2016 17:23:52 +0000 (09:23 -0800)
committerJeremy Allison <jra@samba.org>
Thu, 1 Dec 2016 04:53:43 +0000 (05:53 +0100)
Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
Autobuild-User(master): Jeremy Allison <jra@samba.org>
Autobuild-Date(master): Thu Dec  1 05:53:43 CET 2016 on sn-devel-144

librpc/ndr/ndr_cab.c

index d5ab87fb0afde39711ee60953a2956145adabaac..ae95bf45b3b48601bdcb2a6eddf28db0ca4e1201 100644 (file)
@@ -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;
 }