Shriganesh Shintre
2013-Mar-20 23:33 UTC
xen libxc - xen domain loader issues with handling large size domU ramdisk / kernel images
This is not directly related to xsa-25 (http://wiki.xen.org/wiki/Security_Announcements#XSA_25_Xen_domain_builder_Out-of-memory_due_to_malicious_kernel.2Framdisk), but I found it while applying xsa-25 patch to xen. Please comment on my suggestions and correct me if I am wrong. file: xen-4.1.2/tools/libxc/xc_dom_core.c function: xc_dom_check_gzip() The function returns ''0'' if unzip length of the kernel / ramdisk image is invalid (greater than max allowed), pretending it as NOT gzipped image. This causes the domain builder to proceed with large kernel / ramdisk, which may cause dom0 going out-of-memory. Also one could make a small gzip that unpacks to something big. So small gzipped file will pass the size test and xen will try to load the kernel / ramdisk. My suggestion here is to return ''unziplen'' if (unziplen > max allowed), as further checks (xc_dom_kernel_check_size/xc_dom_ramdisk_check_size) are added by xsa-25 which will make domain loader to quit before loading large files. (please find the code below for reference) Also I am not sure why size_t data type is checked for negative value. The check (unziplen < 0) will always return false as size_t is unsigned. size_t xc_dom_check_gzip(xc_interface *xch, void *blob, size_t ziplen) { unsigned char *gzlen; size_t unziplen; if ( strncmp(blob, "\037\213", 2) ) /* not gzipped */ return 0; gzlen = blob + ziplen - 4; unziplen = gzlen[3] << 24 | gzlen[2] << 16 | gzlen[1] << 8 | gzlen[0]; if ( (unziplen < 0) || (unziplen > XC_DOM_DECOMPRESS_MAX) ) { xc_dom_printf (xch, "%s: size (zip %zd, unzip %zd) looks insane, skip gunzip", __FUNCTION__, ziplen, unziplen); return 0; // instead of zero it should return ''unziplen'' } return unziplen + 16; } The second point is related to xsa-25. After applying xsa-25 patch, in function ''xc_dom_build_image()'' the code checks for ramdisk file size, and if the un-gzipped file size is invalid (greater than max allowed) it assumes the unziplen = 0. It again pretends that the file is not gzipped and proceeds to load domU. The domain loader proceeds further with original ramdisk file size and it may make dom0 out-of-memory. Please find the code below for reference. int xc_dom_build_image(struct xc_dom_image *dom) { ... ... unziplen = xc_dom_check_gzip(dom->xch, dom->ramdisk_blob, dom->ramdisk_size); if ( xc_dom_ramdisk_check_size(dom, unziplen) != 0 ) unziplen = 0; // here instead of unziplen = 0, it should print error, cleanup and return (goto err;) ramdisklen = unziplen ? unziplen : dom->ramdisk_size; .... .... } Thank you. ~Shri
Jan Beulich
2013-Mar-21 09:43 UTC
Re: xen libxc - xen domain loader issues with handling large size domU ramdisk / kernel images
>>> On 21.03.13 at 00:33, Shriganesh Shintre <shriganeshs@gmail.com> wrote: > This is not directly related to xsa-25 > (http://wiki.xen.org/wiki/Security_Announcements#XSA_25_Xen_domain_builder_O > ut-of-memory_due_to_malicious_kernel.2Framdisk), > but I found it while applying xsa-25 patch to xen. Please comment on > my suggestions and correct me if I am wrong. > > file: xen-4.1.2/tools/libxc/xc_dom_core.c > function: xc_dom_check_gzip() > The function returns ''0'' if unzip length of the kernel / ramdisk image > is invalid (greater than max allowed), pretending it as NOT gzipped > image. This causes the domain builder to proceed with large kernel / > ramdisk, which may cause dom0 going out-of-memory.How? The (apparently or truly) uncompressed image is already in memory at this point.> Also one could make > a small gzip that unpacks to something big. So small gzipped file will > pass the size test and xen will try to load the kernel / ramdisk.But you just above correctly said that it''s the decompressed length that is being range checked.> My suggestion here is to return ''unziplen'' if (unziplen > max > allowed), as further checks > (xc_dom_kernel_check_size/xc_dom_ramdisk_check_size) are added by > xsa-25 which will make domain loader to quit before loading large > files. (please find the code below for reference) > Also I am not sure why size_t data type is checked for negative value. > The check (unziplen < 0) will always return false as size_t is > unsigned.This is certainly bogus, but benign, as the check on the right hand side of || will automatically take care of that situation.> The second point is related to xsa-25. After applying xsa-25 patch, in > function ''xc_dom_build_image()'' the code checks for ramdisk file size, > and if the un-gzipped file size is invalid (greater than max allowed) > it assumes the unziplen = 0. It again pretends that the file is not > gzipped and proceeds to load domU. The domain loader proceeds further > with original ramdisk file size and it may make dom0 out-of-memory.Once again - how? The image - again - is already in memory. You may want to note that internally to libxc there''s no caller of xc_linux_build_mem() (i.e. eventual range checks on the memory blocks passed to this function would need to be done by the caller anyway), and all other functions in xc_dom_compat_linux.c end up using mmap() (i.e. don''t have real potential for driving Dom0 out of memory). Jan