Raw Socket Access as Normal User on Linux 2.4

raw socket access as normal user on linux 2.4

Generally, you need root permissions to receive raw packets on an interface. This restriction is a security precaution, because a process that receives raw packets gains access to communications of all other processes and users using that interface.

However, if you have access to root on the machine, you can use the setuid flag to give your process root privileges even when the process is executed as a non-root user.

First, ensure that this capability is set successfully when the process is run as root. Then use

sudo chown root process
sudo chmod ugo+s process

to set root as owner of the process and set the setuid flag. Then check that the capability is set when the process is run by other users. Because this process will now have all superuser privileges, you should observe security precautions, and drop the privileges as soon as your code no longer requires it (after enabling the CAP_NET_RAW).

You can follow this method to ensure you're dropping them properly.

Errno set by socket() is undocumented in the manpage

If you look at man 2 socket, at the bottom of the "ERRORS" section. you'll see that it mentions that other errors can be generated.

ERRORS
EACCES Permission to create a socket of the specified type and/or pro‐
tocol is denied.

EAFNOSUPPORT
The implementation does not support the specified address fam‐
ily.

EINVAL Unknown protocol, or protocol family not available.

EINVAL Invalid flags in type.

EMFILE Process file table overflow.

ENFILE The system limit on the total number of open files has been
reached.

ENOBUFS or ENOMEM
Insufficient memory is available. The socket cannot be created
until sufficient resources are freed.

EPROTONOSUPPORT
The protocol type or the specified protocol is not supported
within this domain.

Other errors may be generated by the underlying protocol modules.

If we then check man 7 raw:

SYNOPSIS

#include <sys/socket.h>
#include <netinet/in.h>
raw_socket = socket(AF_INET, SOCK_RAW, int protocol);

...

ERRORS

EACCES User tried to send to a broadcast address without having
the broadcast flag set on the socket.

EFAULT An invalid memory address was supplied.

EINVAL Invalid argument.

EMSGSIZE
Packet too big. Either Path MTU Discovery is enabled (the
IP_MTU_DISCOVER socket flag) or the packet size exceeds
the maximum allowed IPv4 packet size of 64 kB.

EOPNOTSUPP
Invalid flag has been passed to a socket call (like
MSG_OOB).

EPERM The user doesn't have permission to open raw sockets.
Only processes with an effective user ID of 0 or the
CAP_NET_RAW attribute may do that.

EPROTO An ICMP error has arrived reporting a parameter problem.

We see that EPERM can be generated.

unable open raw socket in a linux container even after setting cap_net_raw

I solved it. I need to set capabilities in the container's security context section of the kubernetes deployment. I added NET_RAW capability to allow raw socket creation. I was under the impression that just adding capability cap_net_raw to the process while building would suffice. But my understanding turns out to be wrong.

I did some study and cleaned up the deployment solution. I added NET_RAW in the allowed capability section of my pod security policy. Then created a role and rolebinding. Through rolebinding linked it to the service account in the namespace where my pod will be deployed. Then used this serviceAccount in the pod deployment. Not sure if this is a good solution.

Changing user IDs for assigning additional capabilities

If your program executes with effective user ID root, then you do have root privileges.


In Linux, capabilities are divided into three sets: inheritable, permitted, and effective. Inheritable defines which capabilities stay permitted across an exec(). Permitted defines which capabilities are permitted for a process. Effective defines which capabilities are currently in effect.

Edited to add: When the filesystem containing the binary that will be exec()'d does support filesystem capabilities, these always affect what capabilities the executed process will have. See the Transformation of capabilities during an execve() in the man 7 capabilities man page.

When changing the owner or group of a process from root to non-root, the effective capability set is always cleared. By default, also the permitted capability set is cleared, but calling prctl(PR_SET_KEEPCAPS, 1L) before the identity change tells the kernel to keep the permitted set intact.

Therefore, to have the CAP_NET_RAW capability, your program has to have it in both permitted and effective sets. If you wish for the CAP_NET_RAW to remain in effect over an exec(), it must be included in all three capability sets.

Edited to add: If file capabilities are supported for the target of the exec(), the file capabilities must also contain those capabilities in the inherited and effective sets. (Only including the capability in the inherited and effective sets does not grant the capability, since it's not in the permitted set in the file capabilities; but, it is enough to allow passing the capability from the executor to the execee, if the executor has the capability).


You can use the setcap command to grant specific capabilities to a binary. (Most Linux filesystems nowadays support these file capabilities.) It does not need to be privileged, or setuid. Just remember to add the desired capabilities to both permitted and effective sets.

Edited to add some examples:

Grant CAP_NET_RAW to /usr/bin/myprog (which must NOT be setuid or setgid root):

sudo setcap 'cap_net_raw=pe' /usr/bin/myprog

By default, do not grant CAP_NET_RAW to /usr/bin/myprog, but if the executor has the capability (in both inheritable and permitted sets), retain the capability (in inheritable and permitted sets, and activating it in the effective set):

sudo setcap 'cap_net_raw=ie' /usr/bin/myprog

If your program has to be setuid root anyway, then you can use e.g.

#define  _GNU_SOURCE
#include <unistd.h>
#include <sys/types.h>
#include <sys/capability.h>
#include <sys/prctl.h>

#define NEED_CAPS 1
static const cap_value_t need_caps[NEED_CAPS] = { CAP_NET_RAW };

int main(void)
{
uid_t real = getuid();
cap_t caps;

/* Elevate privileges */
if (setresuid(0, 0, 0))
return 1; /* Fatal error, probably not setuid root */

/* Add need_caps to current capabilities. */
caps = cap_get_proc();
if (cap_set_flag(caps, CAP_PERMITTED, NEED_CAPS, need_caps, CAP_SET) ||
cap_set_flag(caps, CAP_EFFECTIVE, NEED_CAPS, need_caps, CAP_SET) ||
cap_set_flag(caps, CAP_INHERITABLE, NEED_CAPS, need_caps, CAP_SET))
return 1; /* Fatal error */

/* Update capabilities */
if (cap_set_proc(caps))
return 1; /* Fatal error */

/* Retain capabilities over an identity change */
if (prctl(PR_SET_KEEPCAPS, 1L))
return 1; /* Fatal error */

/* Return to original, real-user identity */
if (setresuid(real, real, real))
return 1; /* Fatal error */

/* Because the identity changed, we need to
* re-install the effective set. */
if (cap_set_proc(caps))
return 1; /* Fatal error */

/* Capability set is no longer needed. */
cap_free(caps);

/* You now have the CAP_NET_RAW capability.
* It will be retained over fork() and exec().
*/

return 0;
}

Raw sockets in Haskell

Network.Pcap can be used to send and receive raw data.

import qualified Data.ByteString.Char8 as B
import Network.Pcap

main = do
-- open device
dev <- openLive "lo" 65535 False 0
setFilter dev "ether proto 0xFFFF" True 0

-- send
sendPacketBS dev (B.pack "\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\255\255Hello, World!")

-- receive
loopBS dev (-1) (\_ packet -> putStrLn (show packet))

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

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.

Why would setsockopt( TCP_REPAIR ) return EPERM when process has root permission?

I did some research and found an answer. here: http://lwn.net/Articles/495304/

"Changing a process's repair mode status requires the CAP_NET_ADMIN capability; the socket must also either be closed or in the established state."

I wrote a test program to emulate the problem. If the socket opens, writes data, and then closes again before the other side has a chance to put it in repair mode, then it will return EPERM.

Its not a very good way for to deal with it. There really should be some other more explanatory error. But instead they just re-use the EPERM error code.



Related Topics



Leave a reply



Submit