linux/lib/kobject_uevent.c
<<
>>
Prefs
   1/*
   2 * kernel userspace event delivery
   3 *
   4 * Copyright (C) 2004 Red Hat, Inc.  All rights reserved.
   5 * Copyright (C) 2004 Novell, Inc.  All rights reserved.
   6 * Copyright (C) 2004 IBM, Inc. All rights reserved.
   7 *
   8 * Licensed under the GNU GPL v2.
   9 *
  10 * Authors:
  11 *      Robert Love             <rml@novell.com>
  12 *      Kay Sievers             <kay.sievers@vrfy.org>
  13 *      Arjan van de Ven        <arjanv@redhat.com>
  14 *      Greg Kroah-Hartman      <greg@kroah.com>
  15 */
  16
  17#include <linux/spinlock.h>
  18#include <linux/string.h>
  19#include <linux/kobject.h>
  20#include <linux/export.h>
  21#include <linux/kmod.h>
  22#include <linux/slab.h>
  23#include <linux/user_namespace.h>
  24#include <linux/socket.h>
  25#include <linux/skbuff.h>
  26#include <linux/netlink.h>
  27#include <net/sock.h>
  28#include <net/net_namespace.h>
  29
  30
  31u64 uevent_seqnum;
  32char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH;
  33#ifdef CONFIG_NET
  34struct uevent_sock {
  35        struct list_head list;
  36        struct sock *sk;
  37};
  38static LIST_HEAD(uevent_sock_list);
  39#endif
  40
  41/* This lock protects uevent_seqnum and uevent_sock_list */
  42static DEFINE_MUTEX(uevent_sock_mutex);
  43
  44/* the strings here must match the enum in include/linux/kobject.h */
  45static const char *kobject_actions[] = {
  46        [KOBJ_ADD] =            "add",
  47        [KOBJ_REMOVE] =         "remove",
  48        [KOBJ_CHANGE] =         "change",
  49        [KOBJ_MOVE] =           "move",
  50        [KOBJ_ONLINE] =         "online",
  51        [KOBJ_OFFLINE] =        "offline",
  52};
  53
  54/**
  55 * kobject_action_type - translate action string to numeric type
  56 *
  57 * @buf: buffer containing the action string, newline is ignored
  58 * @len: length of buffer
  59 * @type: pointer to the location to store the action type
  60 *
  61 * Returns 0 if the action string was recognized.
  62 */
  63int kobject_action_type(const char *buf, size_t count,
  64                        enum kobject_action *type)
  65{
  66        enum kobject_action action;
  67        int ret = -EINVAL;
  68
  69        if (count && (buf[count-1] == '\n' || buf[count-1] == '\0'))
  70                count--;
  71
  72        if (!count)
  73                goto out;
  74
  75        for (action = 0; action < ARRAY_SIZE(kobject_actions); action++) {
  76                if (strncmp(kobject_actions[action], buf, count) != 0)
  77                        continue;
  78                if (kobject_actions[action][count] != '\0')
  79                        continue;
  80                *type = action;
  81                ret = 0;
  82                break;
  83        }
  84out:
  85        return ret;
  86}
  87
  88#ifdef CONFIG_NET
  89static int kobj_bcast_filter(struct sock *dsk, struct sk_buff *skb, void *data)
  90{
  91        struct kobject *kobj = data;
  92        const struct kobj_ns_type_operations *ops;
  93
  94        ops = kobj_ns_ops(kobj);
  95        if (ops) {
  96                const void *sock_ns, *ns;
  97                ns = kobj->ktype->namespace(kobj);
  98                sock_ns = ops->netlink_ns(dsk);
  99                return sock_ns != ns;
 100        }
 101
 102        return 0;
 103}
 104#endif
 105
 106static int kobj_usermode_filter(struct kobject *kobj)
 107{
 108        const struct kobj_ns_type_operations *ops;
 109
 110        ops = kobj_ns_ops(kobj);
 111        if (ops) {
 112                const void *init_ns, *ns;
 113                ns = kobj->ktype->namespace(kobj);
 114                init_ns = ops->initial_ns();
 115                return ns != init_ns;
 116        }
 117
 118        return 0;
 119}
 120
 121/**
 122 * kobject_uevent_env - send an uevent with environmental data
 123 *
 124 * @action: action that is happening
 125 * @kobj: struct kobject that the action is happening to
 126 * @envp_ext: pointer to environmental data
 127 *
 128 * Returns 0 if kobject_uevent_env() is completed with success or the
 129 * corresponding error when it fails.
 130 */
 131int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
 132                       char *envp_ext[])
 133{
 134        struct kobj_uevent_env *env;
 135        const char *action_string = kobject_actions[action];
 136        const char *devpath = NULL;
 137        const char *subsystem;
 138        struct kobject *top_kobj;
 139        struct kset *kset;
 140        const struct kset_uevent_ops *uevent_ops;
 141        int i = 0;
 142        int retval = 0;
 143#ifdef CONFIG_NET
 144        struct uevent_sock *ue_sk;
 145#endif
 146
 147        pr_debug("kobject: '%s' (%p): %s\n",
 148                 kobject_name(kobj), kobj, __func__);
 149
 150        /* search the kset we belong to */
 151        top_kobj = kobj;
 152        while (!top_kobj->kset && top_kobj->parent)
 153                top_kobj = top_kobj->parent;
 154
 155        if (!top_kobj->kset) {
 156                pr_debug("kobject: '%s' (%p): %s: attempted to send uevent "
 157                         "without kset!\n", kobject_name(kobj), kobj,
 158                         __func__);
 159                return -EINVAL;
 160        }
 161
 162        kset = top_kobj->kset;
 163        uevent_ops = kset->uevent_ops;
 164
 165        /* skip the event, if uevent_suppress is set*/
 166        if (kobj->uevent_suppress) {
 167                pr_debug("kobject: '%s' (%p): %s: uevent_suppress "
 168                                 "caused the event to drop!\n",
 169                                 kobject_name(kobj), kobj, __func__);
 170                return 0;
 171        }
 172        /* skip the event, if the filter returns zero. */
 173        if (uevent_ops && uevent_ops->filter)
 174                if (!uevent_ops->filter(kset, kobj)) {
 175                        pr_debug("kobject: '%s' (%p): %s: filter function "
 176                                 "caused the event to drop!\n",
 177                                 kobject_name(kobj), kobj, __func__);
 178                        return 0;
 179                }
 180
 181        /* originating subsystem */
 182        if (uevent_ops && uevent_ops->name)
 183                subsystem = uevent_ops->name(kset, kobj);
 184        else
 185                subsystem = kobject_name(&kset->kobj);
 186        if (!subsystem) {
 187                pr_debug("kobject: '%s' (%p): %s: unset subsystem caused the "
 188                         "event to drop!\n", kobject_name(kobj), kobj,
 189                         __func__);
 190                return 0;
 191        }
 192
 193        /* environment buffer */
 194        env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
 195        if (!env)
 196                return -ENOMEM;
 197
 198        /* complete object path */
 199        devpath = kobject_get_path(kobj, GFP_KERNEL);
 200        if (!devpath) {
 201                retval = -ENOENT;
 202                goto exit;
 203        }
 204
 205        /* default keys */
 206        retval = add_uevent_var(env, "ACTION=%s", action_string);
 207        if (retval)
 208                goto exit;
 209        retval = add_uevent_var(env, "DEVPATH=%s", devpath);
 210        if (retval)
 211                goto exit;
 212        retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);
 213        if (retval)
 214                goto exit;
 215
 216        /* keys passed in from the caller */
 217        if (envp_ext) {
 218                for (i = 0; envp_ext[i]; i++) {
 219                        retval = add_uevent_var(env, "%s", envp_ext[i]);
 220                        if (retval)
 221                                goto exit;
 222                }
 223        }
 224
 225        /* let the kset specific function add its stuff */
 226        if (uevent_ops && uevent_ops->uevent) {
 227                retval = uevent_ops->uevent(kset, kobj, env);
 228                if (retval) {
 229                        pr_debug("kobject: '%s' (%p): %s: uevent() returned "
 230                                 "%d\n", kobject_name(kobj), kobj,
 231                                 __func__, retval);
 232                        goto exit;
 233                }
 234        }
 235
 236        /*
 237         * Mark "add" and "remove" events in the object to ensure proper
 238         * events to userspace during automatic cleanup. If the object did
 239         * send an "add" event, "remove" will automatically generated by
 240         * the core, if not already done by the caller.
 241         */
 242        if (action == KOBJ_ADD)
 243                kobj->state_add_uevent_sent = 1;
 244        else if (action == KOBJ_REMOVE)
 245                kobj->state_remove_uevent_sent = 1;
 246
 247        mutex_lock(&uevent_sock_mutex);
 248        /* we will send an event, so request a new sequence number */
 249        retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)++uevent_seqnum);
 250        if (retval) {
 251                mutex_unlock(&uevent_sock_mutex);
 252                goto exit;
 253        }
 254
 255#if defined(CONFIG_NET)
 256        /* send netlink message */
 257        list_for_each_entry(ue_sk, &uevent_sock_list, list) {
 258                struct sock *uevent_sock = ue_sk->sk;
 259                struct sk_buff *skb;
 260                size_t len;
 261
 262                if (!netlink_has_listeners(uevent_sock, 1))
 263                        continue;
 264
 265                /* allocate message with the maximum possible size */
 266                len = strlen(action_string) + strlen(devpath) + 2;
 267                skb = alloc_skb(len + env->buflen, GFP_KERNEL);
 268                if (skb) {
 269                        char *scratch;
 270
 271                        /* add header */
 272                        scratch = skb_put(skb, len);
 273                        sprintf(scratch, "%s@%s", action_string, devpath);
 274
 275                        /* copy keys to our continuous event payload buffer */
 276                        for (i = 0; i < env->envp_idx; i++) {
 277                                len = strlen(env->envp[i]) + 1;
 278                                scratch = skb_put(skb, len);
 279                                strcpy(scratch, env->envp[i]);
 280                        }
 281
 282                        NETLINK_CB(skb).dst_group = 1;
 283                        retval = netlink_broadcast_filtered(uevent_sock, skb,
 284                                                            0, 1, GFP_KERNEL,
 285                                                            kobj_bcast_filter,
 286                                                            kobj);
 287                        /* ENOBUFS should be handled in userspace */
 288                        if (retval == -ENOBUFS || retval == -ESRCH)
 289                                retval = 0;
 290                } else
 291                        retval = -ENOMEM;
 292        }
 293#endif
 294        mutex_unlock(&uevent_sock_mutex);
 295
 296        /* call uevent_helper, usually only enabled during early boot */
 297        if (uevent_helper[0] && !kobj_usermode_filter(kobj)) {
 298                char *argv [3];
 299
 300                argv [0] = uevent_helper;
 301                argv [1] = (char *)subsystem;
 302                argv [2] = NULL;
 303                retval = add_uevent_var(env, "HOME=/");
 304                if (retval)
 305                        goto exit;
 306                retval = add_uevent_var(env,
 307                                        "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
 308                if (retval)
 309                        goto exit;
 310
 311                retval = call_usermodehelper(argv[0], argv,
 312                                             env->envp, UMH_WAIT_EXEC);
 313        }
 314
 315exit:
 316        kfree(devpath);
 317        kfree(env);
 318        return retval;
 319}
 320EXPORT_SYMBOL_GPL(kobject_uevent_env);
 321
 322/**
 323 * kobject_uevent - notify userspace by sending an uevent
 324 *
 325 * @action: action that is happening
 326 * @kobj: struct kobject that the action is happening to
 327 *
 328 * Returns 0 if kobject_uevent() is completed with success or the
 329 * corresponding error when it fails.
 330 */
 331int kobject_uevent(struct kobject *kobj, enum kobject_action action)
 332{
 333        return kobject_uevent_env(kobj, action, NULL);
 334}
 335EXPORT_SYMBOL_GPL(kobject_uevent);
 336
 337/**
 338 * add_uevent_var - add key value string to the environment buffer
 339 * @env: environment buffer structure
 340 * @format: printf format for the key=value pair
 341 *
 342 * Returns 0 if environment variable was added successfully or -ENOMEM
 343 * if no space was available.
 344 */
 345int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...)
 346{
 347        va_list args;
 348        int len;
 349
 350        if (env->envp_idx >= ARRAY_SIZE(env->envp)) {
 351                WARN(1, KERN_ERR "add_uevent_var: too many keys\n");
 352                return -ENOMEM;
 353        }
 354
 355        va_start(args, format);
 356        len = vsnprintf(&env->buf[env->buflen],
 357                        sizeof(env->buf) - env->buflen,
 358                        format, args);
 359        va_end(args);
 360
 361        if (len >= (sizeof(env->buf) - env->buflen)) {
 362                WARN(1, KERN_ERR "add_uevent_var: buffer size too small\n");
 363                return -ENOMEM;
 364        }
 365
 366        env->envp[env->envp_idx++] = &env->buf[env->buflen];
 367        env->buflen += len + 1;
 368        return 0;
 369}
 370EXPORT_SYMBOL_GPL(add_uevent_var);
 371
 372#if defined(CONFIG_NET)
 373static int uevent_net_init(struct net *net)
 374{
 375        struct uevent_sock *ue_sk;
 376        struct netlink_kernel_cfg cfg = {
 377                .groups = 1,
 378        };
 379
 380        ue_sk = kzalloc(sizeof(*ue_sk), GFP_KERNEL);
 381        if (!ue_sk)
 382                return -ENOMEM;
 383
 384        ue_sk->sk = netlink_kernel_create(net, NETLINK_KOBJECT_UEVENT,
 385                                          THIS_MODULE, &cfg);
 386        if (!ue_sk->sk) {
 387                printk(KERN_ERR
 388                       "kobject_uevent: unable to create netlink socket!\n");
 389                kfree(ue_sk);
 390                return -ENODEV;
 391        }
 392        mutex_lock(&uevent_sock_mutex);
 393        list_add_tail(&ue_sk->list, &uevent_sock_list);
 394        mutex_unlock(&uevent_sock_mutex);
 395        return 0;
 396}
 397
 398static void uevent_net_exit(struct net *net)
 399{
 400        struct uevent_sock *ue_sk;
 401
 402        mutex_lock(&uevent_sock_mutex);
 403        list_for_each_entry(ue_sk, &uevent_sock_list, list) {
 404                if (sock_net(ue_sk->sk) == net)
 405                        goto found;
 406        }
 407        mutex_unlock(&uevent_sock_mutex);
 408        return;
 409
 410found:
 411        list_del(&ue_sk->list);
 412        mutex_unlock(&uevent_sock_mutex);
 413
 414        netlink_kernel_release(ue_sk->sk);
 415        kfree(ue_sk);
 416}
 417
 418static struct pernet_operations uevent_net_ops = {
 419        .init   = uevent_net_init,
 420        .exit   = uevent_net_exit,
 421};
 422
 423static int __init kobject_uevent_init(void)
 424{
 425        netlink_set_nonroot(NETLINK_KOBJECT_UEVENT, NL_NONROOT_RECV);
 426        return register_pernet_subsys(&uevent_net_ops);
 427}
 428
 429
 430postcore_initcall(kobject_uevent_init);
 431#endif
 432
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.