[PATCH 3/8] Xephyr: integer overflow in ephyrHostGLXGetStringFromServer()

walter harms wharms at bfs.de
Sat Jul 6 02:01:05 PDT 2013



Am 06.07.2013 08:47, schrieb Alan Coopersmith:
> reply.length & reply.size are CARD32s and need to be bounds checked before
> multiplying or adding to come up with the total size to allocate, to avoid
> integer overflow leading to underallocation and writing data from the
> network past the end of the allocated buffer.
> 
> Reported-by: Ilja Van Sprundel <ivansprundel at ioactive.com>
> Signed-off-by: Alan Coopersmith <alan.coopersmith at oracle.com>
> ---
>  hw/kdrive/ephyr/ephyrhostglx.c |   47 +++++++++++++++++++++++++---------------
>  1 file changed, 29 insertions(+), 18 deletions(-)
> 
> diff --git a/hw/kdrive/ephyr/ephyrhostglx.c b/hw/kdrive/ephyr/ephyrhostglx.c
> index 5c6c40f..90f450c 100644
> --- a/hw/kdrive/ephyr/ephyrhostglx.c
> +++ b/hw/kdrive/ephyr/ephyrhostglx.c
> @@ -137,7 +137,7 @@ ephyrHostGLXQueryVersion(int *a_major, int *a_minor)
>  }
>  
>  /**
> - * GLX protocol structure for the ficticious "GXLGenericGetString" request.
> + * GLX protocol structure for the ficticious "GLXGenericGetString" request.
>   * 
>   * This is a non-existant protocol packet.  It just so happens that all of
>   * the real protocol packets used to request a string from the server have
> @@ -169,7 +169,8 @@ ephyrHostGLXGetStringFromServer(int a_screen_number,
>      int default_screen = DefaultScreen(dpy);
>      xGLXGenericGetStringReq *req = NULL;
>      xGLXSingleReply reply;
> -    int length = 0, numbytes = 0, major_opcode = 0, get_string_op = 0;
> +    unsigned long length = 0, numbytes = 0;
> +    int major_opcode = 0, get_string_op = 0;
>  
>      EPHYR_RETURN_VAL_IF_FAIL(dpy && a_string, FALSE);
>  
> @@ -209,36 +210,46 @@ ephyrHostGLXGetStringFromServer(int a_screen_number,
>  
>      _XReply(dpy, (xReply *) &reply, 0, False);
>  
> -    length = reply.length * 4;
> -    if (!length) {
> -        numbytes = 0;
> -    }
> -    else {
> +#if UINT32_MAX >= (ULONG_MAX / 4)
> +    if (reply.length >= (ULONG_MAX / 4))
> +        goto eat_out;
> +#endif

I am not sure what is going on here, i am missing the else branch,
For all systems where UINT == ULONG this will be a noop. Is that intended ?

stdint.h:# define UINT32_MAX            (4294967295U)
limits.h:#   define ULONG_MAX   4294967295UL


just my 2 cents

re,
 wh

> +    if (reply.length > 0) {
> +        length = (unsigned long) reply.length * 4;
>          numbytes = reply.size;
> +        if (numbytes > length) {
> +            EPHYR_LOG_ERROR("string length %d longer than reply length %d\n",
> +                            numbytes, length);
> +            goto eat_out;
> +        }
>      }
>      EPHYR_LOG("going to get a string of size:%d\n", numbytes);
>  
> -    *a_string = (char *) Xmalloc(numbytes + 1);
> -    if (!a_string) {
> +    if (numbytes < INT_MAX)
> +        *a_string = Xcalloc(numbytes + 1, 1);
> +    else
> +        *a_string = NULL;
> +    if (*a_string == NULL) {
>          EPHYR_LOG_ERROR("allocation failed\n");
> -        goto out;
> +        goto eat_out;
>      }
>  
> -    memset(*a_string, 0, numbytes + 1);
>      if (_XRead(dpy, *a_string, numbytes)) {
> -        UnlockDisplay(dpy);
> -        SyncHandle();
>          EPHYR_LOG_ERROR("read failed\n");
> -        goto out;
> +        length = 0; /* if read failed, no idea how much to eat */
> +    }
> +    else {
> +        length -= numbytes;
> +        EPHYR_LOG("strname:%#x, strvalue:'%s', strlen:%d\n",
> +                  a_string_name, *a_string, numbytes);
> +        is_ok = TRUE;
>      }
> -    length -= numbytes;
> +
> + eat_out:
>      _XEatData(dpy, length);
>      UnlockDisplay(dpy);
>      SyncHandle();
> -    EPHYR_LOG("strname:%#x, strvalue:'%s', strlen:%d\n",
> -              a_string_name, *a_string, numbytes);
>  
> -    is_ok = TRUE;
>   out:
>      EPHYR_LOG("leave\n");
>      return is_ok;


More information about the xorg-devel mailing list