#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;
}
/**
/**
/*
#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;
}