1 /* 2 * SELinux NetLabel Support 3 * 4 * This file provides the necessary glue to tie NetLabel into the SELinux 5 * subsystem. 6 * 7 * Author: Paul Moore <paul.moore@hp.com> 8 * 9 */ 10 11 /* 12 * (c) Copyright Hewlett-Packard Development Company, L.P., 2007 13 * 14 * This program is free software; you can redistribute it and/or modify 15 * it under the terms of the GNU General Public License as published by 16 * the Free Software Foundation; either version 2 of the License, or 17 * (at your option) any later version. 18 * 19 * This program is distributed in the hope that it will be useful, 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 22 * the GNU General Public License for more details. 23 * 24 * You should have received a copy of the GNU General Public License 25 * along with this program; if not, write to the Free Software 26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 27 * 28 */ 29 30 #include <linux/spinlock.h> 31 #include <linux/rcupdate.h> 32 #include <net/sock.h> 33 #include <net/netlabel.h> 34 35 #include "objsec.h" 36 #include "security.h" 37 #include "netlabel.h" 38 39 /** 40 * selinux_netlbl_sidlookup_cached - Cache a SID lookup 41 * @skb: the packet 42 * @secattr: the NetLabel security attributes 43 * @sid: the SID 44 * 45 * Description: 46 * Query the SELinux security server to lookup the correct SID for the given 47 * security attributes. If the query is successful, cache the result to speed 48 * up future lookups. Returns zero on success, negative values on failure. 49 * 50 */ 51 static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb, 52 struct netlbl_lsm_secattr *secattr, 53 u32 *sid) 54 { 55 int rc; 56 57 rc = security_netlbl_secattr_to_sid(secattr, sid); 58 if (rc == 0 && 59 (secattr->flags & NETLBL_SECATTR_CACHEABLE) && 60 (secattr->flags & NETLBL_SECATTR_CACHE)) 61 netlbl_cache_add(skb, secattr); 62 63 return rc; 64 } 65 66 /** 67 * selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism 68 * @sk: the socket to label 69 * @sid: the SID to use 70 * 71 * Description: 72 * Attempt to label a socket using the NetLabel mechanism using the given 73 * SID. Returns zero values on success, negative values on failure. 74 * 75 */ 76 static int selinux_netlbl_sock_setsid(struct sock *sk, u32 sid) 77 { 78 int rc; 79 struct sk_security_struct *sksec = sk->sk_security; 80 struct netlbl_lsm_secattr secattr; 81 82 netlbl_secattr_init(&secattr); 83 84 rc = security_netlbl_sid_to_secattr(sid, &secattr); 85 if (rc != 0) 86 goto sock_setsid_return; 87 rc = netlbl_sock_setattr(sk, &secattr); 88 if (rc == 0) 89 sksec->nlbl_state = NLBL_LABELED; 90 91 sock_setsid_return: 92 netlbl_secattr_destroy(&secattr); 93 return rc; 94 } 95 96 /** 97 * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache 98 * 99 * Description: 100 * Invalidate the NetLabel security attribute mapping cache. 101 * 102 */ 103 void selinux_netlbl_cache_invalidate(void) 104 { 105 netlbl_cache_invalidate(); 106 } 107 108 /** 109 * selinux_netlbl_sk_security_reset - Reset the NetLabel fields 110 * @ssec: the sk_security_struct 111 * @family: the socket family 112 * 113 * Description: 114 * Called when the NetLabel state of a sk_security_struct needs to be reset. 115 * The caller is responsibile for all the NetLabel sk_security_struct locking. 116 * 117 */ 118 void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec, 119 int family) 120 { 121 if (family == PF_INET) 122 ssec->nlbl_state = NLBL_REQUIRE; 123 else 124 ssec->nlbl_state = NLBL_UNSET; 125 } 126 127 /** 128 * selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel 129 * @skb: the packet 130 * @family: protocol family 131 * @type: NetLabel labeling protocol type 132 * @sid: the SID 133 * 134 * Description: 135 * Call the NetLabel mechanism to get the security attributes of the given 136 * packet and use those attributes to determine the correct context/SID to 137 * assign to the packet. Returns zero on success, negative values on failure. 138 * 139 */ 140 int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, 141 u16 family, 142 u32 *type, 143 u32 *sid) 144 { 145 int rc; 146 struct netlbl_lsm_secattr secattr; 147 148 if (!netlbl_enabled()) { 149 *sid = SECSID_NULL; 150 return 0; 151 } 152 153 netlbl_secattr_init(&secattr); 154 rc = netlbl_skbuff_getattr(skb, family, &secattr); 155 if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE) 156 rc = selinux_netlbl_sidlookup_cached(skb, &secattr, sid); 157 else 158 *sid = SECSID_NULL; 159 *type = secattr.type; 160 netlbl_secattr_destroy(&secattr); 161 162 return rc; 163 } 164 165 /** 166 * selinux_netlbl_sock_graft - Netlabel the new socket 167 * @sk: the new connection 168 * @sock: the new socket 169 * 170 * Description: 171 * The connection represented by @sk is being grafted onto @sock so set the 172 * socket's NetLabel to match the SID of @sk. 173 * 174 */ 175 void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock) 176 { 177 struct sk_security_struct *sksec = sk->sk_security; 178 struct netlbl_lsm_secattr secattr; 179 u32 nlbl_peer_sid; 180 181 if (sksec->nlbl_state != NLBL_REQUIRE) 182 return; 183 184 netlbl_secattr_init(&secattr); 185 if (netlbl_sock_getattr(sk, &secattr) == 0 && 186 secattr.flags != NETLBL_SECATTR_NONE && 187 security_netlbl_secattr_to_sid(&secattr, &nlbl_peer_sid) == 0) 188 sksec->peer_sid = nlbl_peer_sid; 189 netlbl_secattr_destroy(&secattr); 190 191 /* Try to set the NetLabel on the socket to save time later, if we fail 192 * here we will pick up the pieces in later calls to 193 * selinux_netlbl_inode_permission(). */ 194 selinux_netlbl_sock_setsid(sk, sksec->sid); 195 } 196 197 /** 198 * selinux_netlbl_socket_post_create - Label a socket using NetLabel 199 * @sock: the socket to label 200 * 201 * Description: 202 * Attempt to label a socket using the NetLabel mechanism using the given 203 * SID. Returns zero values on success, negative values on failure. 204 * 205 */ 206 int selinux_netlbl_socket_post_create(struct socket *sock) 207 { 208 struct sock *sk = sock->sk; 209 struct sk_security_struct *sksec = sk->sk_security; 210 211 if (sksec->nlbl_state != NLBL_REQUIRE) 212 return 0; 213 214 return selinux_netlbl_sock_setsid(sk, sksec->sid); 215 } 216 217 /** 218 * selinux_netlbl_inode_permission - Verify the socket is NetLabel labeled 219 * @inode: the file descriptor's inode 220 * @mask: the permission mask 221 * 222 * Description: 223 * Looks at a file's inode and if it is marked as a socket protected by 224 * NetLabel then verify that the socket has been labeled, if not try to label 225 * the socket now with the inode's SID. Returns zero on success, negative 226 * values on failure. 227 * 228 */ 229 int selinux_netlbl_inode_permission(struct inode *inode, int mask) 230 { 231 int rc; 232 struct sock *sk; 233 struct socket *sock; 234 struct sk_security_struct *sksec; 235 236 if (!S_ISSOCK(inode->i_mode) || 237 ((mask & (MAY_WRITE | MAY_APPEND)) == 0)) 238 return 0; 239 240 sock = SOCKET_I(inode); 241 sk = sock->sk; 242 sksec = sk->sk_security; 243 if (sksec->nlbl_state != NLBL_REQUIRE) 244 return 0; 245 246 local_bh_disable(); 247 bh_lock_sock_nested(sk); 248 if (likely(sksec->nlbl_state == NLBL_REQUIRE)) 249 rc = selinux_netlbl_sock_setsid(sk, sksec->sid); 250 else 251 rc = 0; 252 bh_unlock_sock(sk); 253 local_bh_enable(); 254 255 return rc; 256 } 257 258 /** 259 * selinux_netlbl_sock_rcv_skb - Do an inbound access check using NetLabel 260 * @sksec: the sock's sk_security_struct 261 * @skb: the packet 262 * @family: protocol family 263 * @ad: the audit data 264 * 265 * Description: 266 * Fetch the NetLabel security attributes from @skb and perform an access check 267 * against the receiving socket. Returns zero on success, negative values on 268 * error. 269 * 270 */ 271 int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, 272 struct sk_buff *skb, 273 u16 family, 274 struct avc_audit_data *ad) 275 { 276 int rc; 277 u32 nlbl_sid; 278 u32 perm; 279 struct netlbl_lsm_secattr secattr; 280 281 if (!netlbl_enabled()) 282 return 0; 283 284 netlbl_secattr_init(&secattr); 285 rc = netlbl_skbuff_getattr(skb, family, &secattr); 286 if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE) 287 rc = selinux_netlbl_sidlookup_cached(skb, &secattr, &nlbl_sid); 288 else 289 nlbl_sid = SECINITSID_UNLABELED; 290 netlbl_secattr_destroy(&secattr); 291 if (rc != 0) 292 return rc; 293 294 switch (sksec->sclass) { 295 case SECCLASS_UDP_SOCKET: 296 perm = UDP_SOCKET__RECVFROM; 297 break; 298 case SECCLASS_TCP_SOCKET: 299 perm = TCP_SOCKET__RECVFROM; 300 break; 301 default: 302 perm = RAWIP_SOCKET__RECVFROM; 303 } 304 305 rc = avc_has_perm(sksec->sid, nlbl_sid, sksec->sclass, perm, ad); 306 if (rc == 0) 307 return 0; 308 309 if (nlbl_sid != SECINITSID_UNLABELED) 310 netlbl_skbuff_err(skb, rc); 311 return rc; 312 } 313 314 /** 315 * selinux_netlbl_socket_setsockopt - Do not allow users to remove a NetLabel 316 * @sock: the socket 317 * @level: the socket level or protocol 318 * @optname: the socket option name 319 * 320 * Description: 321 * Check the setsockopt() call and if the user is trying to replace the IP 322 * options on a socket and a NetLabel is in place for the socket deny the 323 * access; otherwise allow the access. Returns zero when the access is 324 * allowed, -EACCES when denied, and other negative values on error. 325 * 326 */ 327 int selinux_netlbl_socket_setsockopt(struct socket *sock, 328 int level, 329 int optname) 330 { 331 int rc = 0; 332 struct sock *sk = sock->sk; 333 struct sk_security_struct *sksec = sk->sk_security; 334 struct netlbl_lsm_secattr secattr; 335 336 if (level == IPPROTO_IP && optname == IP_OPTIONS && 337 sksec->nlbl_state == NLBL_LABELED) { 338 netlbl_secattr_init(&secattr); 339 lock_sock(sk); 340 rc = netlbl_sock_getattr(sk, &secattr); 341 release_sock(sk); 342 if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE) 343 rc = -EACCES; 344 netlbl_secattr_destroy(&secattr); 345 } 346 347 return rc; 348 } 349