kobject_uevent.c 10.4 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
#include <linux/string.h>
#include <linux/kobject.h>
20 21
#include <linux/export.h>
#include <linux/kmod.h>
22
#include <linux/slab.h>
23
#include <linux/user_namespace.h>
L
Linus Torvalds 已提交
24 25 26 27
#include <linux/socket.h>
#include <linux/skbuff.h>
#include <linux/netlink.h>
#include <net/sock.h>
28
#include <net/net_namespace.h>
L
Linus Torvalds 已提交
29 30


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

41 42 43
/* This lock protects uevent_seqnum and uevent_sock_list */
static DEFINE_MUTEX(uevent_sock_mutex);

44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
/* 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 已提交
69
	if (count && (buf[count-1] == '\n' || buf[count-1] == '\0'))
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
		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;
}

88
#ifdef CONFIG_NET
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
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;
}
104
#endif
105

106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
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 已提交
121
/**
122
 * kobject_uevent_env - send an uevent with environmental data
L
Linus Torvalds 已提交
123
 *
124
 * @action: action that is happening
L
Linus Torvalds 已提交
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.
L
Linus Torvalds 已提交
130
 */
131
int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
132
		       char *envp_ext[])
L
Linus Torvalds 已提交
133
{
134 135
	struct kobj_uevent_env *env;
	const char *action_string = kobject_actions[action];
136 137 138 139
	const char *devpath = NULL;
	const char *subsystem;
	struct kobject *top_kobj;
	struct kset *kset;
140
	const struct kset_uevent_ops *uevent_ops;
L
Linus Torvalds 已提交
141
	int i = 0;
142
	int retval = 0;
143 144 145
#ifdef CONFIG_NET
	struct uevent_sock *ue_sk;
#endif
L
Linus Torvalds 已提交
146

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

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

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

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

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

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

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

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

205
	/* default keys */
206 207 208 209 210 211 212 213 214 215 216 217 218
	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++) {
219
			retval = add_uevent_var(env, "%s", envp_ext[i]);
220 221 222 223
			if (retval)
				goto exit;
		}
	}
L
Linus Torvalds 已提交
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);
L
Linus Torvalds 已提交
228
		if (retval) {
229 230
			pr_debug("kobject: '%s' (%p): %s: uevent() returned "
				 "%d\n", kobject_name(kobj), kobj,
231
				 __func__, retval);
L
Linus Torvalds 已提交
232 233 234 235
			goto exit;
		}
	}

236 237 238 239 240 241 242 243 244 245 246
	/*
	 * 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;

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

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

262 263 264
		if (!netlink_has_listeners(uevent_sock, 1))
			continue;

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

271 272 273 274 275
			/* add header */
			scratch = skb_put(skb, len);
			sprintf(scratch, "%s@%s", action_string, devpath);

			/* copy keys to our continuous event payload buffer */
276 277
			for (i = 0; i < env->envp_idx; i++) {
				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 284 285 286
			retval = netlink_broadcast_filtered(uevent_sock, skb,
							    0, 1, GFP_KERNEL,
							    kobj_bcast_filter,
							    kobj);
287
			/* ENOBUFS should be handled in userspace */
288
			if (retval == -ENOBUFS || retval == -ESRCH)
289
				retval = 0;
290 291
		} else
			retval = -ENOMEM;
292
	}
K
Kay Sievers 已提交
293
#endif
294
	mutex_unlock(&uevent_sock_mutex);
L
Linus Torvalds 已提交
295

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

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

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

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

/**
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 329
 *
 * Returns 0 if kobject_uevent() is completed with success or the
 * corresponding error when it fails.
330
 */
331
int kobject_uevent(struct kobject *kobj, enum kobject_action action)
332
{
333
	return kobject_uevent_env(kobj, action, NULL);
334
}
335
EXPORT_SYMBOL_GPL(kobject_uevent);
L
Linus Torvalds 已提交
336 337

/**
338 339 340
 * 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 已提交
341 342 343 344
 *
 * Returns 0 if environment variable was added successfully or -ENOMEM
 * if no space was available.
 */
345
int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...)
L
Linus Torvalds 已提交
346 347
{
	va_list args;
348
	int len;
L
Linus Torvalds 已提交
349

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

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

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

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

K
Kay Sievers 已提交
372
#if defined(CONFIG_NET)
373
static int uevent_net_init(struct net *net)
374
{
375
	struct uevent_sock *ue_sk;
376 377
	struct netlink_kernel_cfg cfg = {
		.groups	= 1,
378
		.flags	= NL_CFG_F_NONROOT_RECV,
379
	};
380 381 382 383 384

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

385
	ue_sk->sk = netlink_kernel_create(net, NETLINK_KOBJECT_UEVENT, &cfg);
386
	if (!ue_sk->sk) {
387 388
		printk(KERN_ERR
		       "kobject_uevent: unable to create netlink socket!\n");
389
		kfree(ue_sk);
390 391
		return -ENODEV;
	}
392 393 394
	mutex_lock(&uevent_sock_mutex);
	list_add_tail(&ue_sk->list, &uevent_sock_list);
	mutex_unlock(&uevent_sock_mutex);
395 396 397
	return 0;
}

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 424 425 426 427 428
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)
{
	return register_pernet_subsys(&uevent_net_ops);
}


429
postcore_initcall(kobject_uevent_init);
K
Kay Sievers 已提交
430
#endif