diff options
31 files changed, 2028 insertions, 129 deletions
diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile index 6ebd9ad95010..e3cdafff8ece 100644 --- a/drivers/infiniband/core/Makefile +++ b/drivers/infiniband/core/Makefile | |||
@@ -10,7 +10,8 @@ obj-$(CONFIG_INFINIBAND_USER_ACCESS) += ib_uverbs.o ib_ucm.o \ | |||
10 | ib_core-y := packer.o ud_header.o verbs.o cq.o rw.o sysfs.o \ | 10 | ib_core-y := packer.o ud_header.o verbs.o cq.o rw.o sysfs.o \ |
11 | device.o fmr_pool.o cache.o netlink.o \ | 11 | device.o fmr_pool.o cache.o netlink.o \ |
12 | roce_gid_mgmt.o mr_pool.o addr.o sa_query.o \ | 12 | roce_gid_mgmt.o mr_pool.o addr.o sa_query.o \ |
13 | multicast.o mad.o smi.o agent.o mad_rmpp.o | 13 | multicast.o mad.o smi.o agent.o mad_rmpp.o \ |
14 | security.o | ||
14 | ib_core-$(CONFIG_INFINIBAND_USER_MEM) += umem.o | 15 | ib_core-$(CONFIG_INFINIBAND_USER_MEM) += umem.o |
15 | ib_core-$(CONFIG_INFINIBAND_ON_DEMAND_PAGING) += umem_odp.o umem_rbtree.o | 16 | ib_core-$(CONFIG_INFINIBAND_ON_DEMAND_PAGING) += umem_odp.o umem_rbtree.o |
16 | ib_core-$(CONFIG_CGROUP_RDMA) += cgroup.o | 17 | ib_core-$(CONFIG_CGROUP_RDMA) += cgroup.o |
diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c index b1371eb9f46c..efc94304dee3 100644 --- a/drivers/infiniband/core/cache.c +++ b/drivers/infiniband/core/cache.c | |||
@@ -53,6 +53,7 @@ struct ib_update_work { | |||
53 | struct work_struct work; | 53 | struct work_struct work; |
54 | struct ib_device *device; | 54 | struct ib_device *device; |
55 | u8 port_num; | 55 | u8 port_num; |
56 | bool enforce_security; | ||
56 | }; | 57 | }; |
57 | 58 | ||
58 | union ib_gid zgid; | 59 | union ib_gid zgid; |
@@ -911,6 +912,26 @@ int ib_get_cached_pkey(struct ib_device *device, | |||
911 | } | 912 | } |
912 | EXPORT_SYMBOL(ib_get_cached_pkey); | 913 | EXPORT_SYMBOL(ib_get_cached_pkey); |
913 | 914 | ||
915 | int ib_get_cached_subnet_prefix(struct ib_device *device, | ||
916 | u8 port_num, | ||
917 | u64 *sn_pfx) | ||
918 | { | ||
919 | unsigned long flags; | ||
920 | int p; | ||
921 | |||
922 | if (port_num < rdma_start_port(device) || | ||
923 | port_num > rdma_end_port(device)) | ||
924 | return -EINVAL; | ||
925 | |||
926 | p = port_num - rdma_start_port(device); | ||
927 | read_lock_irqsave(&device->cache.lock, flags); | ||
928 | *sn_pfx = device->cache.ports[p].subnet_prefix; | ||
929 | read_unlock_irqrestore(&device->cache.lock, flags); | ||
930 | |||
931 | return 0; | ||
932 | } | ||
933 | EXPORT_SYMBOL(ib_get_cached_subnet_prefix); | ||
934 | |||
914 | int ib_find_cached_pkey(struct ib_device *device, | 935 | int ib_find_cached_pkey(struct ib_device *device, |
915 | u8 port_num, | 936 | u8 port_num, |
916 | u16 pkey, | 937 | u16 pkey, |
@@ -1022,7 +1043,8 @@ int ib_get_cached_port_state(struct ib_device *device, | |||
1022 | EXPORT_SYMBOL(ib_get_cached_port_state); | 1043 | EXPORT_SYMBOL(ib_get_cached_port_state); |
1023 | 1044 | ||
1024 | static void ib_cache_update(struct ib_device *device, | 1045 | static void ib_cache_update(struct ib_device *device, |
1025 | u8 port) | 1046 | u8 port, |
1047 | bool enforce_security) | ||
1026 | { | 1048 | { |
1027 | struct ib_port_attr *tprops = NULL; | 1049 | struct ib_port_attr *tprops = NULL; |
1028 | struct ib_pkey_cache *pkey_cache = NULL, *old_pkey_cache; | 1050 | struct ib_pkey_cache *pkey_cache = NULL, *old_pkey_cache; |
@@ -1108,8 +1130,15 @@ static void ib_cache_update(struct ib_device *device, | |||
1108 | device->cache.ports[port - rdma_start_port(device)].port_state = | 1130 | device->cache.ports[port - rdma_start_port(device)].port_state = |
1109 | tprops->state; | 1131 | tprops->state; |
1110 | 1132 | ||
1133 | device->cache.ports[port - rdma_start_port(device)].subnet_prefix = | ||
1134 | tprops->subnet_prefix; | ||
1111 | write_unlock_irq(&device->cache.lock); | 1135 | write_unlock_irq(&device->cache.lock); |
1112 | 1136 | ||
1137 | if (enforce_security) | ||
1138 | ib_security_cache_change(device, | ||
1139 | port, | ||
1140 | tprops->subnet_prefix); | ||
1141 | |||
1113 | kfree(gid_cache); | 1142 | kfree(gid_cache); |
1114 | kfree(old_pkey_cache); | 1143 | kfree(old_pkey_cache); |
1115 | kfree(tprops); | 1144 | kfree(tprops); |
@@ -1126,7 +1155,9 @@ static void ib_cache_task(struct work_struct *_work) | |||
1126 | struct ib_update_work *work = | 1155 | struct ib_update_work *work = |
1127 | container_of(_work, struct ib_update_work, work); | 1156 | container_of(_work, struct ib_update_work, work); |
1128 | 1157 | ||
1129 | ib_cache_update(work->device, work->port_num); | 1158 | ib_cache_update(work->device, |
1159 | work->port_num, | ||
1160 | work->enforce_security); | ||
1130 | kfree(work); | 1161 | kfree(work); |
1131 | } | 1162 | } |
1132 | 1163 | ||
@@ -1147,6 +1178,12 @@ static void ib_cache_event(struct ib_event_handler *handler, | |||
1147 | INIT_WORK(&work->work, ib_cache_task); | 1178 | INIT_WORK(&work->work, ib_cache_task); |
1148 | work->device = event->device; | 1179 | work->device = event->device; |
1149 | work->port_num = event->element.port_num; | 1180 | work->port_num = event->element.port_num; |
1181 | if (event->event == IB_EVENT_PKEY_CHANGE || | ||
1182 | event->event == IB_EVENT_GID_CHANGE) | ||
1183 | work->enforce_security = true; | ||
1184 | else | ||
1185 | work->enforce_security = false; | ||
1186 | |||
1150 | queue_work(ib_wq, &work->work); | 1187 | queue_work(ib_wq, &work->work); |
1151 | } | 1188 | } |
1152 | } | 1189 | } |
@@ -1172,7 +1209,7 @@ int ib_cache_setup_one(struct ib_device *device) | |||
1172 | goto out; | 1209 | goto out; |
1173 | 1210 | ||
1174 | for (p = 0; p <= rdma_end_port(device) - rdma_start_port(device); ++p) | 1211 | for (p = 0; p <= rdma_end_port(device) - rdma_start_port(device); ++p) |
1175 | ib_cache_update(device, p + rdma_start_port(device)); | 1212 | ib_cache_update(device, p + rdma_start_port(device), true); |
1176 | 1213 | ||
1177 | INIT_IB_EVENT_HANDLER(&device->cache.event_handler, | 1214 | INIT_IB_EVENT_HANDLER(&device->cache.event_handler, |
1178 | device, ib_cache_event); | 1215 | device, ib_cache_event); |
diff --git a/drivers/infiniband/core/core_priv.h b/drivers/infiniband/core/core_priv.h index cb7d372e4bdf..06645272c784 100644 --- a/drivers/infiniband/core/core_priv.h +++ b/drivers/infiniband/core/core_priv.h | |||
@@ -38,6 +38,16 @@ | |||
38 | #include <linux/cgroup_rdma.h> | 38 | #include <linux/cgroup_rdma.h> |
39 | 39 | ||
40 | #include <rdma/ib_verbs.h> | 40 | #include <rdma/ib_verbs.h> |
41 | #include <rdma/ib_mad.h> | ||
42 | #include "mad_priv.h" | ||
43 | |||
44 | struct pkey_index_qp_list { | ||
45 | struct list_head pkey_index_list; | ||
46 | u16 pkey_index; | ||
47 | /* Lock to hold while iterating the qp_list. */ | ||
48 | spinlock_t qp_list_lock; | ||
49 | struct list_head qp_list; | ||
50 | }; | ||
41 | 51 | ||
42 | #if IS_ENABLED(CONFIG_INFINIBAND_ADDR_TRANS_CONFIGFS) | 52 | #if IS_ENABLED(CONFIG_INFINIBAND_ADDR_TRANS_CONFIGFS) |
43 | int cma_configfs_init(void); | 53 | int cma_configfs_init(void); |
@@ -176,4 +186,109 @@ int ib_nl_handle_set_timeout(struct sk_buff *skb, | |||
176 | int ib_nl_handle_ip_res_resp(struct sk_buff *skb, | 186 | int ib_nl_handle_ip_res_resp(struct sk_buff *skb, |
177 | struct netlink_callback *cb); | 187 | struct netlink_callback *cb); |
178 | 188 | ||
189 | int ib_get_cached_subnet_prefix(struct ib_device *device, | ||
190 | u8 port_num, | ||
191 | u64 *sn_pfx); | ||
192 | |||
193 | #ifdef CONFIG_SECURITY_INFINIBAND | ||
194 | int ib_security_pkey_access(struct ib_device *dev, | ||
195 | u8 port_num, | ||
196 | u16 pkey_index, | ||
197 | void *sec); | ||
198 | |||
199 | void ib_security_destroy_port_pkey_list(struct ib_device *device); | ||
200 | |||
201 | void ib_security_cache_change(struct ib_device *device, | ||
202 | u8 port_num, | ||
203 | u64 subnet_prefix); | ||
204 | |||
205 | int ib_security_modify_qp(struct ib_qp *qp, | ||
206 | struct ib_qp_attr *qp_attr, | ||
207 | int qp_attr_mask, | ||
208 | struct ib_udata *udata); | ||
209 | |||
210 | int ib_create_qp_security(struct ib_qp *qp, struct ib_device *dev); | ||
211 | void ib_destroy_qp_security_begin(struct ib_qp_security *sec); | ||
212 | void ib_destroy_qp_security_abort(struct ib_qp_security *sec); | ||
213 | void ib_destroy_qp_security_end(struct ib_qp_security *sec); | ||
214 | int ib_open_shared_qp_security(struct ib_qp *qp, struct ib_device *dev); | ||
215 | void ib_close_shared_qp_security(struct ib_qp_security *sec); | ||
216 | int ib_mad_agent_security_setup(struct ib_mad_agent *agent, | ||
217 | enum ib_qp_type qp_type); | ||
218 | void ib_mad_agent_security_cleanup(struct ib_mad_agent *agent); | ||
219 | int ib_mad_enforce_security(struct ib_mad_agent_private *map, u16 pkey_index); | ||
220 | #else | ||
221 | static inline int ib_security_pkey_access(struct ib_device *dev, | ||
222 | u8 port_num, | ||
223 | u16 pkey_index, | ||
224 | void *sec) | ||
225 | { | ||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | static inline void ib_security_destroy_port_pkey_list(struct ib_device *device) | ||
230 | { | ||
231 | } | ||
232 | |||
233 | static inline void ib_security_cache_change(struct ib_device *device, | ||
234 | u8 port_num, | ||
235 | u64 subnet_prefix) | ||
236 | { | ||
237 | } | ||
238 | |||
239 | static inline int ib_security_modify_qp(struct ib_qp *qp, | ||
240 | struct ib_qp_attr *qp_attr, | ||
241 | int qp_attr_mask, | ||
242 | struct ib_udata *udata) | ||
243 | { | ||
244 | return qp->device->modify_qp(qp->real_qp, | ||
245 | qp_attr, | ||
246 | qp_attr_mask, | ||
247 | udata); | ||
248 | } | ||
249 | |||
250 | static inline int ib_create_qp_security(struct ib_qp *qp, | ||
251 | struct ib_device *dev) | ||
252 | { | ||
253 | return 0; | ||
254 | } | ||
255 | |||
256 | static inline void ib_destroy_qp_security_begin(struct ib_qp_security *sec) | ||
257 | { | ||
258 | } | ||
259 | |||
260 | static inline void ib_destroy_qp_security_abort(struct ib_qp_security *sec) | ||
261 | { | ||
262 | } | ||
263 | |||
264 | static inline void ib_destroy_qp_security_end(struct ib_qp_security *sec) | ||
265 | { | ||
266 | } | ||
267 | |||
268 | static inline int ib_open_shared_qp_security(struct ib_qp *qp, | ||
269 | struct ib_device *dev) | ||
270 | { | ||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | static inline void ib_close_shared_qp_security(struct ib_qp_security *sec) | ||
275 | { | ||
276 | } | ||
277 | |||
278 | static inline int ib_mad_agent_security_setup(struct ib_mad_agent *agent, | ||
279 | enum ib_qp_type qp_type) | ||
280 | { | ||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | static inline void ib_mad_agent_security_cleanup(struct ib_mad_agent *agent) | ||
285 | { | ||
286 | } | ||
287 | |||
288 | static inline int ib_mad_enforce_security(struct ib_mad_agent_private *map, | ||
289 | u16 pkey_index) | ||
290 | { | ||
291 | return 0; | ||
292 | } | ||
293 | #endif | ||
179 | #endif /* _CORE_PRIV_H */ | 294 | #endif /* _CORE_PRIV_H */ |
diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index 81d447da0048..631eaa9daf65 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c | |||
@@ -39,6 +39,8 @@ | |||
39 | #include <linux/init.h> | 39 | #include <linux/init.h> |
40 | #include <linux/mutex.h> | 40 | #include <linux/mutex.h> |
41 | #include <linux/netdevice.h> | 41 | #include <linux/netdevice.h> |
42 | #include <linux/security.h> | ||
43 | #include <linux/notifier.h> | ||
42 | #include <rdma/rdma_netlink.h> | 44 | #include <rdma/rdma_netlink.h> |
43 | #include <rdma/ib_addr.h> | 45 | #include <rdma/ib_addr.h> |
44 | #include <rdma/ib_cache.h> | 46 | #include <rdma/ib_cache.h> |
@@ -82,6 +84,14 @@ static LIST_HEAD(client_list); | |||
82 | static DEFINE_MUTEX(device_mutex); | 84 | static DEFINE_MUTEX(device_mutex); |
83 | static DECLARE_RWSEM(lists_rwsem); | 85 | static DECLARE_RWSEM(lists_rwsem); |
84 | 86 | ||
87 | static int ib_security_change(struct notifier_block *nb, unsigned long event, | ||
88 | void *lsm_data); | ||
89 | static void ib_policy_change_task(struct work_struct *work); | ||
90 | static DECLARE_WORK(ib_policy_change_work, ib_policy_change_task); | ||
91 | |||
92 | static struct notifier_block ibdev_lsm_nb = { | ||
93 | .notifier_call = ib_security_change, | ||
94 | }; | ||
85 | 95 | ||
86 | static int ib_device_check_mandatory(struct ib_device *device) | 96 | static int ib_device_check_mandatory(struct ib_device *device) |
87 | { | 97 | { |
@@ -325,6 +335,64 @@ void ib_get_device_fw_str(struct ib_device *dev, char *str, size_t str_len) | |||
325 | } | 335 | } |
326 | EXPORT_SYMBOL(ib_get_device_fw_str); | 336 | EXPORT_SYMBOL(ib_get_device_fw_str); |
327 | 337 | ||
338 | static int setup_port_pkey_list(struct ib_device *device) | ||
339 | { | ||
340 | int i; | ||
341 | |||
342 | /** | ||
343 | * device->port_pkey_list is indexed directly by the port number, | ||
344 | * Therefore it is declared as a 1 based array with potential empty | ||
345 | * slots at the beginning. | ||
346 | */ | ||
347 | device->port_pkey_list = kcalloc(rdma_end_port(device) + 1, | ||
348 | sizeof(*device->port_pkey_list), | ||
349 | GFP_KERNEL); | ||
350 | |||
351 | if (!device->port_pkey_list) | ||
352 | return -ENOMEM; | ||
353 | |||
354 | for (i = 0; i < (rdma_end_port(device) + 1); i++) { | ||
355 | spin_lock_init(&device->port_pkey_list[i].list_lock); | ||
356 | INIT_LIST_HEAD(&device->port_pkey_list[i].pkey_list); | ||
357 | } | ||
358 | |||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | static void ib_policy_change_task(struct work_struct *work) | ||
363 | { | ||
364 | struct ib_device *dev; | ||
365 | |||
366 | down_read(&lists_rwsem); | ||
367 | list_for_each_entry(dev, &device_list, core_list) { | ||
368 | int i; | ||
369 | |||
370 | for (i = rdma_start_port(dev); i <= rdma_end_port(dev); i++) { | ||
371 | u64 sp; | ||
372 | int ret = ib_get_cached_subnet_prefix(dev, | ||
373 | i, | ||
374 | &sp); | ||
375 | |||
376 | WARN_ONCE(ret, | ||
377 | "ib_get_cached_subnet_prefix err: %d, this should never happen here\n", | ||
378 | ret); | ||
379 | ib_security_cache_change(dev, i, sp); | ||
380 | } | ||
381 | } | ||
382 | up_read(&lists_rwsem); | ||
383 | } | ||
384 | |||
385 | static int ib_security_change(struct notifier_block *nb, unsigned long event, | ||
386 | void *lsm_data) | ||
387 | { | ||
388 | if (event != LSM_POLICY_CHANGE) | ||
389 | return NOTIFY_DONE; | ||
390 | |||
391 | schedule_work(&ib_policy_change_work); | ||
392 | |||
393 | return NOTIFY_OK; | ||
394 | } | ||
395 | |||
328 | /** | 396 | /** |
329 | * ib_register_device - Register an IB device with IB core | 397 | * ib_register_device - Register an IB device with IB core |
330 | * @device:Device to register | 398 | * @device:Device to register |
@@ -385,6 +453,12 @@ int ib_register_device(struct ib_device *device, | |||
385 | goto out; | 453 | goto out; |
386 | } | 454 | } |
387 | 455 | ||
456 | ret = setup_port_pkey_list(device); | ||
457 | if (ret) { | ||
458 | pr_warn("Couldn't create per port_pkey_list\n"); | ||
459 | goto out; | ||
460 | } | ||
461 | |||
388 | ret = ib_cache_setup_one(device); | 462 | ret = ib_cache_setup_one(device); |
389 | if (ret) { | 463 | if (ret) { |
390 | pr_warn("Couldn't set up InfiniBand P_Key/GID cache\n"); | 464 | pr_warn("Couldn't set up InfiniBand P_Key/GID cache\n"); |
@@ -468,6 +542,9 @@ void ib_unregister_device(struct ib_device *device) | |||
468 | ib_device_unregister_sysfs(device); | 542 | ib_device_unregister_sysfs(device); |
469 | ib_cache_cleanup_one(device); | 543 | ib_cache_cleanup_one(device); |
470 | 544 | ||
545 | ib_security_destroy_port_pkey_list(device); | ||
546 | kfree(device->port_pkey_list); | ||
547 | |||
471 | down_write(&lists_rwsem); | 548 | down_write(&lists_rwsem); |
472 | spin_lock_irqsave(&device->client_data_lock, flags); | 549 | spin_lock_irqsave(&device->client_data_lock, flags); |
473 | list_for_each_entry_safe(context, tmp, &device->client_data_list, list) | 550 | list_for_each_entry_safe(context, tmp, &device->client_data_list, list) |
@@ -1082,10 +1159,18 @@ static int __init ib_core_init(void) | |||
1082 | goto err_sa; | 1159 | goto err_sa; |
1083 | } | 1160 | } |
1084 | 1161 | ||
1162 | ret = register_lsm_notifier(&ibdev_lsm_nb); | ||
1163 | if (ret) { | ||
1164 | pr_warn("Couldn't register LSM notifier. ret %d\n", ret); | ||
1165 | goto err_ibnl_clients; | ||
1166 | } | ||
1167 | |||
1085 | ib_cache_setup(); | 1168 | ib_cache_setup(); |
1086 | 1169 | ||
1087 | return 0; | 1170 | return 0; |
1088 | 1171 | ||
1172 | err_ibnl_clients: | ||
1173 | ib_remove_ibnl_clients(); | ||
1089 | err_sa: | 1174 | err_sa: |
1090 | ib_sa_cleanup(); | 1175 | ib_sa_cleanup(); |
1091 | err_mad: | 1176 | err_mad: |
@@ -1105,6 +1190,7 @@ err: | |||
1105 | 1190 | ||
1106 | static void __exit ib_core_cleanup(void) | 1191 | static void __exit ib_core_cleanup(void) |
1107 | { | 1192 | { |
1193 | unregister_lsm_notifier(&ibdev_lsm_nb); | ||
1108 | ib_cache_cleanup(); | 1194 | ib_cache_cleanup(); |
1109 | ib_remove_ibnl_clients(); | 1195 | ib_remove_ibnl_clients(); |
1110 | ib_sa_cleanup(); | 1196 | ib_sa_cleanup(); |
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index 192ee3dafb80..f8f53bb90837 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c | |||
@@ -40,9 +40,11 @@ | |||
40 | #include <linux/dma-mapping.h> | 40 | #include <linux/dma-mapping.h> |
41 | #include <linux/slab.h> | 41 | #include <linux/slab.h> |
42 | #include <linux/module.h> | 42 | #include <linux/module.h> |
43 | #include <linux/security.h> | ||
43 | #include <rdma/ib_cache.h> | 44 | #include <rdma/ib_cache.h> |
44 | 45 | ||
45 | #include "mad_priv.h" | 46 | #include "mad_priv.h" |
47 | #include "core_priv.h" | ||
46 | #include "mad_rmpp.h" | 48 | #include "mad_rmpp.h" |
47 | #include "smi.h" | 49 | #include "smi.h" |
48 | #include "opa_smi.h" | 50 | #include "opa_smi.h" |
@@ -369,6 +371,12 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device, | |||
369 | atomic_set(&mad_agent_priv->refcount, 1); | 371 | atomic_set(&mad_agent_priv->refcount, 1); |
370 | init_completion(&mad_agent_priv->comp); | 372 | init_completion(&mad_agent_priv->comp); |
371 | 373 | ||
374 | ret2 = ib_mad_agent_security_setup(&mad_agent_priv->agent, qp_type); | ||
375 | if (ret2) { | ||
376 | ret = ERR_PTR(ret2); | ||
377 | goto error4; | ||
378 | } | ||
379 | |||
372 | spin_lock_irqsave(&port_priv->reg_lock, flags); | 380 | spin_lock_irqsave(&port_priv->reg_lock, flags); |
373 | mad_agent_priv->agent.hi_tid = ++ib_mad_client_id; | 381 | mad_agent_priv->agent.hi_tid = ++ib_mad_client_id; |
374 | 382 | ||
@@ -386,7 +394,7 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device, | |||
386 | if (method) { | 394 | if (method) { |
387 | if (method_in_use(&method, | 395 | if (method_in_use(&method, |
388 | mad_reg_req)) | 396 | mad_reg_req)) |
389 | goto error4; | 397 | goto error5; |
390 | } | 398 | } |
391 | } | 399 | } |
392 | ret2 = add_nonoui_reg_req(mad_reg_req, mad_agent_priv, | 400 | ret2 = add_nonoui_reg_req(mad_reg_req, mad_agent_priv, |
@@ -402,14 +410,14 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device, | |||
402 | if (is_vendor_method_in_use( | 410 | if (is_vendor_method_in_use( |
403 | vendor_class, | 411 | vendor_class, |
404 | mad_reg_req)) | 412 | mad_reg_req)) |
405 | goto error4; | 413 | goto error5; |
406 | } | 414 | } |
407 | } | 415 | } |
408 | ret2 = add_oui_reg_req(mad_reg_req, mad_agent_priv); | 416 | ret2 = add_oui_reg_req(mad_reg_req, mad_agent_priv); |
409 | } | 417 | } |
410 | if (ret2) { | 418 | if (ret2) { |
411 | ret = ERR_PTR(ret2); | 419 | ret = ERR_PTR(ret2); |
412 | goto error4; | 420 | goto error5; |
413 | } | 421 | } |
414 | } | 422 | } |
415 | 423 | ||
@@ -418,9 +426,10 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device, | |||
418 | spin_unlock_irqrestore(&port_priv->reg_lock, flags); | 426 | spin_unlock_irqrestore(&port_priv->reg_lock, flags); |
419 | 427 | ||
420 | return &mad_agent_priv->agent; | 428 | return &mad_agent_priv->agent; |
421 | 429 | error5: | |
422 | error4: | ||
423 | spin_unlock_irqrestore(&port_priv->reg_lock, flags); | 430 | spin_unlock_irqrestore(&port_priv->reg_lock, flags); |
431 | ib_mad_agent_security_cleanup(&mad_agent_priv->agent); | ||
432 | error4: | ||
424 | kfree(reg_req); | 433 | kfree(reg_req); |
425 | error3: | 434 | error3: |
426 | kfree(mad_agent_priv); | 435 | kfree(mad_agent_priv); |
@@ -491,6 +500,7 @@ struct ib_mad_agent *ib_register_mad_snoop(struct ib_device *device, | |||
491 | struct ib_mad_agent *ret; | 500 | struct ib_mad_agent *ret; |
492 | struct ib_mad_snoop_private *mad_snoop_priv; | 501 | struct ib_mad_snoop_private *mad_snoop_priv; |
493 | int qpn; | 502 | int qpn; |
503 | int err; | ||
494 | 504 | ||
495 | /* Validate parameters */ | 505 | /* Validate parameters */ |
496 | if ((is_snooping_sends(mad_snoop_flags) && !snoop_handler) || | 506 | if ((is_snooping_sends(mad_snoop_flags) && !snoop_handler) || |
@@ -525,17 +535,25 @@ struct ib_mad_agent *ib_register_mad_snoop(struct ib_device *device, | |||
525 | mad_snoop_priv->agent.port_num = port_num; | 535 | mad_snoop_priv->agent.port_num = port_num; |
526 | mad_snoop_priv->mad_snoop_flags = mad_snoop_flags; | 536 | mad_snoop_priv->mad_snoop_flags = mad_snoop_flags; |
527 | init_completion(&mad_snoop_priv->comp); | 537 | init_completion(&mad_snoop_priv->comp); |
538 | |||
539 | err = ib_mad_agent_security_setup(&mad_snoop_priv->agent, qp_type); | ||
540 | if (err) { | ||
541 | ret = ERR_PTR(err); | ||
542 | goto error2; | ||
543 | } | ||
544 | |||
528 | mad_snoop_priv->snoop_index = register_snoop_agent( | 545 | mad_snoop_priv->snoop_index = register_snoop_agent( |
529 | &port_priv->qp_info[qpn], | 546 | &port_priv->qp_info[qpn], |
530 | mad_snoop_priv); | 547 | mad_snoop_priv); |
531 | if (mad_snoop_priv->snoop_index < 0) { | 548 | if (mad_snoop_priv->snoop_index < 0) { |
532 | ret = ERR_PTR(mad_snoop_priv->snoop_index); | 549 | ret = ERR_PTR(mad_snoop_priv->snoop_index); |
533 | goto error2; | 550 | goto error3; |
534 | } | 551 | } |
535 | 552 | ||
536 | atomic_set(&mad_snoop_priv->refcount, 1); | 553 | atomic_set(&mad_snoop_priv->refcount, 1); |
537 | return &mad_snoop_priv->agent; | 554 | return &mad_snoop_priv->agent; |
538 | 555 | error3: | |
556 | ib_mad_agent_security_cleanup(&mad_snoop_priv->agent); | ||
539 | error2: | 557 | error2: |
540 | kfree(mad_snoop_priv); | 558 | kfree(mad_snoop_priv); |
541 | error1: | 559 | error1: |
@@ -581,6 +599,8 @@ static void unregister_mad_agent(struct ib_mad_agent_private *mad_agent_priv) | |||
581 | deref_mad_agent(mad_agent_priv); | 599 | deref_mad_agent(mad_agent_priv); |
582 | wait_for_completion(&mad_agent_priv->comp); | 600 | wait_for_completion(&mad_agent_priv->comp); |
583 | 601 | ||
602 | ib_mad_agent_security_cleanup(&mad_agent_priv->agent); | ||
603 | |||
584 | kfree(mad_agent_priv->reg_req); | 604 | kfree(mad_agent_priv->reg_req); |
585 | kfree(mad_agent_priv); | 605 | kfree(mad_agent_priv); |
586 | } | 606 | } |
@@ -599,6 +619,8 @@ static void unregister_mad_snoop(struct ib_mad_snoop_private *mad_snoop_priv) | |||
599 | deref_snoop_agent(mad_snoop_priv); | 619 | deref_snoop_agent(mad_snoop_priv); |
600 | wait_for_completion(&mad_snoop_priv->comp); | 620 | wait_for_completion(&mad_snoop_priv->comp); |
601 | 621 | ||
622 | ib_mad_agent_security_cleanup(&mad_snoop_priv->agent); | ||
623 | |||
602 | kfree(mad_snoop_priv); | 624 | kfree(mad_snoop_priv); |
603 | } | 625 | } |
604 | 626 | ||
@@ -1215,12 +1237,16 @@ int ib_post_send_mad(struct ib_mad_send_buf *send_buf, | |||
1215 | 1237 | ||
1216 | /* Walk list of send WRs and post each on send list */ | 1238 | /* Walk list of send WRs and post each on send list */ |
1217 | for (; send_buf; send_buf = next_send_buf) { | 1239 | for (; send_buf; send_buf = next_send_buf) { |
1218 | |||
1219 | mad_send_wr = container_of(send_buf, | 1240 | mad_send_wr = container_of(send_buf, |
1220 | struct ib_mad_send_wr_private, | 1241 | struct ib_mad_send_wr_private, |
1221 | send_buf); | 1242 | send_buf); |
1222 | mad_agent_priv = mad_send_wr->mad_agent_priv; | 1243 | mad_agent_priv = mad_send_wr->mad_agent_priv; |
1223 | 1244 | ||
1245 | ret = ib_mad_enforce_security(mad_agent_priv, | ||
1246 | mad_send_wr->send_wr.pkey_index); | ||
1247 | if (ret) | ||
1248 | goto error; | ||
1249 | |||
1224 | if (!send_buf->mad_agent->send_handler || | 1250 | if (!send_buf->mad_agent->send_handler || |
1225 | (send_buf->timeout_ms && | 1251 | (send_buf->timeout_ms && |
1226 | !send_buf->mad_agent->recv_handler)) { | 1252 | !send_buf->mad_agent->recv_handler)) { |
@@ -1946,6 +1972,14 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, | |||
1946 | struct ib_mad_send_wr_private *mad_send_wr; | 1972 | struct ib_mad_send_wr_private *mad_send_wr; |
1947 | struct ib_mad_send_wc mad_send_wc; | 1973 | struct ib_mad_send_wc mad_send_wc; |
1948 | unsigned long flags; | 1974 | unsigned long flags; |
1975 | int ret; | ||
1976 | |||
1977 | ret = ib_mad_enforce_security(mad_agent_priv, | ||
1978 | mad_recv_wc->wc->pkey_index); | ||
1979 | if (ret) { | ||
1980 | ib_free_recv_mad(mad_recv_wc); | ||
1981 | deref_mad_agent(mad_agent_priv); | ||
1982 | } | ||
1949 | 1983 | ||
1950 | INIT_LIST_HEAD(&mad_recv_wc->rmpp_list); | 1984 | INIT_LIST_HEAD(&mad_recv_wc->rmpp_list); |
1951 | list_add(&mad_recv_wc->recv_buf.list, &mad_recv_wc->rmpp_list); | 1985 | list_add(&mad_recv_wc->recv_buf.list, &mad_recv_wc->rmpp_list); |
@@ -2003,6 +2037,8 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, | |||
2003 | mad_recv_wc); | 2037 | mad_recv_wc); |
2004 | deref_mad_agent(mad_agent_priv); | 2038 | deref_mad_agent(mad_agent_priv); |
2005 | } | 2039 | } |
2040 | |||
2041 | return; | ||
2006 | } | 2042 | } |
2007 | 2043 | ||
2008 | static enum smi_action handle_ib_smi(const struct ib_mad_port_private *port_priv, | 2044 | static enum smi_action handle_ib_smi(const struct ib_mad_port_private *port_priv, |
diff --git a/drivers/infiniband/core/security.c b/drivers/infiniband/core/security.c new file mode 100644 index 000000000000..3e8c38953912 --- /dev/null +++ b/drivers/infiniband/core/security.c | |||
@@ -0,0 +1,705 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved. | ||
3 | * | ||
4 | * This software is available to you under a choice of one of two | ||
5 | * licenses. You may choose to be licensed under the terms of the GNU | ||
6 | * General Public License (GPL) Version 2, available from the file | ||
7 | * COPYING in the main directory of this source tree, or the | ||
8 | * OpenIB.org BSD license below: | ||
9 | * | ||
10 | * Redistribution and use in source and binary forms, with or | ||
11 | * without modification, are permitted provided that the following | ||
12 | * conditions are met: | ||
13 | * | ||
14 | * - Redistributions of source code must retain the above | ||
15 | * copyright notice, this list of conditions and the following | ||
16 | * disclaimer. | ||
17 | * | ||
18 | * - Redistributions in binary form must reproduce the above | ||
19 | * copyright notice, this list of conditions and the following | ||
20 | * disclaimer in the documentation and/or other materials | ||
21 | * provided with the distribution. | ||
22 | * | ||
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
30 | * SOFTWARE. | ||
31 | */ | ||
32 | |||
33 | #ifdef CONFIG_SECURITY_INFINIBAND | ||
34 | |||
35 | #include <linux/security.h> | ||
36 | #include <linux/completion.h> | ||
37 | #include <linux/list.h> | ||
38 | |||
39 | #include <rdma/ib_verbs.h> | ||
40 | #include <rdma/ib_cache.h> | ||
41 | #include "core_priv.h" | ||
42 | #include "mad_priv.h" | ||
43 | |||
44 | static struct pkey_index_qp_list *get_pkey_idx_qp_list(struct ib_port_pkey *pp) | ||
45 | { | ||
46 | struct pkey_index_qp_list *pkey = NULL; | ||
47 | struct pkey_index_qp_list *tmp_pkey; | ||
48 | struct ib_device *dev = pp->sec->dev; | ||
49 | |||
50 | spin_lock(&dev->port_pkey_list[pp->port_num].list_lock); | ||
51 | list_for_each_entry(tmp_pkey, | ||
52 | &dev->port_pkey_list[pp->port_num].pkey_list, | ||
53 | pkey_index_list) { | ||
54 | if (tmp_pkey->pkey_index == pp->pkey_index) { | ||
55 | pkey = tmp_pkey; | ||
56 | break; | ||
57 | } | ||
58 | } | ||
59 | spin_unlock(&dev->port_pkey_list[pp->port_num].list_lock); | ||
60 | return pkey; | ||
61 | } | ||
62 | |||
63 | static int get_pkey_and_subnet_prefix(struct ib_port_pkey *pp, | ||
64 | u16 *pkey, | ||
65 | u64 *subnet_prefix) | ||
66 | { | ||
67 | struct ib_device *dev = pp->sec->dev; | ||
68 | int ret; | ||
69 | |||
70 | ret = ib_get_cached_pkey(dev, pp->port_num, pp->pkey_index, pkey); | ||
71 | if (ret) | ||
72 | return ret; | ||
73 | |||
74 | ret = ib_get_cached_subnet_prefix(dev, pp->port_num, subnet_prefix); | ||
75 | |||
76 | return ret; | ||
77 | } | ||
78 | |||
79 | static int enforce_qp_pkey_security(u16 pkey, | ||
80 | u64 subnet_prefix, | ||
81 | struct ib_qp_security *qp_sec) | ||
82 | { | ||
83 | struct ib_qp_security *shared_qp_sec; | ||
84 | int ret; | ||
85 | |||
86 | ret = security_ib_pkey_access(qp_sec->security, subnet_prefix, pkey); | ||
87 | if (ret) | ||
88 | return ret; | ||
89 | |||
90 | if (qp_sec->qp == qp_sec->qp->real_qp) { | ||
91 | list_for_each_entry(shared_qp_sec, | ||
92 | &qp_sec->shared_qp_list, | ||
93 | shared_qp_list) { | ||
94 | ret = security_ib_pkey_access(shared_qp_sec->security, | ||
95 | subnet_prefix, | ||
96 | pkey); | ||
97 | if (ret) | ||
98 | return ret; | ||
99 | } | ||
100 | } | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | /* The caller of this function must hold the QP security | ||
105 | * mutex of the QP of the security structure in *pps. | ||
106 | * | ||
107 | * It takes separate ports_pkeys and security structure | ||
108 | * because in some cases the pps will be for a new settings | ||
109 | * or the pps will be for the real QP and security structure | ||
110 | * will be for a shared QP. | ||
111 | */ | ||
112 | static int check_qp_port_pkey_settings(struct ib_ports_pkeys *pps, | ||
113 | struct ib_qp_security *sec) | ||
114 | { | ||
115 | u64 subnet_prefix; | ||
116 | u16 pkey; | ||
117 | int ret = 0; | ||
118 | |||
119 | if (!pps) | ||
120 | return 0; | ||
121 | |||
122 | if (pps->main.state != IB_PORT_PKEY_NOT_VALID) { | ||
123 | get_pkey_and_subnet_prefix(&pps->main, | ||
124 | &pkey, | ||
125 | &subnet_prefix); | ||
126 | |||
127 | ret = enforce_qp_pkey_security(pkey, | ||
128 | subnet_prefix, | ||
129 | sec); | ||
130 | } | ||
131 | if (ret) | ||
132 | return ret; | ||
133 | |||
134 | if (pps->alt.state != IB_PORT_PKEY_NOT_VALID) { | ||
135 | get_pkey_and_subnet_prefix(&pps->alt, | ||
136 | &pkey, | ||
137 | &subnet_prefix); | ||
138 | |||
139 | ret = enforce_qp_pkey_security(pkey, | ||
140 | subnet_prefix, | ||
141 | sec); | ||
142 | } | ||
143 | |||
144 | return ret; | ||
145 | } | ||
146 | |||
147 | /* The caller of this function must hold the QP security | ||
148 | * mutex. | ||
149 | */ | ||
150 | static void qp_to_error(struct ib_qp_security *sec) | ||
151 | { | ||
152 | struct ib_qp_security *shared_qp_sec; | ||
153 | struct ib_qp_attr attr = { | ||
154 | .qp_state = IB_QPS_ERR | ||
155 | }; | ||
156 | struct ib_event event = { | ||
157 | .event = IB_EVENT_QP_FATAL | ||
158 | }; | ||
159 | |||
160 | /* If the QP is in the process of being destroyed | ||
161 | * the qp pointer in the security structure is | ||
162 | * undefined. It cannot be modified now. | ||
163 | */ | ||
164 | if (sec->destroying) | ||
165 | return; | ||
166 | |||
167 | ib_modify_qp(sec->qp, | ||
168 | &attr, | ||
169 | IB_QP_STATE); | ||
170 | |||
171 | if (sec->qp->event_handler && sec->qp->qp_context) { | ||
172 | event.element.qp = sec->qp; | ||
173 | sec->qp->event_handler(&event, | ||
174 | sec->qp->qp_context); | ||
175 | } | ||
176 | |||
177 | list_for_each_entry(shared_qp_sec, | ||
178 | &sec->shared_qp_list, | ||
179 | shared_qp_list) { | ||
180 | struct ib_qp *qp = shared_qp_sec->qp; | ||
181 | |||
182 | if (qp->event_handler && qp->qp_context) { | ||
183 | event.element.qp = qp; | ||
184 | event.device = qp->device; | ||
185 | qp->event_handler(&event, | ||
186 | qp->qp_context); | ||
187 | } | ||
188 | } | ||
189 | } | ||
190 | |||
191 | static inline void check_pkey_qps(struct pkey_index_qp_list *pkey, | ||
192 | struct ib_device *device, | ||
193 | u8 port_num, | ||
194 | u64 subnet_prefix) | ||
195 | { | ||
196 | struct ib_port_pkey *pp, *tmp_pp; | ||
197 | bool comp; | ||
198 | LIST_HEAD(to_error_list); | ||
199 | u16 pkey_val; | ||
200 | |||
201 | if (!ib_get_cached_pkey(device, | ||
202 | port_num, | ||
203 | pkey->pkey_index, | ||
204 | &pkey_val)) { | ||
205 | spin_lock(&pkey->qp_list_lock); | ||
206 | list_for_each_entry(pp, &pkey->qp_list, qp_list) { | ||
207 | if (atomic_read(&pp->sec->error_list_count)) | ||
208 | continue; | ||
209 | |||
210 | if (enforce_qp_pkey_security(pkey_val, | ||
211 | subnet_prefix, | ||
212 | pp->sec)) { | ||
213 | atomic_inc(&pp->sec->error_list_count); | ||
214 | list_add(&pp->to_error_list, | ||
215 | &to_error_list); | ||
216 | } | ||
217 | } | ||
218 | spin_unlock(&pkey->qp_list_lock); | ||
219 | } | ||
220 | |||
221 | list_for_each_entry_safe(pp, | ||
222 | tmp_pp, | ||
223 | &to_error_list, | ||
224 | to_error_list) { | ||
225 | mutex_lock(&pp->sec->mutex); | ||
226 | qp_to_error(pp->sec); | ||
227 | list_del(&pp->to_error_list); | ||
228 | atomic_dec(&pp->sec->error_list_count); | ||
229 | comp = pp->sec->destroying; | ||
230 | mutex_unlock(&pp->sec->mutex); | ||
231 | |||
232 | if (comp) | ||
233 | complete(&pp->sec->error_complete); | ||
234 | } | ||
235 | } | ||
236 | |||
237 | /* The caller of this function must hold the QP security | ||
238 | * mutex. | ||
239 | */ | ||
240 | static int port_pkey_list_insert(struct ib_port_pkey *pp) | ||
241 | { | ||
242 | struct pkey_index_qp_list *tmp_pkey; | ||
243 | struct pkey_index_qp_list *pkey; | ||
244 | struct ib_device *dev; | ||
245 | u8 port_num = pp->port_num; | ||
246 | int ret = 0; | ||
247 | |||
248 | if (pp->state != IB_PORT_PKEY_VALID) | ||
249 | return 0; | ||
250 | |||
251 | dev = pp->sec->dev; | ||
252 | |||
253 | pkey = get_pkey_idx_qp_list(pp); | ||
254 | |||
255 | if (!pkey) { | ||
256 | bool found = false; | ||
257 | |||
258 | pkey = kzalloc(sizeof(*pkey), GFP_KERNEL); | ||
259 | if (!pkey) | ||
260 | return -ENOMEM; | ||
261 | |||
262 | spin_lock(&dev->port_pkey_list[port_num].list_lock); | ||
263 | /* Check for the PKey again. A racing process may | ||
264 | * have created it. | ||
265 | */ | ||
266 | list_for_each_entry(tmp_pkey, | ||
267 | &dev->port_pkey_list[port_num].pkey_list, | ||
268 | pkey_index_list) { | ||
269 | if (tmp_pkey->pkey_index == pp->pkey_index) { | ||
270 | kfree(pkey); | ||
271 | pkey = tmp_pkey; | ||
272 | found = true; | ||
273 | break; | ||
274 | } | ||
275 | } | ||
276 | |||
277 | if (!found) { | ||
278 | pkey->pkey_index = pp->pkey_index; | ||
279 | spin_lock_init(&pkey->qp_list_lock); | ||
280 | INIT_LIST_HEAD(&pkey->qp_list); | ||
281 | list_add(&pkey->pkey_index_list, | ||
282 | &dev->port_pkey_list[port_num].pkey_list); | ||
283 | } | ||
284 | spin_unlock(&dev->port_pkey_list[port_num].list_lock); | ||
285 | } | ||
286 | |||
287 | spin_lock(&pkey->qp_list_lock); | ||
288 | list_add(&pp->qp_list, &pkey->qp_list); | ||
289 | spin_unlock(&pkey->qp_list_lock); | ||
290 | |||
291 | pp->state = IB_PORT_PKEY_LISTED; | ||
292 | |||
293 | return ret; | ||
294 | } | ||
295 | |||
296 | /* The caller of this function must hold the QP security | ||
297 | * mutex. | ||
298 | */ | ||
299 | static void port_pkey_list_remove(struct ib_port_pkey *pp) | ||
300 | { | ||
301 | struct pkey_index_qp_list *pkey; | ||
302 | |||
303 | if (pp->state != IB_PORT_PKEY_LISTED) | ||
304 | return; | ||
305 | |||
306 | pkey = get_pkey_idx_qp_list(pp); | ||
307 | |||
308 | spin_lock(&pkey->qp_list_lock); | ||
309 | list_del(&pp->qp_list); | ||
310 | spin_unlock(&pkey->qp_list_lock); | ||
311 | |||
312 | /* The setting may still be valid, i.e. after | ||
313 | * a destroy has failed for example. | ||
314 | */ | ||
315 | pp->state = IB_PORT_PKEY_VALID; | ||
316 | } | ||
317 | |||
318 | static void destroy_qp_security(struct ib_qp_security *sec) | ||
319 | { | ||
320 | security_ib_free_security(sec->security); | ||
321 | kfree(sec->ports_pkeys); | ||
322 | kfree(sec); | ||
323 | } | ||
324 | |||
325 | /* The caller of this function must hold the QP security | ||
326 | * mutex. | ||
327 | */ | ||
328 | static struct ib_ports_pkeys *get_new_pps(const struct ib_qp *qp, | ||
329 | const struct ib_qp_attr *qp_attr, | ||
330 | int qp_attr_mask) | ||
331 | { | ||
332 | struct ib_ports_pkeys *new_pps; | ||
333 | struct ib_ports_pkeys *qp_pps = qp->qp_sec->ports_pkeys; | ||
334 | |||
335 | new_pps = kzalloc(sizeof(*new_pps), GFP_KERNEL); | ||
336 | if (!new_pps) | ||
337 | return NULL; | ||
338 | |||
339 | if (qp_attr_mask & (IB_QP_PKEY_INDEX | IB_QP_PORT)) { | ||
340 | if (!qp_pps) { | ||
341 | new_pps->main.port_num = qp_attr->port_num; | ||
342 | new_pps->main.pkey_index = qp_attr->pkey_index; | ||
343 | } else { | ||
344 | new_pps->main.port_num = (qp_attr_mask & IB_QP_PORT) ? | ||
345 | qp_attr->port_num : | ||
346 | qp_pps->main.port_num; | ||
347 | |||
348 | new_pps->main.pkey_index = | ||
349 | (qp_attr_mask & IB_QP_PKEY_INDEX) ? | ||
350 | qp_attr->pkey_index : | ||
351 | qp_pps->main.pkey_index; | ||
352 | } | ||
353 | new_pps->main.state = IB_PORT_PKEY_VALID; | ||
354 | } else if (qp_pps) { | ||
355 | new_pps->main.port_num = qp_pps->main.port_num; | ||
356 | new_pps->main.pkey_index = qp_pps->main.pkey_index; | ||
357 | if (qp_pps->main.state != IB_PORT_PKEY_NOT_VALID) | ||
358 | new_pps->main.state = IB_PORT_PKEY_VALID; | ||
359 | } | ||
360 | |||
361 | if (qp_attr_mask & IB_QP_ALT_PATH) { | ||
362 | new_pps->alt.port_num = qp_attr->alt_port_num; | ||
363 | new_pps->alt.pkey_index = qp_attr->alt_pkey_index; | ||
364 | new_pps->alt.state = IB_PORT_PKEY_VALID; | ||
365 | } else if (qp_pps) { | ||
366 | new_pps->alt.port_num = qp_pps->alt.port_num; | ||
367 | new_pps->alt.pkey_index = qp_pps->alt.pkey_index; | ||
368 | if (qp_pps->alt.state != IB_PORT_PKEY_NOT_VALID) | ||
369 | new_pps->alt.state = IB_PORT_PKEY_VALID; | ||
370 | } | ||
371 | |||
372 | new_pps->main.sec = qp->qp_sec; | ||
373 | new_pps->alt.sec = qp->qp_sec; | ||
374 | return new_pps; | ||
375 | } | ||
376 | |||
377 | int ib_open_shared_qp_security(struct ib_qp *qp, struct ib_device *dev) | ||
378 | { | ||
379 | struct ib_qp *real_qp = qp->real_qp; | ||
380 | int ret; | ||
381 | |||
382 | ret = ib_create_qp_security(qp, dev); | ||
383 | |||
384 | if (ret) | ||
385 | return ret; | ||
386 | |||
387 | mutex_lock(&real_qp->qp_sec->mutex); | ||
388 | ret = check_qp_port_pkey_settings(real_qp->qp_sec->ports_pkeys, | ||
389 | qp->qp_sec); | ||
390 | |||
391 | if (ret) | ||
392 | goto ret; | ||
393 | |||
394 | if (qp != real_qp) | ||
395 | list_add(&qp->qp_sec->shared_qp_list, | ||
396 | &real_qp->qp_sec->shared_qp_list); | ||
397 | ret: | ||
398 | mutex_unlock(&real_qp->qp_sec->mutex); | ||
399 | if (ret) | ||
400 | destroy_qp_security(qp->qp_sec); | ||
401 | |||
402 | return ret; | ||
403 | } | ||
404 | |||
405 | void ib_close_shared_qp_security(struct ib_qp_security *sec) | ||
406 | { | ||
407 | struct ib_qp *real_qp = sec->qp->real_qp; | ||
408 | |||
409 | mutex_lock(&real_qp->qp_sec->mutex); | ||
410 | list_del(&sec->shared_qp_list); | ||
411 | mutex_unlock(&real_qp->qp_sec->mutex); | ||
412 | |||
413 | destroy_qp_security(sec); | ||
414 | } | ||
415 | |||
416 | int ib_create_qp_security(struct ib_qp *qp, struct ib_device *dev) | ||
417 | { | ||
418 | int ret; | ||
419 | |||
420 | qp->qp_sec = kzalloc(sizeof(*qp->qp_sec), GFP_KERNEL); | ||
421 | if (!qp->qp_sec) | ||
422 | return -ENOMEM; | ||
423 | |||
424 | qp->qp_sec->qp = qp; | ||
425 | qp->qp_sec->dev = dev; | ||
426 | mutex_init(&qp->qp_sec->mutex); | ||
427 | INIT_LIST_HEAD(&qp->qp_sec->shared_qp_list); | ||
428 | atomic_set(&qp->qp_sec->error_list_count, 0); | ||
429 | init_completion(&qp->qp_sec->error_complete); | ||
430 | ret = security_ib_alloc_security(&qp->qp_sec->security); | ||
431 | if (ret) | ||
432 | kfree(qp->qp_sec); | ||
433 | |||
434 | return ret; | ||
435 | } | ||
436 | EXPORT_SYMBOL(ib_create_qp_security); | ||
437 | |||
438 | void ib_destroy_qp_security_begin(struct ib_qp_security *sec) | ||
439 | { | ||
440 | mutex_lock(&sec->mutex); | ||
441 | |||
442 | /* Remove the QP from the lists so it won't get added to | ||
443 | * a to_error_list during the destroy process. | ||
444 | */ | ||
445 | if (sec->ports_pkeys) { | ||
446 | port_pkey_list_remove(&sec->ports_pkeys->main); | ||
447 | port_pkey_list_remove(&sec->ports_pkeys->alt); | ||
448 | } | ||
449 | |||
450 | /* If the QP is already in one or more of those lists | ||
451 | * the destroying flag will ensure the to error flow | ||
452 | * doesn't operate on an undefined QP. | ||
453 | */ | ||
454 | sec->destroying = true; | ||
455 | |||
456 | /* Record the error list count to know how many completions | ||
457 | * to wait for. | ||
458 | */ | ||
459 | sec->error_comps_pending = atomic_read(&sec->error_list_count); | ||
460 | |||
461 | mutex_unlock(&sec->mutex); | ||
462 | } | ||
463 | |||
464 | void ib_destroy_qp_security_abort(struct ib_qp_security *sec) | ||
465 | { | ||
466 | int ret; | ||
467 | int i; | ||
468 | |||
469 | /* If a concurrent cache update is in progress this | ||
470 | * QP security could be marked for an error state | ||
471 | * transition. Wait for this to complete. | ||
472 | */ | ||
473 | for (i = 0; i < sec->error_comps_pending; i++) | ||
474 | wait_for_completion(&sec->error_complete); | ||
475 | |||
476 | mutex_lock(&sec->mutex); | ||
477 | sec->destroying = false; | ||
478 | |||
479 | /* Restore the position in the lists and verify | ||
480 | * access is still allowed in case a cache update | ||
481 | * occurred while attempting to destroy. | ||
482 | * | ||
483 | * Because these setting were listed already | ||
484 | * and removed during ib_destroy_qp_security_begin | ||
485 | * we know the pkey_index_qp_list for the PKey | ||
486 | * already exists so port_pkey_list_insert won't fail. | ||
487 | */ | ||
488 | if (sec->ports_pkeys) { | ||
489 | port_pkey_list_insert(&sec->ports_pkeys->main); | ||
490 | port_pkey_list_insert(&sec->ports_pkeys->alt); | ||
491 | } | ||
492 | |||
493 | ret = check_qp_port_pkey_settings(sec->ports_pkeys, sec); | ||
494 | if (ret) | ||
495 | qp_to_error(sec); | ||
496 | |||
497 | mutex_unlock(&sec->mutex); | ||
498 | } | ||
499 | |||
500 | void ib_destroy_qp_security_end(struct ib_qp_security *sec) | ||
501 | { | ||
502 | int i; | ||
503 | |||
504 | /* If a concurrent cache update is occurring we must | ||
505 | * wait until this QP security structure is processed | ||
506 | * in the QP to error flow before destroying it because | ||
507 | * the to_error_list is in use. | ||
508 | */ | ||
509 | for (i = 0; i < sec->error_comps_pending; i++) | ||
510 | wait_for_completion(&sec->error_complete); | ||
511 | |||
512 | destroy_qp_security(sec); | ||
513 | } | ||
514 | |||
515 | void ib_security_cache_change(struct ib_device *device, | ||
516 | u8 port_num, | ||
517 | u64 subnet_prefix) | ||
518 | { | ||
519 | struct pkey_index_qp_list *pkey; | ||
520 | |||
521 | list_for_each_entry(pkey, | ||
522 | &device->port_pkey_list[port_num].pkey_list, | ||
523 | pkey_index_list) { | ||
524 | check_pkey_qps(pkey, | ||
525 | device, | ||
526 | port_num, | ||
527 | subnet_prefix); | ||
528 | } | ||
529 | } | ||
530 | |||
531 | void ib_security_destroy_port_pkey_list(struct ib_device *device) | ||
532 | { | ||
533 | struct pkey_index_qp_list *pkey, *tmp_pkey; | ||
534 | int i; | ||
535 | |||
536 | for (i = rdma_start_port(device); i <= rdma_end_port(device); i++) { | ||
537 | spin_lock(&device->port_pkey_list[i].list_lock); | ||
538 | list_for_each_entry_safe(pkey, | ||
539 | tmp_pkey, | ||
540 | &device->port_pkey_list[i].pkey_list, | ||
541 | pkey_index_list) { | ||
542 | list_del(&pkey->pkey_index_list); | ||
543 | kfree(pkey); | ||
544 | } | ||
545 | spin_unlock(&device->port_pkey_list[i].list_lock); | ||
546 | } | ||
547 | } | ||
548 | |||
549 | int ib_security_modify_qp(struct ib_qp *qp, | ||
550 | struct ib_qp_attr *qp_attr, | ||
551 | int qp_attr_mask, | ||
552 | struct ib_udata *udata) | ||
553 | { | ||
554 | int ret = 0; | ||
555 | struct ib_ports_pkeys *tmp_pps; | ||
556 | struct ib_ports_pkeys *new_pps; | ||
557 | bool special_qp = (qp->qp_type == IB_QPT_SMI || | ||
558 | qp->qp_type == IB_QPT_GSI || | ||
559 | qp->qp_type >= IB_QPT_RESERVED1); | ||
560 | bool pps_change = ((qp_attr_mask & (IB_QP_PKEY_INDEX | IB_QP_PORT)) || | ||
561 | (qp_attr_mask & IB_QP_ALT_PATH)); | ||
562 | |||
563 | if (pps_change && !special_qp) { | ||
564 | mutex_lock(&qp->qp_sec->mutex); | ||
565 | new_pps = get_new_pps(qp, | ||
566 | qp_attr, | ||
567 | qp_attr_mask); | ||
568 | |||
569 | /* Add this QP to the lists for the new port | ||
570 | * and pkey settings before checking for permission | ||
571 | * in case there is a concurrent cache update | ||
572 | * occurring. Walking the list for a cache change | ||
573 | * doesn't acquire the security mutex unless it's | ||
574 | * sending the QP to error. | ||
575 | */ | ||
576 | ret = port_pkey_list_insert(&new_pps->main); | ||
577 | |||
578 | if (!ret) | ||
579 | ret = port_pkey_list_insert(&new_pps->alt); | ||
580 | |||
581 | if (!ret) | ||
582 | ret = check_qp_port_pkey_settings(new_pps, | ||
583 | qp->qp_sec); | ||
584 | } | ||
585 | |||
586 | if (!ret) | ||
587 | ret = qp->device->modify_qp(qp->real_qp, | ||
588 | qp_attr, | ||
589 | qp_attr_mask, | ||
590 | udata); | ||
591 | |||
592 | if (pps_change && !special_qp) { | ||
593 | /* Clean up the lists and free the appropriate | ||
594 | * ports_pkeys structure. | ||
595 | */ | ||
596 | if (ret) { | ||
597 | tmp_pps = new_pps; | ||
598 | } else { | ||
599 | tmp_pps = qp->qp_sec->ports_pkeys; | ||
600 | qp->qp_sec->ports_pkeys = new_pps; | ||
601 | } | ||
602 | |||
603 | if (tmp_pps) { | ||
604 | port_pkey_list_remove(&tmp_pps->main); | ||
605 | port_pkey_list_remove(&tmp_pps->alt); | ||
606 | } | ||
607 | kfree(tmp_pps); | ||
608 | mutex_unlock(&qp->qp_sec->mutex); | ||
609 | } | ||
610 | return ret; | ||
611 | } | ||
612 | EXPORT_SYMBOL(ib_security_modify_qp); | ||
613 | |||
614 | int ib_security_pkey_access(struct ib_device *dev, | ||
615 | u8 port_num, | ||
616 | u16 pkey_index, | ||
617 | void *sec) | ||
618 | { | ||
619 | u64 subnet_prefix; | ||
620 | u16 pkey; | ||
621 | int ret; | ||
622 | |||
623 | ret = ib_get_cached_pkey(dev, port_num, pkey_index, &pkey); | ||
624 | if (ret) | ||
625 | return ret; | ||
626 | |||
627 | ret = ib_get_cached_subnet_prefix(dev, port_num, &subnet_prefix); | ||
628 | |||
629 | if (ret) | ||
630 | return ret; | ||
631 | |||
632 | return security_ib_pkey_access(sec, subnet_prefix, pkey); | ||
633 | } | ||
634 | EXPORT_SYMBOL(ib_security_pkey_access); | ||
635 | |||
636 | static int ib_mad_agent_security_change(struct notifier_block *nb, | ||
637 | unsigned long event, | ||
638 | void *data) | ||
639 | { | ||
640 | struct ib_mad_agent *ag = container_of(nb, struct ib_mad_agent, lsm_nb); | ||
641 | |||
642 | if (event != LSM_POLICY_CHANGE) | ||
643 | return NOTIFY_DONE; | ||
644 | |||
645 | ag->smp_allowed = !security_ib_endport_manage_subnet(ag->security, | ||
646 | ag->device->name, | ||
647 | ag->port_num); | ||
648 | |||
649 | return NOTIFY_OK; | ||
650 | } | ||
651 | |||
652 | int ib_mad_agent_security_setup(struct ib_mad_agent *agent, | ||
653 | enum ib_qp_type qp_type) | ||
654 | { | ||
655 | int ret; | ||
656 | |||
657 | ret = security_ib_alloc_security(&agent->security); | ||
658 | if (ret) | ||
659 | return ret; | ||
660 | |||
661 | if (qp_type != IB_QPT_SMI) | ||
662 | return 0; | ||
663 | |||
664 | ret = security_ib_endport_manage_subnet(agent->security, | ||
665 | agent->device->name, | ||
666 | agent->port_num); | ||
667 | if (ret) | ||
668 | return ret; | ||
669 | |||
670 | agent->lsm_nb.notifier_call = ib_mad_agent_security_change; | ||
671 | ret = register_lsm_notifier(&agent->lsm_nb); | ||
672 | if (ret) | ||
673 | return ret; | ||
674 | |||
675 | agent->smp_allowed = true; | ||
676 | agent->lsm_nb_reg = true; | ||
677 | return 0; | ||
678 | } | ||
679 | |||
680 | void ib_mad_agent_security_cleanup(struct ib_mad_agent *agent) | ||
681 | { | ||
682 | security_ib_free_security(agent->security); | ||
683 | if (agent->lsm_nb_reg) | ||
684 | unregister_lsm_notifier(&agent->lsm_nb); | ||
685 | } | ||
686 | |||
687 | int ib_mad_enforce_security(struct ib_mad_agent_private *map, u16 pkey_index) | ||
688 | { | ||
689 | int ret; | ||
690 | |||
691 | if (map->agent.qp->qp_type == IB_QPT_SMI && !map->agent.smp_allowed) | ||
692 | return -EACCES; | ||
693 | |||
694 | ret = ib_security_pkey_access(map->agent.device, | ||
695 | map->agent.port_num, | ||
696 | pkey_index, | ||
697 | map->agent.security); | ||
698 | |||
699 | if (ret) | ||
700 | return ret; | ||
701 | |||
702 | return 0; | ||
703 | } | ||
704 | |||
705 | #endif /* CONFIG_SECURITY_INFINIBAND */ | ||
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 70b7fb156414..0ad3b05405d8 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c | |||
@@ -1508,6 +1508,10 @@ static int create_qp(struct ib_uverbs_file *file, | |||
1508 | } | 1508 | } |
1509 | 1509 | ||
1510 | if (cmd->qp_type != IB_QPT_XRC_TGT) { | 1510 | if (cmd->qp_type != IB_QPT_XRC_TGT) { |
1511 | ret = ib_create_qp_security(qp, device); | ||
1512 | if (ret) | ||
1513 | goto err_cb; | ||
1514 | |||
1511 | qp->real_qp = qp; | 1515 | qp->real_qp = qp; |
1512 | qp->device = device; | 1516 | qp->device = device; |
1513 | qp->pd = pd; | 1517 | qp->pd = pd; |
@@ -2002,14 +2006,17 @@ static int modify_qp(struct ib_uverbs_file *file, | |||
2002 | if (ret) | 2006 | if (ret) |
2003 | goto release_qp; | 2007 | goto release_qp; |
2004 | } | 2008 | } |
2005 | ret = qp->device->modify_qp(qp, attr, | 2009 | ret = ib_security_modify_qp(qp, |
2010 | attr, | ||
2006 | modify_qp_mask(qp->qp_type, | 2011 | modify_qp_mask(qp->qp_type, |
2007 | cmd->base.attr_mask), | 2012 | cmd->base.attr_mask), |
2008 | udata); | 2013 | udata); |
2009 | } else { | 2014 | } else { |
2010 | ret = ib_modify_qp(qp, attr, | 2015 | ret = ib_security_modify_qp(qp, |
2011 | modify_qp_mask(qp->qp_type, | 2016 | attr, |
2012 | cmd->base.attr_mask)); | 2017 | modify_qp_mask(qp->qp_type, |
2018 | cmd->base.attr_mask), | ||
2019 | NULL); | ||
2013 | } | 2020 | } |
2014 | 2021 | ||
2015 | release_qp: | 2022 | release_qp: |
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 4792f5209ac2..c973a83c898b 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include <linux/in.h> | 44 | #include <linux/in.h> |
45 | #include <linux/in6.h> | 45 | #include <linux/in6.h> |
46 | #include <net/addrconf.h> | 46 | #include <net/addrconf.h> |
47 | #include <linux/security.h> | ||
47 | 48 | ||
48 | #include <rdma/ib_verbs.h> | 49 | #include <rdma/ib_verbs.h> |
49 | #include <rdma/ib_cache.h> | 50 | #include <rdma/ib_cache.h> |
@@ -713,12 +714,20 @@ static struct ib_qp *__ib_open_qp(struct ib_qp *real_qp, | |||
713 | { | 714 | { |
714 | struct ib_qp *qp; | 715 | struct ib_qp *qp; |
715 | unsigned long flags; | 716 | unsigned long flags; |
717 | int err; | ||
716 | 718 | ||
717 | qp = kzalloc(sizeof *qp, GFP_KERNEL); | 719 | qp = kzalloc(sizeof *qp, GFP_KERNEL); |
718 | if (!qp) | 720 | if (!qp) |
719 | return ERR_PTR(-ENOMEM); | 721 | return ERR_PTR(-ENOMEM); |
720 | 722 | ||
721 | qp->real_qp = real_qp; | 723 | qp->real_qp = real_qp; |
724 | err = ib_open_shared_qp_security(qp, real_qp->device); | ||
725 | if (err) { | ||
726 | kfree(qp); | ||
727 | return ERR_PTR(err); | ||
728 | } | ||
729 | |||
730 | qp->real_qp = real_qp; | ||
722 | atomic_inc(&real_qp->usecnt); | 731 | atomic_inc(&real_qp->usecnt); |
723 | qp->device = real_qp->device; | 732 | qp->device = real_qp->device; |
724 | qp->event_handler = event_handler; | 733 | qp->event_handler = event_handler; |
@@ -804,6 +813,12 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd, | |||
804 | if (IS_ERR(qp)) | 813 | if (IS_ERR(qp)) |
805 | return qp; | 814 | return qp; |
806 | 815 | ||
816 | ret = ib_create_qp_security(qp, device); | ||
817 | if (ret) { | ||
818 | ib_destroy_qp(qp); | ||
819 | return ERR_PTR(ret); | ||
820 | } | ||
821 | |||
807 | qp->device = device; | 822 | qp->device = device; |
808 | qp->real_qp = qp; | 823 | qp->real_qp = qp; |
809 | qp->uobject = NULL; | 824 | qp->uobject = NULL; |
@@ -1266,7 +1281,7 @@ int ib_modify_qp(struct ib_qp *qp, | |||
1266 | return ret; | 1281 | return ret; |
1267 | } | 1282 | } |
1268 | 1283 | ||
1269 | return qp->device->modify_qp(qp->real_qp, qp_attr, qp_attr_mask, NULL); | 1284 | return ib_security_modify_qp(qp->real_qp, qp_attr, qp_attr_mask, NULL); |
1270 | } | 1285 | } |
1271 | EXPORT_SYMBOL(ib_modify_qp); | 1286 | EXPORT_SYMBOL(ib_modify_qp); |
1272 | 1287 | ||
@@ -1295,6 +1310,7 @@ int ib_close_qp(struct ib_qp *qp) | |||
1295 | spin_unlock_irqrestore(&real_qp->device->event_handler_lock, flags); | 1310 | spin_unlock_irqrestore(&real_qp->device->event_handler_lock, flags); |
1296 | 1311 | ||
1297 | atomic_dec(&real_qp->usecnt); | 1312 | atomic_dec(&real_qp->usecnt); |
1313 | ib_close_shared_qp_security(qp->qp_sec); | ||
1298 | kfree(qp); | 1314 | kfree(qp); |
1299 | 1315 | ||
1300 | return 0; | 1316 | return 0; |
@@ -1335,6 +1351,7 @@ int ib_destroy_qp(struct ib_qp *qp) | |||
1335 | struct ib_cq *scq, *rcq; | 1351 | struct ib_cq *scq, *rcq; |
1336 | struct ib_srq *srq; | 1352 | struct ib_srq *srq; |
1337 | struct ib_rwq_ind_table *ind_tbl; | 1353 | struct ib_rwq_ind_table *ind_tbl; |
1354 | struct ib_qp_security *sec; | ||
1338 | int ret; | 1355 | int ret; |
1339 | 1356 | ||
1340 | WARN_ON_ONCE(qp->mrs_used > 0); | 1357 | WARN_ON_ONCE(qp->mrs_used > 0); |
@@ -1350,6 +1367,9 @@ int ib_destroy_qp(struct ib_qp *qp) | |||
1350 | rcq = qp->recv_cq; | 1367 | rcq = qp->recv_cq; |
1351 | srq = qp->srq; | 1368 | srq = qp->srq; |
1352 | ind_tbl = qp->rwq_ind_tbl; | 1369 | ind_tbl = qp->rwq_ind_tbl; |
1370 | sec = qp->qp_sec; | ||
1371 | if (sec) | ||
1372 | ib_destroy_qp_security_begin(sec); | ||
1353 | 1373 | ||
1354 | if (!qp->uobject) | 1374 | if (!qp->uobject) |
1355 | rdma_rw_cleanup_mrs(qp); | 1375 | rdma_rw_cleanup_mrs(qp); |
@@ -1366,6 +1386,11 @@ int ib_destroy_qp(struct ib_qp *qp) | |||
1366 | atomic_dec(&srq->usecnt); | 1386 | atomic_dec(&srq->usecnt); |
1367 | if (ind_tbl) | 1387 | if (ind_tbl) |
1368 | atomic_dec(&ind_tbl->usecnt); | 1388 | atomic_dec(&ind_tbl->usecnt); |
1389 | if (sec) | ||
1390 | ib_destroy_qp_security_end(sec); | ||
1391 | } else { | ||
1392 | if (sec) | ||
1393 | ib_destroy_qp_security_abort(sec); | ||
1369 | } | 1394 | } |
1370 | 1395 | ||
1371 | return ret; | 1396 | return ret; |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 2f3822a4a7d5..b8e073546507 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -2544,10 +2544,25 @@ EXPORT_SYMBOL_GPL(nfs_set_sb_security); | |||
2544 | int nfs_clone_sb_security(struct super_block *s, struct dentry *mntroot, | 2544 | int nfs_clone_sb_security(struct super_block *s, struct dentry *mntroot, |
2545 | struct nfs_mount_info *mount_info) | 2545 | struct nfs_mount_info *mount_info) |
2546 | { | 2546 | { |
2547 | int error; | ||
2548 | unsigned long kflags = 0, kflags_out = 0; | ||
2549 | |||
2547 | /* clone any lsm security options from the parent to the new sb */ | 2550 | /* clone any lsm security options from the parent to the new sb */ |
2548 | if (d_inode(mntroot)->i_op != NFS_SB(s)->nfs_client->rpc_ops->dir_inode_ops) | 2551 | if (d_inode(mntroot)->i_op != NFS_SB(s)->nfs_client->rpc_ops->dir_inode_ops) |
2549 | return -ESTALE; | 2552 | return -ESTALE; |
2550 | return security_sb_clone_mnt_opts(mount_info->cloned->sb, s); | 2553 | |
2554 | if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL) | ||
2555 | kflags |= SECURITY_LSM_NATIVE_LABELS; | ||
2556 | |||
2557 | error = security_sb_clone_mnt_opts(mount_info->cloned->sb, s, kflags, | ||
2558 | &kflags_out); | ||
2559 | if (error) | ||
2560 | return error; | ||
2561 | |||
2562 | if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL && | ||
2563 | !(kflags_out & SECURITY_LSM_NATIVE_LABELS)) | ||
2564 | NFS_SB(s)->caps &= ~NFS_CAP_SECURITY_LABEL; | ||
2565 | return 0; | ||
2551 | } | 2566 | } |
2552 | EXPORT_SYMBOL_GPL(nfs_clone_sb_security); | 2567 | EXPORT_SYMBOL_GPL(nfs_clone_sb_security); |
2553 | 2568 | ||
diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h index e58e577117b6..22b5d4e687ce 100644 --- a/include/linux/lsm_audit.h +++ b/include/linux/lsm_audit.h | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/path.h> | 21 | #include <linux/path.h> |
22 | #include <linux/key.h> | 22 | #include <linux/key.h> |
23 | #include <linux/skbuff.h> | 23 | #include <linux/skbuff.h> |
24 | #include <rdma/ib_verbs.h> | ||
24 | 25 | ||
25 | struct lsm_network_audit { | 26 | struct lsm_network_audit { |
26 | int netif; | 27 | int netif; |
@@ -45,6 +46,16 @@ struct lsm_ioctlop_audit { | |||
45 | u16 cmd; | 46 | u16 cmd; |
46 | }; | 47 | }; |
47 | 48 | ||
49 | struct lsm_ibpkey_audit { | ||
50 | u64 subnet_prefix; | ||
51 | u16 pkey; | ||
52 | }; | ||
53 | |||
54 | struct lsm_ibendport_audit { | ||
55 | char dev_name[IB_DEVICE_NAME_MAX]; | ||
56 | u8 port; | ||
57 | }; | ||
58 | |||
48 | /* Auxiliary data to use in generating the audit record. */ | 59 | /* Auxiliary data to use in generating the audit record. */ |
49 | struct common_audit_data { | 60 | struct common_audit_data { |
50 | char type; | 61 | char type; |
@@ -60,6 +71,8 @@ struct common_audit_data { | |||
60 | #define LSM_AUDIT_DATA_DENTRY 10 | 71 | #define LSM_AUDIT_DATA_DENTRY 10 |
61 | #define LSM_AUDIT_DATA_IOCTL_OP 11 | 72 | #define LSM_AUDIT_DATA_IOCTL_OP 11 |
62 | #define LSM_AUDIT_DATA_FILE 12 | 73 | #define LSM_AUDIT_DATA_FILE 12 |
74 | #define LSM_AUDIT_DATA_IBPKEY 13 | ||
75 | #define LSM_AUDIT_DATA_IBENDPORT 14 | ||
63 | union { | 76 | union { |
64 | struct path path; | 77 | struct path path; |
65 | struct dentry *dentry; | 78 | struct dentry *dentry; |
@@ -77,6 +90,8 @@ struct common_audit_data { | |||
77 | char *kmod_name; | 90 | char *kmod_name; |
78 | struct lsm_ioctlop_audit *op; | 91 | struct lsm_ioctlop_audit *op; |
79 | struct file *file; | 92 | struct file *file; |
93 | struct lsm_ibpkey_audit *ibpkey; | ||
94 | struct lsm_ibendport_audit *ibendport; | ||
80 | } u; | 95 | } u; |
81 | /* this union contains LSM specific data */ | 96 | /* this union contains LSM specific data */ |
82 | union { | 97 | union { |
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 080f34e66017..3cc9d77c7527 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h | |||
@@ -8,6 +8,7 @@ | |||
8 | * Copyright (C) 2001 Silicon Graphics, Inc. (Trust Technology Group) | 8 | * Copyright (C) 2001 Silicon Graphics, Inc. (Trust Technology Group) |
9 | * Copyright (C) 2015 Intel Corporation. | 9 | * Copyright (C) 2015 Intel Corporation. |
10 | * Copyright (C) 2015 Casey Schaufler <casey@schaufler-ca.com> | 10 | * Copyright (C) 2015 Casey Schaufler <casey@schaufler-ca.com> |
11 | * Copyright (C) 2016 Mellanox Techonologies | ||
11 | * | 12 | * |
12 | * This program is free software; you can redistribute it and/or modify | 13 | * This program is free software; you can redistribute it and/or modify |
13 | * it under the terms of the GNU General Public License as published by | 14 | * it under the terms of the GNU General Public License as published by |
@@ -911,6 +912,26 @@ | |||
911 | * associated with the TUN device's security structure. | 912 | * associated with the TUN device's security structure. |
912 | * @security pointer to the TUN devices's security structure. | 913 | * @security pointer to the TUN devices's security structure. |
913 | * | 914 | * |
915 | * Security hooks for Infiniband | ||
916 | * | ||
917 | * @ib_pkey_access: | ||
918 | * Check permission to access a pkey when modifing a QP. | ||
919 | * @subnet_prefix the subnet prefix of the port being used. | ||
920 | * @pkey the pkey to be accessed. | ||
921 | * @sec pointer to a security structure. | ||
922 | * @ib_endport_manage_subnet: | ||
923 | * Check permissions to send and receive SMPs on a end port. | ||
924 | * @dev_name the IB device name (i.e. mlx4_0). | ||
925 | * @port_num the port number. | ||
926 | * @sec pointer to a security structure. | ||
927 | * @ib_alloc_security: | ||
928 | * Allocate a security structure for Infiniband objects. | ||
929 | * @sec pointer to a security structure pointer. | ||
930 | * Returns 0 on success, non-zero on failure | ||
931 | * @ib_free_security: | ||
932 | * Deallocate an Infiniband security structure. | ||
933 | * @sec contains the security structure to be freed. | ||
934 | * | ||
914 | * Security hooks for XFRM operations. | 935 | * Security hooks for XFRM operations. |
915 | * | 936 | * |
916 | * @xfrm_policy_alloc_security: | 937 | * @xfrm_policy_alloc_security: |
@@ -1388,7 +1409,9 @@ union security_list_options { | |||
1388 | unsigned long kern_flags, | 1409 | unsigned long kern_flags, |
1389 | unsigned long *set_kern_flags); | 1410 | unsigned long *set_kern_flags); |
1390 | int (*sb_clone_mnt_opts)(const struct super_block *oldsb, | 1411 | int (*sb_clone_mnt_opts)(const struct super_block *oldsb, |
1391 | struct super_block *newsb); | 1412 | struct super_block *newsb, |
1413 | unsigned long kern_flags, | ||
1414 | unsigned long *set_kern_flags); | ||
1392 | int (*sb_parse_opts_str)(char *options, struct security_mnt_opts *opts); | 1415 | int (*sb_parse_opts_str)(char *options, struct security_mnt_opts *opts); |
1393 | int (*dentry_init_security)(struct dentry *dentry, int mode, | 1416 | int (*dentry_init_security)(struct dentry *dentry, int mode, |
1394 | const struct qstr *name, void **ctx, | 1417 | const struct qstr *name, void **ctx, |
@@ -1620,6 +1643,14 @@ union security_list_options { | |||
1620 | int (*tun_dev_open)(void *security); | 1643 | int (*tun_dev_open)(void *security); |
1621 | #endif /* CONFIG_SECURITY_NETWORK */ | 1644 | #endif /* CONFIG_SECURITY_NETWORK */ |
1622 | 1645 | ||
1646 | #ifdef CONFIG_SECURITY_INFINIBAND | ||
1647 | int (*ib_pkey_access)(void *sec, u64 subnet_prefix, u16 pkey); | ||
1648 | int (*ib_endport_manage_subnet)(void *sec, const char *dev_name, | ||
1649 | u8 port_num); | ||
1650 | int (*ib_alloc_security)(void **sec); | ||
1651 | void (*ib_free_security)(void *sec); | ||
1652 | #endif /* CONFIG_SECURITY_INFINIBAND */ | ||
1653 | |||
1623 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 1654 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
1624 | int (*xfrm_policy_alloc_security)(struct xfrm_sec_ctx **ctxp, | 1655 | int (*xfrm_policy_alloc_security)(struct xfrm_sec_ctx **ctxp, |
1625 | struct xfrm_user_sec_ctx *sec_ctx, | 1656 | struct xfrm_user_sec_ctx *sec_ctx, |
@@ -1851,6 +1882,12 @@ struct security_hook_heads { | |||
1851 | struct list_head tun_dev_attach; | 1882 | struct list_head tun_dev_attach; |
1852 | struct list_head tun_dev_open; | 1883 | struct list_head tun_dev_open; |
1853 | #endif /* CONFIG_SECURITY_NETWORK */ | 1884 | #endif /* CONFIG_SECURITY_NETWORK */ |
1885 | #ifdef CONFIG_SECURITY_INFINIBAND | ||
1886 | struct list_head ib_pkey_access; | ||
1887 | struct list_head ib_endport_manage_subnet; | ||
1888 | struct list_head ib_alloc_security; | ||
1889 | struct list_head ib_free_security; | ||
1890 | #endif /* CONFIG_SECURITY_INFINIBAND */ | ||
1854 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 1891 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
1855 | struct list_head xfrm_policy_alloc_security; | 1892 | struct list_head xfrm_policy_alloc_security; |
1856 | struct list_head xfrm_policy_clone_security; | 1893 | struct list_head xfrm_policy_clone_security; |
diff --git a/include/linux/security.h b/include/linux/security.h index caf8b64d8b5c..b6ea1dc9cc9d 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
@@ -6,6 +6,7 @@ | |||
6 | * Copyright (C) 2001 Networks Associates Technology, Inc <ssmalley@nai.com> | 6 | * Copyright (C) 2001 Networks Associates Technology, Inc <ssmalley@nai.com> |
7 | * Copyright (C) 2001 James Morris <jmorris@intercode.com.au> | 7 | * Copyright (C) 2001 James Morris <jmorris@intercode.com.au> |
8 | * Copyright (C) 2001 Silicon Graphics, Inc. (Trust Technology Group) | 8 | * Copyright (C) 2001 Silicon Graphics, Inc. (Trust Technology Group) |
9 | * Copyright (C) 2016 Mellanox Techonologies | ||
9 | * | 10 | * |
10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by | 12 | * it under the terms of the GNU General Public License as published by |
@@ -68,6 +69,10 @@ struct audit_krule; | |||
68 | struct user_namespace; | 69 | struct user_namespace; |
69 | struct timezone; | 70 | struct timezone; |
70 | 71 | ||
72 | enum lsm_event { | ||
73 | LSM_POLICY_CHANGE, | ||
74 | }; | ||
75 | |||
71 | /* These functions are in security/commoncap.c */ | 76 | /* These functions are in security/commoncap.c */ |
72 | extern int cap_capable(const struct cred *cred, struct user_namespace *ns, | 77 | extern int cap_capable(const struct cred *cred, struct user_namespace *ns, |
73 | int cap, int audit); | 78 | int cap, int audit); |
@@ -163,6 +168,10 @@ struct security_mnt_opts { | |||
163 | int num_mnt_opts; | 168 | int num_mnt_opts; |
164 | }; | 169 | }; |
165 | 170 | ||
171 | int call_lsm_notifier(enum lsm_event event, void *data); | ||
172 | int register_lsm_notifier(struct notifier_block *nb); | ||
173 | int unregister_lsm_notifier(struct notifier_block *nb); | ||
174 | |||
166 | static inline void security_init_mnt_opts(struct security_mnt_opts *opts) | 175 | static inline void security_init_mnt_opts(struct security_mnt_opts *opts) |
167 | { | 176 | { |
168 | opts->mnt_opts = NULL; | 177 | opts->mnt_opts = NULL; |
@@ -240,7 +249,9 @@ int security_sb_set_mnt_opts(struct super_block *sb, | |||
240 | unsigned long kern_flags, | 249 | unsigned long kern_flags, |
241 | unsigned long *set_kern_flags); | 250 | unsigned long *set_kern_flags); |
242 | int security_sb_clone_mnt_opts(const struct super_block *oldsb, | 251 | int security_sb_clone_mnt_opts(const struct super_block *oldsb, |
243 | struct super_block *newsb); | 252 | struct super_block *newsb, |
253 | unsigned long kern_flags, | ||
254 | unsigned long *set_kern_flags); | ||
244 | int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts); | 255 | int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts); |
245 | int security_dentry_init_security(struct dentry *dentry, int mode, | 256 | int security_dentry_init_security(struct dentry *dentry, int mode, |
246 | const struct qstr *name, void **ctx, | 257 | const struct qstr *name, void **ctx, |
@@ -381,6 +392,21 @@ int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen); | |||
381 | struct security_mnt_opts { | 392 | struct security_mnt_opts { |
382 | }; | 393 | }; |
383 | 394 | ||
395 | static inline int call_lsm_notifier(enum lsm_event event, void *data) | ||
396 | { | ||
397 | return 0; | ||
398 | } | ||
399 | |||
400 | static inline int register_lsm_notifier(struct notifier_block *nb) | ||
401 | { | ||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | static inline int unregister_lsm_notifier(struct notifier_block *nb) | ||
406 | { | ||
407 | return 0; | ||
408 | } | ||
409 | |||
384 | static inline void security_init_mnt_opts(struct security_mnt_opts *opts) | 410 | static inline void security_init_mnt_opts(struct security_mnt_opts *opts) |
385 | { | 411 | { |
386 | } | 412 | } |
@@ -581,7 +607,9 @@ static inline int security_sb_set_mnt_opts(struct super_block *sb, | |||
581 | } | 607 | } |
582 | 608 | ||
583 | static inline int security_sb_clone_mnt_opts(const struct super_block *oldsb, | 609 | static inline int security_sb_clone_mnt_opts(const struct super_block *oldsb, |
584 | struct super_block *newsb) | 610 | struct super_block *newsb, |
611 | unsigned long kern_flags, | ||
612 | unsigned long *set_kern_flags) | ||
585 | { | 613 | { |
586 | return 0; | 614 | return 0; |
587 | } | 615 | } |
@@ -1406,6 +1434,32 @@ static inline int security_tun_dev_open(void *security) | |||
1406 | } | 1434 | } |
1407 | #endif /* CONFIG_SECURITY_NETWORK */ | 1435 | #endif /* CONFIG_SECURITY_NETWORK */ |
1408 | 1436 | ||
1437 | #ifdef CONFIG_SECURITY_INFINIBAND | ||
1438 | int security_ib_pkey_access(void *sec, u64 subnet_prefix, u16 pkey); | ||
1439 | int security_ib_endport_manage_subnet(void *sec, const char *name, u8 port_num); | ||
1440 | int security_ib_alloc_security(void **sec); | ||
1441 | void security_ib_free_security(void *sec); | ||
1442 | #else /* CONFIG_SECURITY_INFINIBAND */ | ||
1443 | static inline int security_ib_pkey_access(void *sec, u64 subnet_prefix, u16 pkey) | ||
1444 | { | ||
1445 | return 0; | ||
1446 | } | ||
1447 | |||
1448 | static inline int security_ib_endport_manage_subnet(void *sec, const char *dev_name, u8 port_num) | ||
1449 | { | ||
1450 | return 0; | ||
1451 | } | ||
1452 | |||
1453 | static inline int security_ib_alloc_security(void **sec) | ||
1454 | { | ||
1455 | return 0; | ||
1456 | } | ||
1457 | |||
1458 | static inline void security_ib_free_security(void *sec) | ||
1459 | { | ||
1460 | } | ||
1461 | #endif /* CONFIG_SECURITY_INFINIBAND */ | ||
1462 | |||
1409 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 1463 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
1410 | 1464 | ||
1411 | int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, | 1465 | int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, |
diff --git a/include/rdma/ib_mad.h b/include/rdma/ib_mad.h index d67b11b72029..2f4f1768ded4 100644 --- a/include/rdma/ib_mad.h +++ b/include/rdma/ib_mad.h | |||
@@ -575,6 +575,10 @@ struct ib_mad_agent { | |||
575 | u32 flags; | 575 | u32 flags; |
576 | u8 port_num; | 576 | u8 port_num; |
577 | u8 rmpp_version; | 577 | u8 rmpp_version; |
578 | void *security; | ||
579 | bool smp_allowed; | ||
580 | bool lsm_nb_reg; | ||
581 | struct notifier_block lsm_nb; | ||
578 | }; | 582 | }; |
579 | 583 | ||
580 | /** | 584 | /** |
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index ba8314ec5768..0e480a5630d4 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h | |||
@@ -1614,6 +1614,45 @@ struct ib_rwq_ind_table_init_attr { | |||
1614 | struct ib_wq **ind_tbl; | 1614 | struct ib_wq **ind_tbl; |
1615 | }; | 1615 | }; |
1616 | 1616 | ||
1617 | enum port_pkey_state { | ||
1618 | IB_PORT_PKEY_NOT_VALID = 0, | ||
1619 | IB_PORT_PKEY_VALID = 1, | ||
1620 | IB_PORT_PKEY_LISTED = 2, | ||
1621 | }; | ||
1622 | |||
1623 | struct ib_qp_security; | ||
1624 | |||
1625 | struct ib_port_pkey { | ||
1626 | enum port_pkey_state state; | ||
1627 | u16 pkey_index; | ||
1628 | u8 port_num; | ||
1629 | struct list_head qp_list; | ||
1630 | struct list_head to_error_list; | ||
1631 | struct ib_qp_security *sec; | ||
1632 | }; | ||
1633 | |||
1634 | struct ib_ports_pkeys { | ||
1635 | struct ib_port_pkey main; | ||
1636 | struct ib_port_pkey alt; | ||
1637 | }; | ||
1638 | |||
1639 | struct ib_qp_security { | ||
1640 | struct ib_qp *qp; | ||
1641 | struct ib_device *dev; | ||
1642 | /* Hold this mutex when changing port and pkey settings. */ | ||
1643 | struct mutex mutex; | ||
1644 | struct ib_ports_pkeys *ports_pkeys; | ||
1645 | /* A list of all open shared QP handles. Required to enforce security | ||
1646 | * properly for all users of a shared QP. | ||
1647 | */ | ||
1648 | struct list_head shared_qp_list; | ||
1649 | void *security; | ||
1650 | bool destroying; | ||
1651 | atomic_t error_list_count; | ||
1652 | struct completion error_complete; | ||
1653 | int error_comps_pending; | ||
1654 | }; | ||
1655 | |||
1617 | /* | 1656 | /* |
1618 | * @max_write_sge: Maximum SGE elements per RDMA WRITE request. | 1657 | * @max_write_sge: Maximum SGE elements per RDMA WRITE request. |
1619 | * @max_read_sge: Maximum SGE elements per RDMA READ request. | 1658 | * @max_read_sge: Maximum SGE elements per RDMA READ request. |
@@ -1643,6 +1682,7 @@ struct ib_qp { | |||
1643 | u32 max_read_sge; | 1682 | u32 max_read_sge; |
1644 | enum ib_qp_type qp_type; | 1683 | enum ib_qp_type qp_type; |
1645 | struct ib_rwq_ind_table *rwq_ind_tbl; | 1684 | struct ib_rwq_ind_table *rwq_ind_tbl; |
1685 | struct ib_qp_security *qp_sec; | ||
1646 | }; | 1686 | }; |
1647 | 1687 | ||
1648 | struct ib_mr { | 1688 | struct ib_mr { |
@@ -1891,6 +1931,7 @@ enum ib_mad_result { | |||
1891 | }; | 1931 | }; |
1892 | 1932 | ||
1893 | struct ib_port_cache { | 1933 | struct ib_port_cache { |
1934 | u64 subnet_prefix; | ||
1894 | struct ib_pkey_cache *pkey; | 1935 | struct ib_pkey_cache *pkey; |
1895 | struct ib_gid_table *gid; | 1936 | struct ib_gid_table *gid; |
1896 | u8 lmc; | 1937 | u8 lmc; |
@@ -1940,6 +1981,12 @@ struct rdma_netdev { | |||
1940 | union ib_gid *gid, u16 mlid); | 1981 | union ib_gid *gid, u16 mlid); |
1941 | }; | 1982 | }; |
1942 | 1983 | ||
1984 | struct ib_port_pkey_list { | ||
1985 | /* Lock to hold while modifying the list. */ | ||
1986 | spinlock_t list_lock; | ||
1987 | struct list_head pkey_list; | ||
1988 | }; | ||
1989 | |||
1943 | struct ib_device { | 1990 | struct ib_device { |
1944 | /* Do not access @dma_device directly from ULP nor from HW drivers. */ | 1991 | /* Do not access @dma_device directly from ULP nor from HW drivers. */ |
1945 | struct device *dma_device; | 1992 | struct device *dma_device; |
@@ -1963,6 +2010,8 @@ struct ib_device { | |||
1963 | 2010 | ||
1964 | int num_comp_vectors; | 2011 | int num_comp_vectors; |
1965 | 2012 | ||
2013 | struct ib_port_pkey_list *port_pkey_list; | ||
2014 | |||
1966 | struct iw_cm_verbs *iwcm; | 2015 | struct iw_cm_verbs *iwcm; |
1967 | 2016 | ||
1968 | /** | 2017 | /** |
diff --git a/security/Kconfig b/security/Kconfig index bdcbb92927ab..d540bfe73190 100644 --- a/security/Kconfig +++ b/security/Kconfig | |||
@@ -54,6 +54,15 @@ config SECURITY_NETWORK | |||
54 | implement socket and networking access controls. | 54 | implement socket and networking access controls. |
55 | If you are unsure how to answer this question, answer N. | 55 | If you are unsure how to answer this question, answer N. |
56 | 56 | ||
57 | config SECURITY_INFINIBAND | ||
58 | bool "Infiniband Security Hooks" | ||
59 | depends on SECURITY && INFINIBAND | ||
60 | help | ||
61 | This enables the Infiniband security hooks. | ||
62 | If enabled, a security module can use these hooks to | ||
63 | implement Infiniband access controls. | ||
64 | If you are unsure how to answer this question, answer N. | ||
65 | |||
57 | config SECURITY_NETWORK_XFRM | 66 | config SECURITY_NETWORK_XFRM |
58 | bool "XFRM (IPSec) Networking Security Hooks" | 67 | bool "XFRM (IPSec) Networking Security Hooks" |
59 | depends on XFRM && SECURITY_NETWORK | 68 | depends on XFRM && SECURITY_NETWORK |
diff --git a/security/lsm_audit.c b/security/lsm_audit.c index 37f04dadc8d6..28d4c3a528ab 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c | |||
@@ -410,6 +410,22 @@ static void dump_common_audit_data(struct audit_buffer *ab, | |||
410 | audit_log_format(ab, " kmod="); | 410 | audit_log_format(ab, " kmod="); |
411 | audit_log_untrustedstring(ab, a->u.kmod_name); | 411 | audit_log_untrustedstring(ab, a->u.kmod_name); |
412 | break; | 412 | break; |
413 | case LSM_AUDIT_DATA_IBPKEY: { | ||
414 | struct in6_addr sbn_pfx; | ||
415 | |||
416 | memset(&sbn_pfx.s6_addr, 0, | ||
417 | sizeof(sbn_pfx.s6_addr)); | ||
418 | memcpy(&sbn_pfx.s6_addr, &a->u.ibpkey->subnet_prefix, | ||
419 | sizeof(a->u.ibpkey->subnet_prefix)); | ||
420 | audit_log_format(ab, " pkey=0x%x subnet_prefix=%pI6c", | ||
421 | a->u.ibpkey->pkey, &sbn_pfx); | ||
422 | break; | ||
423 | } | ||
424 | case LSM_AUDIT_DATA_IBENDPORT: | ||
425 | audit_log_format(ab, " device=%s port_num=%u", | ||
426 | a->u.ibendport->dev_name, | ||
427 | a->u.ibendport->port); | ||
428 | break; | ||
413 | } /* switch (a->type) */ | 429 | } /* switch (a->type) */ |
414 | } | 430 | } |
415 | 431 | ||
diff --git a/security/security.c b/security/security.c index 38316bb28b16..30132378d103 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -4,6 +4,7 @@ | |||
4 | * Copyright (C) 2001 WireX Communications, Inc <chris@wirex.com> | 4 | * Copyright (C) 2001 WireX Communications, Inc <chris@wirex.com> |
5 | * Copyright (C) 2001-2002 Greg Kroah-Hartman <greg@kroah.com> | 5 | * Copyright (C) 2001-2002 Greg Kroah-Hartman <greg@kroah.com> |
6 | * Copyright (C) 2001 Networks Associates Technology, Inc <ssmalley@nai.com> | 6 | * Copyright (C) 2001 Networks Associates Technology, Inc <ssmalley@nai.com> |
7 | * Copyright (C) 2016 Mellanox Technologies | ||
7 | * | 8 | * |
8 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by | 10 | * it under the terms of the GNU General Public License as published by |
@@ -34,6 +35,8 @@ | |||
34 | #define SECURITY_NAME_MAX 10 | 35 | #define SECURITY_NAME_MAX 10 |
35 | 36 | ||
36 | struct security_hook_heads security_hook_heads __lsm_ro_after_init; | 37 | struct security_hook_heads security_hook_heads __lsm_ro_after_init; |
38 | static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain); | ||
39 | |||
37 | char *lsm_names; | 40 | char *lsm_names; |
38 | /* Boot-time LSM user choice */ | 41 | /* Boot-time LSM user choice */ |
39 | static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] = | 42 | static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] = |
@@ -165,6 +168,24 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count, | |||
165 | panic("%s - Cannot get early memory.\n", __func__); | 168 | panic("%s - Cannot get early memory.\n", __func__); |
166 | } | 169 | } |
167 | 170 | ||
171 | int call_lsm_notifier(enum lsm_event event, void *data) | ||
172 | { | ||
173 | return atomic_notifier_call_chain(&lsm_notifier_chain, event, data); | ||
174 | } | ||
175 | EXPORT_SYMBOL(call_lsm_notifier); | ||
176 | |||
177 | int register_lsm_notifier(struct notifier_block *nb) | ||
178 | { | ||
179 | return atomic_notifier_chain_register(&lsm_notifier_chain, nb); | ||
180 | } | ||
181 | EXPORT_SYMBOL(register_lsm_notifier); | ||
182 | |||
183 | int unregister_lsm_notifier(struct notifier_block *nb) | ||
184 | { | ||
185 | return atomic_notifier_chain_unregister(&lsm_notifier_chain, nb); | ||
186 | } | ||
187 | EXPORT_SYMBOL(unregister_lsm_notifier); | ||
188 | |||
168 | /* | 189 | /* |
169 | * Hook list operation macros. | 190 | * Hook list operation macros. |
170 | * | 191 | * |
@@ -399,9 +420,12 @@ int security_sb_set_mnt_opts(struct super_block *sb, | |||
399 | EXPORT_SYMBOL(security_sb_set_mnt_opts); | 420 | EXPORT_SYMBOL(security_sb_set_mnt_opts); |
400 | 421 | ||
401 | int security_sb_clone_mnt_opts(const struct super_block *oldsb, | 422 | int security_sb_clone_mnt_opts(const struct super_block *oldsb, |
402 | struct super_block *newsb) | 423 | struct super_block *newsb, |
424 | unsigned long kern_flags, | ||
425 | unsigned long *set_kern_flags) | ||
403 | { | 426 | { |
404 | return call_int_hook(sb_clone_mnt_opts, 0, oldsb, newsb); | 427 | return call_int_hook(sb_clone_mnt_opts, 0, oldsb, newsb, |
428 | kern_flags, set_kern_flags); | ||
405 | } | 429 | } |
406 | EXPORT_SYMBOL(security_sb_clone_mnt_opts); | 430 | EXPORT_SYMBOL(security_sb_clone_mnt_opts); |
407 | 431 | ||
@@ -1515,6 +1539,33 @@ EXPORT_SYMBOL(security_tun_dev_open); | |||
1515 | 1539 | ||
1516 | #endif /* CONFIG_SECURITY_NETWORK */ | 1540 | #endif /* CONFIG_SECURITY_NETWORK */ |
1517 | 1541 | ||
1542 | #ifdef CONFIG_SECURITY_INFINIBAND | ||
1543 | |||
1544 | int security_ib_pkey_access(void *sec, u64 subnet_prefix, u16 pkey) | ||
1545 | { | ||
1546 | return call_int_hook(ib_pkey_access, 0, sec, subnet_prefix, pkey); | ||
1547 | } | ||
1548 | EXPORT_SYMBOL(security_ib_pkey_access); | ||
1549 | |||
1550 | int security_ib_endport_manage_subnet(void *sec, const char *dev_name, u8 port_num) | ||
1551 | { | ||
1552 | return call_int_hook(ib_endport_manage_subnet, 0, sec, dev_name, port_num); | ||
1553 | } | ||
1554 | EXPORT_SYMBOL(security_ib_endport_manage_subnet); | ||
1555 | |||
1556 | int security_ib_alloc_security(void **sec) | ||
1557 | { | ||
1558 | return call_int_hook(ib_alloc_security, 0, sec); | ||
1559 | } | ||
1560 | EXPORT_SYMBOL(security_ib_alloc_security); | ||
1561 | |||
1562 | void security_ib_free_security(void *sec) | ||
1563 | { | ||
1564 | call_void_hook(ib_free_security, sec); | ||
1565 | } | ||
1566 | EXPORT_SYMBOL(security_ib_free_security); | ||
1567 | #endif /* CONFIG_SECURITY_INFINIBAND */ | ||
1568 | |||
1518 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 1569 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
1519 | 1570 | ||
1520 | int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, | 1571 | int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, |
diff --git a/security/selinux/Makefile b/security/selinux/Makefile index 3411c33e2a44..ff5895ede96f 100644 --- a/security/selinux/Makefile +++ b/security/selinux/Makefile | |||
@@ -5,7 +5,7 @@ | |||
5 | obj-$(CONFIG_SECURITY_SELINUX) := selinux.o | 5 | obj-$(CONFIG_SECURITY_SELINUX) := selinux.o |
6 | 6 | ||
7 | selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o \ | 7 | selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o \ |
8 | netnode.o netport.o exports.o \ | 8 | netnode.o netport.o ibpkey.o exports.o \ |
9 | ss/ebitmap.o ss/hashtab.o ss/symtab.o ss/sidtab.o ss/avtab.o \ | 9 | ss/ebitmap.o ss/hashtab.o ss/symtab.o ss/sidtab.o ss/avtab.o \ |
10 | ss/policydb.o ss/services.o ss/conditional.o ss/mls.o ss/status.o | 10 | ss/policydb.o ss/services.o ss/conditional.o ss/mls.o ss/status.o |
11 | 11 | ||
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index e67a526d1f30..3a06afbd2f6f 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -17,6 +17,7 @@ | |||
17 | * Paul Moore <paul@paul-moore.com> | 17 | * Paul Moore <paul@paul-moore.com> |
18 | * Copyright (C) 2007 Hitachi Software Engineering Co., Ltd. | 18 | * Copyright (C) 2007 Hitachi Software Engineering Co., Ltd. |
19 | * Yuichi Nakamura <ynakam@hitachisoft.jp> | 19 | * Yuichi Nakamura <ynakam@hitachisoft.jp> |
20 | * Copyright (C) 2016 Mellanox Technologies | ||
20 | * | 21 | * |
21 | * This program is free software; you can redistribute it and/or modify | 22 | * This program is free software; you can redistribute it and/or modify |
22 | * it under the terms of the GNU General Public License version 2, | 23 | * it under the terms of the GNU General Public License version 2, |
@@ -90,6 +91,7 @@ | |||
90 | #include "netif.h" | 91 | #include "netif.h" |
91 | #include "netnode.h" | 92 | #include "netnode.h" |
92 | #include "netport.h" | 93 | #include "netport.h" |
94 | #include "ibpkey.h" | ||
93 | #include "xfrm.h" | 95 | #include "xfrm.h" |
94 | #include "netlabel.h" | 96 | #include "netlabel.h" |
95 | #include "audit.h" | 97 | #include "audit.h" |
@@ -171,6 +173,16 @@ static int selinux_netcache_avc_callback(u32 event) | |||
171 | return 0; | 173 | return 0; |
172 | } | 174 | } |
173 | 175 | ||
176 | static int selinux_lsm_notifier_avc_callback(u32 event) | ||
177 | { | ||
178 | if (event == AVC_CALLBACK_RESET) { | ||
179 | sel_ib_pkey_flush(); | ||
180 | call_lsm_notifier(LSM_POLICY_CHANGE, NULL); | ||
181 | } | ||
182 | |||
183 | return 0; | ||
184 | } | ||
185 | |||
174 | /* | 186 | /* |
175 | * initialise the security for the init task | 187 | * initialise the security for the init task |
176 | */ | 188 | */ |
@@ -398,18 +410,6 @@ static void superblock_free_security(struct super_block *sb) | |||
398 | kfree(sbsec); | 410 | kfree(sbsec); |
399 | } | 411 | } |
400 | 412 | ||
401 | /* The file system's label must be initialized prior to use. */ | ||
402 | |||
403 | static const char *labeling_behaviors[7] = { | ||
404 | "uses xattr", | ||
405 | "uses transition SIDs", | ||
406 | "uses task SIDs", | ||
407 | "uses genfs_contexts", | ||
408 | "not configured for labeling", | ||
409 | "uses mountpoint labeling", | ||
410 | "uses native labeling", | ||
411 | }; | ||
412 | |||
413 | static inline int inode_doinit(struct inode *inode) | 413 | static inline int inode_doinit(struct inode *inode) |
414 | { | 414 | { |
415 | return inode_doinit_with_dentry(inode, NULL); | 415 | return inode_doinit_with_dentry(inode, NULL); |
@@ -524,13 +524,17 @@ static int sb_finish_set_opts(struct super_block *sb) | |||
524 | } | 524 | } |
525 | } | 525 | } |
526 | 526 | ||
527 | if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) | ||
528 | printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n", | ||
529 | sb->s_id, sb->s_type->name); | ||
530 | |||
531 | sbsec->flags |= SE_SBINITIALIZED; | 527 | sbsec->flags |= SE_SBINITIALIZED; |
528 | |||
529 | /* | ||
530 | * Explicitly set or clear SBLABEL_MNT. It's not sufficient to simply | ||
531 | * leave the flag untouched because sb_clone_mnt_opts might be handing | ||
532 | * us a superblock that needs the flag to be cleared. | ||
533 | */ | ||
532 | if (selinux_is_sblabel_mnt(sb)) | 534 | if (selinux_is_sblabel_mnt(sb)) |
533 | sbsec->flags |= SBLABEL_MNT; | 535 | sbsec->flags |= SBLABEL_MNT; |
536 | else | ||
537 | sbsec->flags &= ~SBLABEL_MNT; | ||
534 | 538 | ||
535 | /* Initialize the root inode. */ | 539 | /* Initialize the root inode. */ |
536 | rc = inode_doinit_with_dentry(root_inode, root); | 540 | rc = inode_doinit_with_dentry(root_inode, root); |
@@ -809,6 +813,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, | |||
809 | sbsec->flags |= SE_SBPROC | SE_SBGENFS; | 813 | sbsec->flags |= SE_SBPROC | SE_SBGENFS; |
810 | 814 | ||
811 | if (!strcmp(sb->s_type->name, "debugfs") || | 815 | if (!strcmp(sb->s_type->name, "debugfs") || |
816 | !strcmp(sb->s_type->name, "tracefs") || | ||
812 | !strcmp(sb->s_type->name, "sysfs") || | 817 | !strcmp(sb->s_type->name, "sysfs") || |
813 | !strcmp(sb->s_type->name, "pstore")) | 818 | !strcmp(sb->s_type->name, "pstore")) |
814 | sbsec->flags |= SE_SBGENFS; | 819 | sbsec->flags |= SE_SBGENFS; |
@@ -963,8 +968,11 @@ mismatch: | |||
963 | } | 968 | } |
964 | 969 | ||
965 | static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb, | 970 | static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb, |
966 | struct super_block *newsb) | 971 | struct super_block *newsb, |
972 | unsigned long kern_flags, | ||
973 | unsigned long *set_kern_flags) | ||
967 | { | 974 | { |
975 | int rc = 0; | ||
968 | const struct superblock_security_struct *oldsbsec = oldsb->s_security; | 976 | const struct superblock_security_struct *oldsbsec = oldsb->s_security; |
969 | struct superblock_security_struct *newsbsec = newsb->s_security; | 977 | struct superblock_security_struct *newsbsec = newsb->s_security; |
970 | 978 | ||
@@ -979,6 +987,13 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb, | |||
979 | if (!ss_initialized) | 987 | if (!ss_initialized) |
980 | return 0; | 988 | return 0; |
981 | 989 | ||
990 | /* | ||
991 | * Specifying internal flags without providing a place to | ||
992 | * place the results is not allowed. | ||
993 | */ | ||
994 | if (kern_flags && !set_kern_flags) | ||
995 | return -EINVAL; | ||
996 | |||
982 | /* how can we clone if the old one wasn't set up?? */ | 997 | /* how can we clone if the old one wasn't set up?? */ |
983 | BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED)); | 998 | BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED)); |
984 | 999 | ||
@@ -994,6 +1009,18 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb, | |||
994 | newsbsec->def_sid = oldsbsec->def_sid; | 1009 | newsbsec->def_sid = oldsbsec->def_sid; |
995 | newsbsec->behavior = oldsbsec->behavior; | 1010 | newsbsec->behavior = oldsbsec->behavior; |
996 | 1011 | ||
1012 | if (newsbsec->behavior == SECURITY_FS_USE_NATIVE && | ||
1013 | !(kern_flags & SECURITY_LSM_NATIVE_LABELS) && !set_context) { | ||
1014 | rc = security_fs_use(newsb); | ||
1015 | if (rc) | ||
1016 | goto out; | ||
1017 | } | ||
1018 | |||
1019 | if (kern_flags & SECURITY_LSM_NATIVE_LABELS && !set_context) { | ||
1020 | newsbsec->behavior = SECURITY_FS_USE_NATIVE; | ||
1021 | *set_kern_flags |= SECURITY_LSM_NATIVE_LABELS; | ||
1022 | } | ||
1023 | |||
997 | if (set_context) { | 1024 | if (set_context) { |
998 | u32 sid = oldsbsec->mntpoint_sid; | 1025 | u32 sid = oldsbsec->mntpoint_sid; |
999 | 1026 | ||
@@ -1013,8 +1040,9 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb, | |||
1013 | } | 1040 | } |
1014 | 1041 | ||
1015 | sb_finish_set_opts(newsb); | 1042 | sb_finish_set_opts(newsb); |
1043 | out: | ||
1016 | mutex_unlock(&newsbsec->lock); | 1044 | mutex_unlock(&newsbsec->lock); |
1017 | return 0; | 1045 | return rc; |
1018 | } | 1046 | } |
1019 | 1047 | ||
1020 | static int selinux_parse_opts_str(char *options, | 1048 | static int selinux_parse_opts_str(char *options, |
@@ -2063,8 +2091,9 @@ static inline u32 file_to_av(struct file *file) | |||
2063 | static inline u32 open_file_to_av(struct file *file) | 2091 | static inline u32 open_file_to_av(struct file *file) |
2064 | { | 2092 | { |
2065 | u32 av = file_to_av(file); | 2093 | u32 av = file_to_av(file); |
2094 | struct inode *inode = file_inode(file); | ||
2066 | 2095 | ||
2067 | if (selinux_policycap_openperm) | 2096 | if (selinux_policycap_openperm && inode->i_sb->s_magic != SOCKFS_MAGIC) |
2068 | av |= FILE__OPEN; | 2097 | av |= FILE__OPEN; |
2069 | 2098 | ||
2070 | return av; | 2099 | return av; |
@@ -3059,6 +3088,7 @@ static int selinux_inode_permission(struct inode *inode, int mask) | |||
3059 | static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) | 3088 | static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) |
3060 | { | 3089 | { |
3061 | const struct cred *cred = current_cred(); | 3090 | const struct cred *cred = current_cred(); |
3091 | struct inode *inode = d_backing_inode(dentry); | ||
3062 | unsigned int ia_valid = iattr->ia_valid; | 3092 | unsigned int ia_valid = iattr->ia_valid; |
3063 | __u32 av = FILE__WRITE; | 3093 | __u32 av = FILE__WRITE; |
3064 | 3094 | ||
@@ -3074,8 +3104,10 @@ static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) | |||
3074 | ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET)) | 3104 | ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET)) |
3075 | return dentry_has_perm(cred, dentry, FILE__SETATTR); | 3105 | return dentry_has_perm(cred, dentry, FILE__SETATTR); |
3076 | 3106 | ||
3077 | if (selinux_policycap_openperm && (ia_valid & ATTR_SIZE) | 3107 | if (selinux_policycap_openperm && |
3078 | && !(ia_valid & ATTR_FILE)) | 3108 | inode->i_sb->s_magic != SOCKFS_MAGIC && |
3109 | (ia_valid & ATTR_SIZE) && | ||
3110 | !(ia_valid & ATTR_FILE)) | ||
3079 | av |= FILE__OPEN; | 3111 | av |= FILE__OPEN; |
3080 | 3112 | ||
3081 | return dentry_has_perm(cred, dentry, av); | 3113 | return dentry_has_perm(cred, dentry, av); |
@@ -3107,6 +3139,18 @@ static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name) | |||
3107 | return dentry_has_perm(cred, dentry, FILE__SETATTR); | 3139 | return dentry_has_perm(cred, dentry, FILE__SETATTR); |
3108 | } | 3140 | } |
3109 | 3141 | ||
3142 | static bool has_cap_mac_admin(bool audit) | ||
3143 | { | ||
3144 | const struct cred *cred = current_cred(); | ||
3145 | int cap_audit = audit ? SECURITY_CAP_AUDIT : SECURITY_CAP_NOAUDIT; | ||
3146 | |||
3147 | if (cap_capable(cred, &init_user_ns, CAP_MAC_ADMIN, cap_audit)) | ||
3148 | return false; | ||
3149 | if (cred_has_capability(cred, CAP_MAC_ADMIN, cap_audit, true)) | ||
3150 | return false; | ||
3151 | return true; | ||
3152 | } | ||
3153 | |||
3110 | static int selinux_inode_setxattr(struct dentry *dentry, const char *name, | 3154 | static int selinux_inode_setxattr(struct dentry *dentry, const char *name, |
3111 | const void *value, size_t size, int flags) | 3155 | const void *value, size_t size, int flags) |
3112 | { | 3156 | { |
@@ -3138,7 +3182,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, | |||
3138 | 3182 | ||
3139 | rc = security_context_to_sid(value, size, &newsid, GFP_KERNEL); | 3183 | rc = security_context_to_sid(value, size, &newsid, GFP_KERNEL); |
3140 | if (rc == -EINVAL) { | 3184 | if (rc == -EINVAL) { |
3141 | if (!capable(CAP_MAC_ADMIN)) { | 3185 | if (!has_cap_mac_admin(true)) { |
3142 | struct audit_buffer *ab; | 3186 | struct audit_buffer *ab; |
3143 | size_t audit_size; | 3187 | size_t audit_size; |
3144 | const char *str; | 3188 | const char *str; |
@@ -3264,13 +3308,8 @@ static int selinux_inode_getsecurity(struct inode *inode, const char *name, void | |||
3264 | * and lack of permission just means that we fall back to the | 3308 | * and lack of permission just means that we fall back to the |
3265 | * in-core context value, not a denial. | 3309 | * in-core context value, not a denial. |
3266 | */ | 3310 | */ |
3267 | error = cap_capable(current_cred(), &init_user_ns, CAP_MAC_ADMIN, | ||
3268 | SECURITY_CAP_NOAUDIT); | ||
3269 | if (!error) | ||
3270 | error = cred_has_capability(current_cred(), CAP_MAC_ADMIN, | ||
3271 | SECURITY_CAP_NOAUDIT, true); | ||
3272 | isec = inode_security(inode); | 3311 | isec = inode_security(inode); |
3273 | if (!error) | 3312 | if (has_cap_mac_admin(false)) |
3274 | error = security_sid_to_context_force(isec->sid, &context, | 3313 | error = security_sid_to_context_force(isec->sid, &context, |
3275 | &size); | 3314 | &size); |
3276 | else | 3315 | else |
@@ -3550,6 +3589,18 @@ static int selinux_mmap_addr(unsigned long addr) | |||
3550 | static int selinux_mmap_file(struct file *file, unsigned long reqprot, | 3589 | static int selinux_mmap_file(struct file *file, unsigned long reqprot, |
3551 | unsigned long prot, unsigned long flags) | 3590 | unsigned long prot, unsigned long flags) |
3552 | { | 3591 | { |
3592 | struct common_audit_data ad; | ||
3593 | int rc; | ||
3594 | |||
3595 | if (file) { | ||
3596 | ad.type = LSM_AUDIT_DATA_FILE; | ||
3597 | ad.u.file = file; | ||
3598 | rc = inode_has_perm(current_cred(), file_inode(file), | ||
3599 | FILE__MAP, &ad); | ||
3600 | if (rc) | ||
3601 | return rc; | ||
3602 | } | ||
3603 | |||
3553 | if (selinux_checkreqprot) | 3604 | if (selinux_checkreqprot) |
3554 | prot = reqprot; | 3605 | prot = reqprot; |
3555 | 3606 | ||
@@ -3710,7 +3761,8 @@ static int selinux_file_open(struct file *file, const struct cred *cred) | |||
3710 | 3761 | ||
3711 | /* task security operations */ | 3762 | /* task security operations */ |
3712 | 3763 | ||
3713 | static int selinux_task_create(unsigned long clone_flags) | 3764 | static int selinux_task_alloc(struct task_struct *task, |
3765 | unsigned long clone_flags) | ||
3714 | { | 3766 | { |
3715 | u32 sid = current_sid(); | 3767 | u32 sid = current_sid(); |
3716 | 3768 | ||
@@ -5918,7 +5970,7 @@ static int selinux_setprocattr(const char *name, void *value, size_t size) | |||
5918 | } | 5970 | } |
5919 | error = security_context_to_sid(value, size, &sid, GFP_KERNEL); | 5971 | error = security_context_to_sid(value, size, &sid, GFP_KERNEL); |
5920 | if (error == -EINVAL && !strcmp(name, "fscreate")) { | 5972 | if (error == -EINVAL && !strcmp(name, "fscreate")) { |
5921 | if (!capable(CAP_MAC_ADMIN)) { | 5973 | if (!has_cap_mac_admin(true)) { |
5922 | struct audit_buffer *ab; | 5974 | struct audit_buffer *ab; |
5923 | size_t audit_size; | 5975 | size_t audit_size; |
5924 | 5976 | ||
@@ -6128,7 +6180,70 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer) | |||
6128 | *_buffer = context; | 6180 | *_buffer = context; |
6129 | return rc; | 6181 | return rc; |
6130 | } | 6182 | } |
6183 | #endif | ||
6184 | |||
6185 | #ifdef CONFIG_SECURITY_INFINIBAND | ||
6186 | static int selinux_ib_pkey_access(void *ib_sec, u64 subnet_prefix, u16 pkey_val) | ||
6187 | { | ||
6188 | struct common_audit_data ad; | ||
6189 | int err; | ||
6190 | u32 sid = 0; | ||
6191 | struct ib_security_struct *sec = ib_sec; | ||
6192 | struct lsm_ibpkey_audit ibpkey; | ||
6193 | |||
6194 | err = sel_ib_pkey_sid(subnet_prefix, pkey_val, &sid); | ||
6195 | if (err) | ||
6196 | return err; | ||
6197 | |||
6198 | ad.type = LSM_AUDIT_DATA_IBPKEY; | ||
6199 | ibpkey.subnet_prefix = subnet_prefix; | ||
6200 | ibpkey.pkey = pkey_val; | ||
6201 | ad.u.ibpkey = &ibpkey; | ||
6202 | return avc_has_perm(sec->sid, sid, | ||
6203 | SECCLASS_INFINIBAND_PKEY, | ||
6204 | INFINIBAND_PKEY__ACCESS, &ad); | ||
6205 | } | ||
6206 | |||
6207 | static int selinux_ib_endport_manage_subnet(void *ib_sec, const char *dev_name, | ||
6208 | u8 port_num) | ||
6209 | { | ||
6210 | struct common_audit_data ad; | ||
6211 | int err; | ||
6212 | u32 sid = 0; | ||
6213 | struct ib_security_struct *sec = ib_sec; | ||
6214 | struct lsm_ibendport_audit ibendport; | ||
6215 | |||
6216 | err = security_ib_endport_sid(dev_name, port_num, &sid); | ||
6217 | |||
6218 | if (err) | ||
6219 | return err; | ||
6220 | |||
6221 | ad.type = LSM_AUDIT_DATA_IBENDPORT; | ||
6222 | strncpy(ibendport.dev_name, dev_name, sizeof(ibendport.dev_name)); | ||
6223 | ibendport.port = port_num; | ||
6224 | ad.u.ibendport = &ibendport; | ||
6225 | return avc_has_perm(sec->sid, sid, | ||
6226 | SECCLASS_INFINIBAND_ENDPORT, | ||
6227 | INFINIBAND_ENDPORT__MANAGE_SUBNET, &ad); | ||
6228 | } | ||
6229 | |||
6230 | static int selinux_ib_alloc_security(void **ib_sec) | ||
6231 | { | ||
6232 | struct ib_security_struct *sec; | ||
6131 | 6233 | ||
6234 | sec = kzalloc(sizeof(*sec), GFP_KERNEL); | ||
6235 | if (!sec) | ||
6236 | return -ENOMEM; | ||
6237 | sec->sid = current_sid(); | ||
6238 | |||
6239 | *ib_sec = sec; | ||
6240 | return 0; | ||
6241 | } | ||
6242 | |||
6243 | static void selinux_ib_free_security(void *ib_sec) | ||
6244 | { | ||
6245 | kfree(ib_sec); | ||
6246 | } | ||
6132 | #endif | 6247 | #endif |
6133 | 6248 | ||
6134 | static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { | 6249 | static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { |
@@ -6213,7 +6328,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { | |||
6213 | 6328 | ||
6214 | LSM_HOOK_INIT(file_open, selinux_file_open), | 6329 | LSM_HOOK_INIT(file_open, selinux_file_open), |
6215 | 6330 | ||
6216 | LSM_HOOK_INIT(task_create, selinux_task_create), | 6331 | LSM_HOOK_INIT(task_alloc, selinux_task_alloc), |
6217 | LSM_HOOK_INIT(cred_alloc_blank, selinux_cred_alloc_blank), | 6332 | LSM_HOOK_INIT(cred_alloc_blank, selinux_cred_alloc_blank), |
6218 | LSM_HOOK_INIT(cred_free, selinux_cred_free), | 6333 | LSM_HOOK_INIT(cred_free, selinux_cred_free), |
6219 | LSM_HOOK_INIT(cred_prepare, selinux_cred_prepare), | 6334 | LSM_HOOK_INIT(cred_prepare, selinux_cred_prepare), |
@@ -6315,7 +6430,13 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { | |||
6315 | LSM_HOOK_INIT(tun_dev_attach_queue, selinux_tun_dev_attach_queue), | 6430 | LSM_HOOK_INIT(tun_dev_attach_queue, selinux_tun_dev_attach_queue), |
6316 | LSM_HOOK_INIT(tun_dev_attach, selinux_tun_dev_attach), | 6431 | LSM_HOOK_INIT(tun_dev_attach, selinux_tun_dev_attach), |
6317 | LSM_HOOK_INIT(tun_dev_open, selinux_tun_dev_open), | 6432 | LSM_HOOK_INIT(tun_dev_open, selinux_tun_dev_open), |
6318 | 6433 | #ifdef CONFIG_SECURITY_INFINIBAND | |
6434 | LSM_HOOK_INIT(ib_pkey_access, selinux_ib_pkey_access), | ||
6435 | LSM_HOOK_INIT(ib_endport_manage_subnet, | ||
6436 | selinux_ib_endport_manage_subnet), | ||
6437 | LSM_HOOK_INIT(ib_alloc_security, selinux_ib_alloc_security), | ||
6438 | LSM_HOOK_INIT(ib_free_security, selinux_ib_free_security), | ||
6439 | #endif | ||
6319 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 6440 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
6320 | LSM_HOOK_INIT(xfrm_policy_alloc_security, selinux_xfrm_policy_alloc), | 6441 | LSM_HOOK_INIT(xfrm_policy_alloc_security, selinux_xfrm_policy_alloc), |
6321 | LSM_HOOK_INIT(xfrm_policy_clone_security, selinux_xfrm_policy_clone), | 6442 | LSM_HOOK_INIT(xfrm_policy_clone_security, selinux_xfrm_policy_clone), |
@@ -6379,6 +6500,9 @@ static __init int selinux_init(void) | |||
6379 | if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET)) | 6500 | if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET)) |
6380 | panic("SELinux: Unable to register AVC netcache callback\n"); | 6501 | panic("SELinux: Unable to register AVC netcache callback\n"); |
6381 | 6502 | ||
6503 | if (avc_add_callback(selinux_lsm_notifier_avc_callback, AVC_CALLBACK_RESET)) | ||
6504 | panic("SELinux: Unable to register AVC LSM notifier callback\n"); | ||
6505 | |||
6382 | if (selinux_enforcing) | 6506 | if (selinux_enforcing) |
6383 | printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n"); | 6507 | printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n"); |
6384 | else | 6508 | else |
@@ -6448,6 +6572,23 @@ static struct nf_hook_ops selinux_nf_ops[] = { | |||
6448 | #endif /* IPV6 */ | 6572 | #endif /* IPV6 */ |
6449 | }; | 6573 | }; |
6450 | 6574 | ||
6575 | static int __net_init selinux_nf_register(struct net *net) | ||
6576 | { | ||
6577 | return nf_register_net_hooks(net, selinux_nf_ops, | ||
6578 | ARRAY_SIZE(selinux_nf_ops)); | ||
6579 | } | ||
6580 | |||
6581 | static void __net_exit selinux_nf_unregister(struct net *net) | ||
6582 | { | ||
6583 | nf_unregister_net_hooks(net, selinux_nf_ops, | ||
6584 | ARRAY_SIZE(selinux_nf_ops)); | ||
6585 | } | ||
6586 | |||
6587 | static struct pernet_operations selinux_net_ops = { | ||
6588 | .init = selinux_nf_register, | ||
6589 | .exit = selinux_nf_unregister, | ||
6590 | }; | ||
6591 | |||
6451 | static int __init selinux_nf_ip_init(void) | 6592 | static int __init selinux_nf_ip_init(void) |
6452 | { | 6593 | { |
6453 | int err; | 6594 | int err; |
@@ -6457,13 +6598,12 @@ static int __init selinux_nf_ip_init(void) | |||
6457 | 6598 | ||
6458 | printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n"); | 6599 | printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n"); |
6459 | 6600 | ||
6460 | err = nf_register_hooks(selinux_nf_ops, ARRAY_SIZE(selinux_nf_ops)); | 6601 | err = register_pernet_subsys(&selinux_net_ops); |
6461 | if (err) | 6602 | if (err) |
6462 | panic("SELinux: nf_register_hooks: error %d\n", err); | 6603 | panic("SELinux: register_pernet_subsys: error %d\n", err); |
6463 | 6604 | ||
6464 | return 0; | 6605 | return 0; |
6465 | } | 6606 | } |
6466 | |||
6467 | __initcall(selinux_nf_ip_init); | 6607 | __initcall(selinux_nf_ip_init); |
6468 | 6608 | ||
6469 | #ifdef CONFIG_SECURITY_SELINUX_DISABLE | 6609 | #ifdef CONFIG_SECURITY_SELINUX_DISABLE |
@@ -6471,7 +6611,7 @@ static void selinux_nf_ip_exit(void) | |||
6471 | { | 6611 | { |
6472 | printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n"); | 6612 | printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n"); |
6473 | 6613 | ||
6474 | nf_unregister_hooks(selinux_nf_ops, ARRAY_SIZE(selinux_nf_ops)); | 6614 | unregister_pernet_subsys(&selinux_net_ops); |
6475 | } | 6615 | } |
6476 | #endif | 6616 | #endif |
6477 | 6617 | ||
diff --git a/security/selinux/ibpkey.c b/security/selinux/ibpkey.c new file mode 100644 index 000000000000..e3614ee5f1c0 --- /dev/null +++ b/security/selinux/ibpkey.c | |||
@@ -0,0 +1,245 @@ | |||
1 | /* | ||
2 | * Pkey table | ||
3 | * | ||
4 | * SELinux must keep a mapping of Infinband PKEYs to labels/SIDs. This | ||
5 | * mapping is maintained as part of the normal policy but a fast cache is | ||
6 | * needed to reduce the lookup overhead. | ||
7 | * | ||
8 | * This code is heavily based on the "netif" and "netport" concept originally | ||
9 | * developed by | ||
10 | * James Morris <jmorris@redhat.com> and | ||
11 | * Paul Moore <paul@paul-moore.com> | ||
12 | * (see security/selinux/netif.c and security/selinux/netport.c for more | ||
13 | * information) | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | /* | ||
18 | * (c) Mellanox Technologies, 2016 | ||
19 | * | ||
20 | * This program is free software: you can redistribute it and/or modify | ||
21 | * it under the terms of version 2 of the GNU General Public License as | ||
22 | * published by the Free Software Foundation. | ||
23 | * | ||
24 | * This program is distributed in the hope that it will be useful, | ||
25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
27 | * GNU General Public License for more details. | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #include <linux/types.h> | ||
32 | #include <linux/rcupdate.h> | ||
33 | #include <linux/list.h> | ||
34 | #include <linux/spinlock.h> | ||
35 | |||
36 | #include "ibpkey.h" | ||
37 | #include "objsec.h" | ||
38 | |||
39 | #define SEL_PKEY_HASH_SIZE 256 | ||
40 | #define SEL_PKEY_HASH_BKT_LIMIT 16 | ||
41 | |||
42 | struct sel_ib_pkey_bkt { | ||
43 | int size; | ||
44 | struct list_head list; | ||
45 | }; | ||
46 | |||
47 | struct sel_ib_pkey { | ||
48 | struct pkey_security_struct psec; | ||
49 | struct list_head list; | ||
50 | struct rcu_head rcu; | ||
51 | }; | ||
52 | |||
53 | static LIST_HEAD(sel_ib_pkey_list); | ||
54 | static DEFINE_SPINLOCK(sel_ib_pkey_lock); | ||
55 | static struct sel_ib_pkey_bkt sel_ib_pkey_hash[SEL_PKEY_HASH_SIZE]; | ||
56 | |||
57 | /** | ||
58 | * sel_ib_pkey_hashfn - Hashing function for the pkey table | ||
59 | * @pkey: pkey number | ||
60 | * | ||
61 | * Description: | ||
62 | * This is the hashing function for the pkey table, it returns the bucket | ||
63 | * number for the given pkey. | ||
64 | * | ||
65 | */ | ||
66 | static unsigned int sel_ib_pkey_hashfn(u16 pkey) | ||
67 | { | ||
68 | return (pkey & (SEL_PKEY_HASH_SIZE - 1)); | ||
69 | } | ||
70 | |||
71 | /** | ||
72 | * sel_ib_pkey_find - Search for a pkey record | ||
73 | * @subnet_prefix: subnet_prefix | ||
74 | * @pkey_num: pkey_num | ||
75 | * | ||
76 | * Description: | ||
77 | * Search the pkey table and return the matching record. If an entry | ||
78 | * can not be found in the table return NULL. | ||
79 | * | ||
80 | */ | ||
81 | static struct sel_ib_pkey *sel_ib_pkey_find(u64 subnet_prefix, u16 pkey_num) | ||
82 | { | ||
83 | unsigned int idx; | ||
84 | struct sel_ib_pkey *pkey; | ||
85 | |||
86 | idx = sel_ib_pkey_hashfn(pkey_num); | ||
87 | list_for_each_entry_rcu(pkey, &sel_ib_pkey_hash[idx].list, list) { | ||
88 | if (pkey->psec.pkey == pkey_num && | ||
89 | pkey->psec.subnet_prefix == subnet_prefix) | ||
90 | return pkey; | ||
91 | } | ||
92 | |||
93 | return NULL; | ||
94 | } | ||
95 | |||
96 | /** | ||
97 | * sel_ib_pkey_insert - Insert a new pkey into the table | ||
98 | * @pkey: the new pkey record | ||
99 | * | ||
100 | * Description: | ||
101 | * Add a new pkey record to the hash table. | ||
102 | * | ||
103 | */ | ||
104 | static void sel_ib_pkey_insert(struct sel_ib_pkey *pkey) | ||
105 | { | ||
106 | unsigned int idx; | ||
107 | |||
108 | /* we need to impose a limit on the growth of the hash table so check | ||
109 | * this bucket to make sure it is within the specified bounds | ||
110 | */ | ||
111 | idx = sel_ib_pkey_hashfn(pkey->psec.pkey); | ||
112 | list_add_rcu(&pkey->list, &sel_ib_pkey_hash[idx].list); | ||
113 | if (sel_ib_pkey_hash[idx].size == SEL_PKEY_HASH_BKT_LIMIT) { | ||
114 | struct sel_ib_pkey *tail; | ||
115 | |||
116 | tail = list_entry( | ||
117 | rcu_dereference_protected( | ||
118 | sel_ib_pkey_hash[idx].list.prev, | ||
119 | lockdep_is_held(&sel_ib_pkey_lock)), | ||
120 | struct sel_ib_pkey, list); | ||
121 | list_del_rcu(&tail->list); | ||
122 | kfree_rcu(tail, rcu); | ||
123 | } else { | ||
124 | sel_ib_pkey_hash[idx].size++; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | /** | ||
129 | * sel_ib_pkey_sid_slow - Lookup the SID of a pkey using the policy | ||
130 | * @subnet_prefix: subnet prefix | ||
131 | * @pkey_num: pkey number | ||
132 | * @sid: pkey SID | ||
133 | * | ||
134 | * Description: | ||
135 | * This function determines the SID of a pkey by querying the security | ||
136 | * policy. The result is added to the pkey table to speedup future | ||
137 | * queries. Returns zero on success, negative values on failure. | ||
138 | * | ||
139 | */ | ||
140 | static int sel_ib_pkey_sid_slow(u64 subnet_prefix, u16 pkey_num, u32 *sid) | ||
141 | { | ||
142 | int ret; | ||
143 | struct sel_ib_pkey *pkey; | ||
144 | struct sel_ib_pkey *new = NULL; | ||
145 | unsigned long flags; | ||
146 | |||
147 | spin_lock_irqsave(&sel_ib_pkey_lock, flags); | ||
148 | pkey = sel_ib_pkey_find(subnet_prefix, pkey_num); | ||
149 | if (pkey) { | ||
150 | *sid = pkey->psec.sid; | ||
151 | spin_unlock_irqrestore(&sel_ib_pkey_lock, flags); | ||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | ret = security_ib_pkey_sid(subnet_prefix, pkey_num, sid); | ||
156 | if (ret) | ||
157 | goto out; | ||
158 | |||
159 | /* If this memory allocation fails still return 0. The SID | ||
160 | * is valid, it just won't be added to the cache. | ||
161 | */ | ||
162 | new = kzalloc(sizeof(*new), GFP_ATOMIC); | ||
163 | if (!new) | ||
164 | goto out; | ||
165 | |||
166 | new->psec.subnet_prefix = subnet_prefix; | ||
167 | new->psec.pkey = pkey_num; | ||
168 | new->psec.sid = *sid; | ||
169 | sel_ib_pkey_insert(new); | ||
170 | |||
171 | out: | ||
172 | spin_unlock_irqrestore(&sel_ib_pkey_lock, flags); | ||
173 | return ret; | ||
174 | } | ||
175 | |||
176 | /** | ||
177 | * sel_ib_pkey_sid - Lookup the SID of a PKEY | ||
178 | * @subnet_prefix: subnet_prefix | ||
179 | * @pkey_num: pkey number | ||
180 | * @sid: pkey SID | ||
181 | * | ||
182 | * Description: | ||
183 | * This function determines the SID of a PKEY using the fastest method | ||
184 | * possible. First the pkey table is queried, but if an entry can't be found | ||
185 | * then the policy is queried and the result is added to the table to speedup | ||
186 | * future queries. Returns zero on success, negative values on failure. | ||
187 | * | ||
188 | */ | ||
189 | int sel_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *sid) | ||
190 | { | ||
191 | struct sel_ib_pkey *pkey; | ||
192 | |||
193 | rcu_read_lock(); | ||
194 | pkey = sel_ib_pkey_find(subnet_prefix, pkey_num); | ||
195 | if (pkey) { | ||
196 | *sid = pkey->psec.sid; | ||
197 | rcu_read_unlock(); | ||
198 | return 0; | ||
199 | } | ||
200 | rcu_read_unlock(); | ||
201 | |||
202 | return sel_ib_pkey_sid_slow(subnet_prefix, pkey_num, sid); | ||
203 | } | ||
204 | |||
205 | /** | ||
206 | * sel_ib_pkey_flush - Flush the entire pkey table | ||
207 | * | ||
208 | * Description: | ||
209 | * Remove all entries from the pkey table | ||
210 | * | ||
211 | */ | ||
212 | void sel_ib_pkey_flush(void) | ||
213 | { | ||
214 | unsigned int idx; | ||
215 | struct sel_ib_pkey *pkey, *pkey_tmp; | ||
216 | unsigned long flags; | ||
217 | |||
218 | spin_lock_irqsave(&sel_ib_pkey_lock, flags); | ||
219 | for (idx = 0; idx < SEL_PKEY_HASH_SIZE; idx++) { | ||
220 | list_for_each_entry_safe(pkey, pkey_tmp, | ||
221 | &sel_ib_pkey_hash[idx].list, list) { | ||
222 | list_del_rcu(&pkey->list); | ||
223 | kfree_rcu(pkey, rcu); | ||
224 | } | ||
225 | sel_ib_pkey_hash[idx].size = 0; | ||
226 | } | ||
227 | spin_unlock_irqrestore(&sel_ib_pkey_lock, flags); | ||
228 | } | ||
229 | |||
230 | static __init int sel_ib_pkey_init(void) | ||
231 | { | ||
232 | int iter; | ||
233 | |||
234 | if (!selinux_enabled) | ||
235 | return 0; | ||
236 | |||
237 | for (iter = 0; iter < SEL_PKEY_HASH_SIZE; iter++) { | ||
238 | INIT_LIST_HEAD(&sel_ib_pkey_hash[iter].list); | ||
239 | sel_ib_pkey_hash[iter].size = 0; | ||
240 | } | ||
241 | |||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | subsys_initcall(sel_ib_pkey_init); | ||
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index 1e0cc9b5de20..b9fe3434b036 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h | |||
@@ -1,7 +1,7 @@ | |||
1 | #include <linux/capability.h> | 1 | #include <linux/capability.h> |
2 | 2 | ||
3 | #define COMMON_FILE_SOCK_PERMS "ioctl", "read", "write", "create", \ | 3 | #define COMMON_FILE_SOCK_PERMS "ioctl", "read", "write", "create", \ |
4 | "getattr", "setattr", "lock", "relabelfrom", "relabelto", "append" | 4 | "getattr", "setattr", "lock", "relabelfrom", "relabelto", "append", "map" |
5 | 5 | ||
6 | #define COMMON_FILE_PERMS COMMON_FILE_SOCK_PERMS, "unlink", "link", \ | 6 | #define COMMON_FILE_PERMS COMMON_FILE_SOCK_PERMS, "unlink", "link", \ |
7 | "rename", "execute", "quotaon", "mounton", "audit_access", \ | 7 | "rename", "execute", "quotaon", "mounton", "audit_access", \ |
@@ -231,6 +231,10 @@ struct security_class_mapping secclass_map[] = { | |||
231 | { COMMON_SOCK_PERMS, NULL } }, | 231 | { COMMON_SOCK_PERMS, NULL } }, |
232 | { "smc_socket", | 232 | { "smc_socket", |
233 | { COMMON_SOCK_PERMS, NULL } }, | 233 | { COMMON_SOCK_PERMS, NULL } }, |
234 | { "infiniband_pkey", | ||
235 | { "access", NULL } }, | ||
236 | { "infiniband_endport", | ||
237 | { "manage_subnet", NULL } }, | ||
234 | { NULL } | 238 | { NULL } |
235 | }; | 239 | }; |
236 | 240 | ||
diff --git a/security/selinux/include/ibpkey.h b/security/selinux/include/ibpkey.h new file mode 100644 index 000000000000..b17a19e348e6 --- /dev/null +++ b/security/selinux/include/ibpkey.h | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * pkey table | ||
3 | * | ||
4 | * SELinux must keep a mapping of pkeys to labels/SIDs. This | ||
5 | * mapping is maintained as part of the normal policy but a fast cache is | ||
6 | * needed to reduce the lookup overhead. | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * (c) Mellanox Technologies, 2016 | ||
12 | * | ||
13 | * This program is free software: you can redistribute it and/or modify | ||
14 | * it under the terms of version 2 of the GNU General Public License as | ||
15 | * published by the Free Software Foundation. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef _SELINUX_IB_PKEY_H | ||
25 | #define _SELINUX_IB_PKEY_H | ||
26 | |||
27 | void sel_ib_pkey_flush(void); | ||
28 | |||
29 | int sel_ib_pkey_sid(u64 subnet_prefix, u16 pkey, u32 *sid); | ||
30 | |||
31 | #endif | ||
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index c03cdcd12a3b..6ebc61e370ff 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h | |||
@@ -10,6 +10,7 @@ | |||
10 | * | 10 | * |
11 | * Copyright (C) 2001,2002 Networks Associates Technology, Inc. | 11 | * Copyright (C) 2001,2002 Networks Associates Technology, Inc. |
12 | * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> | 12 | * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> |
13 | * Copyright (C) 2016 Mellanox Technologies | ||
13 | * | 14 | * |
14 | * This program is free software; you can redistribute it and/or modify | 15 | * This program is free software; you can redistribute it and/or modify |
15 | * it under the terms of the GNU General Public License version 2, | 16 | * it under the terms of the GNU General Public License version 2, |
@@ -139,6 +140,16 @@ struct key_security_struct { | |||
139 | u32 sid; /* SID of key */ | 140 | u32 sid; /* SID of key */ |
140 | }; | 141 | }; |
141 | 142 | ||
143 | struct ib_security_struct { | ||
144 | u32 sid; /* SID of the queue pair or MAD agent */ | ||
145 | }; | ||
146 | |||
147 | struct pkey_security_struct { | ||
148 | u64 subnet_prefix; /* Port subnet prefix */ | ||
149 | u16 pkey; /* PKey number */ | ||
150 | u32 sid; /* SID of pkey */ | ||
151 | }; | ||
152 | |||
142 | extern unsigned int selinux_checkreqprot; | 153 | extern unsigned int selinux_checkreqprot; |
143 | 154 | ||
144 | #endif /* _SELINUX_OBJSEC_H_ */ | 155 | #endif /* _SELINUX_OBJSEC_H_ */ |
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index f979c35e037e..e91f08c16c0b 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
@@ -36,10 +36,11 @@ | |||
36 | #define POLICYDB_VERSION_DEFAULT_TYPE 28 | 36 | #define POLICYDB_VERSION_DEFAULT_TYPE 28 |
37 | #define POLICYDB_VERSION_CONSTRAINT_NAMES 29 | 37 | #define POLICYDB_VERSION_CONSTRAINT_NAMES 29 |
38 | #define POLICYDB_VERSION_XPERMS_IOCTL 30 | 38 | #define POLICYDB_VERSION_XPERMS_IOCTL 30 |
39 | #define POLICYDB_VERSION_INFINIBAND 31 | ||
39 | 40 | ||
40 | /* Range of policy versions we understand*/ | 41 | /* Range of policy versions we understand*/ |
41 | #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE | 42 | #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE |
42 | #define POLICYDB_VERSION_MAX POLICYDB_VERSION_XPERMS_IOCTL | 43 | #define POLICYDB_VERSION_MAX POLICYDB_VERSION_INFINIBAND |
43 | 44 | ||
44 | /* Mask for just the mount related flags */ | 45 | /* Mask for just the mount related flags */ |
45 | #define SE_MNTMASK 0x0f | 46 | #define SE_MNTMASK 0x0f |
@@ -76,6 +77,8 @@ enum { | |||
76 | }; | 77 | }; |
77 | #define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1) | 78 | #define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1) |
78 | 79 | ||
80 | extern char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX]; | ||
81 | |||
79 | extern int selinux_policycap_netpeer; | 82 | extern int selinux_policycap_netpeer; |
80 | extern int selinux_policycap_openperm; | 83 | extern int selinux_policycap_openperm; |
81 | extern int selinux_policycap_extsockclass; | 84 | extern int selinux_policycap_extsockclass; |
@@ -178,6 +181,10 @@ int security_get_user_sids(u32 callsid, char *username, | |||
178 | 181 | ||
179 | int security_port_sid(u8 protocol, u16 port, u32 *out_sid); | 182 | int security_port_sid(u8 protocol, u16 port, u32 *out_sid); |
180 | 183 | ||
184 | int security_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *out_sid); | ||
185 | |||
186 | int security_ib_endport_sid(const char *dev_name, u8 port_num, u32 *out_sid); | ||
187 | |||
181 | int security_netif_sid(char *name, u32 *if_sid); | 188 | int security_netif_sid(char *name, u32 *if_sid); |
182 | 189 | ||
183 | int security_node_sid(u16 domain, void *addr, u32 addrlen, | 190 | int security_node_sid(u16 domain, void *addr, u32 addrlen, |
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 50062e70140d..9010a3632d6f 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
@@ -41,15 +41,6 @@ | |||
41 | #include "objsec.h" | 41 | #include "objsec.h" |
42 | #include "conditional.h" | 42 | #include "conditional.h" |
43 | 43 | ||
44 | /* Policy capability filenames */ | ||
45 | static char *policycap_names[] = { | ||
46 | "network_peer_controls", | ||
47 | "open_perms", | ||
48 | "extended_socket_class", | ||
49 | "always_check_network", | ||
50 | "cgroup_seclabel" | ||
51 | }; | ||
52 | |||
53 | unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE; | 44 | unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE; |
54 | 45 | ||
55 | static int __init checkreqprot_setup(char *str) | 46 | static int __init checkreqprot_setup(char *str) |
@@ -163,6 +154,8 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf, | |||
163 | avc_ss_reset(0); | 154 | avc_ss_reset(0); |
164 | selnl_notify_setenforce(selinux_enforcing); | 155 | selnl_notify_setenforce(selinux_enforcing); |
165 | selinux_status_update_setenforce(selinux_enforcing); | 156 | selinux_status_update_setenforce(selinux_enforcing); |
157 | if (!selinux_enforcing) | ||
158 | call_lsm_notifier(LSM_POLICY_CHANGE, NULL); | ||
166 | } | 159 | } |
167 | length = count; | 160 | length = count; |
168 | out: | 161 | out: |
@@ -1750,9 +1743,9 @@ static int sel_make_policycap(void) | |||
1750 | sel_remove_entries(policycap_dir); | 1743 | sel_remove_entries(policycap_dir); |
1751 | 1744 | ||
1752 | for (iter = 0; iter <= POLICYDB_CAPABILITY_MAX; iter++) { | 1745 | for (iter = 0; iter <= POLICYDB_CAPABILITY_MAX; iter++) { |
1753 | if (iter < ARRAY_SIZE(policycap_names)) | 1746 | if (iter < ARRAY_SIZE(selinux_policycap_names)) |
1754 | dentry = d_alloc_name(policycap_dir, | 1747 | dentry = d_alloc_name(policycap_dir, |
1755 | policycap_names[iter]); | 1748 | selinux_policycap_names[iter]); |
1756 | else | 1749 | else |
1757 | dentry = d_alloc_name(policycap_dir, "unknown"); | 1750 | dentry = d_alloc_name(policycap_dir, "unknown"); |
1758 | 1751 | ||
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c index 9db4709a6877..ad38299164c3 100644 --- a/security/selinux/ss/ebitmap.c +++ b/security/selinux/ss/ebitmap.c | |||
@@ -24,6 +24,8 @@ | |||
24 | 24 | ||
25 | #define BITS_PER_U64 (sizeof(u64) * 8) | 25 | #define BITS_PER_U64 (sizeof(u64) * 8) |
26 | 26 | ||
27 | static struct kmem_cache *ebitmap_node_cachep; | ||
28 | |||
27 | int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2) | 29 | int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2) |
28 | { | 30 | { |
29 | struct ebitmap_node *n1, *n2; | 31 | struct ebitmap_node *n1, *n2; |
@@ -54,7 +56,7 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src) | |||
54 | n = src->node; | 56 | n = src->node; |
55 | prev = NULL; | 57 | prev = NULL; |
56 | while (n) { | 58 | while (n) { |
57 | new = kzalloc(sizeof(*new), GFP_ATOMIC); | 59 | new = kmem_cache_zalloc(ebitmap_node_cachep, GFP_ATOMIC); |
58 | if (!new) { | 60 | if (!new) { |
59 | ebitmap_destroy(dst); | 61 | ebitmap_destroy(dst); |
60 | return -ENOMEM; | 62 | return -ENOMEM; |
@@ -162,7 +164,7 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap, | |||
162 | if (e_iter == NULL || | 164 | if (e_iter == NULL || |
163 | offset >= e_iter->startbit + EBITMAP_SIZE) { | 165 | offset >= e_iter->startbit + EBITMAP_SIZE) { |
164 | e_prev = e_iter; | 166 | e_prev = e_iter; |
165 | e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC); | 167 | e_iter = kmem_cache_zalloc(ebitmap_node_cachep, GFP_ATOMIC); |
166 | if (e_iter == NULL) | 168 | if (e_iter == NULL) |
167 | goto netlbl_import_failure; | 169 | goto netlbl_import_failure; |
168 | e_iter->startbit = offset - (offset % EBITMAP_SIZE); | 170 | e_iter->startbit = offset - (offset % EBITMAP_SIZE); |
@@ -288,7 +290,7 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value) | |||
288 | prev->next = n->next; | 290 | prev->next = n->next; |
289 | else | 291 | else |
290 | e->node = n->next; | 292 | e->node = n->next; |
291 | kfree(n); | 293 | kmem_cache_free(ebitmap_node_cachep, n); |
292 | } | 294 | } |
293 | return 0; | 295 | return 0; |
294 | } | 296 | } |
@@ -299,7 +301,7 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value) | |||
299 | if (!value) | 301 | if (!value) |
300 | return 0; | 302 | return 0; |
301 | 303 | ||
302 | new = kzalloc(sizeof(*new), GFP_ATOMIC); | 304 | new = kmem_cache_zalloc(ebitmap_node_cachep, GFP_ATOMIC); |
303 | if (!new) | 305 | if (!new) |
304 | return -ENOMEM; | 306 | return -ENOMEM; |
305 | 307 | ||
@@ -332,7 +334,7 @@ void ebitmap_destroy(struct ebitmap *e) | |||
332 | while (n) { | 334 | while (n) { |
333 | temp = n; | 335 | temp = n; |
334 | n = n->next; | 336 | n = n->next; |
335 | kfree(temp); | 337 | kmem_cache_free(ebitmap_node_cachep, temp); |
336 | } | 338 | } |
337 | 339 | ||
338 | e->highbit = 0; | 340 | e->highbit = 0; |
@@ -400,7 +402,7 @@ int ebitmap_read(struct ebitmap *e, void *fp) | |||
400 | 402 | ||
401 | if (!n || startbit >= n->startbit + EBITMAP_SIZE) { | 403 | if (!n || startbit >= n->startbit + EBITMAP_SIZE) { |
402 | struct ebitmap_node *tmp; | 404 | struct ebitmap_node *tmp; |
403 | tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); | 405 | tmp = kmem_cache_zalloc(ebitmap_node_cachep, GFP_KERNEL); |
404 | if (!tmp) { | 406 | if (!tmp) { |
405 | printk(KERN_ERR | 407 | printk(KERN_ERR |
406 | "SELinux: ebitmap: out of memory\n"); | 408 | "SELinux: ebitmap: out of memory\n"); |
@@ -519,3 +521,15 @@ int ebitmap_write(struct ebitmap *e, void *fp) | |||
519 | } | 521 | } |
520 | return 0; | 522 | return 0; |
521 | } | 523 | } |
524 | |||
525 | void ebitmap_cache_init(void) | ||
526 | { | ||
527 | ebitmap_node_cachep = kmem_cache_create("ebitmap_node", | ||
528 | sizeof(struct ebitmap_node), | ||
529 | 0, SLAB_PANIC, NULL); | ||
530 | } | ||
531 | |||
532 | void ebitmap_cache_destroy(void) | ||
533 | { | ||
534 | kmem_cache_destroy(ebitmap_node_cachep); | ||
535 | } | ||
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h index 9637b8c71085..6d5a9ac4251f 100644 --- a/security/selinux/ss/ebitmap.h +++ b/security/selinux/ss/ebitmap.h | |||
@@ -130,6 +130,9 @@ void ebitmap_destroy(struct ebitmap *e); | |||
130 | int ebitmap_read(struct ebitmap *e, void *fp); | 130 | int ebitmap_read(struct ebitmap *e, void *fp); |
131 | int ebitmap_write(struct ebitmap *e, void *fp); | 131 | int ebitmap_write(struct ebitmap *e, void *fp); |
132 | 132 | ||
133 | void ebitmap_cache_init(void); | ||
134 | void ebitmap_cache_destroy(void); | ||
135 | |||
133 | #ifdef CONFIG_NETLABEL | 136 | #ifdef CONFIG_NETLABEL |
134 | int ebitmap_netlbl_export(struct ebitmap *ebmap, | 137 | int ebitmap_netlbl_export(struct ebitmap *ebmap, |
135 | struct netlbl_lsm_catmap **catmap); | 138 | struct netlbl_lsm_catmap **catmap); |
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 0080122760ad..aa6500abb178 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c | |||
@@ -17,6 +17,11 @@ | |||
17 | * | 17 | * |
18 | * Added support for the policy capability bitmap | 18 | * Added support for the policy capability bitmap |
19 | * | 19 | * |
20 | * Update: Mellanox Techonologies | ||
21 | * | ||
22 | * Added Infiniband support | ||
23 | * | ||
24 | * Copyright (C) 2016 Mellanox Techonologies | ||
20 | * Copyright (C) 2007 Hewlett-Packard Development Company, L.P. | 25 | * Copyright (C) 2007 Hewlett-Packard Development Company, L.P. |
21 | * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. | 26 | * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. |
22 | * Copyright (C) 2003 - 2004 Tresys Technology, LLC | 27 | * Copyright (C) 2003 - 2004 Tresys Technology, LLC |
@@ -76,81 +81,86 @@ static struct policydb_compat_info policydb_compat[] = { | |||
76 | { | 81 | { |
77 | .version = POLICYDB_VERSION_BASE, | 82 | .version = POLICYDB_VERSION_BASE, |
78 | .sym_num = SYM_NUM - 3, | 83 | .sym_num = SYM_NUM - 3, |
79 | .ocon_num = OCON_NUM - 1, | 84 | .ocon_num = OCON_NUM - 3, |
80 | }, | 85 | }, |
81 | { | 86 | { |
82 | .version = POLICYDB_VERSION_BOOL, | 87 | .version = POLICYDB_VERSION_BOOL, |
83 | .sym_num = SYM_NUM - 2, | 88 | .sym_num = SYM_NUM - 2, |
84 | .ocon_num = OCON_NUM - 1, | 89 | .ocon_num = OCON_NUM - 3, |
85 | }, | 90 | }, |
86 | { | 91 | { |
87 | .version = POLICYDB_VERSION_IPV6, | 92 | .version = POLICYDB_VERSION_IPV6, |
88 | .sym_num = SYM_NUM - 2, | 93 | .sym_num = SYM_NUM - 2, |
89 | .ocon_num = OCON_NUM, | 94 | .ocon_num = OCON_NUM - 2, |
90 | }, | 95 | }, |
91 | { | 96 | { |
92 | .version = POLICYDB_VERSION_NLCLASS, | 97 | .version = POLICYDB_VERSION_NLCLASS, |
93 | .sym_num = SYM_NUM - 2, | 98 | .sym_num = SYM_NUM - 2, |
94 | .ocon_num = OCON_NUM, | 99 | .ocon_num = OCON_NUM - 2, |
95 | }, | 100 | }, |
96 | { | 101 | { |
97 | .version = POLICYDB_VERSION_MLS, | 102 | .version = POLICYDB_VERSION_MLS, |
98 | .sym_num = SYM_NUM, | 103 | .sym_num = SYM_NUM, |
99 | .ocon_num = OCON_NUM, | 104 | .ocon_num = OCON_NUM - 2, |
100 | }, | 105 | }, |
101 | { | 106 | { |
102 | .version = POLICYDB_VERSION_AVTAB, | 107 | .version = POLICYDB_VERSION_AVTAB, |
103 | .sym_num = SYM_NUM, | 108 | .sym_num = SYM_NUM, |
104 | .ocon_num = OCON_NUM, | 109 | .ocon_num = OCON_NUM - 2, |
105 | }, | 110 | }, |
106 | { | 111 | { |
107 | .version = POLICYDB_VERSION_RANGETRANS, | 112 | .version = POLICYDB_VERSION_RANGETRANS, |
108 | .sym_num = SYM_NUM, | 113 | .sym_num = SYM_NUM, |
109 | .ocon_num = OCON_NUM, | 114 | .ocon_num = OCON_NUM - 2, |
110 | }, | 115 | }, |
111 | { | 116 | { |
112 | .version = POLICYDB_VERSION_POLCAP, | 117 | .version = POLICYDB_VERSION_POLCAP, |
113 | .sym_num = SYM_NUM, | 118 | .sym_num = SYM_NUM, |
114 | .ocon_num = OCON_NUM, | 119 | .ocon_num = OCON_NUM - 2, |
115 | }, | 120 | }, |
116 | { | 121 | { |
117 | .version = POLICYDB_VERSION_PERMISSIVE, | 122 | .version = POLICYDB_VERSION_PERMISSIVE, |
118 | .sym_num = SYM_NUM, | 123 | .sym_num = SYM_NUM, |
119 | .ocon_num = OCON_NUM, | 124 | .ocon_num = OCON_NUM - 2, |
120 | }, | 125 | }, |
121 | { | 126 | { |
122 | .version = POLICYDB_VERSION_BOUNDARY, | 127 | .version = POLICYDB_VERSION_BOUNDARY, |
123 | .sym_num = SYM_NUM, | 128 | .sym_num = SYM_NUM, |
124 | .ocon_num = OCON_NUM, | 129 | .ocon_num = OCON_NUM - 2, |
125 | }, | 130 | }, |
126 | { | 131 | { |
127 | .version = POLICYDB_VERSION_FILENAME_TRANS, | 132 | .version = POLICYDB_VERSION_FILENAME_TRANS, |
128 | .sym_num = SYM_NUM, | 133 | .sym_num = SYM_NUM, |
129 | .ocon_num = OCON_NUM, | 134 | .ocon_num = OCON_NUM - 2, |
130 | }, | 135 | }, |
131 | { | 136 | { |
132 | .version = POLICYDB_VERSION_ROLETRANS, | 137 | .version = POLICYDB_VERSION_ROLETRANS, |
133 | .sym_num = SYM_NUM, | 138 | .sym_num = SYM_NUM, |
134 | .ocon_num = OCON_NUM, | 139 | .ocon_num = OCON_NUM - 2, |
135 | }, | 140 | }, |
136 | { | 141 | { |
137 | .version = POLICYDB_VERSION_NEW_OBJECT_DEFAULTS, | 142 | .version = POLICYDB_VERSION_NEW_OBJECT_DEFAULTS, |
138 | .sym_num = SYM_NUM, | 143 | .sym_num = SYM_NUM, |
139 | .ocon_num = OCON_NUM, | 144 | .ocon_num = OCON_NUM - 2, |
140 | }, | 145 | }, |
141 | { | 146 | { |
142 | .version = POLICYDB_VERSION_DEFAULT_TYPE, | 147 | .version = POLICYDB_VERSION_DEFAULT_TYPE, |
143 | .sym_num = SYM_NUM, | 148 | .sym_num = SYM_NUM, |
144 | .ocon_num = OCON_NUM, | 149 | .ocon_num = OCON_NUM - 2, |
145 | }, | 150 | }, |
146 | { | 151 | { |
147 | .version = POLICYDB_VERSION_CONSTRAINT_NAMES, | 152 | .version = POLICYDB_VERSION_CONSTRAINT_NAMES, |
148 | .sym_num = SYM_NUM, | 153 | .sym_num = SYM_NUM, |
149 | .ocon_num = OCON_NUM, | 154 | .ocon_num = OCON_NUM - 2, |
150 | }, | 155 | }, |
151 | { | 156 | { |
152 | .version = POLICYDB_VERSION_XPERMS_IOCTL, | 157 | .version = POLICYDB_VERSION_XPERMS_IOCTL, |
153 | .sym_num = SYM_NUM, | 158 | .sym_num = SYM_NUM, |
159 | .ocon_num = OCON_NUM - 2, | ||
160 | }, | ||
161 | { | ||
162 | .version = POLICYDB_VERSION_INFINIBAND, | ||
163 | .sym_num = SYM_NUM, | ||
154 | .ocon_num = OCON_NUM, | 164 | .ocon_num = OCON_NUM, |
155 | }, | 165 | }, |
156 | }; | 166 | }; |
@@ -538,34 +548,30 @@ static int policydb_index(struct policydb *p) | |||
538 | symtab_hash_eval(p->symtab); | 548 | symtab_hash_eval(p->symtab); |
539 | #endif | 549 | #endif |
540 | 550 | ||
541 | rc = -ENOMEM; | ||
542 | p->class_val_to_struct = kcalloc(p->p_classes.nprim, | 551 | p->class_val_to_struct = kcalloc(p->p_classes.nprim, |
543 | sizeof(*p->class_val_to_struct), | 552 | sizeof(*p->class_val_to_struct), |
544 | GFP_KERNEL); | 553 | GFP_KERNEL); |
545 | if (!p->class_val_to_struct) | 554 | if (!p->class_val_to_struct) |
546 | goto out; | 555 | return -ENOMEM; |
547 | 556 | ||
548 | rc = -ENOMEM; | ||
549 | p->role_val_to_struct = kcalloc(p->p_roles.nprim, | 557 | p->role_val_to_struct = kcalloc(p->p_roles.nprim, |
550 | sizeof(*p->role_val_to_struct), | 558 | sizeof(*p->role_val_to_struct), |
551 | GFP_KERNEL); | 559 | GFP_KERNEL); |
552 | if (!p->role_val_to_struct) | 560 | if (!p->role_val_to_struct) |
553 | goto out; | 561 | return -ENOMEM; |
554 | 562 | ||
555 | rc = -ENOMEM; | ||
556 | p->user_val_to_struct = kcalloc(p->p_users.nprim, | 563 | p->user_val_to_struct = kcalloc(p->p_users.nprim, |
557 | sizeof(*p->user_val_to_struct), | 564 | sizeof(*p->user_val_to_struct), |
558 | GFP_KERNEL); | 565 | GFP_KERNEL); |
559 | if (!p->user_val_to_struct) | 566 | if (!p->user_val_to_struct) |
560 | goto out; | 567 | return -ENOMEM; |
561 | 568 | ||
562 | /* Yes, I want the sizeof the pointer, not the structure */ | 569 | /* Yes, I want the sizeof the pointer, not the structure */ |
563 | rc = -ENOMEM; | ||
564 | p->type_val_to_struct_array = flex_array_alloc(sizeof(struct type_datum *), | 570 | p->type_val_to_struct_array = flex_array_alloc(sizeof(struct type_datum *), |
565 | p->p_types.nprim, | 571 | p->p_types.nprim, |
566 | GFP_KERNEL | __GFP_ZERO); | 572 | GFP_KERNEL | __GFP_ZERO); |
567 | if (!p->type_val_to_struct_array) | 573 | if (!p->type_val_to_struct_array) |
568 | goto out; | 574 | return -ENOMEM; |
569 | 575 | ||
570 | rc = flex_array_prealloc(p->type_val_to_struct_array, 0, | 576 | rc = flex_array_prealloc(p->type_val_to_struct_array, 0, |
571 | p->p_types.nprim, GFP_KERNEL | __GFP_ZERO); | 577 | p->p_types.nprim, GFP_KERNEL | __GFP_ZERO); |
@@ -577,12 +583,11 @@ static int policydb_index(struct policydb *p) | |||
577 | goto out; | 583 | goto out; |
578 | 584 | ||
579 | for (i = 0; i < SYM_NUM; i++) { | 585 | for (i = 0; i < SYM_NUM; i++) { |
580 | rc = -ENOMEM; | ||
581 | p->sym_val_to_name[i] = flex_array_alloc(sizeof(char *), | 586 | p->sym_val_to_name[i] = flex_array_alloc(sizeof(char *), |
582 | p->symtab[i].nprim, | 587 | p->symtab[i].nprim, |
583 | GFP_KERNEL | __GFP_ZERO); | 588 | GFP_KERNEL | __GFP_ZERO); |
584 | if (!p->sym_val_to_name[i]) | 589 | if (!p->sym_val_to_name[i]) |
585 | goto out; | 590 | return -ENOMEM; |
586 | 591 | ||
587 | rc = flex_array_prealloc(p->sym_val_to_name[i], | 592 | rc = flex_array_prealloc(p->sym_val_to_name[i], |
588 | 0, p->symtab[i].nprim, | 593 | 0, p->symtab[i].nprim, |
@@ -2211,6 +2216,51 @@ static int ocontext_read(struct policydb *p, struct policydb_compat_info *info, | |||
2211 | goto out; | 2216 | goto out; |
2212 | break; | 2217 | break; |
2213 | } | 2218 | } |
2219 | case OCON_IBPKEY: | ||
2220 | rc = next_entry(nodebuf, fp, sizeof(u32) * 4); | ||
2221 | if (rc) | ||
2222 | goto out; | ||
2223 | |||
2224 | c->u.ibpkey.subnet_prefix = be64_to_cpu(*((__be64 *)nodebuf)); | ||
2225 | |||
2226 | if (nodebuf[2] > 0xffff || | ||
2227 | nodebuf[3] > 0xffff) { | ||
2228 | rc = -EINVAL; | ||
2229 | goto out; | ||
2230 | } | ||
2231 | |||
2232 | c->u.ibpkey.low_pkey = le32_to_cpu(nodebuf[2]); | ||
2233 | c->u.ibpkey.high_pkey = le32_to_cpu(nodebuf[3]); | ||
2234 | |||
2235 | rc = context_read_and_validate(&c->context[0], | ||
2236 | p, | ||
2237 | fp); | ||
2238 | if (rc) | ||
2239 | goto out; | ||
2240 | break; | ||
2241 | case OCON_IBENDPORT: | ||
2242 | rc = next_entry(buf, fp, sizeof(u32) * 2); | ||
2243 | if (rc) | ||
2244 | goto out; | ||
2245 | len = le32_to_cpu(buf[0]); | ||
2246 | |||
2247 | rc = str_read(&c->u.ibendport.dev_name, GFP_KERNEL, fp, len); | ||
2248 | if (rc) | ||
2249 | goto out; | ||
2250 | |||
2251 | if (buf[1] > 0xff || buf[1] == 0) { | ||
2252 | rc = -EINVAL; | ||
2253 | goto out; | ||
2254 | } | ||
2255 | |||
2256 | c->u.ibendport.port = le32_to_cpu(buf[1]); | ||
2257 | |||
2258 | rc = context_read_and_validate(&c->context[0], | ||
2259 | p, | ||
2260 | fp); | ||
2261 | if (rc) | ||
2262 | goto out; | ||
2263 | break; | ||
2214 | } | 2264 | } |
2215 | } | 2265 | } |
2216 | } | 2266 | } |
@@ -3140,6 +3190,33 @@ static int ocontext_write(struct policydb *p, struct policydb_compat_info *info, | |||
3140 | if (rc) | 3190 | if (rc) |
3141 | return rc; | 3191 | return rc; |
3142 | break; | 3192 | break; |
3193 | case OCON_IBPKEY: | ||
3194 | *((__be64 *)nodebuf) = cpu_to_be64(c->u.ibpkey.subnet_prefix); | ||
3195 | |||
3196 | nodebuf[2] = cpu_to_le32(c->u.ibpkey.low_pkey); | ||
3197 | nodebuf[3] = cpu_to_le32(c->u.ibpkey.high_pkey); | ||
3198 | |||
3199 | rc = put_entry(nodebuf, sizeof(u32), 4, fp); | ||
3200 | if (rc) | ||
3201 | return rc; | ||
3202 | rc = context_write(p, &c->context[0], fp); | ||
3203 | if (rc) | ||
3204 | return rc; | ||
3205 | break; | ||
3206 | case OCON_IBENDPORT: | ||
3207 | len = strlen(c->u.ibendport.dev_name); | ||
3208 | buf[0] = cpu_to_le32(len); | ||
3209 | buf[1] = cpu_to_le32(c->u.ibendport.port); | ||
3210 | rc = put_entry(buf, sizeof(u32), 2, fp); | ||
3211 | if (rc) | ||
3212 | return rc; | ||
3213 | rc = put_entry(c->u.ibendport.dev_name, 1, len, fp); | ||
3214 | if (rc) | ||
3215 | return rc; | ||
3216 | rc = context_write(p, &c->context[0], fp); | ||
3217 | if (rc) | ||
3218 | return rc; | ||
3219 | break; | ||
3143 | } | 3220 | } |
3144 | } | 3221 | } |
3145 | } | 3222 | } |
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index 725d5945a97e..5d23eed35fa7 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h | |||
@@ -187,6 +187,15 @@ struct ocontext { | |||
187 | u32 addr[4]; | 187 | u32 addr[4]; |
188 | u32 mask[4]; | 188 | u32 mask[4]; |
189 | } node6; /* IPv6 node information */ | 189 | } node6; /* IPv6 node information */ |
190 | struct { | ||
191 | u64 subnet_prefix; | ||
192 | u16 low_pkey; | ||
193 | u16 high_pkey; | ||
194 | } ibpkey; | ||
195 | struct { | ||
196 | char *dev_name; | ||
197 | u8 port; | ||
198 | } ibendport; | ||
190 | } u; | 199 | } u; |
191 | union { | 200 | union { |
192 | u32 sclass; /* security class for genfs */ | 201 | u32 sclass; /* security class for genfs */ |
@@ -215,14 +224,16 @@ struct genfs { | |||
215 | #define SYM_NUM 8 | 224 | #define SYM_NUM 8 |
216 | 225 | ||
217 | /* object context array indices */ | 226 | /* object context array indices */ |
218 | #define OCON_ISID 0 /* initial SIDs */ | 227 | #define OCON_ISID 0 /* initial SIDs */ |
219 | #define OCON_FS 1 /* unlabeled file systems */ | 228 | #define OCON_FS 1 /* unlabeled file systems */ |
220 | #define OCON_PORT 2 /* TCP and UDP port numbers */ | 229 | #define OCON_PORT 2 /* TCP and UDP port numbers */ |
221 | #define OCON_NETIF 3 /* network interfaces */ | 230 | #define OCON_NETIF 3 /* network interfaces */ |
222 | #define OCON_NODE 4 /* nodes */ | 231 | #define OCON_NODE 4 /* nodes */ |
223 | #define OCON_FSUSE 5 /* fs_use */ | 232 | #define OCON_FSUSE 5 /* fs_use */ |
224 | #define OCON_NODE6 6 /* IPv6 nodes */ | 233 | #define OCON_NODE6 6 /* IPv6 nodes */ |
225 | #define OCON_NUM 7 | 234 | #define OCON_IBPKEY 7 /* Infiniband PKeys */ |
235 | #define OCON_IBENDPORT 8 /* Infiniband end ports */ | ||
236 | #define OCON_NUM 9 | ||
226 | 237 | ||
227 | /* The policy database */ | 238 | /* The policy database */ |
228 | struct policydb { | 239 | struct policydb { |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 60d9b0252321..2f02fa67ec2e 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -70,6 +70,15 @@ | |||
70 | #include "ebitmap.h" | 70 | #include "ebitmap.h" |
71 | #include "audit.h" | 71 | #include "audit.h" |
72 | 72 | ||
73 | /* Policy capability names */ | ||
74 | char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX] = { | ||
75 | "network_peer_controls", | ||
76 | "open_perms", | ||
77 | "extended_socket_class", | ||
78 | "always_check_network", | ||
79 | "cgroup_seclabel" | ||
80 | }; | ||
81 | |||
73 | int selinux_policycap_netpeer; | 82 | int selinux_policycap_netpeer; |
74 | int selinux_policycap_openperm; | 83 | int selinux_policycap_openperm; |
75 | int selinux_policycap_extsockclass; | 84 | int selinux_policycap_extsockclass; |
@@ -1986,6 +1995,9 @@ bad: | |||
1986 | 1995 | ||
1987 | static void security_load_policycaps(void) | 1996 | static void security_load_policycaps(void) |
1988 | { | 1997 | { |
1998 | unsigned int i; | ||
1999 | struct ebitmap_node *node; | ||
2000 | |||
1989 | selinux_policycap_netpeer = ebitmap_get_bit(&policydb.policycaps, | 2001 | selinux_policycap_netpeer = ebitmap_get_bit(&policydb.policycaps, |
1990 | POLICYDB_CAPABILITY_NETPEER); | 2002 | POLICYDB_CAPABILITY_NETPEER); |
1991 | selinux_policycap_openperm = ebitmap_get_bit(&policydb.policycaps, | 2003 | selinux_policycap_openperm = ebitmap_get_bit(&policydb.policycaps, |
@@ -1997,6 +2009,17 @@ static void security_load_policycaps(void) | |||
1997 | selinux_policycap_cgroupseclabel = | 2009 | selinux_policycap_cgroupseclabel = |
1998 | ebitmap_get_bit(&policydb.policycaps, | 2010 | ebitmap_get_bit(&policydb.policycaps, |
1999 | POLICYDB_CAPABILITY_CGROUPSECLABEL); | 2011 | POLICYDB_CAPABILITY_CGROUPSECLABEL); |
2012 | |||
2013 | for (i = 0; i < ARRAY_SIZE(selinux_policycap_names); i++) | ||
2014 | pr_info("SELinux: policy capability %s=%d\n", | ||
2015 | selinux_policycap_names[i], | ||
2016 | ebitmap_get_bit(&policydb.policycaps, i)); | ||
2017 | |||
2018 | ebitmap_for_each_positive_bit(&policydb.policycaps, node, i) { | ||
2019 | if (i >= ARRAY_SIZE(selinux_policycap_names)) | ||
2020 | pr_info("SELinux: unknown policy capability %u\n", | ||
2021 | i); | ||
2022 | } | ||
2000 | } | 2023 | } |
2001 | 2024 | ||
2002 | static int security_preserve_bools(struct policydb *p); | 2025 | static int security_preserve_bools(struct policydb *p); |
@@ -2031,9 +2054,11 @@ int security_load_policy(void *data, size_t len) | |||
2031 | 2054 | ||
2032 | if (!ss_initialized) { | 2055 | if (!ss_initialized) { |
2033 | avtab_cache_init(); | 2056 | avtab_cache_init(); |
2057 | ebitmap_cache_init(); | ||
2034 | rc = policydb_read(&policydb, fp); | 2058 | rc = policydb_read(&policydb, fp); |
2035 | if (rc) { | 2059 | if (rc) { |
2036 | avtab_cache_destroy(); | 2060 | avtab_cache_destroy(); |
2061 | ebitmap_cache_destroy(); | ||
2037 | goto out; | 2062 | goto out; |
2038 | } | 2063 | } |
2039 | 2064 | ||
@@ -2044,6 +2069,7 @@ int security_load_policy(void *data, size_t len) | |||
2044 | if (rc) { | 2069 | if (rc) { |
2045 | policydb_destroy(&policydb); | 2070 | policydb_destroy(&policydb); |
2046 | avtab_cache_destroy(); | 2071 | avtab_cache_destroy(); |
2072 | ebitmap_cache_destroy(); | ||
2047 | goto out; | 2073 | goto out; |
2048 | } | 2074 | } |
2049 | 2075 | ||
@@ -2051,6 +2077,7 @@ int security_load_policy(void *data, size_t len) | |||
2051 | if (rc) { | 2077 | if (rc) { |
2052 | policydb_destroy(&policydb); | 2078 | policydb_destroy(&policydb); |
2053 | avtab_cache_destroy(); | 2079 | avtab_cache_destroy(); |
2080 | ebitmap_cache_destroy(); | ||
2054 | goto out; | 2081 | goto out; |
2055 | } | 2082 | } |
2056 | 2083 | ||
@@ -2210,6 +2237,87 @@ out: | |||
2210 | } | 2237 | } |
2211 | 2238 | ||
2212 | /** | 2239 | /** |
2240 | * security_pkey_sid - Obtain the SID for a pkey. | ||
2241 | * @subnet_prefix: Subnet Prefix | ||
2242 | * @pkey_num: pkey number | ||
2243 | * @out_sid: security identifier | ||
2244 | */ | ||
2245 | int security_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *out_sid) | ||
2246 | { | ||
2247 | struct ocontext *c; | ||
2248 | int rc = 0; | ||
2249 | |||
2250 | read_lock(&policy_rwlock); | ||
2251 | |||
2252 | c = policydb.ocontexts[OCON_IBPKEY]; | ||
2253 | while (c) { | ||
2254 | if (c->u.ibpkey.low_pkey <= pkey_num && | ||
2255 | c->u.ibpkey.high_pkey >= pkey_num && | ||
2256 | c->u.ibpkey.subnet_prefix == subnet_prefix) | ||
2257 | break; | ||
2258 | |||
2259 | c = c->next; | ||
2260 | } | ||
2261 | |||
2262 | if (c) { | ||
2263 | if (!c->sid[0]) { | ||
2264 | rc = sidtab_context_to_sid(&sidtab, | ||
2265 | &c->context[0], | ||
2266 | &c->sid[0]); | ||
2267 | if (rc) | ||
2268 | goto out; | ||
2269 | } | ||
2270 | *out_sid = c->sid[0]; | ||
2271 | } else | ||
2272 | *out_sid = SECINITSID_UNLABELED; | ||
2273 | |||
2274 | out: | ||
2275 | read_unlock(&policy_rwlock); | ||
2276 | return rc; | ||
2277 | } | ||
2278 | |||
2279 | /** | ||
2280 | * security_ib_endport_sid - Obtain the SID for a subnet management interface. | ||
2281 | * @dev_name: device name | ||
2282 | * @port: port number | ||
2283 | * @out_sid: security identifier | ||
2284 | */ | ||
2285 | int security_ib_endport_sid(const char *dev_name, u8 port_num, u32 *out_sid) | ||
2286 | { | ||
2287 | struct ocontext *c; | ||
2288 | int rc = 0; | ||
2289 | |||
2290 | read_lock(&policy_rwlock); | ||
2291 | |||
2292 | c = policydb.ocontexts[OCON_IBENDPORT]; | ||
2293 | while (c) { | ||
2294 | if (c->u.ibendport.port == port_num && | ||
2295 | !strncmp(c->u.ibendport.dev_name, | ||
2296 | dev_name, | ||
2297 | IB_DEVICE_NAME_MAX)) | ||
2298 | break; | ||
2299 | |||
2300 | c = c->next; | ||
2301 | } | ||
2302 | |||
2303 | if (c) { | ||
2304 | if (!c->sid[0]) { | ||
2305 | rc = sidtab_context_to_sid(&sidtab, | ||
2306 | &c->context[0], | ||
2307 | &c->sid[0]); | ||
2308 | if (rc) | ||
2309 | goto out; | ||
2310 | } | ||
2311 | *out_sid = c->sid[0]; | ||
2312 | } else | ||
2313 | *out_sid = SECINITSID_UNLABELED; | ||
2314 | |||
2315 | out: | ||
2316 | read_unlock(&policy_rwlock); | ||
2317 | return rc; | ||
2318 | } | ||
2319 | |||
2320 | /** | ||
2213 | * security_netif_sid - Obtain the SID for a network interface. | 2321 | * security_netif_sid - Obtain the SID for a network interface. |
2214 | * @name: interface name | 2322 | * @name: interface name |
2215 | * @if_sid: interface SID | 2323 | * @if_sid: interface SID |
diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c index f6915f257486..c5f436b15d19 100644 --- a/security/selinux/ss/sidtab.c +++ b/security/selinux/ss/sidtab.c | |||
@@ -32,13 +32,11 @@ int sidtab_init(struct sidtab *s) | |||
32 | 32 | ||
33 | int sidtab_insert(struct sidtab *s, u32 sid, struct context *context) | 33 | int sidtab_insert(struct sidtab *s, u32 sid, struct context *context) |
34 | { | 34 | { |
35 | int hvalue, rc = 0; | 35 | int hvalue; |
36 | struct sidtab_node *prev, *cur, *newnode; | 36 | struct sidtab_node *prev, *cur, *newnode; |
37 | 37 | ||
38 | if (!s) { | 38 | if (!s) |
39 | rc = -ENOMEM; | 39 | return -ENOMEM; |
40 | goto out; | ||
41 | } | ||
42 | 40 | ||
43 | hvalue = SIDTAB_HASH(sid); | 41 | hvalue = SIDTAB_HASH(sid); |
44 | prev = NULL; | 42 | prev = NULL; |
@@ -48,21 +46,17 @@ int sidtab_insert(struct sidtab *s, u32 sid, struct context *context) | |||
48 | cur = cur->next; | 46 | cur = cur->next; |
49 | } | 47 | } |
50 | 48 | ||
51 | if (cur && sid == cur->sid) { | 49 | if (cur && sid == cur->sid) |
52 | rc = -EEXIST; | 50 | return -EEXIST; |
53 | goto out; | ||
54 | } | ||
55 | 51 | ||
56 | newnode = kmalloc(sizeof(*newnode), GFP_ATOMIC); | 52 | newnode = kmalloc(sizeof(*newnode), GFP_ATOMIC); |
57 | if (!newnode) { | 53 | if (!newnode) |
58 | rc = -ENOMEM; | 54 | return -ENOMEM; |
59 | goto out; | 55 | |
60 | } | ||
61 | newnode->sid = sid; | 56 | newnode->sid = sid; |
62 | if (context_cpy(&newnode->context, context)) { | 57 | if (context_cpy(&newnode->context, context)) { |
63 | kfree(newnode); | 58 | kfree(newnode); |
64 | rc = -ENOMEM; | 59 | return -ENOMEM; |
65 | goto out; | ||
66 | } | 60 | } |
67 | 61 | ||
68 | if (prev) { | 62 | if (prev) { |
@@ -78,8 +72,7 @@ int sidtab_insert(struct sidtab *s, u32 sid, struct context *context) | |||
78 | s->nel++; | 72 | s->nel++; |
79 | if (sid >= s->next_sid) | 73 | if (sid >= s->next_sid) |
80 | s->next_sid = sid + 1; | 74 | s->next_sid = sid + 1; |
81 | out: | 75 | return 0; |
82 | return rc; | ||
83 | } | 76 | } |
84 | 77 | ||
85 | static struct context *sidtab_search_core(struct sidtab *s, u32 sid, int force) | 78 | static struct context *sidtab_search_core(struct sidtab *s, u32 sid, int force) |