--- zzzz-none-000/linux-3.10.107/lib/kobject_uevent.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/lib/kobject_uevent.c 2021-02-04 17:41:59.000000000 +0000 @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -29,7 +28,9 @@ u64 uevent_seqnum; +#ifdef CONFIG_UEVENT_HELPER char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH; +#endif #ifdef CONFIG_NET struct uevent_sock { struct list_head list; @@ -51,6 +52,18 @@ [KOBJ_OFFLINE] = "offline", }; +u64 uevent_next_seqnum(void) +{ + u64 seq; + + mutex_lock(&uevent_sock_mutex); + seq = ++uevent_seqnum; + mutex_unlock(&uevent_sock_mutex); + + return seq; +} +EXPORT_SYMBOL_GPL(uevent_next_seqnum); + /** * kobject_action_type - translate action string to numeric type * @@ -88,11 +101,17 @@ #ifdef CONFIG_NET static int kobj_bcast_filter(struct sock *dsk, struct sk_buff *skb, void *data) { - struct kobject *kobj = data; + struct kobject *kobj = data, *ksobj; const struct kobj_ns_type_operations *ops; ops = kobj_ns_ops(kobj); - if (ops) { + if (!ops && kobj->kset) { + ksobj = &kobj->kset->kobj; + if (ksobj->parent != NULL) + ops = kobj_ns_ops(ksobj->parent); + } + + if (ops && ops->netlink_ns && kobj->ktype->namespace) { const void *sock_ns, *ns; ns = kobj->ktype->namespace(kobj); sock_ns = ops->netlink_ns(dsk); @@ -103,6 +122,7 @@ } #endif +#ifdef CONFIG_UEVENT_HELPER static int kobj_usermode_filter(struct kobject *kobj) { const struct kobj_ns_type_operations *ops; @@ -118,6 +138,31 @@ return 0; } +static int init_uevent_argv(struct kobj_uevent_env *env, const char *subsystem) +{ + int len; + + len = strlcpy(&env->buf[env->buflen], subsystem, + sizeof(env->buf) - env->buflen); + if (len >= (sizeof(env->buf) - env->buflen)) { + WARN(1, KERN_ERR "init_uevent_argv: buffer size too small\n"); + return -ENOMEM; + } + + env->argv[0] = uevent_helper; + env->argv[1] = &env->buf[env->buflen]; + env->argv[2] = NULL; + + env->buflen += len + 1; + return 0; +} + +static void cleanup_uevent_env(struct subprocess_info *info) +{ + kfree(info->data); +} +#endif + /** * kobject_uevent_env - send an uevent with environmental data * @@ -293,13 +338,11 @@ #endif mutex_unlock(&uevent_sock_mutex); +#ifdef CONFIG_UEVENT_HELPER /* call uevent_helper, usually only enabled during early boot */ if (uevent_helper[0] && !kobj_usermode_filter(kobj)) { - char *argv [3]; + struct subprocess_info *info; - argv [0] = uevent_helper; - argv [1] = (char *)subsystem; - argv [2] = NULL; retval = add_uevent_var(env, "HOME=/"); if (retval) goto exit; @@ -307,10 +350,20 @@ "PATH=/sbin:/bin:/usr/sbin:/usr/bin"); if (retval) goto exit; + retval = init_uevent_argv(env, subsystem); + if (retval) + goto exit; - retval = call_usermodehelper(argv[0], argv, - env->envp, UMH_WAIT_EXEC); + retval = -ENOMEM; + info = call_usermodehelper_setup(env->argv[0], env->argv, + env->envp, GFP_KERNEL, + NULL, cleanup_uevent_env, env); + if (info) { + retval = call_usermodehelper_exec(info, UMH_NO_WAIT); + env = NULL; /* freed by cleanup_uevent_env */ + } } +#endif exit: kfree(devpath); @@ -370,6 +423,43 @@ EXPORT_SYMBOL_GPL(add_uevent_var); #if defined(CONFIG_NET) +int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group, + gfp_t allocation) +{ + struct uevent_sock *ue_sk; + int err = 0; + + /* send netlink message */ + mutex_lock(&uevent_sock_mutex); + list_for_each_entry(ue_sk, &uevent_sock_list, list) { + struct sock *uevent_sock = ue_sk->sk; + struct sk_buff *skb2; + + skb2 = skb_clone(skb, allocation); + if (!skb2) + break; + + err = netlink_broadcast(uevent_sock, skb2, pid, group, + allocation); + if (err) + break; + } + mutex_unlock(&uevent_sock_mutex); + + kfree_skb(skb); + return err; +} +#else +int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group, + gfp_t allocation) +{ + kfree_skb(skb); + return 0; +} +#endif +EXPORT_SYMBOL_GPL(broadcast_uevent); + +#if defined(CONFIG_NET) static int uevent_net_init(struct net *net) { struct uevent_sock *ue_sk;