Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use after free bug #21

Open
dzfranklin opened this issue May 9, 2021 · 7 comments
Open

Use after free bug #21

dzfranklin opened this issue May 9, 2021 · 7 comments

Comments

@dzfranklin
Copy link
Contributor

When I called debugger.create_target with a platform name I got a error with a nonsensical code (way too big, looked like random memory) that returned an invalid string when asked for its message. I'm pretty sure the error is this code

        // src/debugger.rs:232
        let executable = CString::new(executable).unwrap();
        let target_triple = target_triple.map(|s| CString::new(s).unwrap());
        let platform_name = platform_name.map(|s| CString::new(s).unwrap());
        let error = SBError::new();
        let target = unsafe {
            sys::SBDebuggerCreateTarget(
                self.raw,
                executable.as_ptr(),
                target_triple.map_or(ptr::null(), |s| s.as_ptr()), // <-- HERE
                platform_name.map_or(ptr::null(), |s| s.as_ptr()), // <-- HERE
                add_dependent_modules as u8,
                error.raw,
            )
        };

The problem is that map_or consumes the Option, so when it returns the option (may be) freed. lldb sees some random junk.

Replacing it with this fixes the issue, as the strings live until after the function call, and I no longer get an error.

        let executable = CString::new(executable).unwrap();
        let target_triple = target_triple.map(|s| CString::new(s).unwrap());
        let platform_name = platform_name.map(|s| CString::new(s).unwrap());
        let error = SBError::new();
        let target = unsafe {
            sys::SBDebuggerCreateTarget(
                self.raw,
                executable.as_ptr(),
                target_triple.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
                platform_name.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
                add_dependent_modules as u8,
                error.raw,
            )
        };

I'm relatively certain this isn't the only place with this sort of issue. I'm not up for fixing all of them, but I'll try and fix them when I see them and make a PR with more than just this one bug.

@waywardmonkeys
Copy link
Contributor

Back when I wrote this, I don't remember there being a lot of examples of this sort of FFI. I bet things have improved in the ecosystem / world since then and we can take advantage of that?

@waywardmonkeys
Copy link
Contributor

Also, great catch!

@dzfranklin
Copy link
Contributor Author

Thanks. I've heard good things of cxx, which is supposed to generate safe-ish bindings from c++. While I'm wildly dreaming it sounds possible to generate from the swig templates ...

Unfortunately, I probably won't be able to help with this. It turns out llvm is pretty bad at what I wanted to do (remotely connect to a limited gdb server), so I'm probably going to go down the approach of talking to the machine interface of gdb over stdin.

@waywardmonkeys
Copy link
Contributor

GDB-MI is pretty terrible. What're you trying to do that isn't working? LLDB should still mostly work with a limited gdb server, I think.

@dzfranklin
Copy link
Contributor Author

dzfranklin commented May 10, 2021

I don't want to bug you with my random tech support, so feel free to ignore this. I'm talking to rr (time traveling debugger), which implements a small subset of the gdb remote protocol.

I tried following the guide, but after I connect the server shows lldb unexpectedly closed the connection. Here's me trying with just the interpreter

(lldb) platform status
  Platform: host
    Triple: x86_64-pc-linux-gnu
OS Version: 5.11.0
  Hostname: 127.0.0.1
WorkingDir: /home/daniel/rrr/server/src
    Kernel: Linux
   Release: 5.11.0-7614-generic
   Version: #15~1618626693~20.10~ecb25cd-Ubuntu SMP Thu Apr 22 16:00:45 UTC 

(lldb) platform select remote-gdb-server
  Platform: remote-gdb-server
 Connected: no

(lldb) platform connect connect://127.0.0.1:55520
  Platform: remote-gdb-server
  Hostname: (null)
 Connected: yes

(lldb) platform status
  Platform: remote-gdb-server
  Hostname: (null)
 Connected: yes

(lldb) file /home/daniel/rrr/server/tests/samples/traces/simple/mmap_hardlink_4_blog
Current executable set to '/home/daniel/rrr/server/tests/samples/traces/simple/mmap_hardlink_4_blog' (x86_64).

(lldb) platform status
  Platform: host
    Triple: x86_64-pc-linux-gnu
OS Version: 5.11.0
  Hostname: 127.0.0.1
WorkingDir: /home/daniel/rrr/server/src
    Kernel: Linux
   Release: 5.11.0-7614-generic
   Version: #15~1618626693~20.10~ecb25cd-Ubuntu SMP Thu Apr 22 16:00:45 UTC

(I also tried the gdb-remote command)

I know the guy behind vscode-lldb got this working somehow, but I peeked through his repo and he mostly uses the SBCommandInterpreter. I played around with fleshing out that class in my fork of your repo, but it wasn't super pleasant. I'd also need to either use that to send custom packets for a lot of the functionality. I think I'd rather parse gdbmi that lldb's interpreter's output, but I'd love suggestions if you have better ideas.

@waywardmonkeys
Copy link
Contributor

I'm tired, so can you point me at his code?

@dzfranklin
Copy link
Contributor Author

I'm absolutely not asking you to debug how to get my code working working.

If you're interested in how vscode-lldb works though here's where he sends custom packets and here's his lldb bindings. He uses a pretty different approach to you so I'm not sure how useful they'd be.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants