diff options
| author | Paul Eggert | 2011-07-13 23:20:53 -0700 |
|---|---|---|
| committer | Paul Eggert | 2011-07-13 23:20:53 -0700 |
| commit | ca4aa9359160557f8103639fc3c0ccb16c6ba8d2 (patch) | |
| tree | 5b939640079b6fe042c9509fb0d03bb72495aa2a /src | |
| parent | 5f8f9cc26998b1b74d9ac5c8b68000d53aae31cc (diff) | |
| download | emacs-ca4aa9359160557f8103639fc3c0ccb16c6ba8d2.tar.gz emacs-ca4aa9359160557f8103639fc3c0ccb16c6ba8d2.zip | |
* image.c: Improve checking for integer overflow.
(check_image_size): Assume that f is nonnull, since
it is always nonnull in practice. This is one less thing to
worry about when checking for integer overflow later.
(x_check_image_size): New function, which checks for integer
overflow issues inside X.
(x_create_x_image_and_pixmap, xbm_read_bitmap_data): Use it.
This removes the need for a memory_full check.
(xbm_image_p): Rewrite to avoid integer multiplication overflow.
(Create_Pixmap_From_Bitmap_Data, xbm_load): Use x_check_image_size.
(xbm_read_bitmap_data): Change locals back to 'int', since
their values must fit in 'int'.
(xpm_load_image, png_load, tiff_load):
Invoke x_create_x_image_and_pixmap earlier,
to avoid much needless work if the image is too large.
(tiff_load): Treat overly large images as if
x_create_x_image_and_pixmap failed, not as malloc failures.
(gs_load): Use x_check_image_size.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 21 | ||||
| -rw-r--r-- | src/image.c | 160 |
2 files changed, 129 insertions, 52 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index c986030fcf8..e07b906b56d 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,24 @@ | |||
| 1 | 2011-07-14 Paul Eggert <eggert@cs.ucla.edu> | ||
| 2 | |||
| 3 | * image.c: Improve checking for integer overflow. | ||
| 4 | (check_image_size): Assume that f is nonnull, since | ||
| 5 | it is always nonnull in practice. This is one less thing to | ||
| 6 | worry about when checking for integer overflow later. | ||
| 7 | (x_check_image_size): New function, which checks for integer | ||
| 8 | overflow issues inside X. | ||
| 9 | (x_create_x_image_and_pixmap, xbm_read_bitmap_data): Use it. | ||
| 10 | This removes the need for a memory_full check. | ||
| 11 | (xbm_image_p): Rewrite to avoid integer multiplication overflow. | ||
| 12 | (Create_Pixmap_From_Bitmap_Data, xbm_load): Use x_check_image_size. | ||
| 13 | (xbm_read_bitmap_data): Change locals back to 'int', since | ||
| 14 | their values must fit in 'int'. | ||
| 15 | (xpm_load_image, png_load, tiff_load): | ||
| 16 | Invoke x_create_x_image_and_pixmap earlier, | ||
| 17 | to avoid much needless work if the image is too large. | ||
| 18 | (tiff_load): Treat overly large images as if | ||
| 19 | x_create_x_image_and_pixmap failed, not as malloc failures. | ||
| 20 | (gs_load): Use x_check_image_size. | ||
| 21 | |||
| 1 | 2011-07-13 Paul Eggert <eggert@cs.ucla.edu> | 22 | 2011-07-13 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 23 | ||
| 3 | * gtkutil.c: Omit integer casts. | 24 | * gtkutil.c: Omit integer casts. |
diff --git a/src/image.c b/src/image.c index 1b6e67b4404..7a5ac40b3d2 100644 --- a/src/image.c +++ b/src/image.c | |||
| @@ -1053,13 +1053,9 @@ check_image_size (struct frame *f, int width, int height) | |||
| 1053 | && height <= XINT (Vmax_image_size)); | 1053 | && height <= XINT (Vmax_image_size)); |
| 1054 | else if (FLOATP (Vmax_image_size)) | 1054 | else if (FLOATP (Vmax_image_size)) |
| 1055 | { | 1055 | { |
| 1056 | if (f != NULL) | 1056 | xassert (f); |
| 1057 | { | 1057 | w = FRAME_PIXEL_WIDTH (f); |
| 1058 | w = FRAME_PIXEL_WIDTH (f); | 1058 | h = FRAME_PIXEL_HEIGHT (f); |
| 1059 | h = FRAME_PIXEL_HEIGHT (f); | ||
| 1060 | } | ||
| 1061 | else | ||
| 1062 | w = h = 1024; /* Arbitrary size for unknown frame. */ | ||
| 1063 | return (width <= XFLOAT_DATA (Vmax_image_size) * w | 1059 | return (width <= XFLOAT_DATA (Vmax_image_size) * w |
| 1064 | && height <= XFLOAT_DATA (Vmax_image_size) * h); | 1060 | && height <= XFLOAT_DATA (Vmax_image_size) * h); |
| 1065 | } | 1061 | } |
| @@ -1910,6 +1906,38 @@ static int x_create_x_image_and_pixmap (struct frame *, int, int, int, | |||
| 1910 | static void x_destroy_x_image (XImagePtr); | 1906 | static void x_destroy_x_image (XImagePtr); |
| 1911 | static void x_put_x_image (struct frame *, XImagePtr, Pixmap, int, int); | 1907 | static void x_put_x_image (struct frame *, XImagePtr, Pixmap, int, int); |
| 1912 | 1908 | ||
| 1909 | /* Return nonzero if XIMG's size WIDTH x HEIGHT doesn't break X. | ||
| 1910 | WIDTH and HEIGHT must both be positive. | ||
| 1911 | If XIMG is null, assume it is a bitmap. */ | ||
| 1912 | static int | ||
| 1913 | x_check_image_size (XImagePtr ximg, int width, int height) | ||
| 1914 | { | ||
| 1915 | /* Respect Xlib's limits: it cannot deal with images that have more | ||
| 1916 | than INT_MAX (and/or UINT_MAX) bytes. And respect Emacs's limits | ||
| 1917 | of PTRDIFF_MAX (and/or SIZE_MAX) bytes for any object. For now, | ||
| 1918 | assume all windowing systems have the same limits that X does. */ | ||
| 1919 | enum | ||
| 1920 | { | ||
| 1921 | XLIB_BYTES_MAX = min (INT_MAX, UINT_MAX), | ||
| 1922 | X_IMAGE_BYTES_MAX = min (XLIB_BYTES_MAX, min (PTRDIFF_MAX, SIZE_MAX)) | ||
| 1923 | }; | ||
| 1924 | |||
| 1925 | int bitmap_pad, depth, bytes_per_line; | ||
| 1926 | if (ximg) | ||
| 1927 | { | ||
| 1928 | bitmap_pad = ximg->bitmap_pad; | ||
| 1929 | depth = ximg->depth; | ||
| 1930 | bytes_per_line = ximg->bytes_per_line; | ||
| 1931 | } | ||
| 1932 | else | ||
| 1933 | { | ||
| 1934 | bitmap_pad = 8; | ||
| 1935 | depth = 1; | ||
| 1936 | bytes_per_line = (width >> 3) + ((width & 7) != 0); | ||
| 1937 | } | ||
| 1938 | return (width <= (INT_MAX - (bitmap_pad - 1)) / depth | ||
| 1939 | && height <= X_IMAGE_BYTES_MAX / bytes_per_line); | ||
| 1940 | } | ||
| 1913 | 1941 | ||
| 1914 | /* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on | 1942 | /* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on |
| 1915 | frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created. | 1943 | frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created. |
| @@ -1942,9 +1970,16 @@ x_create_x_image_and_pixmap (struct frame *f, int width, int height, int depth, | |||
| 1942 | return 0; | 1970 | return 0; |
| 1943 | } | 1971 | } |
| 1944 | 1972 | ||
| 1973 | if (! x_check_image_size (*ximg, width, height)) | ||
| 1974 | { | ||
| 1975 | x_destroy_x_image (*ximg); | ||
| 1976 | *ximg = NULL; | ||
| 1977 | image_error ("Image too large (%dx%d)", | ||
| 1978 | make_number (width), make_number (height)); | ||
| 1979 | return 0; | ||
| 1980 | } | ||
| 1981 | |||
| 1945 | /* Allocate image raster. */ | 1982 | /* Allocate image raster. */ |
| 1946 | if (min (PTRDIFF_MAX, SIZE_MAX) / height < (*ximg)->bytes_per_line) | ||
| 1947 | memory_full (SIZE_MAX); | ||
| 1948 | (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height); | 1983 | (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height); |
| 1949 | 1984 | ||
| 1950 | /* Allocate a pixmap of the same size. */ | 1985 | /* Allocate a pixmap of the same size. */ |
| @@ -2361,7 +2396,7 @@ xbm_image_p (Lisp_Object object) | |||
| 2361 | } | 2396 | } |
| 2362 | else if (BOOL_VECTOR_P (data)) | 2397 | else if (BOOL_VECTOR_P (data)) |
| 2363 | { | 2398 | { |
| 2364 | if (XBOOL_VECTOR (data)->size < width * height) | 2399 | if (XBOOL_VECTOR (data)->size / height < width) |
| 2365 | return 0; | 2400 | return 0; |
| 2366 | } | 2401 | } |
| 2367 | else | 2402 | else |
| @@ -2557,13 +2592,15 @@ Create_Pixmap_From_Bitmap_Data (struct frame *f, struct image *img, char *data, | |||
| 2557 | img->pixmap = ns_image_from_XBM (data, img->width, img->height); | 2592 | img->pixmap = ns_image_from_XBM (data, img->width, img->height); |
| 2558 | 2593 | ||
| 2559 | #else | 2594 | #else |
| 2560 | img->pixmap | 2595 | img->pixmap = |
| 2561 | = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f), | 2596 | (x_check_image_size (0, img->width, img->height) |
| 2597 | ? XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f), | ||
| 2562 | FRAME_X_WINDOW (f), | 2598 | FRAME_X_WINDOW (f), |
| 2563 | data, | 2599 | data, |
| 2564 | img->width, img->height, | 2600 | img->width, img->height, |
| 2565 | fg, bg, | 2601 | fg, bg, |
| 2566 | DefaultDepthOfScreen (FRAME_X_SCREEN (f))); | 2602 | DefaultDepthOfScreen (FRAME_X_SCREEN (f))) |
| 2603 | : NO_PIXMAP); | ||
| 2567 | #endif /* !HAVE_NTGUI && !HAVE_NS */ | 2604 | #endif /* !HAVE_NTGUI && !HAVE_NS */ |
| 2568 | } | 2605 | } |
| 2569 | 2606 | ||
| @@ -2587,8 +2624,7 @@ xbm_read_bitmap_data (struct frame *f, unsigned char *contents, unsigned char *e | |||
| 2587 | char buffer[BUFSIZ]; | 2624 | char buffer[BUFSIZ]; |
| 2588 | int padding_p = 0; | 2625 | int padding_p = 0; |
| 2589 | int v10 = 0; | 2626 | int v10 = 0; |
| 2590 | int bytes_per_line; | 2627 | int bytes_per_line, i, nbytes; |
| 2591 | ptrdiff_t i, nbytes; | ||
| 2592 | char *p; | 2628 | char *p; |
| 2593 | int value; | 2629 | int value; |
| 2594 | int LA1; | 2630 | int LA1; |
| @@ -2671,9 +2707,14 @@ xbm_read_bitmap_data (struct frame *f, unsigned char *contents, unsigned char *e | |||
| 2671 | expect ('='); | 2707 | expect ('='); |
| 2672 | expect ('{'); | 2708 | expect ('{'); |
| 2673 | 2709 | ||
| 2710 | if (! x_check_image_size (0, *width, *height)) | ||
| 2711 | { | ||
| 2712 | if (!inhibit_image_error) | ||
| 2713 | image_error ("Image too large (%dx%d)", | ||
| 2714 | make_number (*width), make_number (*height)); | ||
| 2715 | goto failure; | ||
| 2716 | } | ||
| 2674 | bytes_per_line = (*width + 7) / 8 + padding_p; | 2717 | bytes_per_line = (*width + 7) / 8 + padding_p; |
| 2675 | if (min (PTRDIFF_MAX - 1, SIZE_MAX) / *height < bytes_per_line) | ||
| 2676 | memory_full (SIZE_MAX); | ||
| 2677 | nbytes = bytes_per_line * *height; | 2718 | nbytes = bytes_per_line * *height; |
| 2678 | p = *data = (char *) xmalloc (nbytes); | 2719 | p = *data = (char *) xmalloc (nbytes); |
| 2679 | 2720 | ||
| @@ -2863,6 +2904,12 @@ xbm_load (struct frame *f, struct image *img) | |||
| 2863 | img->width = XFASTINT (fmt[XBM_WIDTH].value); | 2904 | img->width = XFASTINT (fmt[XBM_WIDTH].value); |
| 2864 | img->height = XFASTINT (fmt[XBM_HEIGHT].value); | 2905 | img->height = XFASTINT (fmt[XBM_HEIGHT].value); |
| 2865 | xassert (img->width > 0 && img->height > 0); | 2906 | xassert (img->width > 0 && img->height > 0); |
| 2907 | if (!check_image_size (f, img->width, img->height)) | ||
| 2908 | { | ||
| 2909 | image_error ("Invalid image size (see `max-image-size')", | ||
| 2910 | Qnil, Qnil); | ||
| 2911 | return 0; | ||
| 2912 | } | ||
| 2866 | } | 2913 | } |
| 2867 | 2914 | ||
| 2868 | /* Get foreground and background colors, maybe allocate colors. */ | 2915 | /* Get foreground and background colors, maybe allocate colors. */ |
| @@ -2924,9 +2971,13 @@ xbm_load (struct frame *f, struct image *img) | |||
| 2924 | #endif | 2971 | #endif |
| 2925 | /* Create the pixmap. */ | 2972 | /* Create the pixmap. */ |
| 2926 | 2973 | ||
| 2927 | Create_Pixmap_From_Bitmap_Data (f, img, bits, | 2974 | if (x_check_image_size (0, img->width, img->height)) |
| 2928 | foreground, background, | 2975 | Create_Pixmap_From_Bitmap_Data (f, img, bits, |
| 2929 | non_default_colors); | 2976 | foreground, background, |
| 2977 | non_default_colors); | ||
| 2978 | else | ||
| 2979 | img->pixmap = NO_PIXMAP; | ||
| 2980 | |||
| 2930 | if (img->pixmap) | 2981 | if (img->pixmap) |
| 2931 | success_p = 1; | 2982 | success_p = 1; |
| 2932 | else | 2983 | else |
| @@ -3844,6 +3895,18 @@ xpm_load_image (struct frame *f, | |||
| 3844 | goto failure; | 3895 | goto failure; |
| 3845 | } | 3896 | } |
| 3846 | 3897 | ||
| 3898 | if (!x_create_x_image_and_pixmap (f, width, height, 0, | ||
| 3899 | &ximg, &img->pixmap) | ||
| 3900 | #ifndef HAVE_NS | ||
| 3901 | || !x_create_x_image_and_pixmap (f, width, height, 1, | ||
| 3902 | &mask_img, &img->mask) | ||
| 3903 | #endif | ||
| 3904 | ) | ||
| 3905 | { | ||
| 3906 | image_error ("Image too large", Qnil, Qnil); | ||
| 3907 | goto failure; | ||
| 3908 | } | ||
| 3909 | |||
| 3847 | expect (','); | 3910 | expect (','); |
| 3848 | 3911 | ||
| 3849 | XSETFRAME (frame, f); | 3912 | XSETFRAME (frame, f); |
| @@ -3937,18 +4000,6 @@ xpm_load_image (struct frame *f, | |||
| 3937 | expect (','); | 4000 | expect (','); |
| 3938 | } | 4001 | } |
| 3939 | 4002 | ||
| 3940 | if (!x_create_x_image_and_pixmap (f, width, height, 0, | ||
| 3941 | &ximg, &img->pixmap) | ||
| 3942 | #ifndef HAVE_NS | ||
| 3943 | || !x_create_x_image_and_pixmap (f, width, height, 1, | ||
| 3944 | &mask_img, &img->mask) | ||
| 3945 | #endif | ||
| 3946 | ) | ||
| 3947 | { | ||
| 3948 | image_error ("Out of memory (%s)", img->spec, Qnil); | ||
| 3949 | goto error; | ||
| 3950 | } | ||
| 3951 | |||
| 3952 | for (y = 0; y < height; y++) | 4003 | for (y = 0; y < height; y++) |
| 3953 | { | 4004 | { |
| 3954 | expect (XPM_TK_STRING); | 4005 | expect (XPM_TK_STRING); |
| @@ -5685,6 +5736,13 @@ png_load (struct frame *f, struct image *img) | |||
| 5685 | image_error ("Invalid image size (see `max-image-size')", Qnil, Qnil); | 5736 | image_error ("Invalid image size (see `max-image-size')", Qnil, Qnil); |
| 5686 | goto error; | 5737 | goto error; |
| 5687 | } | 5738 | } |
| 5739 | |||
| 5740 | /* Create the X image and pixmap now, so that the work below can be | ||
| 5741 | omitted if the image is too large for X. */ | ||
| 5742 | if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, | ||
| 5743 | &img->pixmap)) | ||
| 5744 | goto error; | ||
| 5745 | |||
| 5688 | /* If image contains simply transparency data, we prefer to | 5746 | /* If image contains simply transparency data, we prefer to |
| 5689 | construct a clipping mask. */ | 5747 | construct a clipping mask. */ |
| 5690 | if (fn_png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) | 5748 | if (fn_png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) |
| @@ -5790,11 +5848,6 @@ png_load (struct frame *f, struct image *img) | |||
| 5790 | fp = NULL; | 5848 | fp = NULL; |
| 5791 | } | 5849 | } |
| 5792 | 5850 | ||
| 5793 | /* Create the X image and pixmap. */ | ||
| 5794 | if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, | ||
| 5795 | &img->pixmap)) | ||
| 5796 | goto error; | ||
| 5797 | |||
| 5798 | /* Create an image and pixmap serving as mask if the PNG image | 5851 | /* Create an image and pixmap serving as mask if the PNG image |
| 5799 | contains an alpha channel. */ | 5852 | contains an alpha channel. */ |
| 5800 | if (channels == 4 | 5853 | if (channels == 4 |
| @@ -6804,8 +6857,15 @@ tiff_load (struct frame *f, struct image *img) | |||
| 6804 | return 0; | 6857 | return 0; |
| 6805 | } | 6858 | } |
| 6806 | 6859 | ||
| 6807 | if (min (PTRDIFF_MAX, SIZE_MAX) / sizeof *buf / width < height) | 6860 | /* Create the X image and pixmap. */ |
| 6808 | memory_full (SIZE_MAX); | 6861 | if (! (height <= min (PTRDIFF_MAX, SIZE_MAX) / sizeof *buf / width |
| 6862 | && x_create_x_image_and_pixmap (f, width, height, 0, | ||
| 6863 | &ximg, &img->pixmap))) | ||
| 6864 | { | ||
| 6865 | fn_TIFFClose (tiff); | ||
| 6866 | return 0; | ||
| 6867 | } | ||
| 6868 | |||
| 6809 | buf = (uint32 *) xmalloc (sizeof *buf * width * height); | 6869 | buf = (uint32 *) xmalloc (sizeof *buf * width * height); |
| 6810 | 6870 | ||
| 6811 | rc = fn_TIFFReadRGBAImage (tiff, width, height, buf, 0); | 6871 | rc = fn_TIFFReadRGBAImage (tiff, width, height, buf, 0); |
| @@ -6827,13 +6887,6 @@ tiff_load (struct frame *f, struct image *img) | |||
| 6827 | return 0; | 6887 | return 0; |
| 6828 | } | 6888 | } |
| 6829 | 6889 | ||
| 6830 | /* Create the X image and pixmap. */ | ||
| 6831 | if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) | ||
| 6832 | { | ||
| 6833 | xfree (buf); | ||
| 6834 | return 0; | ||
| 6835 | } | ||
| 6836 | |||
| 6837 | /* Initialize the color table. */ | 6890 | /* Initialize the color table. */ |
| 6838 | init_color_table (); | 6891 | init_color_table (); |
| 6839 | 6892 | ||
| @@ -8428,12 +8481,15 @@ gs_load (struct frame *f, struct image *img) | |||
| 8428 | /* Create the pixmap. */ | 8481 | /* Create the pixmap. */ |
| 8429 | xassert (img->pixmap == NO_PIXMAP); | 8482 | xassert (img->pixmap == NO_PIXMAP); |
| 8430 | 8483 | ||
| 8431 | /* Only W32 version did BLOCK_INPUT here. ++kfs */ | 8484 | if (x_check_image_size (0, img->width, img->height)) |
| 8432 | BLOCK_INPUT; | 8485 | { |
| 8433 | img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), | 8486 | /* Only W32 version did BLOCK_INPUT here. ++kfs */ |
| 8434 | img->width, img->height, | 8487 | BLOCK_INPUT; |
| 8435 | DefaultDepthOfScreen (FRAME_X_SCREEN (f))); | 8488 | img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), |
| 8436 | UNBLOCK_INPUT; | 8489 | img->width, img->height, |
| 8490 | DefaultDepthOfScreen (FRAME_X_SCREEN (f))); | ||
| 8491 | UNBLOCK_INPUT; | ||
| 8492 | } | ||
| 8437 | 8493 | ||
| 8438 | if (!img->pixmap) | 8494 | if (!img->pixmap) |
| 8439 | { | 8495 | { |