aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kobject_uevent.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kobject_uevent.c')
-rw-r--r--lib/kobject_uevent.c137
1 files changed, 95 insertions, 42 deletions
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
index 649bf60a9440..63d0816ab23b 100644
--- a/lib/kobject_uevent.c
+++ b/lib/kobject_uevent.c
@@ -232,30 +232,6 @@ out:
232 return r; 232 return r;
233} 233}
234 234
235#ifdef CONFIG_NET
236static int kobj_bcast_filter(struct sock *dsk, struct sk_buff *skb, void *data)
237{
238 struct kobject *kobj = data, *ksobj;
239 const struct kobj_ns_type_operations *ops;
240
241 ops = kobj_ns_ops(kobj);
242 if (!ops && kobj->kset) {
243 ksobj = &kobj->kset->kobj;
244 if (ksobj->parent != NULL)
245 ops = kobj_ns_ops(ksobj->parent);
246 }
247
248 if (ops && ops->netlink_ns && kobj->ktype->namespace) {
249 const void *sock_ns, *ns;
250 ns = kobj->ktype->namespace(kobj);
251 sock_ns = ops->netlink_ns(dsk);
252 return sock_ns != ns;
253 }
254
255 return 0;
256}
257#endif
258
259#ifdef CONFIG_UEVENT_HELPER 235#ifdef CONFIG_UEVENT_HELPER
260static int kobj_usermode_filter(struct kobject *kobj) 236static int kobj_usermode_filter(struct kobject *kobj)
261{ 237{
@@ -327,17 +303,14 @@ static struct sk_buff *alloc_uevent_skb(struct kobj_uevent_env *env,
327 303
328 return skb; 304 return skb;
329} 305}
330#endif
331 306
332static int kobject_uevent_net_broadcast(struct kobject *kobj, 307static int uevent_net_broadcast_untagged(struct kobj_uevent_env *env,
333 struct kobj_uevent_env *env, 308 const char *action_string,
334 const char *action_string, 309 const char *devpath)
335 const char *devpath)
336{ 310{
337 int retval = 0;
338#if defined(CONFIG_NET)
339 struct sk_buff *skb = NULL; 311 struct sk_buff *skb = NULL;
340 struct uevent_sock *ue_sk; 312 struct uevent_sock *ue_sk;
313 int retval = 0;
341 314
342 /* send netlink message */ 315 /* send netlink message */
343 list_for_each_entry(ue_sk, &uevent_sock_list, list) { 316 list_for_each_entry(ue_sk, &uevent_sock_list, list) {
@@ -353,19 +326,93 @@ static int kobject_uevent_net_broadcast(struct kobject *kobj,
353 continue; 326 continue;
354 } 327 }
355 328
356 retval = netlink_broadcast_filtered(uevent_sock, skb_get(skb), 329 retval = netlink_broadcast(uevent_sock, skb_get(skb), 0, 1,
357 0, 1, GFP_KERNEL, 330 GFP_KERNEL);
358 kobj_bcast_filter,
359 kobj);
360 /* ENOBUFS should be handled in userspace */ 331 /* ENOBUFS should be handled in userspace */
361 if (retval == -ENOBUFS || retval == -ESRCH) 332 if (retval == -ENOBUFS || retval == -ESRCH)
362 retval = 0; 333 retval = 0;
363 } 334 }
364 consume_skb(skb); 335 consume_skb(skb);
365#endif 336
366 return retval; 337 return retval;
367} 338}
368 339
340static int uevent_net_broadcast_tagged(struct sock *usk,
341 struct kobj_uevent_env *env,
342 const char *action_string,
343 const char *devpath)
344{
345 struct user_namespace *owning_user_ns = sock_net(usk)->user_ns;
346 struct sk_buff *skb = NULL;
347 int ret = 0;
348
349 skb = alloc_uevent_skb(env, action_string, devpath);
350 if (!skb)
351 return -ENOMEM;
352
353 /* fix credentials */
354 if (owning_user_ns != &init_user_ns) {
355 struct netlink_skb_parms *parms = &NETLINK_CB(skb);
356 kuid_t root_uid;
357 kgid_t root_gid;
358
359 /* fix uid */
360 root_uid = make_kuid(owning_user_ns, 0);
361 if (uid_valid(root_uid))
362 parms->creds.uid = root_uid;
363
364 /* fix gid */
365 root_gid = make_kgid(owning_user_ns, 0);
366 if (gid_valid(root_gid))
367 parms->creds.gid = root_gid;
368 }
369
370 ret = netlink_broadcast(usk, skb, 0, 1, GFP_KERNEL);
371 /* ENOBUFS should be handled in userspace */
372 if (ret == -ENOBUFS || ret == -ESRCH)
373 ret = 0;
374
375 return ret;
376}
377#endif
378
379static int kobject_uevent_net_broadcast(struct kobject *kobj,
380 struct kobj_uevent_env *env,
381 const char *action_string,
382 const char *devpath)
383{
384 int ret = 0;
385
386#ifdef CONFIG_NET
387 const struct kobj_ns_type_operations *ops;
388 const struct net *net = NULL;
389
390 ops = kobj_ns_ops(kobj);
391 if (!ops && kobj->kset) {
392 struct kobject *ksobj = &kobj->kset->kobj;
393 if (ksobj->parent != NULL)
394 ops = kobj_ns_ops(ksobj->parent);
395 }
396
397 /* kobjects currently only carry network namespace tags and they
398 * are the only tag relevant here since we want to decide which
399 * network namespaces to broadcast the uevent into.
400 */
401 if (ops && ops->netlink_ns && kobj->ktype->namespace)
402 if (ops->type == KOBJ_NS_TYPE_NET)
403 net = kobj->ktype->namespace(kobj);
404
405 if (!net)
406 ret = uevent_net_broadcast_untagged(env, action_string,
407 devpath);
408 else
409 ret = uevent_net_broadcast_tagged(net->uevent_sock->sk, env,
410 action_string, devpath);
411#endif
412
413 return ret;
414}
415
369static void zap_modalias_env(struct kobj_uevent_env *env) 416static void zap_modalias_env(struct kobj_uevent_env *env)
370{ 417{
371 static const char modalias_prefix[] = "MODALIAS="; 418 static const char modalias_prefix[] = "MODALIAS=";
@@ -724,9 +771,13 @@ static int uevent_net_init(struct net *net)
724 771
725 net->uevent_sock = ue_sk; 772 net->uevent_sock = ue_sk;
726 773
727 mutex_lock(&uevent_sock_mutex); 774 /* Restrict uevents to initial user namespace. */
728 list_add_tail(&ue_sk->list, &uevent_sock_list); 775 if (sock_net(ue_sk->sk)->user_ns == &init_user_ns) {
729 mutex_unlock(&uevent_sock_mutex); 776 mutex_lock(&uevent_sock_mutex);
777 list_add_tail(&ue_sk->list, &uevent_sock_list);
778 mutex_unlock(&uevent_sock_mutex);
779 }
780
730 return 0; 781 return 0;
731} 782}
732 783
@@ -734,9 +785,11 @@ static void uevent_net_exit(struct net *net)
734{ 785{
735 struct uevent_sock *ue_sk = net->uevent_sock; 786 struct uevent_sock *ue_sk = net->uevent_sock;
736 787
737 mutex_lock(&uevent_sock_mutex); 788 if (sock_net(ue_sk->sk)->user_ns == &init_user_ns) {
738 list_del(&ue_sk->list); 789 mutex_lock(&uevent_sock_mutex);
739 mutex_unlock(&uevent_sock_mutex); 790 list_del(&ue_sk->list);
791 mutex_unlock(&uevent_sock_mutex);
792 }
740 793
741 netlink_kernel_release(ue_sk->sk); 794 netlink_kernel_release(ue_sk->sk);
742 kfree(ue_sk); 795 kfree(ue_sk);