【问题标题】:How to debug programs with "sudo" in VSCODE如何在 VSCODE 中使用“sudo”调试程序
【发布时间】:2017-02-23 07:18:14
【问题描述】:

我正在尝试在 VSCODE 中调试程序。该程序需要以 root 身份启动或在 Ubuntu 上使用“sudo”启动。实现这一目标的最佳方法是什么?一个示例启动配置会很有帮助。谢谢。

【问题讨论】:

  • 调试以root身份运行的进程的唯一方法是以root身份运行的调试器。这是 POSIX 安全模型的一个基本方面。 Vscode 对此无能为力。因此,您必须以 root 身份运行 vscode。
  • @SamVarshavchik:至少在 Linux 上运行时,vscode 通过调用调试器(gdb 或 lldb)作为单独的进程进行调试,其路径在名为 @ 的文件中指定为 miDebuggerPath 987654323@。您可能可以指定sudo /usr/bin/gdb,但您可能还想使用--askpass 指定获取凭据的替代方式,因为用户可能无法直接与sudo 交互以进行身份​​验证。

标签: c++ c visual-studio-code


【解决方案1】:

我做了以下事情:

  1. 创建一个名为“gdb”的脚本,例如我的主目录,包含: pkexec /usr/bin/gdb "$@"
  2. 使其可执行
  3. 修改VSCode中的launch.json调用脚本(明显改变用户名),添加“miDebuggerPath”:
...
            "externalConsole": false,
            "miDebuggerPath": "/home/<username>/gdb",
            "MIMode": "gdb",
...
  1. 在调试时,使用top 或类似方法来验证进程是否以root 身份运行。

应该够了。

【讨论】:

  • 超级有帮助。如果我知道如何让 pkexec 记住我的密码就好了!另一个注意事项是 VSCode 如果您取消提示,则不会结束调试会话。
  • 不适用于无密码的基于密钥的身份验证。
【解决方案2】:

我最近也遇到了类似的情况- 我已经通过在 .vscode 目录下的 launch.json 文件中添加 {"sudo": true} 来解决它。

刚刚在 .vscode>launch.json 中添加了以下行

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

我使用的VS代码版本是-

版本:1.49.1 操作系统:Ubuntu 16.04 LTS,64 位

这似乎不适用于所有语言。对我来说,它适用于 python 3.x 其他用户报告它不适用于 C/C++。

【讨论】:

  • 这在调试 C/C++ 代码时不起作用,也许对于其他语言? (OP 没有指定语言)
  • 抱歉没有提到语言。它是 Python 3.x
  • 这适用于我在 Python3.6 上并使用远程机器。
【解决方案3】:

不知道如何让vscode运行sudo gdb。 但是你可以 sudo 来运行 vscode 所以你自然可以 sudo gdb 来调试。

须藤代码。 --user-data-dir='.'

【讨论】:

  • 我正在使用 Visual Studio Code Remote 来编辑远程 ubuntu 服务器上的代码。知道我该怎么做吗?
【解决方案4】:

我的解决方案:

/usr/bin/gdb 添加到/etc/sudoers 就像here 一样

添加一个可执行文件,其内容为

sudo /usr/bin/gdb "$@"

miDebuggerPath 设置为文件

【讨论】:

  • user_name ALL=(ALL) NOPASSWD:/usr/bin/gdb。那行得通。是的,这很糟糕,因为我们为 gdb 添加了 sudo。安全漏洞,除了我正在使用 Raspberry Pi 处理整个本地场景,这是一个永远不会投入生产的物联网设备,所以对我有用。
  • 在远程 Ubuntu 目标上工作时,此解决方案对我有用。请注意,最好将 ALL ALL=(ALL) NOPASSWD:/usr/bin/gdb 添加到 /etc/sudoers.d 文件夹中的单独文件中,而不是更改 /etc/sudoers 文件
【解决方案5】:

与之前的答案一样,我必须在主目录中使用带有可执行文件的方法,例如: /home/youruser/gdbasroot

但我不得不使用内容:

sudo /usr/bin/gdb "$@"

而不是 gdbk,因为我无法在不提示输入密码的情况下让 gdbk 工作(它没有像 vscode 远程调试器调用的那样工作)。我是根据这篇文章(赞成和接受的答案)做到的:

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

使用 sudo 时,您可以在 vscode 终端中发出 sudo 命令,然后您就可以在没有密码的情况下使用“sudo 调试器”。否则vscode会提示无法处理。

问候

【讨论】:

    【解决方案6】:

    我做了以下事情:

    1. 试试Jason 做了什么
    2. 厌倦了无休止的烦人的密码对话框
    3. 编写一个 python 脚本来解决这个问题

    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)
    

    这是一个便携的解决方案,对系统没有影响,不要忘记:chmod +x scripts/gdb_root.py

    【讨论】:

      猜你喜欢
      • 2022-10-14
      • 2017-10-21
      • 2023-03-12
      • 2019-06-27
      • 2016-08-28
      • 2020-05-28
      • 2016-07-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多