kobject_uevent.c 10.3 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * kernel userspace event delivery
 *
 * Copyright (C) 2004 Red Hat, Inc.  All rights reserved.
 * Copyright (C) 2004 Novell, Inc.  All rights reserved.
 * Copyright (C) 2004 IBM, Inc. All rights reserved.
 *
 * Licensed under the GNU GPL v2.
 *
 * Authors:
 *	Robert Love		<rml@novell.com>
 *	Kay Sievers		<kay.sievers@vrfy.org>
 *	Arjan van de Ven	<arjanv@redhat.com>
 *	Greg Kroah-Hartman	<greg@kroah.com>
 */

#include <linux/spinlock.h>
18 19 20
#include <linux/string.h>
#include <linux/kobject.h>
#include <linux/module.h>
21
#include <linux/slab.h>
22
#include <linux/user_namespace.h>
L
Linus Torvalds 已提交
23 24 25 26
#include <linux/socket.h>
#include <linux/skbuff.h>
#include <linux/netlink.h>
#include <net/sock.h>
27
#include <net/net_namespace.h>
L
Linus Torvalds 已提交
28 29


30
u64 uevent_seqnum;
31
char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH;
32
static DEFINE_SPINLOCK(sequence_lock);
33 34 35 36 37 38 39
#ifdef CONFIG_NET
struct uevent_sock {
	struct list_head list;
	struct sock *sk;
};
static LIST_HEAD(uevent_sock_list);
static DEFINE_MUTEX(uevent_sock_mutex);
40 41
#endif

42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
/* the strings here must match the enum in include/linux/kobject.h */
static const char *kobject_actions[] = {
	[KOBJ_ADD] =		"add",
	[KOBJ_REMOVE] =		"remove",
	[KOBJ_CHANGE] =		"change",
	[KOBJ_MOVE] =		"move",
	[KOBJ_ONLINE] =		"online",
	[KOBJ_OFFLINE] =	"offline",
};

/**
 * kobject_action_type - translate action string to numeric type
 *
 * @buf: buffer containing the action string, newline is ignored
 * @len: length of buffer
 * @type: pointer to the location to store the action type
 *
 * Returns 0 if the action string was recognized.
 */
int kobject_action_type(const char *buf, size_t count,
			enum kobject_action *type)
{
	enum kobject_action action;
	int ret = -EINVAL;

M
Mark Lord 已提交
67
	if (count && (buf[count-1] == '\n' || buf[count-1] == '\0'))
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
		count--;

	if (!count)
		goto out;

	for (action = 0; action < ARRAY_SIZE(kobject_actions); action++) {
		if (strncmp(kobject_actions[action], buf, count) != 0)
			continue;
		if (kobject_actions[action][count] != '\0')
			continue;
		*type = action;
		ret = 0;
		break;
	}
out:
	return ret;
}

86
#ifdef CONFIG_NET
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
static int kobj_bcast_filter(struct sock *dsk, struct sk_buff *skb, void *data)
{
	struct kobject *kobj = data;
	const struct kobj_ns_type_operations *ops;

	ops = kobj_ns_ops(kobj);
	if (ops) {
		const void *sock_ns, *ns;
		ns = kobj->ktype->namespace(kobj);
		sock_ns = ops->netlink_ns(dsk);
		return sock_ns != ns;
	}

	return 0;
}
102
#endif
103

104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
static int kobj_usermode_filter(struct kobject *kobj)
{
	const struct kobj_ns_type_operations *ops;

	ops = kobj_ns_ops(kobj);
	if (ops) {
		const void *init_ns, *ns;
		ns = kobj->ktype->namespace(kobj);
		init_ns = ops->initial_ns();
		return ns != init_ns;
	}

	return 0;
}

L
Linus Torvalds 已提交
119
/**
120
 * kobject_uevent_env - send an uevent with environmental data
L
Linus Torvalds 已提交
121
 *
122
 * @action: action that is happening
L
Linus Torvalds 已提交
123
 * @kobj: struct kobject that the action is happening to
124
 * @envp_ext: pointer to environmental data
125 126 127
 *
 * Returns 0 if kobject_uevent() is completed with success or the
 * corresponding error when it fails.
L
Linus Torvalds 已提交
128
 */
129
int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
130
		       char *envp_ext[])
L
Linus Torvalds 已提交
131
{
132 133
	struct kobj_uevent_env *env;
	const char *action_string = kobject_actions[action];
134 135 136 137
	const char *devpath = NULL;
	const char *subsystem;
	struct kobject *top_kobj;
	struct kset *kset;
138
	const struct kset_uevent_ops *uevent_ops;
139
	u64 seq;
L
Linus Torvalds 已提交
140
	int i = 0;
141
	int retval = 0;
142 143 144
#ifdef CONFIG_NET
	struct uevent_sock *ue_sk;
#endif
L
Linus Torvalds 已提交
145

146
	pr_debug("kobject: '%s' (%p): %s\n",
147
		 kobject_name(kobj), kobj, __func__);
148 149 150

	/* search the kset we belong to */
	top_kobj = kobj;
151
	while (!top_kobj->kset && top_kobj->parent)
152
		top_kobj = top_kobj->parent;
153

154
	if (!top_kobj->kset) {
155 156
		pr_debug("kobject: '%s' (%p): %s: attempted to send uevent "
			 "without kset!\n", kobject_name(kobj), kobj,
157
			 __func__);
158 159
		return -EINVAL;
	}
L
Linus Torvalds 已提交
160

161
	kset = top_kobj->kset;
162
	uevent_ops = kset->uevent_ops;
L
Linus Torvalds 已提交
163

164 165 166 167 168 169 170
	/* skip the event, if uevent_suppress is set*/
	if (kobj->uevent_suppress) {
		pr_debug("kobject: '%s' (%p): %s: uevent_suppress "
				 "caused the event to drop!\n",
				 kobject_name(kobj), kobj, __func__);
		return 0;
	}
171
	/* skip the event, if the filter returns zero. */
172
	if (uevent_ops && uevent_ops->filter)
173
		if (!uevent_ops->filter(kset, kobj)) {
174 175
			pr_debug("kobject: '%s' (%p): %s: filter function "
				 "caused the event to drop!\n",
176
				 kobject_name(kobj), kobj, __func__);
177 178
			return 0;
		}
L
Linus Torvalds 已提交
179

180 181 182 183 184 185
	/* originating subsystem */
	if (uevent_ops && uevent_ops->name)
		subsystem = uevent_ops->name(kset, kobj);
	else
		subsystem = kobject_name(&kset->kobj);
	if (!subsystem) {
186 187
		pr_debug("kobject: '%s' (%p): %s: unset subsystem caused the "
			 "event to drop!\n", kobject_name(kobj), kobj,
188
			 __func__);
189 190 191
		return 0;
	}

192 193 194
	/* environment buffer */
	env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
	if (!env)
195
		return -ENOMEM;
L
Linus Torvalds 已提交
196

197 198
	/* complete object path */
	devpath = kobject_get_path(kobj, GFP_KERNEL);
199 200
	if (!devpath) {
		retval = -ENOENT;
201
		goto exit;
202
	}
L
Linus Torvalds 已提交
203

204
	/* default keys */
205 206 207 208 209 210 211 212 213 214 215 216 217
	retval = add_uevent_var(env, "ACTION=%s", action_string);
	if (retval)
		goto exit;
	retval = add_uevent_var(env, "DEVPATH=%s", devpath);
	if (retval)
		goto exit;
	retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);
	if (retval)
		goto exit;

	/* keys passed in from the caller */
	if (envp_ext) {
		for (i = 0; envp_ext[i]; i++) {
218
			retval = add_uevent_var(env, "%s", envp_ext[i]);
219 220 221 222
			if (retval)
				goto exit;
		}
	}
L
Linus Torvalds 已提交
223

224
	/* let the kset specific function add its stuff */
225
	if (uevent_ops && uevent_ops->uevent) {
226
		retval = uevent_ops->uevent(kset, kobj, env);
L
Linus Torvalds 已提交
227
		if (retval) {
228 229
			pr_debug("kobject: '%s' (%p): %s: uevent() returned "
				 "%d\n", kobject_name(kobj), kobj,
230
				 __func__, retval);
L
Linus Torvalds 已提交
231 232 233 234
			goto exit;
		}
	}

235 236 237 238 239 240 241 242 243 244 245
	/*
	 * Mark "add" and "remove" events in the object to ensure proper
	 * events to userspace during automatic cleanup. If the object did
	 * send an "add" event, "remove" will automatically generated by
	 * the core, if not already done by the caller.
	 */
	if (action == KOBJ_ADD)
		kobj->state_add_uevent_sent = 1;
	else if (action == KOBJ_REMOVE)
		kobj->state_remove_uevent_sent = 1;

246
	/* we will send an event, so request a new sequence number */
L
Linus Torvalds 已提交
247
	spin_lock(&sequence_lock);
248
	seq = ++uevent_seqnum;
L
Linus Torvalds 已提交
249
	spin_unlock(&sequence_lock);
250 251 252
	retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)seq);
	if (retval)
		goto exit;
L
Linus Torvalds 已提交
253

K
Kay Sievers 已提交
254
#if defined(CONFIG_NET)
255
	/* send netlink message */
256 257 258
	mutex_lock(&uevent_sock_mutex);
	list_for_each_entry(ue_sk, &uevent_sock_list, list) {
		struct sock *uevent_sock = ue_sk->sk;
259 260 261 262 263
		struct sk_buff *skb;
		size_t len;

		/* allocate message with the maximum possible size */
		len = strlen(action_string) + strlen(devpath) + 2;
264
		skb = alloc_skb(len + env->buflen, GFP_KERNEL);
265
		if (skb) {
266 267
			char *scratch;

268 269 270 271 272
			/* add header */
			scratch = skb_put(skb, len);
			sprintf(scratch, "%s@%s", action_string, devpath);

			/* copy keys to our continuous event payload buffer */
273 274
			for (i = 0; i < env->envp_idx; i++) {
				len = strlen(env->envp[i]) + 1;
275
				scratch = skb_put(skb, len);
276
				strcpy(scratch, env->envp[i]);
277 278 279
			}

			NETLINK_CB(skb).dst_group = 1;
280 281 282 283
			retval = netlink_broadcast_filtered(uevent_sock, skb,
							    0, 1, GFP_KERNEL,
							    kobj_bcast_filter,
							    kobj);
284 285 286
			/* ENOBUFS should be handled in userspace */
			if (retval == -ENOBUFS)
				retval = 0;
287 288
		} else
			retval = -ENOMEM;
289
	}
290
	mutex_unlock(&uevent_sock_mutex);
K
Kay Sievers 已提交
291
#endif
L
Linus Torvalds 已提交
292

293
	/* call uevent_helper, usually only enabled during early boot */
294
	if (uevent_helper[0] && !kobj_usermode_filter(kobj)) {
295
		char *argv [3];
L
Linus Torvalds 已提交
296

297
		argv [0] = uevent_helper;
298 299
		argv [1] = (char *)subsystem;
		argv [2] = NULL;
300 301 302
		retval = add_uevent_var(env, "HOME=/");
		if (retval)
			goto exit;
303 304
		retval = add_uevent_var(env,
					"PATH=/sbin:/bin:/usr/sbin:/usr/bin");
305 306 307
		if (retval)
			goto exit;

308
		retval = call_usermodehelper(argv[0], argv,
309
					     env->envp, UMH_WAIT_EXEC);
310
	}
L
Linus Torvalds 已提交
311 312

exit:
313
	kfree(devpath);
314
	kfree(env);
315
	return retval;
L
Linus Torvalds 已提交
316
}
317 318 319 320 321
EXPORT_SYMBOL_GPL(kobject_uevent_env);

/**
 * kobject_uevent - notify userspace by ending an uevent
 *
322
 * @action: action that is happening
323
 * @kobj: struct kobject that the action is happening to
324 325 326
 *
 * Returns 0 if kobject_uevent() is completed with success or the
 * corresponding error when it fails.
327
 */
328
int kobject_uevent(struct kobject *kobj, enum kobject_action action)
329
{
330
	return kobject_uevent_env(kobj, action, NULL);
331
}
332
EXPORT_SYMBOL_GPL(kobject_uevent);
L
Linus Torvalds 已提交
333 334

/**
335 336 337
 * add_uevent_var - add key value string to the environment buffer
 * @env: environment buffer structure
 * @format: printf format for the key=value pair
L
Linus Torvalds 已提交
338 339 340 341
 *
 * Returns 0 if environment variable was added successfully or -ENOMEM
 * if no space was available.
 */
342
int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...)
L
Linus Torvalds 已提交
343 344
{
	va_list args;
345
	int len;
L
Linus Torvalds 已提交
346

347
	if (env->envp_idx >= ARRAY_SIZE(env->envp)) {
A
Arjan van de Ven 已提交
348
		WARN(1, KERN_ERR "add_uevent_var: too many keys\n");
L
Linus Torvalds 已提交
349
		return -ENOMEM;
350
	}
L
Linus Torvalds 已提交
351 352

	va_start(args, format);
353 354 355
	len = vsnprintf(&env->buf[env->buflen],
			sizeof(env->buf) - env->buflen,
			format, args);
L
Linus Torvalds 已提交
356 357
	va_end(args);

358
	if (len >= (sizeof(env->buf) - env->buflen)) {
A
Arjan van de Ven 已提交
359
		WARN(1, KERN_ERR "add_uevent_var: buffer size too small\n");
L
Linus Torvalds 已提交
360
		return -ENOMEM;
361
	}
L
Linus Torvalds 已提交
362

363 364
	env->envp[env->envp_idx++] = &env->buf[env->buflen];
	env->buflen += len + 1;
L
Linus Torvalds 已提交
365 366
	return 0;
}
367
EXPORT_SYMBOL_GPL(add_uevent_var);
L
Linus Torvalds 已提交
368

K
Kay Sievers 已提交
369
#if defined(CONFIG_NET)
370
static int uevent_net_init(struct net *net)
371
{
372 373 374 375 376 377 378 379 380
	struct uevent_sock *ue_sk;

	ue_sk = kzalloc(sizeof(*ue_sk), GFP_KERNEL);
	if (!ue_sk)
		return -ENOMEM;

	ue_sk->sk = netlink_kernel_create(net, NETLINK_KOBJECT_UEVENT,
					  1, NULL, NULL, THIS_MODULE);
	if (!ue_sk->sk) {
381 382
		printk(KERN_ERR
		       "kobject_uevent: unable to create netlink socket!\n");
383
		kfree(ue_sk);
384 385
		return -ENODEV;
	}
386 387 388
	mutex_lock(&uevent_sock_mutex);
	list_add_tail(&ue_sk->list, &uevent_sock_list);
	mutex_unlock(&uevent_sock_mutex);
389 390 391
	return 0;
}

392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423
static void uevent_net_exit(struct net *net)
{
	struct uevent_sock *ue_sk;

	mutex_lock(&uevent_sock_mutex);
	list_for_each_entry(ue_sk, &uevent_sock_list, list) {
		if (sock_net(ue_sk->sk) == net)
			goto found;
	}
	mutex_unlock(&uevent_sock_mutex);
	return;

found:
	list_del(&ue_sk->list);
	mutex_unlock(&uevent_sock_mutex);

	netlink_kernel_release(ue_sk->sk);
	kfree(ue_sk);
}

static struct pernet_operations uevent_net_ops = {
	.init	= uevent_net_init,
	.exit	= uevent_net_exit,
};

static int __init kobject_uevent_init(void)
{
	netlink_set_nonroot(NETLINK_KOBJECT_UEVENT, NL_NONROOT_RECV);
	return register_pernet_subsys(&uevent_net_ops);
}


424
postcore_initcall(kobject_uevent_init);
K
Kay Sievers 已提交
425
#endif