diff --git a/Documentation/usage/dlv.md b/Documentation/usage/dlv.md index f7e72b12..48684855 100644 --- a/Documentation/usage/dlv.md +++ b/Documentation/usage/dlv.md @@ -25,6 +25,7 @@ Pass flags to the program you are debugging using `--`, for example: --backend string Backend selection (see 'dlv help backend'). (default "default") --build-flags string Build flags, to be passed to the compiler. --check-go-version Checks that the version of Go in use is compatible with Delve. (default true) + --disable-aslr Disables address space randomization --headless Run debug server only, in headless mode. --init string Init file, executed by the terminal client. -l, --listen string Debugging server listen address. (default "127.0.0.1:0") diff --git a/Documentation/usage/dlv_attach.md b/Documentation/usage/dlv_attach.md index 730cc6ef..12515960 100644 --- a/Documentation/usage/dlv_attach.md +++ b/Documentation/usage/dlv_attach.md @@ -31,6 +31,7 @@ dlv attach pid [executable] --backend string Backend selection (see 'dlv help backend'). (default "default") --build-flags string Build flags, to be passed to the compiler. --check-go-version Checks that the version of Go in use is compatible with Delve. (default true) + --disable-aslr Disables address space randomization --headless Run debug server only, in headless mode. --init string Init file, executed by the terminal client. -l, --listen string Debugging server listen address. (default "127.0.0.1:0") diff --git a/Documentation/usage/dlv_backend.md b/Documentation/usage/dlv_backend.md index 09e99224..c7ca4685 100644 --- a/Documentation/usage/dlv_backend.md +++ b/Documentation/usage/dlv_backend.md @@ -24,6 +24,7 @@ are: --backend string Backend selection (see 'dlv help backend'). (default "default") --build-flags string Build flags, to be passed to the compiler. --check-go-version Checks that the version of Go in use is compatible with Delve. (default true) + --disable-aslr Disables address space randomization --headless Run debug server only, in headless mode. --init string Init file, executed by the terminal client. -l, --listen string Debugging server listen address. (default "127.0.0.1:0") diff --git a/Documentation/usage/dlv_connect.md b/Documentation/usage/dlv_connect.md index 9b1cbe99..0c232a0f 100644 --- a/Documentation/usage/dlv_connect.md +++ b/Documentation/usage/dlv_connect.md @@ -20,6 +20,7 @@ dlv connect addr --backend string Backend selection (see 'dlv help backend'). (default "default") --build-flags string Build flags, to be passed to the compiler. --check-go-version Checks that the version of Go in use is compatible with Delve. (default true) + --disable-aslr Disables address space randomization --headless Run debug server only, in headless mode. --init string Init file, executed by the terminal client. -l, --listen string Debugging server listen address. (default "127.0.0.1:0") diff --git a/Documentation/usage/dlv_core.md b/Documentation/usage/dlv_core.md index c625bec5..fe9706cc 100644 --- a/Documentation/usage/dlv_core.md +++ b/Documentation/usage/dlv_core.md @@ -26,6 +26,7 @@ dlv core --backend string Backend selection (see 'dlv help backend'). (default "default") --build-flags string Build flags, to be passed to the compiler. --check-go-version Checks that the version of Go in use is compatible with Delve. (default true) + --disable-aslr Disables address space randomization --headless Run debug server only, in headless mode. --init string Init file, executed by the terminal client. -l, --listen string Debugging server listen address. (default "127.0.0.1:0") diff --git a/Documentation/usage/dlv_dap.md b/Documentation/usage/dlv_dap.md index 931d7a27..14bb4322 100644 --- a/Documentation/usage/dlv_dap.md +++ b/Documentation/usage/dlv_dap.md @@ -27,6 +27,7 @@ dlv dap --backend string Backend selection (see 'dlv help backend'). (default "default") --build-flags string Build flags, to be passed to the compiler. --check-go-version Checks that the version of Go in use is compatible with Delve. (default true) + --disable-aslr Disables address space randomization --headless Run debug server only, in headless mode. --init string Init file, executed by the terminal client. -l, --listen string Debugging server listen address. (default "127.0.0.1:0") diff --git a/Documentation/usage/dlv_debug.md b/Documentation/usage/dlv_debug.md index c5ea8f71..d3366136 100644 --- a/Documentation/usage/dlv_debug.md +++ b/Documentation/usage/dlv_debug.md @@ -33,6 +33,7 @@ dlv debug [package] --backend string Backend selection (see 'dlv help backend'). (default "default") --build-flags string Build flags, to be passed to the compiler. --check-go-version Checks that the version of Go in use is compatible with Delve. (default true) + --disable-aslr Disables address space randomization --headless Run debug server only, in headless mode. --init string Init file, executed by the terminal client. -l, --listen string Debugging server listen address. (default "127.0.0.1:0") diff --git a/Documentation/usage/dlv_exec.md b/Documentation/usage/dlv_exec.md index 350e4183..6e266f81 100644 --- a/Documentation/usage/dlv_exec.md +++ b/Documentation/usage/dlv_exec.md @@ -33,6 +33,7 @@ dlv exec --backend string Backend selection (see 'dlv help backend'). (default "default") --build-flags string Build flags, to be passed to the compiler. --check-go-version Checks that the version of Go in use is compatible with Delve. (default true) + --disable-aslr Disables address space randomization --headless Run debug server only, in headless mode. --init string Init file, executed by the terminal client. -l, --listen string Debugging server listen address. (default "127.0.0.1:0") diff --git a/Documentation/usage/dlv_log.md b/Documentation/usage/dlv_log.md index 503f6ed1..3dd2c4cf 100644 --- a/Documentation/usage/dlv_log.md +++ b/Documentation/usage/dlv_log.md @@ -39,6 +39,7 @@ and dap modes. --backend string Backend selection (see 'dlv help backend'). (default "default") --build-flags string Build flags, to be passed to the compiler. --check-go-version Checks that the version of Go in use is compatible with Delve. (default true) + --disable-aslr Disables address space randomization --headless Run debug server only, in headless mode. --init string Init file, executed by the terminal client. -l, --listen string Debugging server listen address. (default "127.0.0.1:0") diff --git a/Documentation/usage/dlv_redirect.md b/Documentation/usage/dlv_redirect.md index eda39268..f8ef2bfc 100644 --- a/Documentation/usage/dlv_redirect.md +++ b/Documentation/usage/dlv_redirect.md @@ -27,6 +27,7 @@ File redirects can also be changed using the 'restart' command. --backend string Backend selection (see 'dlv help backend'). (default "default") --build-flags string Build flags, to be passed to the compiler. --check-go-version Checks that the version of Go in use is compatible with Delve. (default true) + --disable-aslr Disables address space randomization --headless Run debug server only, in headless mode. --init string Init file, executed by the terminal client. -l, --listen string Debugging server listen address. (default "127.0.0.1:0") diff --git a/Documentation/usage/dlv_replay.md b/Documentation/usage/dlv_replay.md index 16b5fc0d..527b4d86 100644 --- a/Documentation/usage/dlv_replay.md +++ b/Documentation/usage/dlv_replay.md @@ -24,6 +24,7 @@ dlv replay [trace directory] --backend string Backend selection (see 'dlv help backend'). (default "default") --build-flags string Build flags, to be passed to the compiler. --check-go-version Checks that the version of Go in use is compatible with Delve. (default true) + --disable-aslr Disables address space randomization --headless Run debug server only, in headless mode. --init string Init file, executed by the terminal client. -l, --listen string Debugging server listen address. (default "127.0.0.1:0") diff --git a/Documentation/usage/dlv_run.md b/Documentation/usage/dlv_run.md index 979c1e9f..b39653f2 100644 --- a/Documentation/usage/dlv_run.md +++ b/Documentation/usage/dlv_run.md @@ -20,6 +20,7 @@ dlv run --backend string Backend selection (see 'dlv help backend'). (default "default") --build-flags string Build flags, to be passed to the compiler. --check-go-version Checks that the version of Go in use is compatible with Delve. (default true) + --disable-aslr Disables address space randomization --headless Run debug server only, in headless mode. --init string Init file, executed by the terminal client. -l, --listen string Debugging server listen address. (default "127.0.0.1:0") diff --git a/Documentation/usage/dlv_test.md b/Documentation/usage/dlv_test.md index 87737be8..ab484ff6 100644 --- a/Documentation/usage/dlv_test.md +++ b/Documentation/usage/dlv_test.md @@ -31,6 +31,7 @@ dlv test [package] --backend string Backend selection (see 'dlv help backend'). (default "default") --build-flags string Build flags, to be passed to the compiler. --check-go-version Checks that the version of Go in use is compatible with Delve. (default true) + --disable-aslr Disables address space randomization --headless Run debug server only, in headless mode. --init string Init file, executed by the terminal client. -l, --listen string Debugging server listen address. (default "127.0.0.1:0") diff --git a/Documentation/usage/dlv_trace.md b/Documentation/usage/dlv_trace.md index 8e7cc4d4..34afd913 100644 --- a/Documentation/usage/dlv_trace.md +++ b/Documentation/usage/dlv_trace.md @@ -38,6 +38,7 @@ dlv trace [package] regexp --backend string Backend selection (see 'dlv help backend'). (default "default") --build-flags string Build flags, to be passed to the compiler. --check-go-version Checks that the version of Go in use is compatible with Delve. (default true) + --disable-aslr Disables address space randomization --headless Run debug server only, in headless mode. --init string Init file, executed by the terminal client. -l, --listen string Debugging server listen address. (default "127.0.0.1:0") diff --git a/Documentation/usage/dlv_version.md b/Documentation/usage/dlv_version.md index c0ab1f4b..c5d7a2ea 100644 --- a/Documentation/usage/dlv_version.md +++ b/Documentation/usage/dlv_version.md @@ -20,6 +20,7 @@ dlv version --backend string Backend selection (see 'dlv help backend'). (default "default") --build-flags string Build flags, to be passed to the compiler. --check-go-version Checks that the version of Go in use is compatible with Delve. (default true) + --disable-aslr Disables address space randomization --headless Run debug server only, in headless mode. --init string Init file, executed by the terminal client. -l, --listen string Debugging server listen address. (default "127.0.0.1:0") diff --git a/cmd/dlv/cmds/commands.go b/cmd/dlv/cmds/commands.go index e28a0a16..aaa74759 100644 --- a/cmd/dlv/cmds/commands.go +++ b/cmd/dlv/cmds/commands.go @@ -58,6 +58,8 @@ var ( checkLocalConnUser bool // tty is used to provide an alternate TTY for the program you wish to debug. tty string + // disableASLR is used to disable ASLR + disableASLR bool // backend selection backend string @@ -131,6 +133,7 @@ func New(docCall bool) *cobra.Command { rootCommand.PersistentFlags().StringVar(&backend, "backend", "default", `Backend selection (see 'dlv help backend').`) rootCommand.PersistentFlags().StringArrayVarP(&redirects, "redirect", "r", []string{}, "Specifies redirect rules for target process (see 'dlv help redirect')") rootCommand.PersistentFlags().BoolVar(&allowNonTerminalInteractive, "allow-non-terminal-interactive", false, "Allows interactive sessions of Delve that don't have a terminal as stdin, stdout and stderr") + rootCommand.PersistentFlags().BoolVar(&disableASLR, "disable-aslr", false, "Disables address space randomization") // 'attach' subcommand. attachCommand := &cobra.Command{ @@ -842,6 +845,7 @@ func execute(attachPid int, processArgs []string, conf *config.Config, coreFile CheckGoVersion: checkGoVersion, TTY: tty, Redirects: redirects, + DisableASLR: disableASLR, }, }) default: diff --git a/pkg/proc/gdbserial/gdbserver.go b/pkg/proc/gdbserial/gdbserver.go index 26883047..b1937b86 100644 --- a/pkg/proc/gdbserial/gdbserver.go +++ b/pkg/proc/gdbserial/gdbserver.go @@ -342,11 +342,13 @@ func getLdEnvVars() []string { // LLDBLaunch starts an instance of lldb-server and connects to it, asking // it to launch the specified target program with the specified arguments // (cmd) on the specified directory wd. -func LLDBLaunch(cmd []string, wd string, foreground bool, debugInfoDirs []string, tty string, redirects [3]string) (*proc.Target, error) { +func LLDBLaunch(cmd []string, wd string, flags proc.LaunchFlags, debugInfoDirs []string, tty string, redirects [3]string) (*proc.Target, error) { if runtime.GOOS == "windows" { return nil, ErrUnsupportedOS } + foreground := flags&proc.LaunchForeground != 0 + if foreground { // Disable foregrounding if we can't open /dev/tty or debugserver will // crash. See issue #1215. @@ -400,6 +402,9 @@ func LLDBLaunch(cmd []string, wd string, foreground bool, debugInfoDirs []string if logflags.LLDBServerOutput() { args = append(args, "-g", "-l", "stdout") } + if flags&proc.LaunchDisableASLR != 0 { + args = append(args, "-D") + } args = append(args, "-F", "-R", fmt.Sprintf("127.0.0.1:%d", listener.Addr().(*net.TCPAddr).Port), "--") args = append(args, cmd...) diff --git a/pkg/proc/native/nonative_darwin.go b/pkg/proc/native/nonative_darwin.go index 544b2d73..2c00425b 100644 --- a/pkg/proc/native/nonative_darwin.go +++ b/pkg/proc/native/nonative_darwin.go @@ -12,7 +12,7 @@ import ( var ErrNativeBackendDisabled = errors.New("native backend disabled during compilation") // Launch returns ErrNativeBackendDisabled. -func Launch(_ []string, _ string, _ bool, _ []string, _ string, _ [3]string) (*proc.Target, error) { +func Launch(_ []string, _ string, _ proc.LaunchFlags, _ []string, _ string, _ [3]string) (*proc.Target, error) { return nil, ErrNativeBackendDisabled } diff --git a/pkg/proc/native/proc_darwin.go b/pkg/proc/native/proc_darwin.go index d8dfb758..5d5320b6 100644 --- a/pkg/proc/native/proc_darwin.go +++ b/pkg/proc/native/proc_darwin.go @@ -37,7 +37,7 @@ type osProcessDetails struct { // custom fork/exec process in order to take advantage of // PT_SIGEXC on Darwin which will turn Unix signals into // Mach exceptions. -func Launch(cmd []string, wd string, foreground bool, _ []string, _ string, _ [3]string) (*proc.Target, error) { +func Launch(cmd []string, wd string, flags proc.LaunchFlags, _ []string, _ string, _ [3]string) (*proc.Target, error) { argv0Go, err := filepath.Abs(cmd[0]) if err != nil { return nil, err diff --git a/pkg/proc/native/proc_freebsd.go b/pkg/proc/native/proc_freebsd.go index f2fe628a..9457161e 100644 --- a/pkg/proc/native/proc_freebsd.go +++ b/pkg/proc/native/proc_freebsd.go @@ -42,12 +42,14 @@ type osProcessDetails struct { // to be supplied to that process. `wd` is working directory of the program. // If the DWARF information cannot be found in the binary, Delve will look // for external debug files in the directories passed in. -func Launch(cmd []string, wd string, foreground bool, debugInfoDirs []string, tty string, redirects [3]string) (*proc.Target, error) { +func Launch(cmd []string, wd string, flags proc.LaunchFlags, debugInfoDirs []string, tty string, redirects [3]string) (*proc.Target, error) { var ( process *exec.Cmd err error ) + foreground := flags&proc.LaunchForeground != 0 + stdin, stdout, stderr, closefn, err := openRedirects(redirects, foreground) if err != nil { return nil, err diff --git a/pkg/proc/native/proc_linux.go b/pkg/proc/native/proc_linux.go index 626383b5..00a01038 100644 --- a/pkg/proc/native/proc_linux.go +++ b/pkg/proc/native/proc_linux.go @@ -36,6 +36,9 @@ const ( // version of the kernel ('T' is job control stop on modern 3.x+ kernels) we // may want to differentiate at some point. statusTraceStopT = 'T' + + personalityGetPersonality = 0xffffffff // argument to pass to personality syscall to get the current personality + _ADDR_NO_RANDOMIZE = 0x0040000 // ADDR_NO_RANDOMIZE linux constant ) // osProcessDetails contains Linux specific @@ -49,12 +52,14 @@ type osProcessDetails struct { // to be supplied to that process. `wd` is working directory of the program. // If the DWARF information cannot be found in the binary, Delve will look // for external debug files in the directories passed in. -func Launch(cmd []string, wd string, foreground bool, debugInfoDirs []string, tty string, redirects [3]string) (*proc.Target, error) { +func Launch(cmd []string, wd string, flags proc.LaunchFlags, debugInfoDirs []string, tty string, redirects [3]string) (*proc.Target, error) { var ( process *exec.Cmd err error ) + foreground := flags&proc.LaunchForeground != 0 + stdin, stdout, stderr, closefn, err := openRedirects(redirects, foreground) if err != nil { return nil, err @@ -73,6 +78,15 @@ func Launch(cmd []string, wd string, foreground bool, debugInfoDirs []string, tt } }() dbp.execPtraceFunc(func() { + if flags&proc.LaunchDisableASLR != 0 { + oldPersonality, _, err := syscall.Syscall(sys.SYS_PERSONALITY, personalityGetPersonality, 0, 0) + if err == syscall.Errno(0) { + newPersonality := oldPersonality | _ADDR_NO_RANDOMIZE + syscall.Syscall(sys.SYS_PERSONALITY, newPersonality, 0, 0) + defer syscall.Syscall(sys.SYS_PERSONALITY, oldPersonality, 0, 0) + } + } + process = exec.Command(cmd[0]) process.Args = cmd process.Stdin = stdin diff --git a/pkg/proc/native/proc_windows.go b/pkg/proc/native/proc_windows.go index fa32ebb4..c7ce90a5 100644 --- a/pkg/proc/native/proc_windows.go +++ b/pkg/proc/native/proc_windows.go @@ -21,7 +21,7 @@ type osProcessDetails struct { } // Launch creates and begins debugging a new process. -func Launch(cmd []string, wd string, foreground bool, _ []string, _ string, redirects [3]string) (*proc.Target, error) { +func Launch(cmd []string, wd string, flags proc.LaunchFlags, _ []string, _ string, redirects [3]string) (*proc.Target, error) { argv0Go, err := filepath.Abs(cmd[0]) if err != nil { return nil, err diff --git a/pkg/proc/proc_linux_test.go b/pkg/proc/proc_linux_test.go index 4f8b9458..d10e17ff 100644 --- a/pkg/proc/proc_linux_test.go +++ b/pkg/proc/proc_linux_test.go @@ -14,7 +14,7 @@ func TestLoadingExternalDebugInfo(t *testing.T) { fixture := protest.BuildFixture("locationsprog", 0) defer os.Remove(fixture.Path) stripAndCopyDebugInfo(fixture, t) - p, err := native.Launch(append([]string{fixture.Path}, ""), "", false, []string{filepath.Dir(fixture.Path)}, "", [3]string{}) + p, err := native.Launch(append([]string{fixture.Path}, ""), "", 0, []string{filepath.Dir(fixture.Path)}, "", [3]string{}) if err != nil { t.Fatal(err) } diff --git a/pkg/proc/proc_test.go b/pkg/proc/proc_test.go index d08cb7b3..83c953b9 100644 --- a/pkg/proc/proc_test.go +++ b/pkg/proc/proc_test.go @@ -97,9 +97,9 @@ func withTestProcessArgs(name string, t testing.TB, wd string, args []string, bu switch testBackend { case "native": - p, err = native.Launch(append([]string{fixture.Path}, args...), wd, false, []string{}, "", [3]string{}) + p, err = native.Launch(append([]string{fixture.Path}, args...), wd, 0, []string{}, "", [3]string{}) case "lldb": - p, err = gdbserial.LLDBLaunch(append([]string{fixture.Path}, args...), wd, false, []string{}, "", [3]string{}) + p, err = gdbserial.LLDBLaunch(append([]string{fixture.Path}, args...), wd, 0, []string{}, "", [3]string{}) case "rr": protest.MustHaveRecordingAllowed(t) t.Log("recording") @@ -2108,9 +2108,9 @@ func TestUnsupportedArch(t *testing.T) { switch testBackend { case "native": - p, err = native.Launch([]string{outfile}, ".", false, []string{}, "", [3]string{}) + p, err = native.Launch([]string{outfile}, ".", 0, []string{}, "", [3]string{}) case "lldb": - p, err = gdbserial.LLDBLaunch([]string{outfile}, ".", false, []string{}, "", [3]string{}) + p, err = gdbserial.LLDBLaunch([]string{outfile}, ".", 0, []string{}, "", [3]string{}) default: t.Skip("test not valid for this backend") } diff --git a/pkg/proc/target.go b/pkg/proc/target.go index 9711275e..1eafc43c 100644 --- a/pkg/proc/target.go +++ b/pkg/proc/target.go @@ -23,6 +23,13 @@ var ( ErrProcessDetached = errors.New("detached from the process") ) +type LaunchFlags uint8 + +const ( + LaunchForeground LaunchFlags = 1 << iota + LaunchDisableASLR +) + // Target represents the process being debugged. type Target struct { Process diff --git a/service/debugger/debugger.go b/service/debugger/debugger.go index c58ae2bf..b4c8398f 100644 --- a/service/debugger/debugger.go +++ b/service/debugger/debugger.go @@ -120,6 +120,9 @@ type Config struct { // Redirects specifies redirect rules for stdin, stdout and stderr Redirects [3]string + + // DisableASLR disables ASLR + DisableASLR bool } // New creates a new Debugger. ProcessArgs specify the commandline arguments for the @@ -222,11 +225,20 @@ func (d *Debugger) Launch(processArgs []string, wd string) (*proc.Target, error) if err := verifyBinaryFormat(processArgs[0]); err != nil { return nil, err } + + launchFlags := proc.LaunchFlags(0) + if d.config.Foreground { + launchFlags |= proc.LaunchForeground + } + if d.config.DisableASLR { + launchFlags |= proc.LaunchDisableASLR + } + switch d.config.Backend { case "native": - return native.Launch(processArgs, wd, d.config.Foreground, d.config.DebugInfoDirectories, d.config.TTY, d.config.Redirects) + return native.Launch(processArgs, wd, launchFlags, d.config.DebugInfoDirectories, d.config.TTY, d.config.Redirects) case "lldb": - return betterGdbserialLaunchError(gdbserial.LLDBLaunch(processArgs, wd, d.config.Foreground, d.config.DebugInfoDirectories, d.config.TTY, d.config.Redirects)) + return betterGdbserialLaunchError(gdbserial.LLDBLaunch(processArgs, wd, launchFlags, d.config.DebugInfoDirectories, d.config.TTY, d.config.Redirects)) case "rr": if d.target != nil { // restart should not call us if the backend is 'rr' @@ -268,9 +280,9 @@ func (d *Debugger) Launch(processArgs []string, wd string) (*proc.Target, error) case "default": if runtime.GOOS == "darwin" { - return betterGdbserialLaunchError(gdbserial.LLDBLaunch(processArgs, wd, d.config.Foreground, d.config.DebugInfoDirectories, d.config.TTY, d.config.Redirects)) + return betterGdbserialLaunchError(gdbserial.LLDBLaunch(processArgs, wd, launchFlags, d.config.DebugInfoDirectories, d.config.TTY, d.config.Redirects)) } - return native.Launch(processArgs, wd, d.config.Foreground, d.config.DebugInfoDirectories, d.config.TTY, d.config.Redirects) + return native.Launch(processArgs, wd, launchFlags, d.config.DebugInfoDirectories, d.config.TTY, d.config.Redirects) default: return nil, fmt.Errorf("unknown backend %q", d.config.Backend) } diff --git a/service/test/variables_test.go b/service/test/variables_test.go index a20cbfba..a196ed96 100644 --- a/service/test/variables_test.go +++ b/service/test/variables_test.go @@ -131,9 +131,9 @@ func withTestProcessArgs(name string, t *testing.T, wd string, args []string, bu var tracedir string switch testBackend { case "native": - p, err = native.Launch(append([]string{fixture.Path}, args...), wd, false, []string{}, "", [3]string{}) + p, err = native.Launch(append([]string{fixture.Path}, args...), wd, 0, []string{}, "", [3]string{}) case "lldb": - p, err = gdbserial.LLDBLaunch(append([]string{fixture.Path}, args...), wd, false, []string{}, "", [3]string{}) + p, err = gdbserial.LLDBLaunch(append([]string{fixture.Path}, args...), wd, 0, []string{}, "", [3]string{}) case "rr": protest.MustHaveRecordingAllowed(t) t.Log("recording")