Compare commits

..

3 Commits

Author SHA1 Message Date
Chris Down
a9aa0d8ffb dwm: Fix getatomprop regression from heap overflow fix
Commit 244fa852fe ("dwm: Fix heap buffer overflow in getatomprop")
introduced a check for dl > 0 before dereferencing the property pointer.
However, I missed that the variable dl is passed to XGetWindowProperty
for both nitems_return and bytes_after_return parameters:

    XGetWindowProperty(..., &dl, &dl, &p)

The final value in dl is bytes_after_return, not nitems_return. For a
successfully read property, bytes_after is typically 0 (indicating all
data was retrieved), so the check `dl > 0` is always false and dwm never
reads any atom properties. So this is safe, but not very helpful :-)

dl is probably just a dummy variable anyway, so fix by using a separate
variable for nitems, and check nitems > 0 as originally intended.
2026-01-16 14:13:51 +01:00
Hiltjo Posthuma
85fe518c1a bump version to 6.7
Put the maintainer at the top and bump years (time flies).
2026-01-10 11:31:44 +01:00
Chris Down
244fa852fe dwm: Fix heap buffer overflow in getatomprop
When getatomprop() is called, it invokes XGetWindowProperty() to
retrieve an Atom. If the property exists but has zero elements (length
0), Xlib returns Success and sets p to a valid, non-NULL memory address
containing a single null byte.

However, dl (that is, the number of items) is 0. dwm blindly casts p to
Atom* and dereferences it. While Xlib guarantees that p is safe to read
as a string (that is, it is null-terminated), it does _not_ guarantee it
is safe to read as an Atom (an unsigned long).

The Atom type is a typedef for unsigned long. Reading an Atom (which
thus will either likely be 4 or 8 bytes) from a 1-byte allocated buffer
results in a heap buffer overflow. Since property content is user
controlled, this allows any client to trigger an out of bounds read
simply by setting a property with format 32 and length 0.

An example client which reliably crashes dwm under ASAN:

    #include <X11/Xlib.h>
    #include <X11/Xatom.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>

    int main(void) {
        Display *d;
        Window root, w;
        Atom net_wm_state;

        d = XOpenDisplay(NULL);
        if (!d) return 1;

        root = DefaultRootWindow(d);
        w = XCreateSimpleWindow(d, root, 10, 10, 200, 200, 1, 0, 0);
        net_wm_state = XInternAtom(d, "_NET_WM_STATE", False);
        if (net_wm_state == None) return 1;

        XChangeProperty(d, w, net_wm_state, XA_ATOM, 32,
                        PropModeReplace, NULL, 0);
        XMapWindow(d, w);
        XSync(d, False);
        sleep(1);

        XCloseDisplay(d);
        return 0;
    }

In order to avoid this, check that the number of items returned is
greater than zero before dereferencing the pointer.
2026-01-10 11:27:23 +01:00
3 changed files with 6 additions and 5 deletions

View File

@@ -1,5 +1,6 @@
MIT/X Consortium License
© 2010-2026 Hiltjo Posthuma <hiltjo@codemadness.org>
© 2006-2019 Anselm R Garbe <anselm@garbe.ca>
© 2006-2009 Jukka Salmi <jukka at salmi dot ch>
© 2006-2007 Sander van Dijk <a dot h dot vandijk at gmail dot com>
@@ -11,7 +12,6 @@ MIT/X Consortium License
© 2008 Martin Hurton <martin dot hurton at gmail dot com>
© 2008 Neale Pickett <neale dot woozle dot org>
© 2009 Mate Nagy <mnagy at port70 dot net>
© 2010-2016 Hiltjo Posthuma <hiltjo@codemadness.org>
© 2010-2012 Connor Lane Smith <cls@lubutu.com>
© 2011 Christoph Lohmann <20h@r-36.net>
© 2015-2016 Quentin Rameau <quinq@fifth.space>

View File

@@ -1,5 +1,5 @@
# dwm version
VERSION = 6.6
VERSION = 6.7
# Customize below to fit your system

7
dwm.c
View File

@@ -864,13 +864,14 @@ Atom
getatomprop(Client *c, Atom prop)
{
int di;
unsigned long dl;
unsigned long nitems, dl;
unsigned char *p = NULL;
Atom da, atom = None;
if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
&da, &di, &dl, &dl, &p) == Success && p) {
atom = *(Atom *)p;
&da, &di, &nitems, &dl, &p) == Success && p) {
if (nitems > 0)
atom = *(Atom *)p;
XFree(p);
}
return atom;