【问题标题】:gdb appears to ignore executable capabilitiesgdb 似乎忽略了可执行功能
【发布时间】:2011-05-20 09:56:39
【问题描述】:

我正在调试一个使用libnetfilter_queue 的程序。该文档指出用户空间队列处理应用程序需要CAP_NET_ADMIN 功能才能运行。我已使用setcap 实用程序完成此操作,如下所示:

$ sudo setcap cap_net_raw,cap_net_admin=eip ./a.out

我已验证这些功能已正确应用,因为 a) 程序正常运行 b) getcap 返回以下输出:

$ getcap ./a.out
./a.out = cap_net_admin,cap_net_raw+eip

但是,当我尝试从命令行使用gdb(例如$ gdb ./a.out)调试该程序时,由于没有设置正确的权限而失败。 gdb 的调试功能可以正常工作并正常调试。

我什至尝试将这些功能应用于gdb 二进制文件本身,但无济于事。我这样做了(正如manpages 所记录的那样,“i”标志可能允许被调试者从调试器继承该功能。

我是否遗漏了一些琐碎的事情,或者这真的不能完成吗?

【问题讨论】:

  • GDB 使用 ptrace 子系统。它是否具有 CAP_SYS_PTRACE 功能?它是否适用于任何其他二进制文件?例如。 hello world 程序?
  • @thkala:我将问题编辑得更准确。 gdb 工作正常,否则它可以调试任何程序(包括这个)。
  • 您介意提及确切的错误消息吗?
  • 本身没有错误信息。我使用的是开发者提供的this示例代码,nfq_unbind_pf()返回-1(并且errno设置为1),表示失败。

标签: linux network-programming gdb sniffing linux-capabilities


【解决方案1】:

不久前我确实遇到了同样的问题。我的猜测是,运行带有附加功能的调试程序是一个安全问题。

您的程序比运行它的用户拥有更多权限。使用调试器,用户可以操纵程序的执行。因此,如果程序在具有额外特权的调试器下运行,则用户可以将这些特权用于程序打算使用它们的其他目的。这将是一个严重的安全漏洞,因为用户一开始就没有权限。

【讨论】:

  • 这个答案对我来说很有意义。我会尝试查看gdb 来源以确认是这种情况,但无论如何我都会将您的答案标记为已接受。
  • 我的猜测是这是由内核而不是 gdb 处理的。您可能应该查看 ptrace 系统调用。
  • 来自 linux execve 手册页:“如果在 filename 指向的程序文件上设置了 set-user-ID 位,并且底层文件系统没有挂载 nosuid(挂载的 MS_NOSUID 标志(2 )),并且调用进程未被ptrace,则调用进程的有效用户ID更改为程序文件所有者的有效用户ID。”这可能也适用于文件功能,因为它们像 suid/sgid 一样提供特权提升。
  • 猜错了 - 请参阅 Nick Huang 的回答。它对我有用。
【解决方案2】:

有同样问题的朋友可以通过sudo执行gdb来绕过这个问题。

【讨论】:

  • +1,虽然它不是适用于所有情况的解决方案。我有两个应用程序。首先设置了一些功能,但取决于第二个应用程序,它通过 RT 信号与第一个应用程序通信。因此,仅使用gdb ./a.out 不起作用,因为应用程序失去了她的功能,使用sudo gdb ./a.out 不起作用,因为用户运行的应用程序无法向在根目录下运行的应用程序发送信号。很难调试它,看起来没有解决方法:)
【解决方案3】:

我遇到了同样的问题,一开始我的想法和上面一样,可能 gdb 由于安全原因而忽略了可执行文件的功能。然而,阅读源代码,甚至在调试我的打开/dev/sda1的ext2fs-prog时使用eclipse调试gdb本身,我意识到:

  1. gdb 与任何其他程序没有什么特别之处。 (就像在矩阵中一样,即使是代理本身,他们也遵守相同的物理定律、重力等,只是他们都是守门人。)
  2. gdb 不是被调试的可执行文件的父进程,而是祖父进程。
  3. 被调试的可执行文件的真正父进程是“shell”,在我的例子中是/bin/bash

因此,解决方案非常简单,除了将cap_net_admin,cap_net_raw+eip 添加到gdb 之外,您还可以将其应用于您的shell。即setcap cap_net_admin,cap_net_raw+eip /bin/bash

您还必须对 gdb 执行此操作的原因是因为 gdb 在创建调试进程之前是 /bin/bash 的父进程。

gdb中真正的可执行命令行如下:

/bin/bash exec /my/executable/program/path

这是 gdb 中 vfork 的参数。

【讨论】:

    【解决方案4】:

    对于那些通过 IDE 运行 GDB 的人来说,sudo-ing GDB(如@Stéphane J. 的回答)可能是不可能的。在这种情况下,您可以运行:

    sudo gdbserver localhost:12345 /path/to/application
    

    然后将您的 IDE 的 GDB 实例附加到该(本地)GDBServer。

    对于 Eclipse CDT,这意味着进行新的“C/C++ 远程应用程序”调试配置,然后在“调试器”>“连接”选项卡下,输入 TCP / localhost / 12345(或您在上面选择的任何端口)。这使您可以在 Eclipse 中进行调试,同时您的应用程序具有特权访问权限。

    【讨论】:

      【解决方案5】:

      好的,所以我对此有点挣扎,所以我想我会结合答案和总结。

      简单的解决方案就是按照建议发送给sudo gdb,但要小心一点。您在这里所做的是以 root 身份运行调试程序。这很可能会导致它的运行方式与您从命令行以普通用户身份运行时不同。可能有点混乱。并不是说我会掉进这个陷阱……哎呀。

      如果您使用sudo 以root 身份运行调试程序,或者如果调试程序设置了setuid 位,这将很好。但是,如果调试的程序使用 POSIX 功能 (setcap / getcap) 运行,那么您需要按照 Nick Huang 的建议在 bash 和 gdb 中镜像这些更精细的权限,而不仅仅是使用“sudo”强制权限。

      做任何其他事情都可能导致你陷入极端学习的糟糕境地。

      【讨论】:

        【解决方案6】:

        我使用了@NickHuang 的解决方案,直到其中一个系统更新破坏了 systemd 服务(bash 上的功能太多,systemd 无法启动它或类似的东西)。切换到单独保留 bash,而是将命令传递给 gdb 以直接调用可执行文件。命令是

        set startup-with-shell off
        

        【讨论】:

          猜你喜欢
          • 2021-10-28
          • 2016-09-30
          • 2016-03-16
          • 2014-02-03
          • 2012-03-11
          • 2013-09-07
          • 2016-08-12
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多