proc/*: add launch option to disable ASLR (#2202)

Fixes #1847
This commit is contained in:
Alessandro Arzilli 2020-10-21 21:50:52 +02:00 committed by GitHub
parent 0bbf9e4eaf
commit 9a3c9ebad1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 76 additions and 17 deletions

@ -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")

@ -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")

@ -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")

@ -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")

@ -26,6 +26,7 @@ dlv core <executable> <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")

@ -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")

@ -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")

@ -33,6 +33,7 @@ dlv exec <path/to/binary>
--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")

@ -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")

@ -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")

@ -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")

@ -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")

@ -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")

@ -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")

@ -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")

@ -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:

@ -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...)

@ -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
}

@ -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

@ -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

@ -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

@ -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

@ -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)
}

@ -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")
}

@ -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

@ -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)
}

@ -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")