rust-x-bindings / rust-xcb

Rust bindings and wrapper for XCB.
MIT License
165 stars 64 forks source link

NULL pointer dereference when XCB connection is in an error state #64

Closed psychon closed 4 years ago

psychon commented 5 years ago

The following program shows two and a half ways to get NULL pointer dereferences in safe rust code via rust-xcb. They are all about somehow getting the underlying xcb_connection_t into an error state, after which xcb_*_reply will start returning both reply and error as NULL. The code in rust-xcb assumes that when no error was returned, the reply is a valid pointer.

extern crate xcb;

use std::iter::repeat;

fn main() {
    let (conn, screen_no) = xcb::Connection::connect(None).unwrap();
    let setup = conn.get_setup();
    let screen = setup.roots().nth(screen_no as usize).unwrap();

    let variant = 1; // Choose a variant of your liking here
    match variant {
        1 => {
            // My X11 server does not support XEVIE. Use this to break the connection.
            xcb::xevie::query_version(&conn, 0, 0);
            println!("Connection should be broken now: {:?}", conn.has_error());
            // With the broken connection, xcb_get_input_focus() will return NULL and also error=NULL
            println!("{:?}", xcb::get_input_focus(&conn).get_reply().unwrap().focus());
        },
        2 => {
            // Accessing the reply to XEVIE's QueryVersion already segfaults (same kind of NULL pointer)
            let query_version = xcb::xevie::query_version(&conn, 0, 0);
            println!("Connection should be broken now: {:?}", conn.has_error());
            println!("{:?}", query_version.get_reply().unwrap().server_major_version());
        },
        3 => {
            // Exceed the maximum request size (just to show that there are more ways to break the
            // connection than "unsupported extension"; it could also just be the X11 server dying)
            let max_length = conn.get_maximum_request_length() as usize;
            let larger_size = (max_length + 1) * 4;
            let data: Vec<_> = repeat(0).take(larger_size).collect();
            xcb::put_image(&conn, 0, screen.root(), 0, 0, 0, 0, 0, 0, 0, &data);
            println!("Connection should be broken now: {:?}", conn.has_error());
            println!("{:?}", xcb::get_input_focus(&conn).get_reply().unwrap().focus());
        },
        _ => panic!()
    }
}