Skip to content

Commit 6c5b3fc

Browse files
committed
selinux: Cache NetLabel secattrs in the socket's security struct
Previous work enabled the use of address based NetLabel selectors, which while highly useful, brought the potential for additional per-packet overhead when used. This patch attempts to mitigate some of that overhead by caching the NetLabel security attribute struct within the SELinux socket security structure. This should help eliminate the need to recreate the NetLabel secattr structure for each packet resulting in less overhead. Signed-off-by: Paul Moore <paul.moore@hp.com> Acked-by: James Morris <jmorris@namei.org>
1 parent 014ab19 commit 6c5b3fc

File tree

4 files changed

+91
-39
lines changed

4 files changed

+91
-39
lines changed

security/selinux/hooks.c

+1
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ static void sk_free_security(struct sock *sk)
291291
struct sk_security_struct *ssec = sk->sk_security;
292292

293293
sk->sk_security = NULL;
294+
selinux_netlbl_sk_security_free(ssec);
294295
kfree(ssec);
295296
}
296297

security/selinux/include/netlabel.h

+7
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ void selinux_netlbl_cache_invalidate(void);
4141

4242
void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway);
4343

44+
void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec);
4445
void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec,
4546
int family);
4647

@@ -77,6 +78,12 @@ static inline void selinux_netlbl_err(struct sk_buff *skb,
7778
return;
7879
}
7980

81+
static inline void selinux_netlbl_sk_security_free(
82+
struct sk_security_struct *ssec)
83+
{
84+
return;
85+
}
86+
8087
static inline void selinux_netlbl_sk_security_reset(
8188
struct sk_security_struct *ssec,
8289
int family)

security/selinux/include/objsec.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,6 @@ struct netport_security_struct {
109109
};
110110

111111
struct sk_security_struct {
112-
u32 sid; /* SID of this object */
113-
u32 peer_sid; /* SID of peer */
114-
u16 sclass; /* sock security class */
115112
#ifdef CONFIG_NETLABEL
116113
enum { /* NetLabel state */
117114
NLBL_UNSET = 0,
@@ -120,7 +117,11 @@ struct sk_security_struct {
120117
NLBL_REQSKB,
121118
NLBL_CONNLABELED,
122119
} nlbl_state;
120+
struct netlbl_lsm_secattr *nlbl_secattr; /* NetLabel sec attributes */
123121
#endif
122+
u32 sid; /* SID of this object */
123+
u32 peer_sid; /* SID of peer */
124+
u16 sclass; /* sock security class */
124125
};
125126

126127
struct key_security_struct {

security/selinux/netlabel.c

+79-36
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,38 @@ static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
6767
return rc;
6868
}
6969

70+
/**
71+
* selinux_netlbl_sock_genattr - Generate the NetLabel socket secattr
72+
* @sk: the socket
73+
*
74+
* Description:
75+
* Generate the NetLabel security attributes for a socket, making full use of
76+
* the socket's attribute cache. Returns a pointer to the security attributes
77+
* on success, NULL on failure.
78+
*
79+
*/
80+
static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
81+
{
82+
int rc;
83+
struct sk_security_struct *sksec = sk->sk_security;
84+
struct netlbl_lsm_secattr *secattr;
85+
86+
if (sksec->nlbl_secattr != NULL)
87+
return sksec->nlbl_secattr;
88+
89+
secattr = netlbl_secattr_alloc(GFP_ATOMIC);
90+
if (secattr == NULL)
91+
return NULL;
92+
rc = security_netlbl_sid_to_secattr(sksec->sid, secattr);
93+
if (rc != 0) {
94+
netlbl_secattr_free(secattr);
95+
return NULL;
96+
}
97+
sksec->nlbl_secattr = secattr;
98+
99+
return secattr;
100+
}
101+
70102
/**
71103
* selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism
72104
* @sk: the socket to label
@@ -80,17 +112,15 @@ static int selinux_netlbl_sock_setsid(struct sock *sk)
80112
{
81113
int rc;
82114
struct sk_security_struct *sksec = sk->sk_security;
83-
struct netlbl_lsm_secattr secattr;
115+
struct netlbl_lsm_secattr *secattr;
84116

85117
if (sksec->nlbl_state != NLBL_REQUIRE)
86118
return 0;
87119

88-
netlbl_secattr_init(&secattr);
89-
90-
rc = security_netlbl_sid_to_secattr(sksec->sid, &secattr);
91-
if (rc != 0)
92-
goto sock_setsid_return;
93-
rc = netlbl_sock_setattr(sk, &secattr);
120+
secattr = selinux_netlbl_sock_genattr(sk);
121+
if (secattr == NULL)
122+
return -ENOMEM;
123+
rc = netlbl_sock_setattr(sk, secattr);
94124
switch (rc) {
95125
case 0:
96126
sksec->nlbl_state = NLBL_LABELED;
@@ -101,8 +131,6 @@ static int selinux_netlbl_sock_setsid(struct sock *sk)
101131
break;
102132
}
103133

104-
sock_setsid_return:
105-
netlbl_secattr_destroy(&secattr);
106134
return rc;
107135
}
108136

@@ -136,6 +164,20 @@ void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway)
136164
netlbl_skbuff_err(skb, error, gateway);
137165
}
138166

167+
/**
168+
* selinux_netlbl_sk_security_free - Free the NetLabel fields
169+
* @sssec: the sk_security_struct
170+
*
171+
* Description:
172+
* Free all of the memory in the NetLabel fields of a sk_security_struct.
173+
*
174+
*/
175+
void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec)
176+
{
177+
if (ssec->nlbl_secattr != NULL)
178+
netlbl_secattr_free(ssec->nlbl_secattr);
179+
}
180+
139181
/**
140182
* selinux_netlbl_sk_security_reset - Reset the NetLabel fields
141183
* @ssec: the sk_security_struct
@@ -209,7 +251,8 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
209251
u32 sid)
210252
{
211253
int rc;
212-
struct netlbl_lsm_secattr secattr;
254+
struct netlbl_lsm_secattr secattr_storage;
255+
struct netlbl_lsm_secattr *secattr = NULL;
213256
struct sock *sk;
214257

215258
/* if this is a locally generated packet check to see if it is already
@@ -219,16 +262,21 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
219262
struct sk_security_struct *sksec = sk->sk_security;
220263
if (sksec->nlbl_state != NLBL_REQSKB)
221264
return 0;
265+
secattr = sksec->nlbl_secattr;
266+
}
267+
if (secattr == NULL) {
268+
secattr = &secattr_storage;
269+
netlbl_secattr_init(secattr);
270+
rc = security_netlbl_sid_to_secattr(sid, secattr);
271+
if (rc != 0)
272+
goto skbuff_setsid_return;
222273
}
223274

224-
netlbl_secattr_init(&secattr);
225-
rc = security_netlbl_sid_to_secattr(sid, &secattr);
226-
if (rc != 0)
227-
goto skbuff_setsid_return;
228-
rc = netlbl_skbuff_setattr(skb, family, &secattr);
275+
rc = netlbl_skbuff_setattr(skb, family, secattr);
229276

230277
skbuff_setsid_return:
231-
netlbl_secattr_destroy(&secattr);
278+
if (secattr == &secattr_storage)
279+
netlbl_secattr_destroy(secattr);
232280
return rc;
233281
}
234282

@@ -245,18 +293,18 @@ void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family)
245293
{
246294
int rc;
247295
struct sk_security_struct *sksec = sk->sk_security;
248-
struct netlbl_lsm_secattr secattr;
296+
struct netlbl_lsm_secattr *secattr;
249297
struct inet_sock *sk_inet = inet_sk(sk);
250298
struct sockaddr_in addr;
251299

252300
if (sksec->nlbl_state != NLBL_REQUIRE)
253301
return;
254302

255-
netlbl_secattr_init(&secattr);
256-
if (security_netlbl_sid_to_secattr(sksec->sid, &secattr) != 0)
257-
goto inet_conn_established_return;
303+
secattr = selinux_netlbl_sock_genattr(sk);
304+
if (secattr == NULL)
305+
return;
258306

259-
rc = netlbl_sock_setattr(sk, &secattr);
307+
rc = netlbl_sock_setattr(sk, secattr);
260308
switch (rc) {
261309
case 0:
262310
sksec->nlbl_state = NLBL_LABELED;
@@ -266,13 +314,13 @@ void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family)
266314
* labeling protocols */
267315
if (family != PF_INET) {
268316
sksec->nlbl_state = NLBL_UNSET;
269-
goto inet_conn_established_return;
317+
return;
270318
}
271319

272320
addr.sin_family = family;
273321
addr.sin_addr.s_addr = sk_inet->daddr;
274322
if (netlbl_conn_setattr(sk, (struct sockaddr *)&addr,
275-
&secattr) != 0) {
323+
secattr) != 0) {
276324
/* we failed to label the connected socket (could be
277325
* for a variety of reasons, the actual "why" isn't
278326
* important here) so we have to go to our backup plan,
@@ -300,10 +348,6 @@ void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family)
300348
* return an error code */
301349
break;
302350
}
303-
304-
inet_conn_established_return:
305-
netlbl_secattr_destroy(&secattr);
306-
return;
307351
}
308352

309353
/**
@@ -468,13 +512,12 @@ int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)
468512
{
469513
int rc;
470514
struct sk_security_struct *sksec = sk->sk_security;
471-
struct netlbl_lsm_secattr secattr;
515+
struct netlbl_lsm_secattr *secattr;
472516

473517
if (sksec->nlbl_state != NLBL_REQSKB &&
474518
sksec->nlbl_state != NLBL_CONNLABELED)
475519
return 0;
476520

477-
netlbl_secattr_init(&secattr);
478521
local_bh_disable();
479522
bh_lock_sock_nested(sk);
480523

@@ -487,17 +530,17 @@ int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)
487530
rc = 0;
488531
goto socket_connect_return;
489532
}
490-
rc = security_netlbl_sid_to_secattr(sksec->sid, &secattr);
491-
if (rc != 0)
533+
secattr = selinux_netlbl_sock_genattr(sk);
534+
if (secattr == NULL) {
535+
rc = -ENOMEM;
492536
goto socket_connect_return;
493-
rc = netlbl_conn_setattr(sk, addr, &secattr);
494-
if (rc != 0)
495-
goto socket_connect_return;
496-
sksec->nlbl_state = NLBL_CONNLABELED;
537+
}
538+
rc = netlbl_conn_setattr(sk, addr, secattr);
539+
if (rc == 0)
540+
sksec->nlbl_state = NLBL_CONNLABELED;
497541

498542
socket_connect_return:
499543
bh_unlock_sock(sk);
500544
local_bh_enable();
501-
netlbl_secattr_destroy(&secattr);
502545
return rc;
503546
}

0 commit comments

Comments
 (0)