用户空间接收uevent示例

#include
#include
#include
#include
#include
#include
#include
#include

#include
#include

#define SCM_CREDENTIALS 0x02 /* rw: struct ucred */

struct ucred {
__u32 pid;
__u32 uid;
__u32 gid;
};

static int uevent_open_socket(int buf_sz, bool passcred)
{
struct sockaddr_nl addr;
int on = passcred;
int s;

memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_pid = getpid();
addr.nl_groups = 0xffffffff;

s = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT);
if(s < 0)
	return -1;

setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &buf_sz, sizeof(buf_sz));
setsockopt(s, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));

if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
	close(s);
	return -1;
}

return s;

}

ssize_t uevent_kernel_recv(int socket, void *buffer, size_t length, bool require_group, uid_t *uid)
{
struct iovec iov = { buffer, length };
struct sockaddr_nl addr;
char control[CMSG_SPACE(sizeof(struct ucred))];
struct msghdr hdr = {
&addr,
sizeof(addr),
&iov,
1,
control,
sizeof(control),
0,
};

*uid = -1;
ssize_t n = recvmsg(socket, &hdr, 0);
if (n <= 0) {
	return n;
}

struct cmsghdr *cmsg = CMSG_FIRSTHDR(&hdr);
if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
	/* ignoring netlink message with no sender credentials */
	goto out;
}

struct ucred *cred = (struct ucred *)CMSG_DATA(cmsg);
*uid = cred->uid;
if (cred->uid != 0) {
	/* ignoring netlink message from non-root user */
	goto out;
}

if (addr.nl_pid != 0) {
	/* ignore non-kernel */

	goto out;
}
if (require_group && addr.nl_groups == 0) {
	/* ignore unicast messages when requested */
	goto out;
}

return n;

out:
/* clear residual potentially malicious data */
bzero(buffer, length);
errno = EIO;
return -1;
}

/**

  • Like the above, but passes a uid_t in by pointer. In the event that this
  • fails due to a bad uid check, the uid_t will be set to the uid of the
  • socket’s peer.
  • If this method rejects a netlink message from outside the kernel, it
  • returns -1, sets errno to EIO, and sets “user” to the UID associated with the
  • message. If the peer UID cannot be determined, “user” is set to -1."
    */
    ssize_t my_uevent_kernel_multicast_uid_recv(int socket, void *buffer, size_t length, uid_t *uid)
    {
    return uevent_kernel_recv(socket, buffer, length, true, uid);
    }

/**

  • Like recv(), but checks that messages actually originate from the kernel.
    */
    ssize_t uevent_kernel_multicast_recv(int socket, void *buffer, size_t length)
    {
    uid_t uid = -1;
    return my_uevent_kernel_multicast_uid_recv(socket, buffer, length, &uid);
    }

/*
#define UEVENT_MSG_LEN 2048
void handle_device_fd()
{
char msg[UEVENT_MSG_LEN+2];
int n;
while ((n = uevent_kernel_multicast_recv(device_fd, msg, UEVENT_MSG_LEN)) > 0) {
if(n >= UEVENT_MSG_LEN) // overflow – discard //
continue;

	msg[n] = '\0';
	msg[n+1] = '\0';

	struct uevent uevent;
	parse_event(msg, &uevent);

	if (sehandle && selinux_status_updated() > 0) {
		struct selabel_handle *sehandle2;
		sehandle2 = selinux_android_file_context_handle();
		if (sehandle2) {
			selabel_close(sehandle);
			sehandle = sehandle2;
		}
	}

	handle_device_event(&uevent);
	handle_firmware_event(&uevent);
}

}
*/

static void parse_event(const char *msg, struct uevent *uevent)
{

struct uevent *ue = uevent;
ue->action = "";
ue->path = "";
ue->subsystem = "";
ue->firmware = "";
ue->major = -1;
ue->minor = -1;
ue->partition_name = NULL;
ue->partition_num = -1;
ue->device_name = NULL;

// currently ignoring SEQNUM //
while(*msg) {
	if(!strncmp(msg, "ACTION=", 7)) {
		msg += 7;
		ue->action = msg;
	} else if(!strncmp(msg, "DEVPATH=", 8)) {
		msg += 8;
		ue->path = msg;
	} else if(!strncmp(msg, "SUBSYSTEM=", 10)) {
		msg += 10;
		ue->subsystem = msg;
	} else if(!strncmp(msg, "FIRMWARE=", 9)) {
		msg += 9;
		ue->firmware = msg;
	} else if(!strncmp(msg, "MAJOR=", 6)) {
		msg += 6;
		ue->major = atoi(msg);
	} else if(!strncmp(msg, "MINOR=", 6)) {
		msg += 6;
		ue->minor = atoi(msg);
	} else if(!strncmp(msg, "PARTN=", 6)) {
		msg += 6;
		ue->partition_num = atoi(msg);
	} else if(!strncmp(msg, "PARTNAME=", 9)) {
		msg += 9;
		ue->partition_name = msg;
	} else if(!strncmp(msg, "DEVNAME=", 8)) {
		msg += 8;
		ue->device_name = msg;
	}

	// advance to after the next \0 //
	while(*msg++)
		;
}

//if (LOG_UEVENTS) {
//	INFO("event { '%s', '%s', '%s', '%s', %d, %d }\n",
//			uevent->action, uevent->path, uevent->subsystem,
//			uevent->firmware, uevent->major, uevent->minor);
//}
	printf("event { '%s', '%s', '%s', '%s', %d, %d }\n",
			ue->action, ue->path, ue->subsystem,
			ue->firmware, ue->major, ue->minor);

}

//#define UEVENT_MSG_LEN 2048
#define UEVENT_MSG_LEN 64 * 1024

int main(void)
{
int socket_fd = -1;
int ret = -1;
int uevent_len = 0;
char msg[UEVENT_MSG_LEN+2];
char* msg_p = msg;
struct uevent uevent;

printf("[rickey] enter %s \n", __func__);
//socket_fd = uevent_open_socket(256*1024, true);
socket_fd = uevent_open_socket(256*1024, true);
if (socket_fd < 0) {
	printf("[rickey] open socket failed %s : errno %s\n", __func__, strerror(errno));
}

printf("[rickey] open socket ok %s \n", __func__);
printf("\n============ Get kernel uevent ===========\n");
while ((uevent_len = uevent_kernel_multicast_recv(socket_fd, msg, UEVENT_MSG_LEN))>0) {
	if (uevent_len > UEVENT_MSG_LEN) {
		continue;
	}

//	if (uevent_len <= 0) {
//		printf("[rickey] recv uevent msg failed, %s : errno %s\n", __func__, strerror(errno));
//	}

	//printf("[rickey]  recv socket ok %s \n", __func__);
	//parse_event(const char *msg, struct uevent *uevent);
	msg[uevent_len] = '\0';
	//msg[uevent_len+1] = '\0';

	//printf("%s", msg_p);


	parse_event(msg, &uevent);


	while (*msg_p) {

		printf("%c", *msg_p);

		msg_p++;
	}
}
printf("\n============ End ===========\n");

return 0;

}

你可能感兴趣的:(kernel)