0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
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
0031
0032
0033
0034
0035
0036
0037
0038
0039
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
0060
0061
0062
0063
0064
0065
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
0093
0094
0095
0096
0097
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
0119
0120
0121
0122
0123
0124 void selinux_netlbl_cache_invalidate(void)
0125 {
0126 netlbl_cache_invalidate();
0127 }
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
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
0150
0151
0152
0153
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
0164
0165
0166
0167
0168
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
0178
0179
0180
0181
0182
0183
0184
0185
0186
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
0217
0218
0219
0220
0221
0222
0223
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
0236
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
0264
0265
0266
0267
0268
0269
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
0292
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
0316
0317
0318
0319
0320
0321
0322
0323
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
0347
0348
0349
0350
0351
0352
0353
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
0368
0369
0370
0371
0372
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
0384
0385
0386
0387
0388
0389
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
0420
0421
0422
0423
0424
0425
0426
0427
0428
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
0478
0479
0480
0481
0482
0483
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
0493
0494
0495
0496
0497
0498
0499
0500
0501
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
0519
0520
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
0535
0536
0537
0538
0539
0540
0541
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
0552
0553
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
0574
0575
0576
0577
0578
0579
0580
0581
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
0598
0599
0600
0601
0602
0603
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 }