is it possible in Linux to change capabilities of process that is run? Is it possible to change path to the opened files (for example to redirect output).

If yes, how to?

  • 1
    Are you talking about the capabilities as in man 7 capabilities, i.e. the restrictions imposed onto programs run as superuser? If yes, a thread may only change its own capabilities. – lgeorget Mar 30 at 22:04
  • There appears to be two questions here. Please split. And tell us what your goals are. It will help us answer. I suspect that the answers are simpler than the ones we have so far. – ctrl-alt-delor Mar 31 at 10:28

You can't change this kind of process' environment from outside, but if you really have to, you can ptrace(2) the process (actually a thread, but I will continue saying process for simplicity) with an adequate tool to make changes from within the running process. Of course it would be weird to rely on ptrace for production usage, but if it were the only choice left...

gdb can do this

You can attach to a process (or some threads with more gdb-fu) and make it alter its own behaviour and detach from it. If done fast enough (ie: scripted) the process will be none the wiser. Depending on the process running and its actions at initialization, you can't always ptrace from the same user, then requiring root access or at least CAP_SYS_PTRACE capability. What is done to the process is actually done by itself: if the process is already permitted to change its capabilities (usually requires CAP_SETPCAP), then it's possible to make itself do it. If it's not permitted an action, then ptrace won't help, even done by root. Likewise, it's easy to make it close a log file and reopen it elsewhere.

Examples with some UL Q/A, some of them mine:

To address your question's first example...

Restrict capabilities of a running process with gdb

The example will be done on a bash shell running as root (thus having full capababilities), using gdb (also running as root). It's quite convoluted because libcap's functions aren't known if the program wasn't linked to it, so I chose the simplier but more tedious (because it requires manipulating structures) method which doesn't require any development environment nor extra gdb-fu: directly using syscalls definitions which are always known in gdb.


# echo test > /tmp/test
# chown nobody /tmp/test
# chmod 600 /tmp/test
# cat < /tmp/test
# cat /tmp/test
# echo $$
# grep ^Cap /proc/$$/status
CapInh: 0000000000000000
CapPrm: 0000003fffffffff
CapEff: 0000003fffffffff
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000


# gdb -q -p 5237
Attaching to process 5237
Reading symbols from /bin/bash...(no debugging symbols found)...done.


0x00007fb774737681 in pselect () from /lib/x86_64-linux-gnu/libc.so.6
(gdb) set $malloc=(void *(*)(long long)) malloc
(gdb) print $malloc(4*(2+3*2))
$1 = (void *) 0xc4ecc8
(gdb) set *((unsigned int *)($1))=0x20080522
(gdb) set *((unsigned int *)($1)+1)=getpid()
(gdb) print capget($1, (unsigned int *)$1+2)
$2 = 0
(gdb) set *((unsigned int *)($1)+2) &= ~(1<<1|1<<2)
(gdb) print capset($1, (unsigned int *)$1+2)
$3 = 0
(gdb) call free($1)
$4 = 0
(gdb) quit
A debugging session is active.

    Inferior 1 [process 5237] will be detached.

Quit anyway? (y or n) y
Detaching from program: /bin/bash, process 5237

So this allocated memory, 64bits workaround style, for the needed *cap_user_header_t and cap_user_data_t[2] structures, set some magic value, retrieved the current process capabilities and removed CAP_DAC_OVERRIDE and CAP_DAC_READ_SEARCH from the capability Effective set, thus preventing it to read /tmp/test, and finally freed the allocated memory.

Back in Term1:

# grep ^Cap /proc/$$/status
CapInh: 0000000000000000
CapPrm: 0000003fffffffff
CapEff: 0000003ffffffff9
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
# cat < /tmp/test
bash: /tmp/test: Permission denied
# cat /tmp/test

What's the difference? The bash process can't access anymore the non-root file with its restricted access when using the redirection and fails (after forking but before exec-ing cat). When (forking and) exec-ing a new process, root recovers all its capabilities unless they are removed from yet-an-other-set: the capability Bounding set which can be changed by a different method (prctl(PR_CAPBSET_DROP, ...)). That's why running cat without redirection still works normally (for root).

  • note: I was puzzled about the malloc returning a quite short (void *) value and wondering if the cast to malloc was wrong. It was correct. It turns out, Debian 9 amd64's bash 4.4.12 always has heap at a low address (as seen with grep heap /proc/$$/maps), while other processes or Debian buster's bash 5.0.2 don't behave like this and use an high address heap. I don't have the knowledge to understand why. – A.B Mar 31 at 14:58

In order to change the path of an open file, you might be able to use a hard link, but it would have to remain on the same filesystem as the original file. Once an app has opened a file, only the file handle matters, and the inode of the file. A hard link just provides a different filename/paths for the same inode.

If you just want to rename/reorganize this might work. be sure to update any config files so if you do restart the new location is picked up. If you're looking to move to a new filesystem to free up space or something this method will not work.

Sometimes sending a specific single (often SIGHUP) and the app will close all file handles, and reopen them. In this case it would usually reload the conf and so might pick up a new file path too. This behavior is highly dependent on the application though. Depending on the type of data this could also be really risky, and result in data loss, or corruption.

While, I'm not positive, I don't think you can change capabilities on a process. You'd have to exit and restart.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.