xserver/present/present_notify.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

113 lines
3.2 KiB
C
Raw Permalink Normal View History

/*
* Copyright © 2013 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#include <dix-config.h>
#include "dix/dix_priv.h"
#include "present/present_priv.h"
/*
* Mark all pending notifies for 'window' as invalid when
* the window is destroyed
*/
void
present_clear_window_notifies(WindowPtr window)
{
present_notify_ptr notify;
present_window_priv_ptr window_priv = present_window_priv(window);
if (!window_priv)
return;
xorg_list_for_each_entry(notify, &window_priv->notifies, window_list) {
notify->window = NULL;
}
}
/*
* 'notify' is being freed; remove it from the window's notify list
*/
void
present_free_window_notify(present_notify_ptr notify)
{
xorg_list_del(&notify->window_list);
}
/*
* 'notify' is new; add it to the specified window
*/
int
present_add_window_notify(present_notify_ptr notify)
{
WindowPtr window = notify->window;
present_window_priv_ptr window_priv = present_get_window_priv(window, TRUE);
if (!window_priv)
return BadAlloc;
xorg_list_add(&notify->window_list, &window_priv->notifies);
return Success;
}
int
present_create_notifies(ClientPtr client, int num_notifies, xPresentNotify *x_notifies, present_notify_ptr *p_notifies)
{
present_notify_ptr notifies;
int i;
int added = 0;
int status;
notifies = calloc (num_notifies, sizeof (present_notify_rec));
if (!notifies)
return BadAlloc;
for (i = 0; i < num_notifies; i++) {
status = dixLookupWindow(&notifies[i].window, x_notifies[i].window, client, DixGetAttrAccess);
if (status != Success)
goto bail;
notifies[i].serial = x_notifies[i].serial;
status = present_add_window_notify(&notifies[i]);
if (status != Success)
goto bail;
present: Fix use-after-free in present_create_notifies() Using the Present extension, if an error occurs while processing and adding the notifications after presenting a pixmap, the function present_create_notifies() will clean up and remove the notifications it added. However, there are two different code paths that can lead to an error creating the notify, one being before the notify is being added to the list, and another one after the notify is added. When the error occurs before it's been added, it removes the elements up to the last added element, instead of the actual number of elements which were added. As a result, in case of error, as with an invalid window for example, it leaves a dangling pointer to the last element, leading to a use after free case later: | Invalid write of size 8 | at 0x5361D5: present_clear_window_notifies (present_notify.c:42) | by 0x534A56: present_destroy_window (present_screen.c:107) | by 0x41E441: xwl_destroy_window (xwayland-window.c:1959) | by 0x4F9EC9: compDestroyWindow (compwindow.c:622) | by 0x51EAC4: damageDestroyWindow (damage.c:1592) | by 0x4FDC29: DbeDestroyWindow (dbe.c:1291) | by 0x4EAC55: FreeWindowResources (window.c:1023) | by 0x4EAF59: DeleteWindow (window.c:1091) | by 0x4DE59A: doFreeResource (resource.c:890) | by 0x4DEFB2: FreeClientResources (resource.c:1156) | by 0x4A9AFB: CloseDownClient (dispatch.c:3567) | by 0x5DCC78: ClientReady (connection.c:603) | Address 0x16126200 is 16 bytes inside a block of size 2,048 free'd | at 0x4841E43: free (vg_replace_malloc.c:989) | by 0x5363DD: present_destroy_notifies (present_notify.c:111) | by 0x53638D: present_create_notifies (present_notify.c:100) | by 0x5368E9: proc_present_pixmap_common (present_request.c:164) | by 0x536A7D: proc_present_pixmap (present_request.c:189) | by 0x536FA9: proc_present_dispatch (present_request.c:337) | by 0x4A1E4E: Dispatch (dispatch.c:561) | by 0x4B00F1: dix_main (main.c:284) | by 0x42879D: main (stubmain.c:34) | Block was alloc'd at | at 0x48463F3: calloc (vg_replace_malloc.c:1675) | by 0x5362A1: present_create_notifies (present_notify.c:81) | by 0x5368E9: proc_present_pixmap_common (present_request.c:164) | by 0x536A7D: proc_present_pixmap (present_request.c:189) | by 0x536FA9: proc_present_dispatch (present_request.c:337) | by 0x4A1E4E: Dispatch (dispatch.c:561) | by 0x4B00F1: dix_main (main.c:284) | by 0x42879D: main (stubmain.c:34) To fix the issue, count and remove the actual number of notify elements added in case of error. CVE-2025-62229, ZDI-CAN-27238 This vulnerability was discovered by: Jan-Niklas Sohn working with Trend Micro Zero Day Initiative Signed-off-by: Olivier Fourdan <ofourdan@redhat.com> Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2086>
2025-07-02 09:46:22 +02:00
added++;
}
return Success;
bail:
present_destroy_notifies(notifies, added);
return status;
}
void
present_destroy_notifies(present_notify_ptr notifies, int num_notifies)
{
int i;
for (i = 0; i < num_notifies; i++)
present_free_window_notify(&notifies[i]);
free(notifies);
}