17. Socket Hook Functions

The SELinux socket hook function implementations manage the security fields of socket structures and perform access control for socket operations. This section describes these hooks and their helper functions. The section concludes by describing the optional hook function processing for the extended socket calls.

17.1. Socket Related Security Structures

Security information can be attached to two additional kernel objects, the kernel socket (struct sock) and the open request information block (struct open_request). The security fields attached to these objects are used to reliably store the remote (peer) SID for a connection, and to label server sockets with the client SID when extended socket calls are used.

The sock_security_struct is used to store security information about the peer during connection establishment when the user socket is not yet allocated for the new connection.

struct sock_security_struct {
        unsigned long magic;           /* magic number for this module */
        struct sock *sk;               /* back pointer to sock object */
        struct list_head list;         /* list of sock_security_struct */
        security_id_t sid;             /* SID of the sock */
        security_id_t peer_sid;        /* SID of the network peer */
}

Table 31. sock_security_struct

FieldDescription
magicModule id for the SELinux module.
skBack pointer to the associated sock structure.
listPointer used to maintain the list of allocated sock security structures.
sidSID of the socket; equal to user space socket SID.
peer_sidSID of the peer socket.

The socket_sock_alloc_security and socket_sock_free_security hooks are used to allocate and free the security structure associated with the kernel socket. Security information is stored in the kernel socket in order to propagate the SID for a client to the user socket that is ultimately created on the server. However, because the new server socket is not created until the connection has been established, the SID for the client is stored in the kernel socket which is always present.

The kernel object, struct open_request, has an LSM security field as well. SELinux uses this field to store security information about the TCP client during connection establishment. See Section 17.4 for information on the definition of the open request security structure and it's use.

17.2. Managing Socket Related Security Fields

The SELinux module uses the security structure for the inode associated with the user space socket, so the inode_alloc_security, inode_free_security and inode_precondition functions are also applicable to sockets. See Section 14.1 for a discussion of these functions. However, additional socket-specific hook functions are necessary to initialize and manage the information in these inode security structures for sockets. These hook functions are described below.

17.2.1. selinux_socket_post_create

After a socket structure has been successfully created, this hook function is called to update the inode security field with information that was not previously available. By default, the inode SID is set to the SID of the creating task. The socket object class is refined into separate object classes for the different types of sockets, as determined by the type and protocol family specified as parameters to the socket system call. The security class is assigned according to Table 32. If the socket does not match any of the specified types, it defaults to the generic socket security class. The kernel socket (struct sock) associated with the socket will have it's SID set to the user socket SID. This SID is used to label outgoing packets from a socket that has no user space socket structure associated with it.

Table 32. Socket Security Classes

Protocol FamilyTypeSecurity Class
PF_UNIXSOCK_STREAMunix_stream_socket
PF_UNIXSOCK_DGRAMunix_dgram_socket
PF_INET/PF_INET6SOCK_STREAMtcp_socket
PF_INET/PF_INET6SOCK_DGRAMudp_socket
PF_INET/PF_INET6SOCK_RAWrawip_socket
PF_NETLINK*netlink_socket
PF_PACKET*packet_socket
PF_KEY*key_socket

17.2.2. selinux_socket_accept

This hook function is called after a new socket has been created for the connection but prior to calling the protocol family's accept function. In addition to checking permission (discussed further in Section 17.3), this hook function sets the SID and security class for the new socket. The new socket always inherits the security class of the listening socket. By default, the new socket SID is initialized to the SID of the listening socket. The new socket initialization must occur in this hook, since traffic can occur on the socket before the post_accept hook is called.

17.2.3. selinux_socket_post_accept

This hook function is called after calling the protocol family's accept function. This hook calls the extsocket_post_accept function (see Section 17.4).

17.2.4. selinux_tcp_connection_request

A new connection is being requested on a listening socket. This hook allows the LSM module to maintain security information about the client during the connection establishment. The only function performed by this hook is to call the extsocket_tcp_connection_request hook.

17.2.5. selinux_tcp_synack

A reply SYN/ACK is being sent for a connection request. This hook allows the LSM module to label the SYN/ACK packet. For SELinux, the label used will be the client SID or the listening socket SID, depending on the use of extended socket functionality. This hook is called after the skb_set_owner_w hook, and therefore, will override any labeling done by that hook. The only function performed by this hook is to call the extsocket_tcp_synack hook.

17.2.6. selinux_tcp_create_openreq_child

This hook is called when a new TCP kernel socket is created, typically during the accept system call. The security data associated with the listening socket is preserved in the new kernel socket, and later used to label packets that are sent from the socket after the user space socket has been detached. After labeling the new socket, this hook calls the extsocket_tcp_create_openreq_child hook.

17.3. Controlling Socket Operations

17.3.1. socket_has_perm

This helper function checks whether a task has a particular permission to a socket. It first calls the precondition functions for the task and the socket's inode. It then calls the AVC to check the permission.

17.3.2. Socket Layer Hooks

The socket layer access control hook functions first check a permission between the current task and the socket using the socket_has_perm helper function (or inlining the logic of this function when the task and/or inode security structures are needed for additional processing). Some of the hook functions perform additional processing. The hook functions and the initial permission that they check are shown in Table 33. Any additional processing for the hook functions, excluding the optional extended socket call processing, is then described in the following subsections.

Table 33. Socket Layer Hook Permission Checks

Hook FunctionSourceTargetPermission
selinux_socket_createCurrentNewSocketcreate
selinux_socket_bindCurrentSocketbind
selinux_socket_connectCurrentSocketconnect
selinux_socket_listenCurrentSocketlisten
selinux_socket_acceptCurrentSocketaccept
selinux_socket_sendmsgCurrentSocketwrite
selinux_socket_recvmsgCurrentSocketread
selinux_socket_getsocknameCurrentSocketgetattr
selinux_socket_getpeernameCurrentSocketgetattr
selinux_socket_setsockoptCurrentSocketsetopt
selinux_socket_getsockoptCurrentSocketgetopt
selinux_socket_shutdownCurrentSocketshutdown

17.3.2.1. selinux_socket_bind

The selinux_socket_bind hook function performs an additional name_bind permission check between the socket and the SID associated with the port number for ports that are outside the range used to automatically bind.

17.3.2.2. selinux_socket_sendmsg

Prior to returning, this hook function calls the NSID hook nsid_sock_sendmsg to adjust the maximum segment size (MSS) for the IP packet to account for the IP options. See Section 20 for a description of the NSID functions.

17.3.3. selinux_socket_sock_rcv_skb (Transport Layer Hook)

This hook function is called by the transport layer network protocols (e.g. UDP, TCP, raw IP, etc) to control receipt of individual packets on a socket at a point where the destination socket and the receiving network device information is available. Unlike the previously discussed socket hook functions, this hook is passed a pointer to a kernel socket (sock) structure rather than a socket structure. This hook function must first dereference the socket field of the sock structure and then dereference the inode field of the resulting socket structure in order to obtain security information about the receiving socket. However, security information is not always available. If the socket is in a TCP TIME_WAIT state, then the sock structure pointer actually refers to a tcp_tw_bucket structure. The tcp_tw_bucket structure does not contain a socket field, so the socket field cannot be accessed in this case. In other cases, the socket field can be accessed but may be NULL, indicating that the socket has not yet been associated with an active user socket. In these cases, the hook function merely returns success. Further study of these cases is needed to determine whether this behavior is safe.

After obtaining the socket security information, the hook function must also obtain security information for the packet (network buffer). If no receiving network device is set for the packet, then the hook function merely returns success, since this implies that the communication is local and this hook function is not applicable. Otherwise, if the network buffer is still unlabeled, then this hook initializes the network buffer to the default message SID for the receiving network device. Normally, the network buffer is labeled during IP input processing, but an unlabeled network buffer might reach this hook if the kernel was configured without the LSM IP hooks or if SELinux was dynamically inserted into a running kernel with network buffers that had already been processed by the IP layer.

The hook function then checks recvfrom permission between the socket and the packet's source socket SID to control the receipt of the packet on the socket. Depending on the type and state of the socket and the kind of packet, additional processing may be performed. The additional processing is described below, and the additional permission checks are shown in Table 34. The optional extended socket call processing is described separately in Section 17.4.

If the socket is a TCP socket in the TCP_LISTEN state (server) and the packet has the SYN bit set, then the acceptfrom permission is checked between the listening socket SID and the packet's source socket SID (i.e. the client socket SID). If the socket is a TCP socket in the TCP_SYN_SENT state (client) and the packet has the ACK or SYN bits set (without the RST bit), then the connectto permission is checked between the client socket SID and packet's source socket SID (i.e. the server socket SID).

Table 34. Connection Establishment Permission Checks

Socket StatePacket BitsSourceTargetPermission
TCP_LISTENSYNListeningSocketClientSocketacceptfrom
TCP_SYN_SENT

ACK
SYN

ClientSocketServerSocketconnectto

17.3.4. Hooks for Unix Domain Socket IPC

LSM places calls to two hooks, unix_stream_connect and unix_may_send, within the Unix domain socket code to provide consistent control over Unix domain socket IPC. These hooks are placed into the Unix domain socket code in order to have access to the destination socket, which is not available to the socket layer hooks. For sockets that use the file namespace, the inode hook functions could be used to control IPC, but this would not address sockets that use the abstract namespace. Hence, these two hooks were added by LSM.

The selinux_socket_unix_stream_connect hook function is called for Unix stream connections. It checks the connectto permission between the client socket and the listening socket. The selinux_socket_unix_may_send hook function is called for Unix datagram communications. It checks the sendto permission between the sending socket and the receiving socket. These permission checks are summarized in Table 35.

Table 35. Unix Domain Permission Checks

HookSourceTargetPermission
unix_stream_connectClientSocketServerSocketconnectto
unix_may_sendSendingSocketReceivingSocketsendto

17.4. Extended Socket Call Processing

The original SELinux kernel patch implemented a set of extended socket calls that could be used to specify and obtain SIDs for sockets, connections, and datagrams. The implementation of these calls for the LSM-based SELinux module is not yet complete and several unresolved issues still remain. The calls and their processing can be completely disabled via a separate kernel configuration option without any affect on the enforcement of the network policy by the kernel. No applications have been modified yet to use these calls, so they can be disabled without harm for now.

This section describes the current state of the extended socket call implementation in the SELinux module. The extended socket call processing is implemented within inline functions defined in the extsocket.h file. These functions are called by the appropriate hook functions. This section begins by describing the fields added to the inode security and open request structures to support the extended socket calls. It then describes each of the inline functions in extsocket.h.

17.4.1. Extended Inode Security Structure

When the extended socket call option is enabled, the inode_security_struct structure is extended to include additional fields related to the extended socket calls. The additional fields are defined as shown below.

        security_id_t msid;            /* SID of message on the socket */
        security_id_t dsid;            /* SID of desired destination socket */
        security_id_t peer_sid;        /* SID of the peer socket */
        security_id_t newconn_sid;     /* SID to use for new connections */
        int useclient;                 /* Use client SID for connections */
        access_vector_t conn_perm;     /* connection permission */

Table 36. Extended inode_security_struct

FieldDescription
msidMessage SID.
dsidDestination socket SID.
peer_sidSID of the peer socket.
newconn_sidSID for new connection sockets.
useclientFlag indicating to use client SID for new connection sockets.
conn_permConnection permission for revalidation.

17.4.2. Open Request Security Structure

When the extended socket call option is enabled, the open_request_security_struct structure is available. This structure is used to store security information for during connection requests, before the new socket is created.

struct open_request_security_struct {
        unsigned long magic;           /* magic number for this module */
        struct open_request *req;      /* back pointer to open request object */
        struct list_head list;         /* list of open_request_security_struct*/
        security_id_t newconn_sid;     /* SID of the new connection */
};

Table 37. open_request_security_struct

FieldDescription
magicModule id for the SELinux module.
skBack pointer to the associated open_request structure.
listPointer used to maintain the list of allocated open_request security structures.
peer_sidSID of the new connection; either the listening socket SID, or the client SID

17.4.3. Extended Socket Functions

The optional hook function processing for the extended socket calls is implemented in a set of inline functions in extsocket.h. Each function is described below.

17.4.3.1. extsocket_open_request_alloc_security

Allocate and initialize the open_request_security_struct security structure for the open request kernel object. Called by selinux_open_request_alloc_security.

17.4.3.2. extsocket_open_request_free_security

Free the open_request_security_struct security structure for the open request kernel object. Called by selinux_open_request_free_security.

17.4.3.3. extsocket_init

This function is called by inode_alloc_security to initialize the additional fields as necessary. The socket peer SID field is set to the any_socket initial SID.

17.4.3.4. extsocket_create

This function is called by selinux_socket_create and selinux_socket_post_create to obtain the SID for the new socket. If the socket_secure call was used, then the SID given in that call is returned. Otherwise, the SID of the creating task is returned. If the extended socket option is disabled, then this function always returns the SID of the creating task.

17.4.3.5. extsocket_connect

This function is called by selinux_socket_connect. If a particular destination socket SID was specified via the connect_secure call, then additional processing is performed. If the socket is an INET socket, then an additional enforce_dest permission check is performed between the destination socket SID and the destination node SID. This check ensures that the destination node is trusted to enforce the restriction on the destination socket. For all sockets, the destination socket SID is copied to the dsid field of the socket's inode in order to pass it to the extsocket_skb_set_owner_w function for labeling the outgoing packet. The peer SID of the socket is also set to the destination socket SID.

17.4.3.6. extsocket_listen

This function is called by selinux_socket_listen. If both a new connection SID and the useclient flag are set, then an error is returned. For non-stream sockets, use of the client SID is not supported, so an error is returned. Also, if the new connection SID is given and is not equal to the socket SID, and error is returned. Otherwise, the socket's use client flag is cleared and the new connection SID is set to the socket SID. No further processing is performed for non-stream sockets.

For stream sockets, if a new connection SID was specified via listen_secure, then an additional newconn permission check is performed between the socket SID and the new connection SID. The new connection SID is then copied into the socket's new connection SID. Otherwise, the socket new connection SID is set to the SID of the socket. The use client flag is also copied into the socket's useclient field.

17.4.3.7. extsocket_accept

This function is called by selinux_socket_accept to set the connection permission of the new socket to acceptfrom for subsequent revalidation.

17.4.3.8. extsocket_post_accept

This function is called by selinux_socket_post_accept. The peer SID of the new connection socket is set to the peer SID field of the kernel socket. This field was set during extsocket_tcp_create_openreq_child for INET sockets, or during extsocket_unix_stream_connect for Unix sockets. If the listening socket's use client flag is set, then the SID of the new connection socket is changed to the peer SID, i.e. the client socket SID. The peer SID is also copied into the out SID array of the current task, so that it is accessible to the accept_secure system call and can be passed back to the application.

17.4.3.9. extsocket_sendmsg

This function is called by selinux_socket_sendmsg. If the socket is a stream socket, then this function verifies that the message SID and destination socket SID are valid if they were specified using the extended socket calls. For stream sockets, the message SID must equal the sending socket SID, and the destination socket SID must equal the peer SID. For TCP sockets, this function also revalidates the connection permission between the socket and its peer. For client sockets, the connection permission and the peer SID are set during connection establishment by extsocket_sock_rcv_skb. For server sockets, the connection permission is set by extsocket_accept and the peer SID is set by extsocket_post_accept.

If the socket is a non-stream socket and a message SID was specified, then send_msg permission is checked between the socket SID and the message SID. If the socket is a non-stream INET socket (e.g. UDP, raw IP), then this function also checks sendto permission between the socket and the destination socket SID. By default, the destination socket SID is set to the peer SID for the socket, which defaults to the any_socket initial SID unless specified by a prior connect_secure call. If a particular destination socket SID was specified via send*_secure, then the enforce_dest permission is checked between the destination socket SID and the destination node SID.

For all sockets, the destination socket SID, if specified, is copied to the dsid field of the socket's inode security structure in order to pass it to the extsocket_skb_set_owner_w function for labeling the outgoing packet. For non-stream sockets, the message SID is similarly copied to the msid field if it was specified.

[XXX Need to bind the (msid, dsid) pair to the particular message in some manner so that extsocket_skb_set_owner_w can ensure that it is only applied to the corresponding network buffers. Possibly maintain a list of (message identifier, msid, dsid) triples on the socket in the extsocket_sendmsg function that can be consumed by extsocket_skb_set_owner_w, but not clear how to identify the message uniquely and consistently across both functions. Possibly bind security data to struct msghdr via a security field or control data, but a security field would break application compatibility (msghdr is an exported structure) and control data may interfere with application-specified control data. The original SELinux kernel patch required invasive changes to propagate the SIDs down to the skb allocation.]

17.4.3.10. extsocket_recvmsg

This function is called by selinux_socket_recvmsg. For stream sockets, this function copies the peer SID into both elements of the out SID array of the current task's security structure so that the recv*_secure calls can return this SID as the source socket SID and message SID to the application. For datagram sockets, the SIDs are copied from the individual datagram by the extsocket_skb_recv_datagram function.

17.4.3.11. extsocket_getsockname

This function is called by selinux_socket_getsockname. This function copies the socket SID into the out SID array of the current task's security structure so that the socket SID can be returned via the getsockname_secure extended system call.

17.4.3.12. extsocket_getpeername

This function is called by selinux_socket_getpeername. This function copies the peer socket SID into the out SID array of the current task's security structure so that the peer socket SID can be returned via the getpeername_secure extended system call. For client sockets, the peer SID are set during connection establishment by extsocket_sock_rcv_skb. For server sockets, the peer SID is set by extsocket_post_accept.

17.4.3.13. extsocket_sock_rcv_skb

This function is called by selinux_sock_rcv_skb. If the socket is a TCP socket in the TCP_LISTEN state (server socket) and the packet has the SYN bit set, then a connection is being requested, and several checks are performed. If the listening socket was set to use the client socket SID for new connection sockets (via a listen_secure call on the server), then the newconn permission is checked between the listening socket SID and the packet's source socket SID (i.e. the client socket SID) to ensure that the listening socket is allowed to create a new connection socket with the same SID as the client socket.

At this point, the new connection SID will be either the client SID (when the listening socket was set to use client) or the listening socket SID. Next, the acceptfrom permission is checked between the new connection SID and the SID of the packet.

If the packet's destination socket SID is set (due to a connect_secure call on the client) and this SID does not match the listening socket's new connection SID, the connection is refused. (XXX The listening socket's peer SID is set to the packet's source socket SID, but this will be overwritten by subsequent connections. This is unreliable.)

If the socket is a TCP socket in the TCP_SYN_SENT state (client socket), and the packet has the ACK or SYN bits set (without the RST bit), then the client is receiving connection acknowledgment from the server. Several checks are made and the peer SID is saved. If the socket's peer SID is set (via a connect_secure call) and this SID does not match the source socket SID of the packet, then the connection is reset. This check parallels the server-side check for the same condition. The client socket's peer SID is set to the source socket SID of the packet, and the connection permission is set to connectto for subsequent revalidation.

If the TCP socket is in the TCP_ESTABLISHED state, then the connection permission (either acceptfrom or connectto) is revalidated so that policy changes can be reflected by the permission checks.

For non-stream sockets, if the packet's destination socket SID is set (via send*_secure) and it does not match the receiving socket's SID, then the packet is rejected. Likewise, if the receiving socket's peer SID has been set (via connect_secure), and it does not match the source socket SID of the packet, then the packet is rejected.

17.4.3.14. extsocket_tcp_connection_request

This hook is called by selinux_tcp_connection_request. The purpose of this hook is to set the new connection SID for the open request associated with the requested connection. If the listening socket is set to use the client SID on new connections, the new connection SID is set to the SID of the packet that initiated the connection request. In this manner the SID of the new server socket will be reliably set with the client SID when multiple connections are being established on a busy server socket. Otherwise, new connection SID is set to the listening socket's new connection SID.

17.4.3.15. extsocket_tcp_synack

This hook is called by selinux_tcp_synack to label the outgoing network packet for the SYN/ACK with the new connection SID taken from the open request structure. This SID was set by the extsocket_tcp_connection_request hook.

17.4.3.16. extsocket_tcp_create_openreq_child

This function is called by selinux_tcp_create_openreq_child. When the listening socket is set to use the client SID for new connections, this hook sets the SID of the newly created kernel socket to the SID from the open request structure. This SID is used to label outgoing packets from a socket that has no user space socket structure associated with it (as can happen during the socket shutdown operation). The hook also copies the SID of the network packet that established the connection into the kernel socket peer SID field. This peer SID is used by extsocket_post_accept to reliably set the peer SID of the user socket structure.

17.4.3.17. extsocket_unix_stream_connect

This function is called by selinux_unix_stream_connect. If the listening socket was set to use the client socket SID for new connection sockets (via a listen_secure call on the server), then the newconn permission is checked between the listening socket SID and the client socket SID to ensure that the listening socket is allowed to create a new connection socket with the same SID as the client socket. If the new connection SID does not match the listening socket SID, then the connectto permission is rechecked based on the new connection socket SID rather than the listening socket SID. If the destination socket SID is set (due to a connect_secure call on the client) and this SID does not match the new connection socket SID, then access is denied. The peer SID of the kernel socket associated with the new connection is set to the sending socket SID. This peer SID can be used by extsocket_post_accept to reliably set the peer SID of the user socket structure. The connection permission is set for subsequent revalidation [XXX Revalidation for Unix stream traffic is not yet implemented].

17.4.3.18. extsocket_unix_may_send

This function is called by selinux_unix_may_send. If the receiving socket's peer SID has been set (via connect_secure), and it does not match the sending socket SID, then access is denied. Likewise, if the destination socket SID is set (via send*_secure) and it does not match the receiving socket's SID, then access is denied.

17.4.3.19. extsocket_skb_set_owner_w

This function is called by selinux_skb_set_owner_w. If the message SID (non-stream only) or destination socket SID are set for the socket, then these SIDs are copied into the network buffer and then cleared from the socket. These SID fields in the socket's inode security structure are set during selinux_socket_sendmsg. [XXX This is unreliable, see Section 17.4.3.9.]

17.4.3.20. extsocket_skb_recv_datagram

This function is called by selinux_skb_recv_datagram. This function copies the SIDs from a network buffer into the out SID array of the task security structure when a datagram is received by a task. This enables the extended socket calls to return these SIDs to applications.