Commit 6c5b3fc0147f79d714d2fe748b5869d7892ef2e7

Authored by Paul Moore
1 parent 014ab19a69

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>

Showing 4 changed files with 91 additions and 39 deletions Side-by-side Diff

security/selinux/hooks.c
... ... @@ -291,6 +291,7 @@
291 291 struct sk_security_struct *ssec = sk->sk_security;
292 292  
293 293 sk->sk_security = NULL;
  294 + selinux_netlbl_sk_security_free(ssec);
294 295 kfree(ssec);
295 296 }
296 297  
security/selinux/include/netlabel.h
... ... @@ -41,6 +41,7 @@
41 41  
42 42 void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway);
43 43  
  44 +void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec);
44 45 void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec,
45 46 int family);
46 47  
... ... @@ -73,6 +74,12 @@
73 74 static inline void selinux_netlbl_err(struct sk_buff *skb,
74 75 int error,
75 76 int gateway)
  77 +{
  78 + return;
  79 +}
  80 +
  81 +static inline void selinux_netlbl_sk_security_free(
  82 + struct sk_security_struct *ssec)
76 83 {
77 84 return;
78 85 }
security/selinux/include/objsec.h
... ... @@ -109,9 +109,6 @@
109 109 };
110 110  
111 111 struct sk_security_struct {
112   - u32 sid; /* SID of this object */
113   - u32 peer_sid; /* SID of peer */
114   - u16 sclass; /* sock security class */
115 112 #ifdef CONFIG_NETLABEL
116 113 enum { /* NetLabel state */
117 114 NLBL_UNSET = 0,
118 115  
... ... @@ -120,7 +117,11 @@
120 117 NLBL_REQSKB,
121 118 NLBL_CONNLABELED,
122 119 } nlbl_state;
  120 + struct netlbl_lsm_secattr *nlbl_secattr; /* NetLabel sec attributes */
123 121 #endif
  122 + u32 sid; /* SID of this object */
  123 + u32 peer_sid; /* SID of peer */
  124 + u16 sclass; /* sock security class */
124 125 };
125 126  
126 127 struct key_security_struct {
security/selinux/netlabel.c
... ... @@ -68,6 +68,38 @@
68 68 }
69 69  
70 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 +
  102 +/**
71 103 * selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism
72 104 * @sk: the socket to label
73 105 *
74 106  
... ... @@ -80,17 +112,15 @@
80 112 {
81 113 int rc;
82 114 struct sk_security_struct *sksec = sk->sk_security;
83   - struct netlbl_lsm_secattr secattr;
  115 + struct netlbl_lsm_secattr *secattr;
84 116  
85 117 if (sksec->nlbl_state != NLBL_REQUIRE)
86 118 return 0;
87 119  
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);
94 124 switch (rc) {
95 125 case 0:
96 126 sksec->nlbl_state = NLBL_LABELED;
... ... @@ -101,8 +131,6 @@
101 131 break;
102 132 }
103 133  
104   -sock_setsid_return:
105   - netlbl_secattr_destroy(&secattr);
106 134 return rc;
107 135 }
108 136  
... ... @@ -137,6 +165,20 @@
137 165 }
138 166  
139 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 +
  181 +/**
140 182 * selinux_netlbl_sk_security_reset - Reset the NetLabel fields
141 183 * @ssec: the sk_security_struct
142 184 * @family: the socket family
... ... @@ -209,7 +251,8 @@
209 251 u32 sid)
210 252 {
211 253 int rc;
212   - struct netlbl_lsm_secattr secattr;
  254 + struct netlbl_lsm_secattr secattr_storage;
  255 + struct netlbl_lsm_secattr *secattr = NULL;
213 256 struct sock *sk;
214 257  
215 258 /* if this is a locally generated packet check to see if it is already
216 259  
217 260  
218 261  
... ... @@ -219,16 +262,21 @@
219 262 struct sk_security_struct *sksec = sk->sk_security;
220 263 if (sksec->nlbl_state != NLBL_REQSKB)
221 264 return 0;
  265 + secattr = sksec->nlbl_secattr;
222 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;
  273 + }
223 274  
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);
229 276  
230 277 skbuff_setsid_return:
231   - netlbl_secattr_destroy(&secattr);
  278 + if (secattr == &secattr_storage)
  279 + netlbl_secattr_destroy(secattr);
232 280 return rc;
233 281 }
234 282  
235 283  
236 284  
... ... @@ -245,18 +293,18 @@
245 293 {
246 294 int rc;
247 295 struct sk_security_struct *sksec = sk->sk_security;
248   - struct netlbl_lsm_secattr secattr;
  296 + struct netlbl_lsm_secattr *secattr;
249 297 struct inet_sock *sk_inet = inet_sk(sk);
250 298 struct sockaddr_in addr;
251 299  
252 300 if (sksec->nlbl_state != NLBL_REQUIRE)
253 301 return;
254 302  
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;
258 306  
259   - rc = netlbl_sock_setattr(sk, &secattr);
  307 + rc = netlbl_sock_setattr(sk, secattr);
260 308 switch (rc) {
261 309 case 0:
262 310 sksec->nlbl_state = NLBL_LABELED;
263 311  
... ... @@ -266,13 +314,13 @@
266 314 * labeling protocols */
267 315 if (family != PF_INET) {
268 316 sksec->nlbl_state = NLBL_UNSET;
269   - goto inet_conn_established_return;
  317 + return;
270 318 }
271 319  
272 320 addr.sin_family = family;
273 321 addr.sin_addr.s_addr = sk_inet->daddr;
274 322 if (netlbl_conn_setattr(sk, (struct sockaddr *)&addr,
275   - &secattr) != 0) {
  323 + secattr) != 0) {
276 324 /* we failed to label the connected socket (could be
277 325 * for a variety of reasons, the actual "why" isn't
278 326 * important here) so we have to go to our backup plan,
... ... @@ -300,10 +348,6 @@
300 348 * return an error code */
301 349 break;
302 350 }
303   -
304   -inet_conn_established_return:
305   - netlbl_secattr_destroy(&secattr);
306   - return;
307 351 }
308 352  
309 353 /**
310 354  
... ... @@ -468,13 +512,12 @@
468 512 {
469 513 int rc;
470 514 struct sk_security_struct *sksec = sk->sk_security;
471   - struct netlbl_lsm_secattr secattr;
  515 + struct netlbl_lsm_secattr *secattr;
472 516  
473 517 if (sksec->nlbl_state != NLBL_REQSKB &&
474 518 sksec->nlbl_state != NLBL_CONNLABELED)
475 519 return 0;
476 520  
477   - netlbl_secattr_init(&secattr);
478 521 local_bh_disable();
479 522 bh_lock_sock_nested(sk);
480 523  
481 524  
482 525  
... ... @@ -487,18 +530,18 @@
487 530 rc = 0;
488 531 goto socket_connect_return;
489 532 }
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;
492 536 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;
497 541  
498 542 socket_connect_return:
499 543 bh_unlock_sock(sk);
500 544 local_bh_enable();
501   - netlbl_secattr_destroy(&secattr);
502 545 return rc;
503 546 }