Quuxplusone / LLVMBugzillaTest

0 stars 0 forks source link

LLDB lies about --disable-aslr and leaves ASLR enabled on Linux #20655

Closed Quuxplusone closed 10 years ago

Quuxplusone commented 10 years ago
Bugzilla Link PR20658
Status RESOLVED FIXED
Importance P normal
Reported by Chandler Carruth (chandlerc@gmail.com)
Reported on 2014-08-13 22:21:46 -0700
Last modified on 2014-08-19 12:44:43 -0700
Version unspecified
Hardware PC Linux
CC david.majnemer@gmail.com, emaste@freebsd.org, jingham@apple.com, rnk@google.com, tfiala@google.com, todd.fiala@gmail.com
Fixed by commit(s)
Attachments
Blocks
Blocked by
See also
A transcript follows:

% cat x.cpp
int main() {
  int *ip = new int(42);
  return *ip;
}
% nl x.cpp
     1  int main() {
     2    int *ip = new int(42);
     3    return *ip;
     4  }
% clang++ -g -o x x.cpp
% lldb -- ./x
Current executable set to './x' (x86_64).
(lldb) b x.cpp:3
Breakpoint 1: where = x`main + 43 at x.cpp:3, address = 0x000000000040065b
(lldb) process launch --disable-aslr
Process 7581 launching
Process 7581 launched: './x' (x86_64)
Process 7581 stopped
* thread #1: tid = 7581, , name = 'x'
    frame #0:
Process 7581 stopped
* thread #1: tid = 7581, 0x000000000040065b x`main + 43 at x.cpp:3, name = 'x',
stop reason = breakpoint 1.1
    frame #0: 0x000000000040065b x`main + 43 at x.cpp:3
   1    int main() {
   2      int *ip = new int(42);
-> 3      return *ip;
   4    }
(lldb) p ip
(int *) $0 = 0x0000000001ed9010
(lldb) process launch --disable-aslr
There is a running process, kill it and restart?: [Y/n] y
Process 7581 exited with status = 0 (0x00000000)
Process 15338 launching
Process 15338 launched: './x' (x86_64)
Process 15338 stopped
* thread #1: tid = 15338, 0x00007ff3b04432d0, name = 'x'
    frame #0:
Process 15338 stopped
* thread #1: tid = 15338, 0x000000000040065b x`main + 43 at x.cpp:3, name =
'x', stop reason = breakpoint 1.1
    frame #0: 0x000000000040065b x`main + 43 at x.cpp:3
   1    int main() {
   2      int *ip = new int(42);
-> 3      return *ip;
   4    }
(lldb) p ip
(int *) $1 = 0x000000000234e010

Nope! Let's try GDB:

% gdb --args ./x
Reading symbols from ./x...done.
(gdb) b x.cpp:3
Breakpoint 1 at 0x40065b: file x.cpp, line 3.
(gdb) r
Starting program: /usr/local/google/home/chandlerc/tmp/x

Breakpoint 1, main () at x.cpp:3
3         return *ip;
(gdb) p ip
$1 = (int *) 0x403010
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /usr/local/google/home/chandlerc/tmp/x

Breakpoint 1, main () at x.cpp:3
3         return *ip;
(gdb) p ip
$2 = (int *) 0x403010

Yep. That's what I wanted.

Also, please make this the default and make the flag '--enable-aslr'. I really
never, ever want my debugger to default to ASLR. I only want that when I'm
chasing a bug which manifests in no other way.
Quuxplusone commented 10 years ago
Implementation note:

This link shows a response that indicates how to disable via shell execution:
https://stackoverflow.com/questions/5194666/disable-randomization-of-memory-addresses

So a shell wrapping the inferior with proper flags set is one way to go about
it for per-process-level ASLR setting (rather than the whole-system kernel
flag).

I'll look at getting the disable aslr support in after my next task wraps up.

As for making it the default, great thing to discuss on lldb-dev.  At the very
least I'm good with making it the default on Linux.  If everyone else agrees,
we can get it working as a global default.

-Todd
Quuxplusone commented 10 years ago

In my opinion it makes sense to universally default to --disable-aslr (or do so for all platforms except Mac, if there are legacy reasons to leave it as is there).

Quuxplusone commented 10 years ago

I'm fully behind pursuing that course - just want to discuss it to see if we (as you mentioned) might have legacy reasons for leaving it as is in at least some places. We might even be able to flip it wholesale, which would be great.

Quuxplusone commented 10 years ago
Not sure what's going on - I posted two emails (one from tfiala@google.com at
roughly 7:45 AM PDT, and another from todd.fiala@gmail.com at roughly 9:45 AM
PDT), and neither has hit the llvm.org archive site for lldb-dev yet.  It's a
discussion item for seeing if there's any reason not to disable ASLR by default
(with possible reasons for why to do it and not do it as a discussion starter).
That *should* show up soon if it hasn't already.  I'm just not seeing either of
them in the archive.
Quuxplusone commented 10 years ago

FYI, disabling ASLR on Linux does really weird things to PIE binaries. Instead of loading at some random address in the shared library address range, they load at 0x5555..., or 1/3-ish of the userspace address space.

IIRC this affects MSan and TSan binaries, which are PIE by default these days. When you gdb such a binary, you need to disable the disabling of ASLR (blech). If you make this change to LLDB on Linux, you will need to do the same.

Quuxplusone commented 10 years ago
(In reply to comment #5)
> FYI, disabling ASLR on Linux does really weird things to PIE binaries.
> Instead of loading at some random address in the shared library address
> range, they load at 0x5555..., or 1/3-ish of the userspace address space.
>
> IIRC this affects MSan and TSan binaries, which are PIE by default these
> days.  When you gdb such a binary, you need to disable the disabling of ASLR
> (blech).  If you make this change to LLDB on Linux, you will need to do the
> same.

I meant to link to the documentation for this:
http://clang.llvm.org/docs/MemorySanitizer.html#limitations
Quuxplusone commented 10 years ago
Disabling ASLR is the default on the Mac, and has been since the OS X
introduced it.  I agree with Chandler, you never want ASLR on when debugging
unless forced to by some odd circumstance.

(In reply to comment #2)
> In my opinion it makes sense to universally default to --disable-aslr (or do
> so for all platforms except Mac, if there are legacy reasons to leave it as
> is there).
Quuxplusone commented 10 years ago

Ah! That's a gotcha. From the limitations page, it looks like the user is expected to enable (disable the disable) of ASLR on gdb. So we're not talking about auto-detecting, simply having the user need to take that step when they initiate debugging with msan. Right?

Quuxplusone commented 10 years ago

Disabling ASLR is the default on the Mac, and has been since the OS X introduced it.

Okay, thanks Jim. This should be a no-brainer then to disable by default.

It simply looks like it (the lldb handling one way or another of ASLR) was never implemented for Linux (and probably anything else), so if the default was to "shut it off", that mechanism was likely ignored.

In any event, I'll have a look at this as soon as I finish what I'm currently tracking down.

Quuxplusone commented 10 years ago

(and probably anything else)

That is, anything else non-Apple.

Quuxplusone commented 10 years ago

More implementation notes:

For the Linux local debugging with llgs (not yet upstream), I'll be calling personality() to do this during a fork/sync/exec-style launch. See here:

https://stackoverflow.com/questions/1455904/how-to-disable-address-space-randomization-for-a-binary-on-linux

That code is not ready-enough yet, so in the meanwhile I'll work on an upstream solution that follows my earlier implementation note (i.e. wrap inferior launch in a shell if not already, call /usr/bin/setarch -R $SHELL to run the shell with ASLR disabled).

Quuxplusone commented 10 years ago

I'm probably going to do this as two check-ins - first one to just implement it for Linux. Second one, flip the orientation of the flag to --enable-aslr after double checking with the Apple folks.

Quuxplusone commented 10 years ago

Hah ok so I implemented this with an extra wrapped version of /usr/bin/setarch -R, but that has a few issues I would still need to resolve. But - totally unnecessary and more complicated in TOT than it needs to be. The old Linux ProcessMonitor for local debugging can handle this easily in its fork/exec without adding any such complexity (i.e. this is what I was going to do in llgs-launched as well).

So the personality() call should work and it'll be simpler than what I was implying below.

Quuxplusone commented 10 years ago
Hey Chandler,

I put in a fix here:

 svn commit
Sending        lldb.xcodeproj/project.pbxproj
Sending        source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
Sending        source/Plugins/Process/FreeBSD/ProcessMonitor.h
Sending        source/Plugins/Process/Linux/NativeProcessLinux.cpp
Sending        source/Plugins/Process/Linux/NativeProcessLinux.h
Sending        source/Plugins/Process/Linux/ProcessMonitor.cpp
Sending        source/Plugins/Process/Linux/ProcessMonitor.h
Sending        source/Plugins/Process/POSIX/ProcessPOSIX.cpp
Transmitting file data ........
Committed revision 215822.

Until I get in the --enable-aslr flag (my next task), I think you'll be stuck
in ASLR-disabled mode since I don't actually see a way to say "enable it", and
it is disabled by default.  (We just weren't paying attention to the flag on
Linux until this change here).
Quuxplusone commented 10 years ago
For a related change, the 'process launch' (aka 'run') --disable-aslr flag now
takes an arg of true/false (or other boolean equivalents).  For a discussion on
this, see these links:

(Where we ultimately do away with the idea of --enable-aslr):
http://lists.cs.uiuc.edu/pipermail/lldb-commits/Week-of-Mon-20140818/012419.html

(The change, r215996):
http://lists.cs.uiuc.edu/pipermail/lldb-commits/Week-of-Mon-20140818/012445.html