gdb appears to ignore executable capabilities
Asked Answered
V

6

12

I am debugging a program that makes use of libnetfilter_queue. The documentation states that a userspace queue-handling application needs the CAP_NET_ADMIN capability to function. I have done this using the setcap utility as follows:

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

I have verified that the capabilities are applied correctly as a) the program works and b) getcap returns the following output:

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

However, when I attempt to debug this program using gdb (e.g. $ gdb ./a.out) from the command line, it fails on account of not having the correct permissions set. The debugging functionality of gdb works perfectly otherwise and debugs as per normal.

I have even attempted to apply these capabilities to the gdb binary itself to no avail. I did this as it seemed (as documented by the manpages that the "i" flag might allowed the debugee to inherit the capability from the debugger.

Is there something trivial I am missing or can this really not be done?

Vacillating answered 5/12, 2010 at 2:37 Comment(4)
GDB uses the ptrace subsystem. Does it have the CAP_SYS_PTRACE capability ? Does it work with any other binary? E.g. a hello world program ?Nussbaum
@thkala: I edited the question to be more precise. gdb does work fine, it can debug any program (including this one) otherwise.Vacillating
Would you mind mentioning the exact error message?Nussbaum
There is no error message per se. I am using this sample code provided by the developers and nfq_unbind_pf() is returning -1 (and errno is set to 1), indicating failure.Vacillating
L
3

A while ago I did run into the same problem. My guess is that running the debugged program with the additional capabilities is a security issue.

Your program has more privileges than the user that runs it. With a debugger a user can manipulate the execution of the program. So if the program runs under the debugger with the extra privileges then the user could use these privileges for other purposes than for which the program intended to use them. This would be a serious security hole, because the user does not have the privileges in the first place.

Lanettelaney answered 5/12, 2010 at 8:8 Comment(4)
That answer makes a lot of sense to me. I'll try looking into the gdb source to confirm this is the case, but I'll mark your answer as accepted now anyway.Vacillating
My guess is that this is handled by the kernel instead of gdb. You should probably look into the ptrace system call.Lanettelaney
From linux execve manpage: "If the set-user-ID bit is set on the program file pointed to by filename, and the underlying file system is not mounted nosuid (the MS_NOSUID flag for mount(2)), and the calling process is not being ptraced, then the effective user ID of the calling process is changed to that of the owner of the program file." This probably also holds for file capabilities, because like suid/sgid they provide privilege elevation.Lanettelaney
The guess is wrong - see answer by Nick Huang. It worked for me.Rheingold
M
21

I run into same problem and at beginning I thought the same as above that maybe gdb is ignoring the executable's capability due to security reason. However, reading source code and even using eclipse debugging gdb itself when it is debugging my ext2fs-prog which opens /dev/sda1, I realize that:

  1. gdb is no special as any other program. (Just like it is in the matrix, even the agents themselves they obey the same physical law, gravity etc, except that they are all door-keepers.)
  2. gdb is not the parent process of debugged executable, instead it is grand father.
  3. The true parent process of debugged executable is "shell", i.e. /bin/bash in my case.

So, the solution is very simple, apart from adding cap_net_admin,cap_net_raw+eip to gdb, you have also apply this to your shell. i.e. setcap cap_net_admin,cap_net_raw+eip /bin/bash

The reason that you have also to do this to gdb is because gdb is parent process of /bin/bash before create debugged process.

The true executable command line inside gdb is like following:

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

And this is parameter to vfork inside gdb.

Mauer answered 18/8, 2014 at 14:3 Comment(2)
Thankyou for this answer! God I burnt some time trying to work this out!!!Prieto
Why on earth is none of this mentioned anywhere in the capabilities documentation floating around in the webs. Or in any of those countless examples on how to use capabilities (they all just talk about ping). Haven't found a single good "POSIX capabilities for Programmers" kind of summary that would guide how to tackle issues like this one that one is likely to encounter when developing programs that need & use capabilities. @nick-huang Your answer is pure gold. Thank you!Adamson
G
5

I used @NickHuang's solution until, with one of system updates, it broke systemd services (too much capabilities on bash for systemd to start it or some such). Switched to leaving bash alone and instead pass a command to gdb to invoke the executable directly. The command is

set startup-with-shell off
Gamble answered 15/5, 2020 at 4:32 Comment(2)
This is great. Makes much more sense to have just GDB with added capabilities (in addition to the debuggee) I.e. at least to me it seems more logical that the debugger needs at least the same privileges as the debuggee, whereas having to grant the privileges to "common" shell smells like a sub-optimal workaround.Adamson
This solution worked for me, but I needed to add the command to ~/.gdbinit to make the change permanent (from: https://mcmap.net/q/279694/-permanently-change-disassembly-flavor-in-gdb)Sander
M
4

For those who have the same problem, you can bypass this one by executing gdb with sudo.

Monarda answered 13/2, 2013 at 13:48 Comment(1)
+1, although it is not solution for every case. I have two applications. First have set some capabilities but depends on second application, which is communicating with first via RT signals. Thus using only gdb ./a.out don't work because app lost her capabilities and using sudo gdb ./a.out don't work, because user-running application cannot send signals to applications running under root. It is hard to debug this and it looks like there is no workaround :)Misery
L
3

A while ago I did run into the same problem. My guess is that running the debugged program with the additional capabilities is a security issue.

Your program has more privileges than the user that runs it. With a debugger a user can manipulate the execution of the program. So if the program runs under the debugger with the extra privileges then the user could use these privileges for other purposes than for which the program intended to use them. This would be a serious security hole, because the user does not have the privileges in the first place.

Lanettelaney answered 5/12, 2010 at 8:8 Comment(4)
That answer makes a lot of sense to me. I'll try looking into the gdb source to confirm this is the case, but I'll mark your answer as accepted now anyway.Vacillating
My guess is that this is handled by the kernel instead of gdb. You should probably look into the ptrace system call.Lanettelaney
From linux execve manpage: "If the set-user-ID bit is set on the program file pointed to by filename, and the underlying file system is not mounted nosuid (the MS_NOSUID flag for mount(2)), and the calling process is not being ptraced, then the effective user ID of the calling process is changed to that of the owner of the program file." This probably also holds for file capabilities, because like suid/sgid they provide privilege elevation.Lanettelaney
The guess is wrong - see answer by Nick Huang. It worked for me.Rheingold
V
3

For those running GDB through an IDE, sudo-ing GDB (as in @Stéphane J.'s answer) may not be possible. In this case, you can run:

sudo gdbserver localhost:12345 /path/to/application

and then attach your IDE's GDB instance to that (local) GDBServer.

In the case of Eclipse CDT, this means making a new 'C/C++ Remote Application' debug configuration, then under the Debugger > Connection tab, entering TCP / localhost / 12345 (or whatever port you chose above). This lets you debug within Eclipse, whilst your application has privileged access.

Vilipend answered 4/1, 2018 at 23:43 Comment(0)
F
0

OK, so I struggled a bit with this so I thought I'd combine answers and summarise.

The easy solution is just to sudo gdb as suggested but just be a bit careful. What you're doing here is running the debugged program as root. This may well cause it to operate differently than when you run it from the command line as a normal user. Could be a bit confusing. Not that I would EVER fall into this trap... Oopsies.

This will be fine if you're running the debugged program as root with sudo OR if the debugged program has the setuid bit set. But if the debugged program is running with POSIX capabilities (setcap / getcap) then you need to mirror these more granular permissions in bash and gdb as Nick Huang suggested rather than just brute forcing permissions with 'sudo'.

Doing anything else may lead you to a bad place of extreme learning.

Flood answered 14/1, 2020 at 20:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.