I am developing a program in C that requires temporary use of some capabilities that require elevation to acquire and would rather not just have users issue sudo because it will be one time setup.
How would I go about granting capabilities such as CAP_CHOWN to enable changing file ownership or similar actions guarded by a capability?
A note on possible duplicates
When I asked this before it got closed as a duplicate. The question that was cited as the original question isn't the same question I had posted. I want a very specific set of capabilities, not root access.
The most common method to do provide extra capabilities to a process is to assign filesystem capabilities to its binary.
For example, if you want the processes executing /sbin/yourprog to have the CAP_CHOWN capability, add that capability to the permitted and effective sets of that file: sudo setcap cap_chown=ep /sbin/yourprog.
The setcap utility is provided by the libcap2-bin package, and is installed by default on most Linux distributions.
It is also possible to provide the capabilities to the original process, and have that process manipulate its effective capability set as needed. For example, Wireshark's dumpcap is typically installed with CAP_NET_ADMIN and CAP_NET_RAW filesystem capabilities in the effective, permitted, and inheritable sets.
I dislike the idea of adding any filesystem capabilities to the inheritable set. When the capabilities are not in the inheritable set, executing another binary causes the kernel to drop those capabilities (assuming KEEPCAPS is zero; see prctl(PR_SET_KEEPCAPS) and man 7 capabilities for details).
As an example, if you granted /sbin/yourprog only the CAP_CHOWN capability and only in the permitted set (sudo setcap cap_chown=p /sbin/yourprog), then the CAP_CHOWN capability will not be automatically effective, and it will be dropped if the process executes some other binary. To use the CAP_CHOWN capability, a thread can add the capability to its effective set for the duration of the operations needed, then remove it from the effective set (but keep it in the permitted set), via prctl() calls. Note that the libcap cap_get_proc()/cap_set_proc() interface applies the changes to all threads in the process, which may not be what you want.
For temporarily granting a capability, a worker sub-process can be used. This makes sense for a complex process, as it allows delegating/separating the privileged operations to a separate binary. A child process is forked, connected to the parent via an Unix domain stream or datagram socket created via socketpair(), and executes the helper binary that grants it the necessary capabilities. It then uses the Unix domain stream socket to verify the identity (process ID, user ID, group ID, and via the process ID, the executable the other end of the socket is executing). The reason a pipe is not used, is that an Unix domain stream socket or datagram socketpair socket is needed to use the SO_PEERCRED socket option to query the kernel the identity of the other end of the socket.
There are known attack patterns that need to be anticipated and thwarted. The most common attack pattern is causing the parent process to immediately execute a compromised binary after forking and executing the privileged child process, timed just right so the capabled child process trusts the other end is its proper parent executing the proper binary, but in fact control has been transferred to a completely different, compromised or untrustworthy binary.
The details on exactly how to do this securely are a software engineering question much more than a programming question, but using socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fdpair) and verifying the socket peer is the parent process still executing the expected binary more than just once at the beginning, are the key steps needed.
The simplest example I can think of is using prctl() and CAP_NET_BIND_SERVICE filesystem capability only in the permitted set, so that an otherwise unprivileged process can use a privileged port (1-1024, preferably a system-wide subset defined/listed in a root or admin-owned configuration file somewhere under /etc) to provide a network service. If the service will close and reopen its listening socket when told to do so (perhaps via SIGUSR1 signal), the listening socket cannot simply be created once at the beginning then dropped. It is a pretty good match for the "keep in permitted set, but only add to effective set of the thread that actually needs it, then drop it immediately afterwards" pattern.
For CAP_CHOWN, an example program might acquire it into its effective and permitted sets via the filesystem capability, but use a trusted configuration file (root/admin modifiable only) to list the ownership changes it is allowed to do based on the real user and group identity running the process. Consider a dedicated "sudo"-style "chown" utility, intended for say organizations to allow team leads to shift file ownership between their team members, but one that does not use sudo.)
It is not realistically possible to gain capabilities during runtime. The capabilities need to be already set before your software is started.
Some API functions like capset and cap_set_proc exist, but don't expect magic because the situation in which you could gain more capabilities will be both rare and a security oversight.
There are a few general ways of giving your software the required capabilities.
Set a specific capability on your binary with the setcap tool.
Use sudo to call your program. You already mentioned this yourself.
Set the setuid bit on your binary and set ownership to root. In this particular case that will be largely equivalent to calling your program with sudo.
Create a utility program that you apply one of the other methods on. Typically you would find such utility in a place like /usr/libexec. You then call the utility as a subprocess. I would consider this unnecessarily complex for simple situations. However, depending on the situations, this may be preferred over having a potential security risk of your software constantly running with too many privileges.
The first method should be considered the desired way. Your software should drop the capability as soon as it no longer requires it.
The CAP_CHOWN could be used for example to change ownership of /etc/shadow. The new owner could then change password for other users such as root, so effectively it could be equivalent to granting all capabilities. Hence, this capability is -like many others- potentially dangerous.
Related
Is it possible for one executable (process) to modify the value of a variable of another executable (process) during runtime?
Yes, it is possible. For e.g. The Linux operating system provides ptrace system call's by which you can not only examine but change the tracee's memory. From ptrace [emphasis added]:
The ptrace() system call provides a means by which one process (the "tracer") may observe and control the execution of another process (the "tracee"), and examine and change the tracee's memory and registers. It is primarily used to implement breakpoint debugging and system call tracing.
Possible, yes, but not guaranteed.
In normal operation, the address space of each process is completely separate.
Processes can use shared memory to allow access to the same memory region in different processes (noting that the address at which the region is visible in each process is not necessarily the same). In most operating systems, you can even map files that way.
Operating systems provide various facilities to help with development and debugging. In Linux and BSDs (originally from Unix System V), the ptrace interface is probably the most powerful. In general, the interface works between processes running under the same user ID, and requires superuser privileges to use otherwise. (In Linux, depending on the kernel configuration, it may also be possible to manipulate the memory contents each process sees directly, via /proc/PID/mem. This too has similar security considerations.)
In Linux, a process can call prctl(PR_SET_DUMPABLE, 0uL) to make itself and its children not ptraceable. This is common for example when a privileged service starts a helper process that does something on behalf of an unprivileged user, but that helper process needs to be secure against manipulation by that user (for example, the helper process returns some privileged data the user should not be able to spoof or fake).
(In fact, if a process changes its identity via the seteuid(), setegid(), setfsuid(), setfsgid(), or related calls, or the process was executed as a setuid/setgid binary, or gained extra capabilities based on filesystem capabilities for its binary, the kernel automatically does an equivalent of the above prctl() call, disallowing ptracing such processes.)
The dynamic linker in Linux can also be used to interpose or inject code to any (non-setuid/setgid/gaining-capabilities) process the user starts, by specifying the paths to those extra dynamic libraries in the LD_PRELOAD environment variable. This allows things like replacing standard C library functions with your own wrappers. The ELF executable file format also supports "constructors" and "destructors"; functions that get automatically called when the binary is executed and exits (before and after main(), that is). These allow you to essentially inject a small service to any processes you start (that run with your own user account and your user privileges), that you can remotely connect to, and do mischief to the process, like redirecting files, or changing data stored at some memory addresses.
As you can see, the better question is how and when one process can change the value of a variable in another process at runtime. And the answer to that depends on the situation. The most common case is to have the two processes talk to each other -- interprocess communication --, so that the target process actually does the modification when asked to do so by the other process. The solutions vary depending on the exact situation -- and the OS used, of course; my answer here is specific to Linux, but similar or related features are available in all operating systems, they just vary a bit.
I'm creating a raw ethernet socket in a C application, e.g.
s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
and its returning -1 indicating an error
I'm pretty sure its a permissions issue - You can only open a raw socket if you have a UID of 0 (root) or have the CAP_NET_RAW capability
I don't think running the application as root is reasonable, therefore my question is how can I 'add' the CAP_NET_RAW capability permission to my user account?
From http://manpages.ubuntu.com/manpages/zesty/en/man7/packet.7.html
In order to create a packet socket, a process must have the CAP_NET_RAW
capability in the user namespace that governs its network namespace.
But how does one achieve that end?
You set the capabilities on the executable that needs that capability, not a user account. The syntax is
setcap cap_net_raw,cap_net_admin=eip ./your_exeutable
(Note, you need to run setcap as root, so use e.g. sudo setcap ... Also make sure there are no space characters in cap_net_raw,cap_net_admin=eip
Being able to read all network packets is considered a severe security risk, that is why this needs a privileged account.
You can make the application "suid root" to elevate your own rights when starting this application as a "normal" user. But that is a security risk as well and needs a bit of thorough thinking when designing the application (it should at least give up the higher privilege as soon as it doesn't need it any more - i.e. after having opened the raw socket).
You cannot add the CAP_NET_RAW permission to your account, because capabilities on Linux do not follow users. They follow executables.
To make this work, you need to add the CAP_NET_RAW capability to your compiled executable. See the setcap command in order to see how to do that.
Is it possible to limit access to a named pipe by process (either image name, or process ID would work)?
The context here is a Filter Minidriver which has to communicate with a user-space service that would do most of the business logic. Since this communication is security-sensitive, I'd like to protect it from external interference, while by default it seems the named pipe, created by the driver can be communicated with by any user-space process that knows the name of the pipe (which is trivial to discover by static or dynamic analysis).
This is what I already know: Pipes are securable objects in Windows, and as such, they have a security descriptor. This security descriptor can contain a DACL, which is supposed to limit access to the object. I have searched extensively for documentation and examples of conditional ACEs, which I hoped could do what I want, but I failed to find anything related.
EDIT: I have accepted MSalters' answer. It is generally accepted that SYSTEM == ring0 and while code signing of drivers may seem like it matters, SYSTEM can disable code signing easily, so there is no need for privilege escalation from SYSTEM to ring0 - they're already the same. On the other hand, even the default security descriptor (in the minifilter driver context - see FltBuildDefaultSecurityDescriptor) contains a restriction so that only SYSTEM and Administrators can access the object, so no further action is necessary (or possible, it seems).
Image names are not secured anyway, anyone can create a "Notepad.EXE". And a process ID is just a number and can be reused, so that's no protection either. Besides, there are many ways in which you can smuggle a DLL inside another process, so even if you knew that a particular process was running your EXE, you still wouldn't know if it was running just your EXE.
The Windows security model uses the notion of security principals (user and system accounts). Those are directly supported by ACL's, and those are protected against spoofing. It makes sense if your filter driver refuses to talk to just anyone, but it's willing to talk to process A of user X, it should be willing to talk to any process of user X.
The code I have calls openlog() once, before altering the effective uid/gid of the program (a daemon). From a security standpoint, or a predictability standpoint, would calling openlog() after setting the effective uid/gid be better?
I'm guessing on most platforms openlog() will open a Unix Socket to syslogd? Are permissions on this likely too restrictive to allow the socket to be opened by system users.
Perhaps someone has a specific case where openlog requires elevated privileges, but I found none (and have in mind lynx, which used to have this in its compiled-in default features - up til 2009). daemons (see this page) do not have to run as root, and often use the feature.
The book The Hacker's Handbook: The Strategy Behind Breaking into and Defending Networks cites openlog and its associated functions as a vulnerability,
which allow an attacker to inject "counterfeit" syslog messages into a log file
Given that, ensuring that there are no weaknesses in your application is doubly important (since there is always the possibility of becoming an agent of some other program's intrusion).
So the answer seems to be that no, there may be no need to do this, but dropping privileges early is always a good rule. If you find a specific case where you need the privileges, that is the point at which to reconsider their use.
I am trying to make a c program to access GPIOs on an embedded linux system which will be run by a non root user. I can already access the GPIOs through sysfs (/sys/class/gpio) and have made a simple program that used mmap (through /dev/mem/) to control the GPIOs. However to write to /sys/class/gpio/ and /dev/mem/ you must have root privileges. What would be the most "correct" or standard way to access the GPIO in a program run as a non-root user?Writing a device driver?
Giving the user read/write access to /sys/class/gpio/ so the program can use sysfs?
Or Giving the user read/write access to /dev/mem/ so the program can use mmap()?
Thanks
One potential option is to make a process setuid by setting the s bit.
e.g.
chmod +s myExectuable
However, this has terrible security implications as the process then runs as root - with all the hazards that entails. Only an option if you really trust the user-space app, and even then, risky.
I don't think changing the default ownership and permissions of sysfs is possible without hacking up your kernel, and even then it would be tricky: sysfs is intricately connected with object model of the the Linux Driver model.
You may have more luck with the permissions on /dev/.
Ultimately, the correct way of solving this problem is a kernel-mode driver - in which you can implement whatever finely grained security (or lack thereof) you wish. Furthermore, you can implement mitigation against any potential ill-effects of allowing a user-mode application to control hardware.
Granting a custom user group access to specifically needed nodes under /sys/class/gpio is a fairly solid solution where applicable - it can be done entirely from boot scripts, needing no kernel-level programming.