[comp.windows.x] server can coredump due to thaws

mouse@LARRY.MCRCIM.MCGILL.EDU (der Mouse) (03/08/90)

			  X Window System Bug Report
			    xbugs@expo.lcs.mit.edu


VERSION:
    R4

CLIENT MACHINE and OPERATING SYSTEM:
    any

DISPLAY TYPE:
    any

WINDOW MANAGER:
    any

AREA:
    server

SYNOPSIS:
    Under certain circumstances, PlayReleasedEvents can free a
    QdEventRec that is still being pointed to.

DESCRIPTION:
    The queue of events waiting for a freeze to be thawed has a tail
    pointer, which is used for two things: (1) to append quickly to the
    tail of the queue and (2) to collapse consecutive MotionNotify
    events.  However, PlayReleasedEvents doesn't check carefully
    enough, and if syncEvents.pendtail points into the next-to-last
    event, and PlayReleasedEvents replays the next-to-last event but
    not the last, syncEvents.pendtail will be left pointing into a
    freed block of memory.

REPEAT BY:
    The simplest thing is to examine the code.  It is possible to
    create this condition from clients, but I do not know precisely
    what does it.  I suspect that changing focus while the keyboard is
    frozen may do it.

SAMPLE FIX:

    The patch given below changes the meaning of syncEvents.pendtail to
    be nothing but a pointer to the last pointer in the list, thus
    simplifying the code to maintain and use it (and making it more
    understandable thereby).  A new field, syncEvents.tail, is created
    to serve the other function, allowing MotionNotify event collapsing.

    This patch also includes two enhancements to os/4.2bsd/utils.c:

    - If gcc 1.37.1 is used to build the server on a Sun-3 running
      release 3.5 (and possibly other compilers or platforms) with
      MEMBUG defined, MemoryValidate is defined but it goes in the bss
      segment, making it impossible to use adb to set it in the
      executable file.  The patch initializes it to zero, which (at
      least under the above combination) puts it in the data segment
      instead, where it can be patched with adb.

    - When MEMBUG is defined, the entire contents of any block passed
      to Xfree will be overwritten with 'Z' bytes.  This greatly
      increases the probability of catching a use-after-free bug (such
      as the main one in this report) early.

    *** /@apollo/u3/X11R4/mit/server/dix/events.c	Wed Jan 24 10:17:52 1990
    --- mit/server/dix/events.c	Wed Mar  7 12:46:44 1990
    ***************
    *** 90,95 ****
    --- 90,96 ----
      
      static struct {
          QdEventPtr		pending, *pendtail;
    +     QdEventPtr		tail;
          DeviceIntPtr	replayDev;	/* kludgy rock to put flag for */
          WindowPtr		replayWin;	/*   ComputeFreezes            */
          Bool		playingEvents;
    ***************
    *** 482,488 ****
          DeviceIntPtr	device;
          int			count;
      {
    -     register QdEventPtr tail = *syncEvents.pendtail;
          register QdEventPtr qe;
          xEvent		*qxE;
      
    --- 483,488 ----
    ***************
    *** 492,503 ****
      	sprite.hotPhys.x = xE->u.keyButtonPointer.rootX;
      	sprite.hotPhys.y = xE->u.keyButtonPointer.rootY;
      	/* do motion compression */
    ! 	if (tail &&
    ! 	    (tail->event->u.u.type == MotionNotify) &&
    ! 	    (tail->pScreen == sprite.hotPhys.pScreen))
      	{
    ! 	    tail->event->u.keyButtonPointer.rootX = sprite.hotPhys.x;
    ! 	    tail->event->u.keyButtonPointer.rootY = sprite.hotPhys.y;
      	    return;
      	}
          }
    --- 492,503 ----
      	sprite.hotPhys.x = xE->u.keyButtonPointer.rootX;
      	sprite.hotPhys.y = xE->u.keyButtonPointer.rootY;
      	/* do motion compression */
    ! 	if (syncEvents.tail &&
    ! 	    (syncEvents.tail->event->u.u.type == MotionNotify) &&
    ! 	    (syncEvents.tail->pScreen == sprite.hotPhys.pScreen))
      	{
    ! 	    syncEvents.tail->event->u.keyButtonPointer.rootX = sprite.hotPhys.x;
    ! 	    syncEvents.tail->event->u.keyButtonPointer.rootY = sprite.hotPhys.y;
      	    return;
      	}
          }
    ***************
    *** 512,520 ****
          qe->evcount = count;
          for (qxE = qe->event; --count >= 0; qxE++, xE++)
      	*qxE = *xE;
    -     if (tail)
    - 	syncEvents.pendtail = &tail->next;
          *syncEvents.pendtail = qe;
      }
      
      static void
    --- 512,520 ----
          qe->evcount = count;
          for (qxE = qe->event; --count >= 0; qxE++, xE++)
      	*qxE = *xE;
          *syncEvents.pendtail = qe;
    +     syncEvents.tail = qe;
    +     syncEvents.pendtail = &qe->next;
      }
      
      static void
    ***************
    *** 529,535 ****
    --- 529,540 ----
      	{
      	    *prev = qe->next;
      	    if (!qe->next)
    + 	    {
      		syncEvents.pendtail = prev;
    + 		syncEvents.tail = 0;
    + 	    }
    + 	    if (qe == syncEvents.tail)
    + 		FatalError("PlayReleasedEvents: tail pointer wrong");
      	    if (qe->event->u.u.type == MotionNotify)
      		CheckVirtualMotion(qe, NullWindow);
      	    syncEvents.time.months = qe->months;
    ***************
    *** 2883,2888 ****
    --- 2888,2895 ----
          sprite.hotLimits.x2 = 0;
          sprite.hotLimits.y2 = 0;
          syncEvents.replayDev = (DeviceIntPtr)NULL;
    +     syncEvents.pendtail = &syncEvents.pending;
    +     syncEvents.tail = 0;
          while (syncEvents.pending)
          {
      	QdEventPtr next = syncEvents.pending->next;
    ***************
    *** 2889,2895 ****
      	xfree(syncEvents.pending);
      	syncEvents.pending = next;
          }
    -     syncEvents.pendtail = &syncEvents.pending;
          syncEvents.playingEvents = FALSE;
          currentTime.months = 0;
          currentTime.milliseconds = GetTimeInMillis();
    --- 2896,2901 ----
    

    *** /@apollo/u3/X11R4/mit/server/os/4.2bsd/utils.c	Thu Jan 11 13:12:40 1990
    --- mit/server/os/4.2bsd/utils.c	Wed Mar  7 13:06:35 1990
    ***************
    *** 431,437 ****
      unsigned long	MemoryAllocTime;
      unsigned long	MemoryAllocBreakpoint = ~0;
      unsigned long	MemoryActive = 0;
    ! unsigned long	MemoryValidate;
      
      MallocHeaderPtr	MemoryInUse;
      
    --- 431,437 ----
      unsigned long	MemoryAllocTime;
      unsigned long	MemoryAllocBreakpoint = ~0;
      unsigned long	MemoryActive = 0;
    ! unsigned long	MemoryValidate = 0;
      
      MallocHeaderPtr	MemoryInUse;
      
    ***************
    *** 604,612 ****
    --- 604,615 ----
          if (ptr)
          {
      	MallocHeaderPtr head;
    + 	register char *cp;
    + 	register int n;
      
      	CheckNode(ptr);
      	head = Header(ptr);
    + 	for (cp=(char *)ptr,n=(int)head->amount;n>0;n--,cp++) *cp = 'Z';
      	head->magic = FREEDMAGIC;
      	free ((char *) head);
          }
    
    
					der Mouse

			old: mcgill-vision!mouse
			new: mouse@larry.mcrcim.mcgill.edu