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.c79
1 files changed, 78 insertions, 1 deletions
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
index 54cfbaeb3a4e..fa10ad8e9b17 100644
--- a/lib/kobject_uevent.c
+++ b/lib/kobject_uevent.c
@@ -25,6 +25,7 @@
25#include <linux/uuid.h> 25#include <linux/uuid.h>
26#include <linux/ctype.h> 26#include <linux/ctype.h>
27#include <net/sock.h> 27#include <net/sock.h>
28#include <net/netlink.h>
28#include <net/net_namespace.h> 29#include <net/net_namespace.h>
29 30
30 31
@@ -604,12 +605,88 @@ int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...)
604EXPORT_SYMBOL_GPL(add_uevent_var); 605EXPORT_SYMBOL_GPL(add_uevent_var);
605 606
606#if defined(CONFIG_NET) 607#if defined(CONFIG_NET)
608static int uevent_net_broadcast(struct sock *usk, struct sk_buff *skb,
609 struct netlink_ext_ack *extack)
610{
611 /* u64 to chars: 2^64 - 1 = 21 chars */
612 char buf[sizeof("SEQNUM=") + 21];
613 struct sk_buff *skbc;
614 int ret;
615
616 /* bump and prepare sequence number */
617 ret = snprintf(buf, sizeof(buf), "SEQNUM=%llu", ++uevent_seqnum);
618 if (ret < 0 || (size_t)ret >= sizeof(buf))
619 return -ENOMEM;
620 ret++;
621
622 /* verify message does not overflow */
623 if ((skb->len + ret) > UEVENT_BUFFER_SIZE) {
624 NL_SET_ERR_MSG(extack, "uevent message too big");
625 return -EINVAL;
626 }
627
628 /* copy skb and extend to accommodate sequence number */
629 skbc = skb_copy_expand(skb, 0, ret, GFP_KERNEL);
630 if (!skbc)
631 return -ENOMEM;
632
633 /* append sequence number */
634 skb_put_data(skbc, buf, ret);
635
636 /* remove msg header */
637 skb_pull(skbc, NLMSG_HDRLEN);
638
639 /* set portid 0 to inform userspace message comes from kernel */
640 NETLINK_CB(skbc).portid = 0;
641 NETLINK_CB(skbc).dst_group = 1;
642
643 ret = netlink_broadcast(usk, skbc, 0, 1, GFP_KERNEL);
644 /* ENOBUFS should be handled in userspace */
645 if (ret == -ENOBUFS || ret == -ESRCH)
646 ret = 0;
647
648 return ret;
649}
650
651static int uevent_net_rcv_skb(struct sk_buff *skb, struct nlmsghdr *nlh,
652 struct netlink_ext_ack *extack)
653{
654 struct net *net;
655 int ret;
656
657 if (!nlmsg_data(nlh))
658 return -EINVAL;
659
660 /*
661 * Verify that we are allowed to send messages to the target
662 * network namespace. The caller must have CAP_SYS_ADMIN in the
663 * owning user namespace of the target network namespace.
664 */
665 net = sock_net(NETLINK_CB(skb).sk);
666 if (!netlink_ns_capable(skb, net->user_ns, CAP_SYS_ADMIN)) {
667 NL_SET_ERR_MSG(extack, "missing CAP_SYS_ADMIN capability");
668 return -EPERM;
669 }
670
671 mutex_lock(&uevent_sock_mutex);
672 ret = uevent_net_broadcast(net->uevent_sock->sk, skb, extack);
673 mutex_unlock(&uevent_sock_mutex);
674
675 return ret;
676}
677
678static void uevent_net_rcv(struct sk_buff *skb)
679{
680 netlink_rcv_skb(skb, &uevent_net_rcv_skb);
681}
682
607static int uevent_net_init(struct net *net) 683static int uevent_net_init(struct net *net)
608{ 684{
609 struct uevent_sock *ue_sk; 685 struct uevent_sock *ue_sk;
610 struct netlink_kernel_cfg cfg = { 686 struct netlink_kernel_cfg cfg = {
611 .groups = 1, 687 .groups = 1,
612 .flags = NL_CFG_F_NONROOT_RECV, 688 .input = uevent_net_rcv,
689 .flags = NL_CFG_F_NONROOT_RECV
613 }; 690 };
614 691
615 ue_sk = kzalloc(sizeof(*ue_sk), GFP_KERNEL); 692 ue_sk = kzalloc(sizeof(*ue_sk), GFP_KERNEL);