Skip to content

Commit 3eb8eaf

Browse files
WOnder93pcmoore
authored andcommitted
security: implement sctp_assoc_established hook in selinux
Do this by extracting the peer labeling per-association logic from selinux_sctp_assoc_request() into a new helper selinux_sctp_process_new_assoc() and use this helper in both selinux_sctp_assoc_request() and selinux_sctp_assoc_established(). This ensures that the peer labeling behavior as documented in Documentation/security/SCTP.rst is applied both on the client and server side: """ An SCTP socket will only have one peer label assigned to it. This will be assigned during the establishment of the first association. Any further associations on this socket will have their packet peer label compared to the sockets peer label, and only if they are different will the ``association`` permission be validated. This is validated by checking the socket peer sid against the received packets peer sid to determine whether the association should be allowed or denied. """ At the same time, it also ensures that the peer label of the association is set to the correct value, such that if it is peeled off into a new socket, the socket's peer label will then be set to the association's peer label, same as it already works on the server side. While selinux_inet_conn_established() (which we are replacing by selinux_sctp_assoc_established() for SCTP) only deals with assigning a peer label to the connection (socket), in case of SCTP we need to also copy the (local) socket label to the association, so that selinux_sctp_sk_clone() can then pick it up for the new socket in case of SCTP peeloff. Careful readers will notice that the selinux_sctp_process_new_assoc() helper also includes the "IPv4 packet received over an IPv6 socket" check, even though it hadn't been in selinux_sctp_assoc_request() before. While such check is not necessary in selinux_inet_conn_request() (because struct request_sock's family field is already set according to the skb's family), here it is needed, as we don't have request_sock and we take the initial family from the socket. In selinux_sctp_assoc_established() it is similarly needed as well (and also selinux_inet_conn_established() already has it). Fixes: 72e89f5 ("security: Add support for SCTP security hooks") Reported-by: Prashanth Prahlad <pprahlad@redhat.com> Based-on-patch-by: Xin Long <lucien.xin@gmail.com> Reviewed-by: Xin Long <lucien.xin@gmail.com> Tested-by: Richard Haines <richard_c_haines@btinternet.com> Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com> Signed-off-by: Paul Moore <paul@paul-moore.com>
1 parent 5e50f5d commit 3eb8eaf

1 file changed

Lines changed: 66 additions & 24 deletions

File tree

security/selinux/hooks.c

Lines changed: 66 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5238,37 +5238,38 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent)
52385238
sksec->sclass = isec->sclass;
52395239
}
52405240

5241-
/* Called whenever SCTP receives an INIT chunk. This happens when an incoming
5242-
* connect(2), sctp_connectx(3) or sctp_sendmsg(3) (with no association
5243-
* already present).
5241+
/*
5242+
* Determines peer_secid for the asoc and updates socket's peer label
5243+
* if it's the first association on the socket.
52445244
*/
5245-
static int selinux_sctp_assoc_request(struct sctp_association *asoc,
5246-
struct sk_buff *skb)
5245+
static int selinux_sctp_process_new_assoc(struct sctp_association *asoc,
5246+
struct sk_buff *skb)
52475247
{
5248-
struct sk_security_struct *sksec = asoc->base.sk->sk_security;
5248+
struct sock *sk = asoc->base.sk;
5249+
u16 family = sk->sk_family;
5250+
struct sk_security_struct *sksec = sk->sk_security;
52495251
struct common_audit_data ad;
52505252
struct lsm_network_audit net = {0,};
5251-
u8 peerlbl_active;
5252-
u32 peer_sid = SECINITSID_UNLABELED;
5253-
u32 conn_sid;
5254-
int err = 0;
5253+
int err;
52555254

5256-
if (!selinux_policycap_extsockclass())
5257-
return 0;
5255+
/* handle mapped IPv4 packets arriving via IPv6 sockets */
5256+
if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
5257+
family = PF_INET;
52585258

5259-
peerlbl_active = selinux_peerlbl_enabled();
5259+
if (selinux_peerlbl_enabled()) {
5260+
asoc->peer_secid = SECSID_NULL;
52605261

5261-
if (peerlbl_active) {
52625262
/* This will return peer_sid = SECSID_NULL if there are
52635263
* no peer labels, see security_net_peersid_resolve().
52645264
*/
5265-
err = selinux_skb_peerlbl_sid(skb, asoc->base.sk->sk_family,
5266-
&peer_sid);
5265+
err = selinux_skb_peerlbl_sid(skb, family, &asoc->peer_secid);
52675266
if (err)
52685267
return err;
52695268

5270-
if (peer_sid == SECSID_NULL)
5271-
peer_sid = SECINITSID_UNLABELED;
5269+
if (asoc->peer_secid == SECSID_NULL)
5270+
asoc->peer_secid = SECINITSID_UNLABELED;
5271+
} else {
5272+
asoc->peer_secid = SECINITSID_UNLABELED;
52725273
}
52735274

52745275
if (sksec->sctp_assoc_state == SCTP_ASSOC_UNSET) {
@@ -5279,38 +5280,78 @@ static int selinux_sctp_assoc_request(struct sctp_association *asoc,
52795280
* then it is approved by policy and used as the primary
52805281
* peer SID for getpeercon(3).
52815282
*/
5282-
sksec->peer_sid = peer_sid;
5283-
} else if (sksec->peer_sid != peer_sid) {
5283+
sksec->peer_sid = asoc->peer_secid;
5284+
} else if (sksec->peer_sid != asoc->peer_secid) {
52845285
/* Other association peer SIDs are checked to enforce
52855286
* consistency among the peer SIDs.
52865287
*/
52875288
ad.type = LSM_AUDIT_DATA_NET;
52885289
ad.u.net = &net;
52895290
ad.u.net->sk = asoc->base.sk;
52905291
err = avc_has_perm(&selinux_state,
5291-
sksec->peer_sid, peer_sid, sksec->sclass,
5292-
SCTP_SOCKET__ASSOCIATION, &ad);
5292+
sksec->peer_sid, asoc->peer_secid,
5293+
sksec->sclass, SCTP_SOCKET__ASSOCIATION,
5294+
&ad);
52935295
if (err)
52945296
return err;
52955297
}
5298+
return 0;
5299+
}
5300+
5301+
/* Called whenever SCTP receives an INIT or COOKIE ECHO chunk. This
5302+
* happens on an incoming connect(2), sctp_connectx(3) or
5303+
* sctp_sendmsg(3) (with no association already present).
5304+
*/
5305+
static int selinux_sctp_assoc_request(struct sctp_association *asoc,
5306+
struct sk_buff *skb)
5307+
{
5308+
struct sk_security_struct *sksec = asoc->base.sk->sk_security;
5309+
u32 conn_sid;
5310+
int err;
5311+
5312+
if (!selinux_policycap_extsockclass())
5313+
return 0;
5314+
5315+
err = selinux_sctp_process_new_assoc(asoc, skb);
5316+
if (err)
5317+
return err;
52965318

52975319
/* Compute the MLS component for the connection and store
52985320
* the information in asoc. This will be used by SCTP TCP type
52995321
* sockets and peeled off connections as they cause a new
53005322
* socket to be generated. selinux_sctp_sk_clone() will then
53015323
* plug this into the new socket.
53025324
*/
5303-
err = selinux_conn_sid(sksec->sid, peer_sid, &conn_sid);
5325+
err = selinux_conn_sid(sksec->sid, asoc->peer_secid, &conn_sid);
53045326
if (err)
53055327
return err;
53065328

53075329
asoc->secid = conn_sid;
5308-
asoc->peer_secid = peer_sid;
53095330

53105331
/* Set any NetLabel labels including CIPSO/CALIPSO options. */
53115332
return selinux_netlbl_sctp_assoc_request(asoc, skb);
53125333
}
53135334

5335+
/* Called when SCTP receives a COOKIE ACK chunk as the final
5336+
* response to an association request (initited by us).
5337+
*/
5338+
static int selinux_sctp_assoc_established(struct sctp_association *asoc,
5339+
struct sk_buff *skb)
5340+
{
5341+
struct sk_security_struct *sksec = asoc->base.sk->sk_security;
5342+
5343+
if (!selinux_policycap_extsockclass())
5344+
return 0;
5345+
5346+
/* Inherit secid from the parent socket - this will be picked up
5347+
* by selinux_sctp_sk_clone() if the association gets peeled off
5348+
* into a new socket.
5349+
*/
5350+
asoc->secid = sksec->sid;
5351+
5352+
return selinux_sctp_process_new_assoc(asoc, skb);
5353+
}
5354+
53145355
/* Check if sctp IPv4/IPv6 addresses are valid for binding or connecting
53155356
* based on their @optname.
53165357
*/
@@ -7131,6 +7172,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
71317172
LSM_HOOK_INIT(sctp_assoc_request, selinux_sctp_assoc_request),
71327173
LSM_HOOK_INIT(sctp_sk_clone, selinux_sctp_sk_clone),
71337174
LSM_HOOK_INIT(sctp_bind_connect, selinux_sctp_bind_connect),
7175+
LSM_HOOK_INIT(sctp_assoc_established, selinux_sctp_assoc_established),
71347176
LSM_HOOK_INIT(inet_conn_request, selinux_inet_conn_request),
71357177
LSM_HOOK_INIT(inet_csk_clone, selinux_inet_csk_clone),
71367178
LSM_HOOK_INIT(inet_conn_established, selinux_inet_conn_established),

0 commit comments

Comments
 (0)