linux/security/selinux/netlabel.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * SELinux NetLabel Support
   4 *
   5 * This file provides the necessary glue to tie NetLabel into the SELinux
   6 * subsystem.
   7 *
   8 * Author: Paul Moore <paul@paul-moore.com>
   9 */
  10
  11/*
  12 * (c) Copyright Hewlett-Packard Development Company, L.P., 2007, 2008
  13 */
  14
  15#include <linux/spinlock.h>
  16#include <linux/rcupdate.h>
  17#include <linux/gfp.h>
  18#include <linux/ip.h>
  19#include <linux/ipv6.h>
  20#include <net/sock.h>
  21#include <net/netlabel.h>
  22#include <net/ip.h>
  23#include <net/ipv6.h>
  24
  25#include "objsec.h"
  26#include "security.h"
  27#include "netlabel.h"
  28
  29/**
  30 * selinux_netlbl_sidlookup_cached - Cache a SID lookup
  31 * @skb: the packet
  32 * @secattr: the NetLabel security attributes
  33 * @sid: the SID
  34 *
  35 * Description:
  36 * Query the SELinux security server to lookup the correct SID for the given
  37 * security attributes.  If the query is successful, cache the result to speed
  38 * up future lookups.  Returns zero on success, negative values on failure.
  39 *
  40 */
  41static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
  42                                           u16 family,
  43                                           struct netlbl_lsm_secattr *secattr,
  44                                           u32 *sid)
  45{
  46        int rc;
  47
  48        rc = security_netlbl_secattr_to_sid(&selinux_state, secattr, sid);
  49        if (rc == 0 &&
  50            (secattr->flags & NETLBL_SECATTR_CACHEABLE) &&
  51            (secattr->flags & NETLBL_SECATTR_CACHE))
  52                netlbl_cache_add(skb, family, secattr);
  53
  54        return rc;
  55}
  56
  57/**
  58 * selinux_netlbl_sock_genattr - Generate the NetLabel socket secattr
  59 * @sk: the socket
  60 *
  61 * Description:
  62 * Generate the NetLabel security attributes for a socket, making full use of
  63 * the socket's attribute cache.  Returns a pointer to the security attributes
  64 * on success, NULL on failure.
  65 *
  66 */
  67static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
  68{
  69        int rc;
  70        struct sk_security_struct *sksec = sk->sk_security;
  71        struct netlbl_lsm_secattr *secattr;
  72
  73        if (sksec->nlbl_secattr != NULL)
  74                return sksec->nlbl_secattr;
  75
  76        secattr = netlbl_secattr_alloc(GFP_ATOMIC);
  77        if (secattr == NULL)
  78                return NULL;
  79        rc = security_netlbl_sid_to_secattr(&selinux_state, sksec->sid,
  80                                            secattr);
  81        if (rc != 0) {
  82                netlbl_secattr_free(secattr);
  83                return NULL;
  84        }
  85        sksec->nlbl_secattr = secattr;
  86
  87        return secattr;
  88}
  89
  90/**
  91 * selinux_netlbl_sock_getattr - Get the cached NetLabel secattr
  92 * @sk: the socket
  93 * @sid: the SID
  94 *
  95 * Query the socket's cached secattr and if the SID matches the cached value
  96 * return the cache, otherwise return NULL.
  97 *
  98 */
  99static struct netlbl_lsm_secattr *selinux_netlbl_sock_getattr(
 100                                                        const struct sock *sk,
 101                                                        u32 sid)
 102{
 103        struct sk_security_struct *sksec = sk->sk_security;
 104        struct netlbl_lsm_secattr *secattr = sksec->nlbl_secattr;
 105
 106        if (secattr == NULL)
 107                return NULL;
 108
 109        if ((secattr->flags & NETLBL_SECATTR_SECID) &&
 110            (secattr->attr.secid == sid))
 111                return secattr;
 112
 113        return NULL;
 114}
 115
 116/**
 117 * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache
 118 *
 119 * Description:
 120 * Invalidate the NetLabel security attribute mapping cache.
 121 *
 122 */
 123void selinux_netlbl_cache_invalidate(void)
 124{
 125        netlbl_cache_invalidate();
 126}
 127
 128/**
 129 * selinux_netlbl_err - Handle a NetLabel packet error
 130 * @skb: the packet
 131 * @error: the error code
 132 * @gateway: true if host is acting as a gateway, false otherwise
 133 *
 134 * Description:
 135 * When a packet is dropped due to a call to avc_has_perm() pass the error
 136 * code to the NetLabel subsystem so any protocol specific processing can be
 137 * done.  This is safe to call even if you are unsure if NetLabel labeling is
 138 * present on the packet, NetLabel is smart enough to only act when it should.
 139 *
 140 */
 141void selinux_netlbl_err(struct sk_buff *skb, u16 family, int error, int gateway)
 142{
 143        netlbl_skbuff_err(skb, family, error, gateway);
 144}
 145
 146/**
 147 * selinux_netlbl_sk_security_free - Free the NetLabel fields
 148 * @sksec: the sk_security_struct
 149 *
 150 * Description:
 151 * Free all of the memory in the NetLabel fields of a sk_security_struct.
 152 *
 153 */
 154void selinux_netlbl_sk_security_free(struct sk_security_struct *sksec)
 155{
 156        if (sksec->nlbl_secattr != NULL)
 157                netlbl_secattr_free(sksec->nlbl_secattr);
 158}
 159
 160/**
 161 * selinux_netlbl_sk_security_reset - Reset the NetLabel fields
 162 * @sksec: the sk_security_struct
 163 * @family: the socket family
 164 *
 165 * Description:
 166 * Called when the NetLabel state of a sk_security_struct needs to be reset.
 167 * The caller is responsible for all the NetLabel sk_security_struct locking.
 168 *
 169 */
 170void selinux_netlbl_sk_security_reset(struct sk_security_struct *sksec)
 171{
 172        sksec->nlbl_state = NLBL_UNSET;
 173}
 174
 175/**
 176 * selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel
 177 * @skb: the packet
 178 * @family: protocol family
 179 * @type: NetLabel labeling protocol type
 180 * @sid: the SID
 181 *
 182 * Description:
 183 * Call the NetLabel mechanism to get the security attributes of the given
 184 * packet and use those attributes to determine the correct context/SID to
 185 * assign to the packet.  Returns zero on success, negative values on failure.
 186 *
 187 */
 188int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
 189                                 u16 family,
 190                                 u32 *type,
 191                                 u32 *sid)
 192{
 193        int rc;
 194        struct netlbl_lsm_secattr secattr;
 195
 196        if (!netlbl_enabled()) {
 197                *sid = SECSID_NULL;
 198                return 0;
 199        }
 200
 201        netlbl_secattr_init(&secattr);
 202        rc = netlbl_skbuff_getattr(skb, family, &secattr);
 203        if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
 204                rc = selinux_netlbl_sidlookup_cached(skb, family,
 205                                                     &secattr, sid);
 206        else
 207                *sid = SECSID_NULL;
 208        *type = secattr.type;
 209        netlbl_secattr_destroy(&secattr);
 210
 211        return rc;
 212}
 213
 214/**
 215 * selinux_netlbl_skbuff_setsid - Set the NetLabel on a packet given a sid
 216 * @skb: the packet
 217 * @family: protocol family
 218 * @sid: the SID
 219 *
 220 * Description
 221 * Call the NetLabel mechanism to set the label of a packet using @sid.
 222 * Returns zero on success, negative values on failure.
 223 *
 224 */
 225int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
 226                                 u16 family,
 227                                 u32 sid)
 228{
 229        int rc;
 230        struct netlbl_lsm_secattr secattr_storage;
 231        struct netlbl_lsm_secattr *secattr = NULL;
 232        struct sock *sk;
 233
 234        /* if this is a locally generated packet check to see if it is already
 235         * being labeled by it's parent socket, if it is just exit */
 236        sk = skb_to_full_sk(skb);
 237        if (sk != NULL) {
 238                struct sk_security_struct *sksec = sk->sk_security;
 239
 240                if (sksec->nlbl_state != NLBL_REQSKB)
 241                        return 0;
 242                secattr = selinux_netlbl_sock_getattr(sk, sid);
 243        }
 244        if (secattr == NULL) {
 245                secattr = &secattr_storage;
 246                netlbl_secattr_init(secattr);
 247                rc = security_netlbl_sid_to_secattr(&selinux_state, sid,
 248                                                    secattr);
 249                if (rc != 0)
 250                        goto skbuff_setsid_return;
 251        }
 252
 253        rc = netlbl_skbuff_setattr(skb, family, secattr);
 254
 255skbuff_setsid_return:
 256        if (secattr == &secattr_storage)
 257                netlbl_secattr_destroy(secattr);
 258        return rc;
 259}
 260
 261/**
 262 * selinux_netlbl_sctp_assoc_request - Label an incoming sctp association.
 263 * @ep: incoming association endpoint.
 264 * @skb: the packet.
 265 *
 266 * Description:
 267 * A new incoming connection is represented by @ep, ......
 268 * Returns zero on success, negative values on failure.
 269 *
 270 */
 271int selinux_netlbl_sctp_assoc_request(struct sctp_endpoint *ep,
 272                                     struct sk_buff *skb)
 273{
 274        int rc;
 275        struct netlbl_lsm_secattr secattr;
 276        struct sk_security_struct *sksec = ep->base.sk->sk_security;
 277        struct sockaddr_in addr4;
 278        struct sockaddr_in6 addr6;
 279
 280        if (ep->base.sk->sk_family != PF_INET &&
 281                                ep->base.sk->sk_family != PF_INET6)
 282                return 0;
 283
 284        netlbl_secattr_init(&secattr);
 285        rc = security_netlbl_sid_to_secattr(&selinux_state,
 286                                            ep->secid, &secattr);
 287        if (rc != 0)
 288                goto assoc_request_return;
 289
 290        /* Move skb hdr address info to a struct sockaddr and then call
 291         * netlbl_conn_setattr().
 292         */
 293        if (ip_hdr(skb)->version == 4) {
 294                addr4.sin_family = AF_INET;
 295                addr4.sin_addr.s_addr = ip_hdr(skb)->saddr;
 296                rc = netlbl_conn_setattr(ep->base.sk, (void *)&addr4, &secattr);
 297        } else if (IS_ENABLED(CONFIG_IPV6) && ip_hdr(skb)->version == 6) {
 298                addr6.sin6_family = AF_INET6;
 299                addr6.sin6_addr = ipv6_hdr(skb)->saddr;
 300                rc = netlbl_conn_setattr(ep->base.sk, (void *)&addr6, &secattr);
 301        } else {
 302                rc = -EAFNOSUPPORT;
 303        }
 304
 305        if (rc == 0)
 306                sksec->nlbl_state = NLBL_LABELED;
 307
 308assoc_request_return:
 309        netlbl_secattr_destroy(&secattr);
 310        return rc;
 311}
 312
 313/**
 314 * selinux_netlbl_inet_conn_request - Label an incoming stream connection
 315 * @req: incoming connection request socket
 316 *
 317 * Description:
 318 * A new incoming connection request is represented by @req, we need to label
 319 * the new request_sock here and the stack will ensure the on-the-wire label
 320 * will get preserved when a full sock is created once the connection handshake
 321 * is complete.  Returns zero on success, negative values on failure.
 322 *
 323 */
 324int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family)
 325{
 326        int rc;
 327        struct netlbl_lsm_secattr secattr;
 328
 329        if (family != PF_INET && family != PF_INET6)
 330                return 0;
 331
 332        netlbl_secattr_init(&secattr);
 333        rc = security_netlbl_sid_to_secattr(&selinux_state, req->secid,
 334                                            &secattr);
 335        if (rc != 0)
 336                goto inet_conn_request_return;
 337        rc = netlbl_req_setattr(req, &secattr);
 338inet_conn_request_return:
 339        netlbl_secattr_destroy(&secattr);
 340        return rc;
 341}
 342
 343/**
 344 * selinux_netlbl_inet_csk_clone - Initialize the newly created sock
 345 * @sk: the new sock
 346 *
 347 * Description:
 348 * A new connection has been established using @sk, we've already labeled the
 349 * socket via the request_sock struct in selinux_netlbl_inet_conn_request() but
 350 * we need to set the NetLabel state here since we now have a sock structure.
 351 *
 352 */
 353void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
 354{
 355        struct sk_security_struct *sksec = sk->sk_security;
 356
 357        if (family == PF_INET)
 358                sksec->nlbl_state = NLBL_LABELED;
 359        else
 360                sksec->nlbl_state = NLBL_UNSET;
 361}
 362
 363/**
 364 * selinux_netlbl_sctp_sk_clone - Copy state to the newly created sock
 365 * @sk: current sock
 366 * @newsk: the new sock
 367 *
 368 * Description:
 369 * Called whenever a new socket is created by accept(2) or sctp_peeloff(3).
 370 */
 371void selinux_netlbl_sctp_sk_clone(struct sock *sk, struct sock *newsk)
 372{
 373        struct sk_security_struct *sksec = sk->sk_security;
 374        struct sk_security_struct *newsksec = newsk->sk_security;
 375
 376        newsksec->nlbl_state = sksec->nlbl_state;
 377}
 378
 379/**
 380 * selinux_netlbl_socket_post_create - Label a socket using NetLabel
 381 * @sock: the socket to label
 382 * @family: protocol family
 383 *
 384 * Description:
 385 * Attempt to label a socket using the NetLabel mechanism using the given
 386 * SID.  Returns zero values on success, negative values on failure.
 387 *
 388 */
 389int selinux_netlbl_socket_post_create(struct sock *sk, u16 family)
 390{
 391        int rc;
 392        struct sk_security_struct *sksec = sk->sk_security;
 393        struct netlbl_lsm_secattr *secattr;
 394
 395        if (family != PF_INET && family != PF_INET6)
 396                return 0;
 397
 398        secattr = selinux_netlbl_sock_genattr(sk);
 399        if (secattr == NULL)
 400                return -ENOMEM;
 401        rc = netlbl_sock_setattr(sk, family, secattr);
 402        switch (rc) {
 403        case 0:
 404                sksec->nlbl_state = NLBL_LABELED;
 405                break;
 406        case -EDESTADDRREQ:
 407                sksec->nlbl_state = NLBL_REQSKB;
 408                rc = 0;
 409                break;
 410        }
 411
 412        return rc;
 413}
 414
 415/**
 416 * selinux_netlbl_sock_rcv_skb - Do an inbound access check using NetLabel
 417 * @sksec: the sock's sk_security_struct
 418 * @skb: the packet
 419 * @family: protocol family
 420 * @ad: the audit data
 421 *
 422 * Description:
 423 * Fetch the NetLabel security attributes from @skb and perform an access check
 424 * against the receiving socket.  Returns zero on success, negative values on
 425 * error.
 426 *
 427 */
 428int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
 429                                struct sk_buff *skb,
 430                                u16 family,
 431                                struct common_audit_data *ad)
 432{
 433        int rc;
 434        u32 nlbl_sid;
 435        u32 perm;
 436        struct netlbl_lsm_secattr secattr;
 437
 438        if (!netlbl_enabled())
 439                return 0;
 440
 441        netlbl_secattr_init(&secattr);
 442        rc = netlbl_skbuff_getattr(skb, family, &secattr);
 443        if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
 444                rc = selinux_netlbl_sidlookup_cached(skb, family,
 445                                                     &secattr, &nlbl_sid);
 446        else
 447                nlbl_sid = SECINITSID_UNLABELED;
 448        netlbl_secattr_destroy(&secattr);
 449        if (rc != 0)
 450                return rc;
 451
 452        switch (sksec->sclass) {
 453        case SECCLASS_UDP_SOCKET:
 454                perm = UDP_SOCKET__RECVFROM;
 455                break;
 456        case SECCLASS_TCP_SOCKET:
 457                perm = TCP_SOCKET__RECVFROM;
 458                break;
 459        default:
 460                perm = RAWIP_SOCKET__RECVFROM;
 461        }
 462
 463        rc = avc_has_perm(&selinux_state,
 464                          sksec->sid, nlbl_sid, sksec->sclass, perm, ad);
 465        if (rc == 0)
 466                return 0;
 467
 468        if (nlbl_sid != SECINITSID_UNLABELED)
 469                netlbl_skbuff_err(skb, family, rc, 0);
 470        return rc;
 471}
 472
 473/**
 474 * selinux_netlbl_option - Is this a NetLabel option
 475 * @level: the socket level or protocol
 476 * @optname: the socket option name
 477 *
 478 * Description:
 479 * Returns true if @level and @optname refer to a NetLabel option.
 480 * Helper for selinux_netlbl_socket_setsockopt().
 481 */
 482static inline int selinux_netlbl_option(int level, int optname)
 483{
 484        return (level == IPPROTO_IP && optname == IP_OPTIONS) ||
 485                (level == IPPROTO_IPV6 && optname == IPV6_HOPOPTS);
 486}
 487
 488/**
 489 * selinux_netlbl_socket_setsockopt - Do not allow users to remove a NetLabel
 490 * @sock: the socket
 491 * @level: the socket level or protocol
 492 * @optname: the socket option name
 493 *
 494 * Description:
 495 * Check the setsockopt() call and if the user is trying to replace the IP
 496 * options on a socket and a NetLabel is in place for the socket deny the
 497 * access; otherwise allow the access.  Returns zero when the access is
 498 * allowed, -EACCES when denied, and other negative values on error.
 499 *
 500 */
 501int selinux_netlbl_socket_setsockopt(struct socket *sock,
 502                                     int level,
 503                                     int optname)
 504{
 505        int rc = 0;
 506        struct sock *sk = sock->sk;
 507        struct sk_security_struct *sksec = sk->sk_security;
 508        struct netlbl_lsm_secattr secattr;
 509
 510        if (selinux_netlbl_option(level, optname) &&
 511            (sksec->nlbl_state == NLBL_LABELED ||
 512             sksec->nlbl_state == NLBL_CONNLABELED)) {
 513                netlbl_secattr_init(&secattr);
 514                lock_sock(sk);
 515                /* call the netlabel function directly as we want to see the
 516                 * on-the-wire label that is assigned via the socket's options
 517                 * and not the cached netlabel/lsm attributes */
 518                rc = netlbl_sock_getattr(sk, &secattr);
 519                release_sock(sk);
 520                if (rc == 0)
 521                        rc = -EACCES;
 522                else if (rc == -ENOMSG)
 523                        rc = 0;
 524                netlbl_secattr_destroy(&secattr);
 525        }
 526
 527        return rc;
 528}
 529
 530/**
 531 * selinux_netlbl_socket_connect_helper - Help label a client-side socket on
 532 * connect
 533 * @sk: the socket to label
 534 * @addr: the destination address
 535 *
 536 * Description:
 537 * Attempt to label a connected socket with NetLabel using the given address.
 538 * Returns zero values on success, negative values on failure.
 539 *
 540 */
 541static int selinux_netlbl_socket_connect_helper(struct sock *sk,
 542                                                struct sockaddr *addr)
 543{
 544        int rc;
 545        struct sk_security_struct *sksec = sk->sk_security;
 546        struct netlbl_lsm_secattr *secattr;
 547
 548        /* connected sockets are allowed to disconnect when the address family
 549         * is set to AF_UNSPEC, if that is what is happening we want to reset
 550         * the socket */
 551        if (addr->sa_family == AF_UNSPEC) {
 552                netlbl_sock_delattr(sk);
 553                sksec->nlbl_state = NLBL_REQSKB;
 554                rc = 0;
 555                return rc;
 556        }
 557        secattr = selinux_netlbl_sock_genattr(sk);
 558        if (secattr == NULL) {
 559                rc = -ENOMEM;
 560                return rc;
 561        }
 562        rc = netlbl_conn_setattr(sk, addr, secattr);
 563        if (rc == 0)
 564                sksec->nlbl_state = NLBL_CONNLABELED;
 565
 566        return rc;
 567}
 568
 569/**
 570 * selinux_netlbl_socket_connect_locked - Label a client-side socket on
 571 * connect
 572 * @sk: the socket to label
 573 * @addr: the destination address
 574 *
 575 * Description:
 576 * Attempt to label a connected socket that already has the socket locked
 577 * with NetLabel using the given address.
 578 * Returns zero values on success, negative values on failure.
 579 *
 580 */
 581int selinux_netlbl_socket_connect_locked(struct sock *sk,
 582                                         struct sockaddr *addr)
 583{
 584        struct sk_security_struct *sksec = sk->sk_security;
 585
 586        if (sksec->nlbl_state != NLBL_REQSKB &&
 587            sksec->nlbl_state != NLBL_CONNLABELED)
 588                return 0;
 589
 590        return selinux_netlbl_socket_connect_helper(sk, addr);
 591}
 592
 593/**
 594 * selinux_netlbl_socket_connect - Label a client-side socket on connect
 595 * @sk: the socket to label
 596 * @addr: the destination address
 597 *
 598 * Description:
 599 * Attempt to label a connected socket with NetLabel using the given address.
 600 * Returns zero values on success, negative values on failure.
 601 *
 602 */
 603int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)
 604{
 605        int rc;
 606
 607        lock_sock(sk);
 608        rc = selinux_netlbl_socket_connect_locked(sk, addr);
 609        release_sock(sk);
 610
 611        return rc;
 612}
 613