'How to debug programs with "sudo" in VSCODE

I am trying to debug a program in VSCODE. The program needs to be launched as root or with "sudo" on Ubuntu. What's the best way to achieve this? An example launch configuration would be helpful. Thanks.



Solution 1:[1]

I have been in a similar situation recently- I have solved it by adding {"sudo": true} in launch.json file under .vscode directory.

just added the following line in .vscode>launch.json

{
    "version": "0.2.0",
    "configurations": [
        {
            "other..." : "configs...",
            "request": "launch",
            "console": "integratedTerminal",
            "args": [
                "${file}"
            ],
            "sudo": true
        }
    ]
}

VS code version I'm using is -

Version: 1.49.1 OS: Ubuntu 16.04 LTS, 64-bit

This appears to not work on all languages. For me it worked for python 3.x Other users reported it doesn't work for C/C++.

Solution 2:[2]

I did the following:

  1. create a script called "gdb" in e.g. my home directory, containing: pkexec /usr/bin/gdb "$@"
  2. make it executable
  3. modify the launch.json in VSCode to call the script (obviously change username accordingly) by adding "miDebuggerPath":
...
            "externalConsole": false,
            "miDebuggerPath": "/home/<username>/gdb",
            "MIMode": "gdb",
...
  1. whilst debugging, use top or such like to verify the process is running as root.

That should be enough.

Solution 3:[3]

My solution:

add /usr/bin/gdb to /etc/sudoers like here

add a executable file whose content is

sudo /usr/bin/gdb "$@"

set miDebuggerPath to the file

Solution 4:[4]

Do not know the way to make vscode to run sudo gdb. But you can sudo to run vscode so natually you can sudo gdb for debug.

sudo code . --user-data-dir='.'

Solution 5:[5]

As from the previous answers I had to use the method with a executable file in the home directory like: /home/youruser/gdbasroot

But I had to use the content:

sudo /usr/bin/gdb "$@"

instead of gdbk because I couldn't get gdbk to work without prompting for a password (which didnt work as its called by vscode remote debuger). I did it according this post (the upvoted and accepted answer):

https://askubuntu.com/questions/542397/change-default-user-for-authentication

When using sudo you can issue a sudo command in the vscode terminal and from then on you can use the "sudo debugger" without the password. Otherwise vscode gets prompted and can't handle it.

Greetings

Solution 6:[6]

I did the following:

  1. try what Jason did
  2. tired with endless annoying dialogue box for password
  3. write a python script to resolve that

launch.json:

...
"externalConsole": false,
"miDebuggerPath": "${workspaceFolder}/scripts/gdb_root.py",
"MIMode": "gdb",
...

gdb_root.py:

#!/usr/bin/python3
import os
import sys
import stat
import time
import json
import hashlib
from pathlib import Path

GRANT_EXPIRE_SEC = 2 * 60 * 60
TARGET_EXECUTABLE = '/usr/bin/gdb'
TMP_BIN_DIR = '/tmp/exec_as_root'


class ExecFailed(Exception):
    pass


def instance_hash(argv):
    command = ' '.join(argv)
    return hashlib.md5(command.encode()).hexdigest()


def write_c_code(path, argv):
    CODE_TEMPLATE = '''
    #include <time.h>
    #include <stdlib.h>
    #include <unistd.h>

    int main(int argc, char *argv[])
    {
        int test_mode = (argc > 1);
        if (time(NULL) > (time_t)EXPIRE) {
            char path[1024] = { 0 };
            readlink("/proc/self/exe", path, sizeof(path));
            unlink(path);
            return !test_mode;
        }

        if (!test_mode)
            execl(PARAMS, NULL);

        return 0;
    }'''

    expire = time.time() + GRANT_EXPIRE_SEC
    params = [argv[0]] + argv
    params = json.dumps(params)[1:-1]
    content = CODE_TEMPLATE \
        .replace('EXPIRE', str(expire)) \
        .replace('PARAMS', params)

    with open(path, 'w') as f:
        f.write(content)


def system(cmd):
    is_ok = os.system(cmd) == 0
    if not is_ok:
        cmd_str = json.dumps(cmd)
        summary = 'failed to execute:'
        os.system(f'notify-send -- "{summary}" {cmd_str}')
        raise ExecFailed()


def build_instance(instance, argv):
    c_file = instance.with_suffix('.c')
    write_c_code(c_file, argv)
    compile_cmd = f'gcc -o {instance} {c_file}'
    system(compile_cmd)


def did_grant_root(file):
    fs = os.stat(file)
    root_own = (fs.st_uid == 0)
    uid_set = fs.st_mode & stat.S_ISUID
    return root_own and uid_set


def grant_root(file):
    setuid_cmd = f'chown root:root {file}; chmod 4111 {file}'
    pkexec_cmd = f'pkexec bash -c "{setuid_cmd}"'
    system(pkexec_cmd)


def main():
    bin_dir = Path(TMP_BIN_DIR)
    bin_dir.mkdir(exist_ok=True)

    argv = [TARGET_EXECUTABLE] + sys.argv[1:]
    instance = bin_dir / instance_hash(argv)

    if instance.exists():
        system(f'{instance} test')

    if not instance.exists():
        build_instance(instance, argv)

    if not did_grant_root(instance):
        grant_root(instance)

    os.execv(instance, [instance.name])


if __name__ == '__main__':
    try:
        main()
    except ExecFailed:
        exit(1)

This is a portable solution, no effect to system, and do not forget: chmod +x scripts/gdb_root.py

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 bolov
Solution 2 Den-Jason
Solution 3 Yong-Hao Zou
Solution 4 user7469511
Solution 5 Alex
Solution 6