GNOME Bugzilla – Bug 65877
gdk_event_copy() should only read parts of union for that event type
Last modified: 2017-08-28 12:06:49 UTC
Purify reports Stack array bounds read error when gdk_event_copy is called from the above function. GdkEvent* gdk_event_copy (GdkEvent *event) { GdkEvent *new_event; g_return_val_if_fail (event != NULL, NULL); new_event = _gdk_event_new (); *new_event = *event; <=== SBR errors reported here if (new_event->any.window) gdk_window_ref (new_event->any.window); ... This is because the pointer to the GdkEventWindowState struct(sizeof 20) is cast to GdkEvent*(pointer to the sizeof 72) and passed to the gdk_event_put() (gdkevents.c:line 981).
function trace around the error is below. SBR: Stack array bounds read (13 times) This is occurring while in: gdk_event_copy [gdkgdkevents.c:289] gdk_event_put [gdkgdkevents.c:238] gdk_synthesize_window_state [gdkgdkevents.c:980] show_window_internal [x11gdkwindow-x11.c:902] gdk_window_show [x11gdkwindow-x11.c:954] gtk_window_map [gtkgtkwindow.c:3083] Reading 4 bytes from 0xffbedfc0. Frame pointer 0xffbedf90 Address 0xffbedfc0 is 48 bytes above stack pointer in function show_window_internal. A sample patch will be attached after tbis comment.
Created attachment 6134 [details] [review] Use GdkEvent to allocate sufficient buffer
Will commit shortly. Tue Dec 4 11:38:40 2001 Owen Taylor <otaylor@redhat.com> * gdk/gdkevents.c (gdk_synthesize_window_state): Use a full GdkEvent structure to avoid reads of uninitialized/ invalid memory in gdk_event_put() (#65877, patch from Hidetoshi Tajima) But eventually, I think it's better if gdk_event_copy() only copied the part of the structure that is used for the current event type to just eliminate bugs of this type ... this is not the first we've had.
I verified the fix. Do you want to keep this bug open and make a better fix in gdk_event_copy()?
Yes, I want to keep this open on the future milestone (post-2.0) as an API enhancement (which is why I've changed the Subject: line) Thanks for verifying.
Comment on attachment 6134 [details] [review] Use GdkEvent to allocate sufficient buffer committed, two and a half years ago.
Created attachment 87543 [details] [review] only copy meaningful fields from GdkEvent I was bored. Is there a definitive test for gdk_event_copy() somewhere?
Comment on attachment 87543 [details] [review] only copy meaningful fields from GdkEvent (In reply to comment #7) > Created an attachment (id=87543) [edit] > only copy meaningful fields from GdkEvent > > I was bored. thanks. > > Is there a definitive test for gdk_event_copy() somewhere? no, it'd be very good to have one though, care to cook one up? >Index: gdk/gdkevents.c >=================================================================== >--- gdk/gdkevents.c (revision 17786) >+++ gdk/gdkevents.c (working copy) >@@ -361,10 +361,6 @@ > new_event = gdk_event_new (GDK_NOTHING); > new_private = (GdkEventPrivate *)new_event; > >- *new_event = *event; >- if (new_event->any.window) >- g_object_ref (new_event->any.window); >- > if (gdk_event_is_allocated (event)) > { > GdkEventPrivate *private = (GdkEventPrivate *)event; >@@ -374,13 +370,24 @@ > > switch (event->any.type) > { >+ case GDK_CLIENT_EVENT: >+ new_event->client = event->client; >+ break; >+ >+ case GDK_CONFIGURE: >+ new_event->configure = event->configure; >+ break; >+ > case GDK_KEY_PRESS: > case GDK_KEY_RELEASE: >+ new_event->key = event->key; > new_event->key.string = g_strdup (event->key.string); > break; > > case GDK_ENTER_NOTIFY: > case GDK_LEAVE_NOTIFY: >+ new_event->crossing = event->crossing; >+ > if (event->crossing.subwindow != NULL) > g_object_ref (event->crossing.subwindow); > break; >@@ -391,36 +398,100 @@ > case GDK_DRAG_STATUS: > case GDK_DROP_START: > case GDK_DROP_FINISHED: >+ new_event->dnd = event->dnd; > g_object_ref (event->dnd.context); > break; > > case GDK_EXPOSE: >+ new_event->expose = event->expose; >+ > if (event->expose.region) > new_event->expose.region = gdk_region_copy (event->expose.region); > break; >- >+ >+ case GDK_FOCUS_CHANGE: >+ new_event->focus_change = event->focus_change; >+ break; >+ >+ case GDK_GRAB_BROKEN: >+ new_event->grab_broken = event->grab_broken; >+ break; >+ >+ case GDK_NO_EXPOSE: >+ new_event->no_expose = event->no_expose; >+ break; >+ > case GDK_SETTING: >+ new_event->setting = event->setting; > new_event->setting.name = g_strdup (new_event->setting.name); > break; > > case GDK_BUTTON_PRESS: > case GDK_BUTTON_RELEASE: >- if (event->button.axes) >- new_event->button.axes = g_memdup (event->button.axes, >+ new_event->button = event->button; >+ >+ if (event->any.type == GDK_BUTTON_PRESS || event->any.type == GDK_BUTTON_RELEASE) this check is redundant, we already switched on any.type above and only enter here for GDK_BUTTON_PRESS or GDK_BUTTON_RELEASE. the original condition of if(event->button.axes) makes more sense to have here. >+ new_event->button.axes = g_memdup (event->button.axes, > sizeof (gdouble) * event->button.device->num_axes); > break; > >+ case GDK_2BUTTON_PRESS: >+ case GDK_3BUTTON_PRESS: >+ new_event->button = event->button; hm, it'd make sense to verify here that button.axes os always NULL, or have thy copying code here as well. >+ break; >+ > case GDK_MOTION_NOTIFY: >+ new_event->motion = event->motion; >+ > if (event->motion.axes) > new_event->motion.axes = g_memdup (event->motion.axes, > sizeof (gdouble) * event->motion.device->num_axes); > > break; >- >- default: >+ >+ case GDK_OWNER_CHANGE: >+ new_event->owner_change = event->owner_change; > break; >+ >+ case GDK_PROPERTY_NOTIFY: >+ new_event->property = event->property; >+ break; >+ >+ case GDK_PROXIMITY_IN: >+ case GDK_PROXIMITY_OUT: >+ new_event->proximity = event->proximity; >+ break; >+ >+ case GDK_SCROLL: >+ new_event->scroll = event->scroll; >+ break; >+ >+ case GDK_SELECTION_CLEAR: >+ case GDK_SELECTION_REQUEST: >+ case GDK_SELECTION_NOTIFY: >+ new_event->selection = event->selection; >+ break; >+ >+ case GDK_VISIBILITY_NOTIFY: >+ new_event->visibility = event->visibility; >+ break; >+ >+ case GDK_WINDOW_STATE: >+ new_event->window_state = event->window_state; >+ break; >+ >+ case GDK_NOTHING: >+ case GDK_DELETE: >+ case GDK_DESTROY: >+ case GDK_MAP: >+ case GDK_UNMAP: >+ new_event->any = event->any; >+ break; > } > >+ if (new_event->any.window) >+ g_object_ref (new_event->any.window); >+ > return new_event; > }
(In reply to comment #0) > Purify reports Stack array bounds read error when gdk_event_copy is called > from the above function. > > GdkEvent* > gdk_event_copy (GdkEvent *event) > { > GdkEvent *new_event; > > g_return_val_if_fail (event != NULL, NULL); > > new_event = _gdk_event_new (); > > *new_event = *event; <=== SBR errors reported here > if (new_event->any.window) > gdk_window_ref (new_event->any.window); > ... > > This is because the pointer to the GdkEventWindowState struct(sizeof 20) > is cast to GdkEvent*(pointer to the sizeof 72) and passed to the > gdk_event_put() (gdkevents.c:line 981). ******************************************************************************** ******************************************************************************** ******************************************************************************** ******************************************************************************** *DOES THIS HELP IT WAS WRITTEN IN ANSI C99 International Standards Organization* *Form: *I do not even know why I chose this code I guess I wanted to try something * *in *C and help at the same time * /////////////////////////////////////////////////////////////////////////////// #ifndef GTK_Event_Copy_H #define GTK_Event_Copy_H /////////////////////////////////////////////////////////////////////////////// #include <stdio.h> #include <stdbool.h> #include <stdio.h> #include <STL_Include_Packet.h> /////////////////////////////////////////////////////////////////////////////// //Purify reports Stack array bounds read error when gdk_event_copy is called //from the above function. struct All_Events { };struct All_Events new_event; ///////////////////////////////////////////////////// struct Any_Property { char* window[]; };struct Any_Property Any; ///////////////////////////////////////////////////// typedef char* GDK_Event[]; //recieving input GDK_Event new_event; // creating a new event as: "new_event" // //////////////////////////////////////////////////// // g_return_val_if_fail (event != NULL, NULL); // creating a new array of type: "GDK_Event" // GDK_Event new_event, event_01, event_02; ///////////////////////////////////////////////////////////////////////////////////////// char* gdk_event_new(void) { char* array_01[]; return(array_01); }; ///////////////////////////////////////////////////////////////////////////////////////// void gdk_window_ref(char the_switch) { if(new_event-> *Any.window) { char* variable[]; return(variable);// generating a new variable // }; }; //////////////////////////////////////////////////////////////////////////////////////// void g_return_val_if_fail(char* event_array_01[], char* event_array_02[]) { if(event_array_01[]!= false && event_array_02[]!= false) { new_event+= gdk_event_new; }; if(new_event-> *Any.window) { gdk_window_ref(); }; }; #endif
//Sorry here is a cleaner Header file /////////////////////////////////////////////////////////////////////////////// #ifndef GTK_Event_Copy_H #define GTK_Event_Copy_H /////////////////////////////////////////////////////////////////////////////// #include <stdio.h> #include <stdbool.h> #include <stdio.h> #include <STL_Include_Packet.h> /////////////////////////////////////////////////////////////////////////////// struct Any_Property { char* window[]; };struct Any_Property Any; ///////////////////////////////////////////////////// typedef char* GDK_Event[]; //recieving input GDK_Event new_event, event_01, event_02; ///////////////////////////////////////////////////////////////////////////////////////// char* gdk_event_new(void) { char* array_01[]; return(array_01); }; ///////////////////////////////////////////////////////////////////////////////////////// void gdk_window_ref(char the_switch) { if(new_event-> *Any.window) { char* variable[]; return(variable);// generating a new variable // }; }; //////////////////////////////////////////////////////////////////////////////////////// void g_return_val_if_fail(char* event_array_01[], char* event_array_02[]) { if(event_array_01[]!= false && event_array_02[]!= false) { new_event+= gdk_event_new; }; if(new_event-> *Any.window) { gdk_window_ref(); }; }; #endif
...what
This definitely goes onto the obsolete pile.