summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--init/devices.c36
1 files changed, 31 insertions, 5 deletions
diff --git a/init/devices.c b/init/devices.c
index bde906bc6..530d6d79d 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -53,6 +53,7 @@ static int open_uevent_socket(void)
53{ 53{
54 struct sockaddr_nl addr; 54 struct sockaddr_nl addr;
55 int sz = 64*1024; // XXX larger? udev uses 16MB! 55 int sz = 64*1024; // XXX larger? udev uses 16MB!
56 int on = 1;
56 int s; 57 int s;
57 58
58 memset(&addr, 0, sizeof(addr)); 59 memset(&addr, 0, sizeof(addr));
@@ -65,6 +66,7 @@ static int open_uevent_socket(void)
65 return -1; 66 return -1;
66 67
67 setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)); 68 setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));
69 setsockopt(s, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
68 70
69 if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 71 if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
70 close(s); 72 close(s);
@@ -571,18 +573,42 @@ static void handle_firmware_event(struct uevent *uevent)
571#define UEVENT_MSG_LEN 1024 573#define UEVENT_MSG_LEN 1024
572void handle_device_fd(int fd) 574void handle_device_fd(int fd)
573{ 575{
574 char msg[UEVENT_MSG_LEN+2]; 576 for(;;) {
575 int n; 577 char msg[UEVENT_MSG_LEN+2];
578 char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
579 struct iovec iov = {msg, sizeof(msg)};
580 struct sockaddr_nl snl;
581 struct msghdr hdr = {&snl, sizeof(snl), &iov, 1, cred_msg, sizeof(cred_msg), 0};
582
583 ssize_t n = recvmsg(fd, &hdr, 0);
584 if (n <= 0) {
585 break;
586 }
576 587
577 while((n = recv(fd, msg, UEVENT_MSG_LEN, 0)) > 0) { 588 if ((snl.nl_groups != 1) || (snl.nl_pid != 0)) {
578 struct uevent uevent; 589 /* ignoring non-kernel netlink multicast message */
590 continue;
591 }
592
593 struct cmsghdr * cmsg = CMSG_FIRSTHDR(&hdr);
594 if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
595 /* no sender credentials received, ignore message */
596 continue;
597 }
598
599 struct ucred * cred = (struct ucred *)CMSG_DATA(cmsg);
600 if (cred->uid != 0) {
601 /* message from non-root user, ignore */
602 continue;
603 }
579 604
580 if(n == UEVENT_MSG_LEN) /* overflow -- discard */ 605 if(n >= UEVENT_MSG_LEN) /* overflow -- discard */
581 continue; 606 continue;
582 607
583 msg[n] = '\0'; 608 msg[n] = '\0';
584 msg[n+1] = '\0'; 609 msg[n+1] = '\0';
585 610
611 struct uevent uevent;
586 parse_event(msg, &uevent); 612 parse_event(msg, &uevent);
587 613
588 handle_device_event(&uevent); 614 handle_device_event(&uevent);