[PATCH RESEND 1/8] netlink: call get_fd_nl_family before decode nlmsghdr
JingPiao Chen
chenjingpiao at gmail.com
Sat Aug 5 12:59:12 UTC 2017
On Tue, Aug 04, 2017 Dmitry V. Levin wrote:
> On Tue, Aug 01, 2017 at 07:48:41AM +0800, JingPiao Chen wrote:
> > Prepare for NETLINK_KOBJECT_UEVENT decode. The messages
> > of NETLINK_KOBJECT_UEVENT do not contain nlmsghdr.
>
> A netlink message without a netlink message header? Ouch.
> Could you give a link to the exact place in kernel sources
> or documentation where this marvel of design is described, please?
Documentation/kobject.txt: 166
Uevents
=======
After a kobject has been registered with the kobject core, you need to
announce to the world that it has been created. This can be done with a
call to kobject_uevent()::
int kobject_uevent(struct kobject *kobj, enum kobject_action action);
lib/kobject_uevent.c:
/**
* kobject_uevent - notify userspace by sending an uevent
*
* @kobj: struct kobject that the action is happening to
* @action: action that is happening
*
* Returns 0 if kobject_uevent() is completed with success or the
* corresponding error when it fails.
*/
int kobject_uevent(struct kobject *kobj, enum kobject_action action)
{
return kobject_uevent_env(kobj, action, NULL);
}
EXPORT_SYMBOL_GPL(kobject_uevent);
/**
* kobject_uevent_env - send an uevent with environmental data
*
* @kobj: struct kobject that the action is happening to
* @action: action that is happening
* @envp_ext: pointer to environmental data
*
* Returns 0 if kobject_uevent_env() is completed with success or the
* corresponding error when it fails.
*/
int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
char *envp_ext[])
{
...
/* default keys */
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++) {
retval = add_uevent_var(env, "%s", envp_ext[i]);
if (retval)
goto exit;
}
}
...
/* send netlink message */
list_for_each_entry(ue_sk, &uevent_sock_list, list) {
struct sock *uevent_sock = ue_sk->sk;
struct sk_buff *skb;
size_t len;
if (!netlink_has_listeners(uevent_sock, 1))
continue;
/* allocate message with the maximum possible size */
len = strlen(action_string) + strlen(devpath) + 2;
skb = alloc_skb(len + env->buflen, GFP_KERNEL);
if (skb) {
char *scratch;
/* add header */
scratch = skb_put(skb, len);
sprintf(scratch, "%s@%s", action_string, devpath);
/* copy keys to our continuous event payload buffer */
for (i = 0; i < env->envp_idx; i++) {
len = strlen(env->envp[i]) + 1;
scratch = skb_put(skb, len);
strcpy(scratch, env->envp[i]);
}
NETLINK_CB(skb).dst_group = 1;
retval = netlink_broadcast_filtered(uevent_sock, skb,
0, 1, GFP_KERNEL,
kobj_bcast_filter,
kobj);
/* ENOBUFS should be handled in userspace */
if (retval == -ENOBUFS || retval == -ESRCH)
retval = 0;
} else
retval = -ENOMEM;
}
...
}
/**
* add_uevent_var - add key value string to the environment buffer
* @env: environment buffer structure
* @format: printf format for the key=value pair
*
* Returns 0 if environment variable was added successfully or -ENOMEM
* if no space was available.
*/
int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...)
{
...
len = vsnprintf(&env->buf[env->buflen],
sizeof(env->buf) - env->buflen,
format, args);
...
}
A demo of NETLINK_KOBJECT_UEVENT:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <linux/netlink.h>
int
main(void)
{
struct sockaddr_nl nl;
size_t i, len;
int fd;
char buf[4096];
if ((fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT)) == -1) {
perror("socket");
return EXIT_FAILURE;
}
memset(&nl, 0, sizeof(nl));
nl.nl_family = AF_NETLINK;
nl.nl_pid = getpid();
nl.nl_groups = 1;
if (bind(fd, (struct sockaddr *)&nl, sizeof(nl)) == -1) {
perror("bind");
return EXIT_FAILURE;
}
for (;;) {
len = recv(fd, buf, sizeof(buf), 0);
if (!len)
break;
write(STDOUT_FILENO, buf, len);
}
close(fd);
return 0;
}
$ gcc uevent.c
$ ./a.out # Remove your mouse
--
JingPiao Chen
More information about the Strace-devel
mailing list