kobject_uevent.c 10.5 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
static int kobj_bcast_filter(struct sock *dsk, struct sk_buff *skb, void *data)
{
91
	struct kobject *kobj = data, *ksobj;
92 93 94
	const struct kobj_ns_type_operations *ops;

	ops = kobj_ns_ops(kobj);
95 96 97 98 99 100 101
	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) {
102 103 104 105 106 107 108 109
		const void *sock_ns, *ns;
		ns = kobj->ktype->namespace(kobj);
		sock_ns = ops->netlink_ns(dsk);
		return sock_ns != ns;
	}

	return 0;
}
110
#endif
111

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

153
	pr_debug("kobject: '%s' (%p): %s\n",
154
		 kobject_name(kobj), kobj, __func__);
155 156 157

	/* search the kset we belong to */
	top_kobj = kobj;
158
	while (!top_kobj->kset && top_kobj->parent)
159
		top_kobj = top_kobj->parent;
160

161
	if (!top_kobj->kset) {
162 163
		pr_debug("kobject: '%s' (%p): %s: attempted to send uevent "
			 "without kset!\n", kobject_name(kobj), kobj,
164
			 __func__);
165 166
		return -EINVAL;
	}
L
Linus Torvalds 已提交
167

168
	kset = top_kobj->kset;
169
	uevent_ops = kset->uevent_ops;
L
Linus Torvalds 已提交
170

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

187 188 189 190 191 192
	/* originating subsystem */
	if (uevent_ops && uevent_ops->name)
		subsystem = uevent_ops->name(kset, kobj);
	else
		subsystem = kobject_name(&kset->kobj);
	if (!subsystem) {
193 194
		pr_debug("kobject: '%s' (%p): %s: unset subsystem caused the "
			 "event to drop!\n", kobject_name(kobj), kobj,
195
			 __func__);
196 197 198
		return 0;
	}

199 200 201
	/* environment buffer */
	env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
	if (!env)
202
		return -ENOMEM;
L
Linus Torvalds 已提交
203

204 205
	/* complete object path */
	devpath = kobject_get_path(kobj, GFP_KERNEL);
206 207
	if (!devpath) {
		retval = -ENOENT;
208
		goto exit;
209
	}
L
Linus Torvalds 已提交
210

211
	/* default keys */
212 213 214 215 216 217 218 219 220 221 222 223 224
	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++) {
225
			retval = add_uevent_var(env, "%s", envp_ext[i]);
226 227 228 229
			if (retval)
				goto exit;
		}
	}
L
Linus Torvalds 已提交
230

231
	/* let the kset specific function add its stuff */
232
	if (uevent_ops && uevent_ops->uevent) {
233
		retval = uevent_ops->uevent(kset, kobj, env);
L
Linus Torvalds 已提交
234
		if (retval) {
235 236
			pr_debug("kobject: '%s' (%p): %s: uevent() returned "
				 "%d\n", kobject_name(kobj), kobj,
237
				 __func__, retval);
L
Linus Torvalds 已提交
238 239 240 241
			goto exit;
		}
	}

242 243 244 245 246 247 248 249 250 251 252
	/*
	 * 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;

253
	mutex_lock(&uevent_sock_mutex);
254
	/* we will send an event, so request a new sequence number */
255 256 257
	retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)++uevent_seqnum);
	if (retval) {
		mutex_unlock(&uevent_sock_mutex);
258
		goto exit;
259
	}
L
Linus Torvalds 已提交
260

K
Kay Sievers 已提交
261
#if defined(CONFIG_NET)
262
	/* send netlink message */
263 264
	list_for_each_entry(ue_sk, &uevent_sock_list, list) {
		struct sock *uevent_sock = ue_sk->sk;
265 266 267
		struct sk_buff *skb;
		size_t len;

268 269 270
		if (!netlink_has_listeners(uevent_sock, 1))
			continue;

271 272
		/* allocate message with the maximum possible size */
		len = strlen(action_string) + strlen(devpath) + 2;
273
		skb = alloc_skb(len + env->buflen, GFP_KERNEL);
274
		if (skb) {
275 276
			char *scratch;

277 278 279 280 281
			/* add header */
			scratch = skb_put(skb, len);
			sprintf(scratch, "%s@%s", action_string, devpath);

			/* copy keys to our continuous event payload buffer */
282 283
			for (i = 0; i < env->envp_idx; i++) {
				len = strlen(env->envp[i]) + 1;
284
				scratch = skb_put(skb, len);
285
				strcpy(scratch, env->envp[i]);
286 287 288
			}

			NETLINK_CB(skb).dst_group = 1;
289 290 291 292
			retval = netlink_broadcast_filtered(uevent_sock, skb,
							    0, 1, GFP_KERNEL,
							    kobj_bcast_filter,
							    kobj);
293
			/* ENOBUFS should be handled in userspace */
294
			if (retval == -ENOBUFS || retval == -ESRCH)
295
				retval = 0;
296 297
		} else
			retval = -ENOMEM;
298
	}
K
Kay Sievers 已提交
299
#endif
300
	mutex_unlock(&uevent_sock_mutex);
L
Linus Torvalds 已提交
301

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

306
		argv [0] = uevent_helper;
307 308
		argv [1] = (char *)subsystem;
		argv [2] = NULL;
309 310 311
		retval = add_uevent_var(env, "HOME=/");
		if (retval)
			goto exit;
312 313
		retval = add_uevent_var(env,
					"PATH=/sbin:/bin:/usr/sbin:/usr/bin");
314 315 316
		if (retval)
			goto exit;

317
		retval = call_usermodehelper(argv[0], argv,
318
					     env->envp, UMH_WAIT_EXEC);
319
	}
L
Linus Torvalds 已提交
320 321

exit:
322
	kfree(devpath);
323
	kfree(env);
324
	return retval;
L
Linus Torvalds 已提交
325
}
326 327 328
EXPORT_SYMBOL_GPL(kobject_uevent_env);

/**
329
 * kobject_uevent - notify userspace by sending an uevent
330
 *
331
 * @action: action that is happening
332
 * @kobj: struct kobject that the action is happening to
333 334 335
 *
 * Returns 0 if kobject_uevent() is completed with success or the
 * corresponding error when it fails.
336
 */
337
int kobject_uevent(struct kobject *kobj, enum kobject_action action)
338
{
339
	return kobject_uevent_env(kobj, action, NULL);
340
}
341
EXPORT_SYMBOL_GPL(kobject_uevent);
L
Linus Torvalds 已提交
342 343

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

356
	if (env->envp_idx >= ARRAY_SIZE(env->envp)) {
A
Arjan van de Ven 已提交
357
		WARN(1, KERN_ERR "add_uevent_var: too many keys\n");
L
Linus Torvalds 已提交
358
		return -ENOMEM;
359
	}
L
Linus Torvalds 已提交
360 361

	va_start(args, format);
362 363 364
	len = vsnprintf(&env->buf[env->buflen],
			sizeof(env->buf) - env->buflen,
			format, args);
L
Linus Torvalds 已提交
365 366
	va_end(args);

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

372 373
	env->envp[env->envp_idx++] = &env->buf[env->buflen];
	env->buflen += len + 1;
L
Linus Torvalds 已提交
374 375
	return 0;
}
376
EXPORT_SYMBOL_GPL(add_uevent_var);
L
Linus Torvalds 已提交
377

K
Kay Sievers 已提交
378
#if defined(CONFIG_NET)
379
static int uevent_net_init(struct net *net)
380
{
381
	struct uevent_sock *ue_sk;
382 383
	struct netlink_kernel_cfg cfg = {
		.groups	= 1,
384
		.flags	= NL_CFG_F_NONROOT_RECV,
385
	};
386 387 388 389 390

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

391
	ue_sk->sk = netlink_kernel_create(net, NETLINK_KOBJECT_UEVENT, &cfg);
392
	if (!ue_sk->sk) {
393 394
		printk(KERN_ERR
		       "kobject_uevent: unable to create netlink socket!\n");
395
		kfree(ue_sk);
396 397
		return -ENODEV;
	}
398 399 400
	mutex_lock(&uevent_sock_mutex);
	list_add_tail(&ue_sk->list, &uevent_sock_list);
	mutex_unlock(&uevent_sock_mutex);
401 402 403
	return 0;
}

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 429 430 431 432 433 434
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);
}


435
postcore_initcall(kobject_uevent_init);
K
Kay Sievers 已提交
436
#endif