I'm attempting to make a program which uses raw sockets run correctly as non-root with Linux capabilities. The program is as follows:
#include <netinet/ip.h>
int main()
{
int sd = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);
if(sd < 0)
{
perror("socket() error");
return 1;
}
return 0;
}
If I compile it and run it as non-root, I get an error, as expected:
[user@localhost ~]$ make socket
cc socket.c -o socket
[user@localhost ~]$ ./socket
socket() error: Operation not permitted
If I add the cap_net_raw
capability, as an effective and permitted capability, it works.
[user@localhost ~]$ sudo setcap cap_net_raw+ep socket
[sudo] password for user:
[user@localhost ~]$ ./socket
[user@localhost ~]$
Now, I want to use pam_cap.so
to make it so that only a particular user can run this program with cap_net_raw
, instead of everyone. My /etc/security/capability.conf
is:
cap_net_raw user
My /etc/pam.d/login
is (note that I also tried /etc/pam.d/sshd
but that did not seem to work either):
#%PAM-1.0
auth [user_unknown=ignore success=ok ignore=ignore default=bad] pam_securetty.so
auth substack system-auth
auth include postlogin
#Added this line to use pam_cap
auth required pam_cap.so
account required pam_nologin.so
account include system-auth
password include system-auth
# pam_selinux.so close should be the first session rule
session required pam_selinux.so close
session required pam_loginuid.so
session optional pam_console.so
# pam_selinux.so open should only be followed by sessions to be executed in the user context
session required pam_selinux.so open
session required pam_namespace.so
session optional pam_keyinit.so force revoke
session include system-auth
session include postlogin
-session optional pam_ck_connector.so
I had an ssh session, I logged out and back in after that and executed the following commands:
[user@localhost ~]$ sudo setcap cap_net_raw+p socket
[sudo] password for user:
[user@localhost ~]$ getcap socket
socket = cap_net_raw+p
[user@localhost ~]$ ./socket
socket() error: Operation not permitted
[user@localhost ~]$
My question is: Why was I not able to execute the 'socket' program with cap_net_raw
? I thought that when I logged in, my user would obtain it as a permitted capability, and it would allow 'user' to run 'socket' with the cap_net_raw
.
This is what I'm running on:
[user@localhost ~]$ uname -a
Linux localhost.localdomain 3.10.0-123.el7.x86_64 #1 SMP Mon Jun 30 12:09:22 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
[user@localhost ~]$ cat /etc/redhat-release
CentOS Linux release 7.0.1406 (Core)
I figured out that I had the wrong capabilities on the file. In order for the process to be able to obtain effective capabilities from the pam_cap module, the file needs to be configured with the "inherited" capability as well. So, setting caps on the file should be:
sudo setcap cap_net_raw+ip socket
However, I still could only get the program to work successfully from a normal tty login, and not an ssh login.
I came across this question when trying to use Google to jump to the pam_cap.so
documentation.
The way to use setcap
to set this binary up for use with pam_cap.so
is:
sudo setcap cap_net_raw=ie socket
That is, the i
instructs the binary to promote the process Inheritable capability flag into a process Permitted p
capability, and the legacy e
instructs the kernel to raise its value in the process' Effective flag when the program is invoked.
You can skip the e
part if you want to use libcap
s cap_set_proc()
function to raise the Effective flag from inside the program. Something like:
cap_t c = cap_get_proc();
cap_fill(c, CAP_EFFECTIVE, CAP_PERMITTED);
cap_set_proc(c);
cap_free(c);
FWIW I've recently written an article on the various ways you can inherit capabilities in the modern kernel.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With