Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * SELinux NetLabel Support
0004  *
0005  * This file provides the necessary glue to tie NetLabel into the SELinux
0006  * subsystem.
0007  *
0008  * Author: Paul Moore <paul@paul-moore.com>
0009  */
0010 
0011 /*
0012  * (c) Copyright Hewlett-Packard Development Company, L.P., 2007, 2008
0013  */
0014 
0015 #include <linux/spinlock.h>
0016 #include <linux/rcupdate.h>
0017 #include <linux/gfp.h>
0018 #include <linux/ip.h>
0019 #include <linux/ipv6.h>
0020 #include <net/sock.h>
0021 #include <net/netlabel.h>
0022 #include <net/ip.h>
0023 #include <net/ipv6.h>
0024 
0025 #include "objsec.h"
0026 #include "security.h"
0027 #include "netlabel.h"
0028 
0029 /**
0030  * selinux_netlbl_sidlookup_cached - Cache a SID lookup
0031  * @skb: the packet
0032  * @family: the packet's address family
0033  * @secattr: the NetLabel security attributes
0034  * @sid: the SID
0035  *
0036  * Description:
0037  * Query the SELinux security server to lookup the correct SID for the given
0038  * security attributes.  If the query is successful, cache the result to speed
0039  * up future lookups.  Returns zero on success, negative values on failure.
0040  *
0041  */
0042 static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
0043                        u16 family,
0044                        struct netlbl_lsm_secattr *secattr,
0045                        u32 *sid)
0046 {
0047     int rc;
0048 
0049     rc = security_netlbl_secattr_to_sid(&selinux_state, secattr, sid);
0050     if (rc == 0 &&
0051         (secattr->flags & NETLBL_SECATTR_CACHEABLE) &&
0052         (secattr->flags & NETLBL_SECATTR_CACHE))
0053         netlbl_cache_add(skb, family, secattr);
0054 
0055     return rc;
0056 }
0057 
0058 /**
0059  * selinux_netlbl_sock_genattr - Generate the NetLabel socket secattr
0060  * @sk: the socket
0061  *
0062  * Description:
0063  * Generate the NetLabel security attributes for a socket, making full use of
0064  * the socket's attribute cache.  Returns a pointer to the security attributes
0065  * on success, NULL on failure.
0066  *
0067  */
0068 static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
0069 {
0070     int rc;
0071     struct sk_security_struct *sksec = sk->sk_security;
0072     struct netlbl_lsm_secattr *secattr;
0073 
0074     if (sksec->nlbl_secattr != NULL)
0075         return sksec->nlbl_secattr;
0076 
0077     secattr = netlbl_secattr_alloc(GFP_ATOMIC);
0078     if (secattr == NULL)
0079         return NULL;
0080     rc = security_netlbl_sid_to_secattr(&selinux_state, sksec->sid,
0081                         secattr);
0082     if (rc != 0) {
0083         netlbl_secattr_free(secattr);
0084         return NULL;
0085     }
0086     sksec->nlbl_secattr = secattr;
0087 
0088     return secattr;
0089 }
0090 
0091 /**
0092  * selinux_netlbl_sock_getattr - Get the cached NetLabel secattr
0093  * @sk: the socket
0094  * @sid: the SID
0095  *
0096  * Query the socket's cached secattr and if the SID matches the cached value
0097  * return the cache, otherwise return NULL.
0098  *
0099  */
0100 static struct netlbl_lsm_secattr *selinux_netlbl_sock_getattr(
0101                             const struct sock *sk,
0102                             u32 sid)
0103 {
0104     struct sk_security_struct *sksec = sk->sk_security;
0105     struct netlbl_lsm_secattr *secattr = sksec->nlbl_secattr;
0106 
0107     if (secattr == NULL)
0108         return NULL;
0109 
0110     if ((secattr->flags & NETLBL_SECATTR_SECID) &&
0111         (secattr->attr.secid == sid))
0112         return secattr;
0113 
0114     return NULL;
0115 }
0116 
0117 /**
0118  * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache
0119  *
0120  * Description:
0121  * Invalidate the NetLabel security attribute mapping cache.
0122  *
0123  */
0124 void selinux_netlbl_cache_invalidate(void)
0125 {
0126     netlbl_cache_invalidate();
0127 }
0128 
0129 /**
0130  * selinux_netlbl_err - Handle a NetLabel packet error
0131  * @skb: the packet
0132  * @family: the packet's address family
0133  * @error: the error code
0134  * @gateway: true if host is acting as a gateway, false otherwise
0135  *
0136  * Description:
0137  * When a packet is dropped due to a call to avc_has_perm() pass the error
0138  * code to the NetLabel subsystem so any protocol specific processing can be
0139  * done.  This is safe to call even if you are unsure if NetLabel labeling is
0140  * present on the packet, NetLabel is smart enough to only act when it should.
0141  *
0142  */
0143 void selinux_netlbl_err(struct sk_buff *skb, u16 family, int error, int gateway)
0144 {
0145     netlbl_skbuff_err(skb, family, error, gateway);
0146 }
0147 
0148 /**
0149  * selinux_netlbl_sk_security_free - Free the NetLabel fields
0150  * @sksec: the sk_security_struct
0151  *
0152  * Description:
0153  * Free all of the memory in the NetLabel fields of a sk_security_struct.
0154  *
0155  */
0156 void selinux_netlbl_sk_security_free(struct sk_security_struct *sksec)
0157 {
0158     if (sksec->nlbl_secattr != NULL)
0159         netlbl_secattr_free(sksec->nlbl_secattr);
0160 }
0161 
0162 /**
0163  * selinux_netlbl_sk_security_reset - Reset the NetLabel fields
0164  * @sksec: the sk_security_struct
0165  *
0166  * Description:
0167  * Called when the NetLabel state of a sk_security_struct needs to be reset.
0168  * The caller is responsible for all the NetLabel sk_security_struct locking.
0169  *
0170  */
0171 void selinux_netlbl_sk_security_reset(struct sk_security_struct *sksec)
0172 {
0173     sksec->nlbl_state = NLBL_UNSET;
0174 }
0175 
0176 /**
0177  * selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel
0178  * @skb: the packet
0179  * @family: protocol family
0180  * @type: NetLabel labeling protocol type
0181  * @sid: the SID
0182  *
0183  * Description:
0184  * Call the NetLabel mechanism to get the security attributes of the given
0185  * packet and use those attributes to determine the correct context/SID to
0186  * assign to the packet.  Returns zero on success, negative values on failure.
0187  *
0188  */
0189 int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
0190                  u16 family,
0191                  u32 *type,
0192                  u32 *sid)
0193 {
0194     int rc;
0195     struct netlbl_lsm_secattr secattr;
0196 
0197     if (!netlbl_enabled()) {
0198         *sid = SECSID_NULL;
0199         return 0;
0200     }
0201 
0202     netlbl_secattr_init(&secattr);
0203     rc = netlbl_skbuff_getattr(skb, family, &secattr);
0204     if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
0205         rc = selinux_netlbl_sidlookup_cached(skb, family,
0206                              &secattr, sid);
0207     else
0208         *sid = SECSID_NULL;
0209     *type = secattr.type;
0210     netlbl_secattr_destroy(&secattr);
0211 
0212     return rc;
0213 }
0214 
0215 /**
0216  * selinux_netlbl_skbuff_setsid - Set the NetLabel on a packet given a sid
0217  * @skb: the packet
0218  * @family: protocol family
0219  * @sid: the SID
0220  *
0221  * Description
0222  * Call the NetLabel mechanism to set the label of a packet using @sid.
0223  * Returns zero on success, negative values on failure.
0224  *
0225  */
0226 int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
0227                  u16 family,
0228                  u32 sid)
0229 {
0230     int rc;
0231     struct netlbl_lsm_secattr secattr_storage;
0232     struct netlbl_lsm_secattr *secattr = NULL;
0233     struct sock *sk;
0234 
0235     /* if this is a locally generated packet check to see if it is already
0236      * being labeled by it's parent socket, if it is just exit */
0237     sk = skb_to_full_sk(skb);
0238     if (sk != NULL) {
0239         struct sk_security_struct *sksec = sk->sk_security;
0240 
0241         if (sksec->nlbl_state != NLBL_REQSKB)
0242             return 0;
0243         secattr = selinux_netlbl_sock_getattr(sk, sid);
0244     }
0245     if (secattr == NULL) {
0246         secattr = &secattr_storage;
0247         netlbl_secattr_init(secattr);
0248         rc = security_netlbl_sid_to_secattr(&selinux_state, sid,
0249                             secattr);
0250         if (rc != 0)
0251             goto skbuff_setsid_return;
0252     }
0253 
0254     rc = netlbl_skbuff_setattr(skb, family, secattr);
0255 
0256 skbuff_setsid_return:
0257     if (secattr == &secattr_storage)
0258         netlbl_secattr_destroy(secattr);
0259     return rc;
0260 }
0261 
0262 /**
0263  * selinux_netlbl_sctp_assoc_request - Label an incoming sctp association.
0264  * @asoc: incoming association.
0265  * @skb: the packet.
0266  *
0267  * Description:
0268  * A new incoming connection is represented by @asoc, ......
0269  * Returns zero on success, negative values on failure.
0270  *
0271  */
0272 int selinux_netlbl_sctp_assoc_request(struct sctp_association *asoc,
0273                      struct sk_buff *skb)
0274 {
0275     int rc;
0276     struct netlbl_lsm_secattr secattr;
0277     struct sk_security_struct *sksec = asoc->base.sk->sk_security;
0278     struct sockaddr_in addr4;
0279     struct sockaddr_in6 addr6;
0280 
0281     if (asoc->base.sk->sk_family != PF_INET &&
0282         asoc->base.sk->sk_family != PF_INET6)
0283         return 0;
0284 
0285     netlbl_secattr_init(&secattr);
0286     rc = security_netlbl_sid_to_secattr(&selinux_state,
0287                         asoc->secid, &secattr);
0288     if (rc != 0)
0289         goto assoc_request_return;
0290 
0291     /* Move skb hdr address info to a struct sockaddr and then call
0292      * netlbl_conn_setattr().
0293      */
0294     if (ip_hdr(skb)->version == 4) {
0295         addr4.sin_family = AF_INET;
0296         addr4.sin_addr.s_addr = ip_hdr(skb)->saddr;
0297         rc = netlbl_conn_setattr(asoc->base.sk, (void *)&addr4, &secattr);
0298     } else if (IS_ENABLED(CONFIG_IPV6) && ip_hdr(skb)->version == 6) {
0299         addr6.sin6_family = AF_INET6;
0300         addr6.sin6_addr = ipv6_hdr(skb)->saddr;
0301         rc = netlbl_conn_setattr(asoc->base.sk, (void *)&addr6, &secattr);
0302     } else {
0303         rc = -EAFNOSUPPORT;
0304     }
0305 
0306     if (rc == 0)
0307         sksec->nlbl_state = NLBL_LABELED;
0308 
0309 assoc_request_return:
0310     netlbl_secattr_destroy(&secattr);
0311     return rc;
0312 }
0313 
0314 /**
0315  * selinux_netlbl_inet_conn_request - Label an incoming stream connection
0316  * @req: incoming connection request socket
0317  * @family: the request socket's address family
0318  *
0319  * Description:
0320  * A new incoming connection request is represented by @req, we need to label
0321  * the new request_sock here and the stack will ensure the on-the-wire label
0322  * will get preserved when a full sock is created once the connection handshake
0323  * is complete.  Returns zero on success, negative values on failure.
0324  *
0325  */
0326 int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family)
0327 {
0328     int rc;
0329     struct netlbl_lsm_secattr secattr;
0330 
0331     if (family != PF_INET && family != PF_INET6)
0332         return 0;
0333 
0334     netlbl_secattr_init(&secattr);
0335     rc = security_netlbl_sid_to_secattr(&selinux_state, req->secid,
0336                         &secattr);
0337     if (rc != 0)
0338         goto inet_conn_request_return;
0339     rc = netlbl_req_setattr(req, &secattr);
0340 inet_conn_request_return:
0341     netlbl_secattr_destroy(&secattr);
0342     return rc;
0343 }
0344 
0345 /**
0346  * selinux_netlbl_inet_csk_clone - Initialize the newly created sock
0347  * @sk: the new sock
0348  * @family: the sock's address family
0349  *
0350  * Description:
0351  * A new connection has been established using @sk, we've already labeled the
0352  * socket via the request_sock struct in selinux_netlbl_inet_conn_request() but
0353  * we need to set the NetLabel state here since we now have a sock structure.
0354  *
0355  */
0356 void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
0357 {
0358     struct sk_security_struct *sksec = sk->sk_security;
0359 
0360     if (family == PF_INET)
0361         sksec->nlbl_state = NLBL_LABELED;
0362     else
0363         sksec->nlbl_state = NLBL_UNSET;
0364 }
0365 
0366 /**
0367  * selinux_netlbl_sctp_sk_clone - Copy state to the newly created sock
0368  * @sk: current sock
0369  * @newsk: the new sock
0370  *
0371  * Description:
0372  * Called whenever a new socket is created by accept(2) or sctp_peeloff(3).
0373  */
0374 void selinux_netlbl_sctp_sk_clone(struct sock *sk, struct sock *newsk)
0375 {
0376     struct sk_security_struct *sksec = sk->sk_security;
0377     struct sk_security_struct *newsksec = newsk->sk_security;
0378 
0379     newsksec->nlbl_state = sksec->nlbl_state;
0380 }
0381 
0382 /**
0383  * selinux_netlbl_socket_post_create - Label a socket using NetLabel
0384  * @sk: the sock to label
0385  * @family: protocol family
0386  *
0387  * Description:
0388  * Attempt to label a socket using the NetLabel mechanism using the given
0389  * SID.  Returns zero values on success, negative values on failure.
0390  *
0391  */
0392 int selinux_netlbl_socket_post_create(struct sock *sk, u16 family)
0393 {
0394     int rc;
0395     struct sk_security_struct *sksec = sk->sk_security;
0396     struct netlbl_lsm_secattr *secattr;
0397 
0398     if (family != PF_INET && family != PF_INET6)
0399         return 0;
0400 
0401     secattr = selinux_netlbl_sock_genattr(sk);
0402     if (secattr == NULL)
0403         return -ENOMEM;
0404     rc = netlbl_sock_setattr(sk, family, secattr);
0405     switch (rc) {
0406     case 0:
0407         sksec->nlbl_state = NLBL_LABELED;
0408         break;
0409     case -EDESTADDRREQ:
0410         sksec->nlbl_state = NLBL_REQSKB;
0411         rc = 0;
0412         break;
0413     }
0414 
0415     return rc;
0416 }
0417 
0418 /**
0419  * selinux_netlbl_sock_rcv_skb - Do an inbound access check using NetLabel
0420  * @sksec: the sock's sk_security_struct
0421  * @skb: the packet
0422  * @family: protocol family
0423  * @ad: the audit data
0424  *
0425  * Description:
0426  * Fetch the NetLabel security attributes from @skb and perform an access check
0427  * against the receiving socket.  Returns zero on success, negative values on
0428  * error.
0429  *
0430  */
0431 int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
0432                 struct sk_buff *skb,
0433                 u16 family,
0434                 struct common_audit_data *ad)
0435 {
0436     int rc;
0437     u32 nlbl_sid;
0438     u32 perm;
0439     struct netlbl_lsm_secattr secattr;
0440 
0441     if (!netlbl_enabled())
0442         return 0;
0443 
0444     netlbl_secattr_init(&secattr);
0445     rc = netlbl_skbuff_getattr(skb, family, &secattr);
0446     if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
0447         rc = selinux_netlbl_sidlookup_cached(skb, family,
0448                              &secattr, &nlbl_sid);
0449     else
0450         nlbl_sid = SECINITSID_UNLABELED;
0451     netlbl_secattr_destroy(&secattr);
0452     if (rc != 0)
0453         return rc;
0454 
0455     switch (sksec->sclass) {
0456     case SECCLASS_UDP_SOCKET:
0457         perm = UDP_SOCKET__RECVFROM;
0458         break;
0459     case SECCLASS_TCP_SOCKET:
0460         perm = TCP_SOCKET__RECVFROM;
0461         break;
0462     default:
0463         perm = RAWIP_SOCKET__RECVFROM;
0464     }
0465 
0466     rc = avc_has_perm(&selinux_state,
0467               sksec->sid, nlbl_sid, sksec->sclass, perm, ad);
0468     if (rc == 0)
0469         return 0;
0470 
0471     if (nlbl_sid != SECINITSID_UNLABELED)
0472         netlbl_skbuff_err(skb, family, rc, 0);
0473     return rc;
0474 }
0475 
0476 /**
0477  * selinux_netlbl_option - Is this a NetLabel option
0478  * @level: the socket level or protocol
0479  * @optname: the socket option name
0480  *
0481  * Description:
0482  * Returns true if @level and @optname refer to a NetLabel option.
0483  * Helper for selinux_netlbl_socket_setsockopt().
0484  */
0485 static inline int selinux_netlbl_option(int level, int optname)
0486 {
0487     return (level == IPPROTO_IP && optname == IP_OPTIONS) ||
0488         (level == IPPROTO_IPV6 && optname == IPV6_HOPOPTS);
0489 }
0490 
0491 /**
0492  * selinux_netlbl_socket_setsockopt - Do not allow users to remove a NetLabel
0493  * @sock: the socket
0494  * @level: the socket level or protocol
0495  * @optname: the socket option name
0496  *
0497  * Description:
0498  * Check the setsockopt() call and if the user is trying to replace the IP
0499  * options on a socket and a NetLabel is in place for the socket deny the
0500  * access; otherwise allow the access.  Returns zero when the access is
0501  * allowed, -EACCES when denied, and other negative values on error.
0502  *
0503  */
0504 int selinux_netlbl_socket_setsockopt(struct socket *sock,
0505                      int level,
0506                      int optname)
0507 {
0508     int rc = 0;
0509     struct sock *sk = sock->sk;
0510     struct sk_security_struct *sksec = sk->sk_security;
0511     struct netlbl_lsm_secattr secattr;
0512 
0513     if (selinux_netlbl_option(level, optname) &&
0514         (sksec->nlbl_state == NLBL_LABELED ||
0515          sksec->nlbl_state == NLBL_CONNLABELED)) {
0516         netlbl_secattr_init(&secattr);
0517         lock_sock(sk);
0518         /* call the netlabel function directly as we want to see the
0519          * on-the-wire label that is assigned via the socket's options
0520          * and not the cached netlabel/lsm attributes */
0521         rc = netlbl_sock_getattr(sk, &secattr);
0522         release_sock(sk);
0523         if (rc == 0)
0524             rc = -EACCES;
0525         else if (rc == -ENOMSG)
0526             rc = 0;
0527         netlbl_secattr_destroy(&secattr);
0528     }
0529 
0530     return rc;
0531 }
0532 
0533 /**
0534  * selinux_netlbl_socket_connect_helper - Help label a client-side socket on
0535  * connect
0536  * @sk: the socket to label
0537  * @addr: the destination address
0538  *
0539  * Description:
0540  * Attempt to label a connected socket with NetLabel using the given address.
0541  * Returns zero values on success, negative values on failure.
0542  *
0543  */
0544 static int selinux_netlbl_socket_connect_helper(struct sock *sk,
0545                         struct sockaddr *addr)
0546 {
0547     int rc;
0548     struct sk_security_struct *sksec = sk->sk_security;
0549     struct netlbl_lsm_secattr *secattr;
0550 
0551     /* connected sockets are allowed to disconnect when the address family
0552      * is set to AF_UNSPEC, if that is what is happening we want to reset
0553      * the socket */
0554     if (addr->sa_family == AF_UNSPEC) {
0555         netlbl_sock_delattr(sk);
0556         sksec->nlbl_state = NLBL_REQSKB;
0557         rc = 0;
0558         return rc;
0559     }
0560     secattr = selinux_netlbl_sock_genattr(sk);
0561     if (secattr == NULL) {
0562         rc = -ENOMEM;
0563         return rc;
0564     }
0565     rc = netlbl_conn_setattr(sk, addr, secattr);
0566     if (rc == 0)
0567         sksec->nlbl_state = NLBL_CONNLABELED;
0568 
0569     return rc;
0570 }
0571 
0572 /**
0573  * selinux_netlbl_socket_connect_locked - Label a client-side socket on
0574  * connect
0575  * @sk: the socket to label
0576  * @addr: the destination address
0577  *
0578  * Description:
0579  * Attempt to label a connected socket that already has the socket locked
0580  * with NetLabel using the given address.
0581  * Returns zero values on success, negative values on failure.
0582  *
0583  */
0584 int selinux_netlbl_socket_connect_locked(struct sock *sk,
0585                      struct sockaddr *addr)
0586 {
0587     struct sk_security_struct *sksec = sk->sk_security;
0588 
0589     if (sksec->nlbl_state != NLBL_REQSKB &&
0590         sksec->nlbl_state != NLBL_CONNLABELED)
0591         return 0;
0592 
0593     return selinux_netlbl_socket_connect_helper(sk, addr);
0594 }
0595 
0596 /**
0597  * selinux_netlbl_socket_connect - Label a client-side socket on connect
0598  * @sk: the socket to label
0599  * @addr: the destination address
0600  *
0601  * Description:
0602  * Attempt to label a connected socket with NetLabel using the given address.
0603  * Returns zero values on success, negative values on failure.
0604  *
0605  */
0606 int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)
0607 {
0608     int rc;
0609 
0610     lock_sock(sk);
0611     rc = selinux_netlbl_socket_connect_locked(sk, addr);
0612     release_sock(sk);
0613 
0614     return rc;
0615 }