Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use the PAM capabilities module to grant capabilities to a particular user and executable?

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) 
like image 681
heath Avatar asked Nov 09 '22 16:11

heath


2 Answers

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.

like image 87
heath Avatar answered Nov 15 '22 06:11

heath


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 libcaps 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.

like image 37
Andrew G Morgan Avatar answered Nov 15 '22 05:11

Andrew G Morgan