13f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang/* 23f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang * Copyright (C) 2011 The Android Open Source Project 33f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang * 43f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang * Licensed under the Apache License, Version 2.0 (the "License"); 53f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang * you may not use this file except in compliance with the License. 63f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang * You may obtain a copy of the License at 73f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang * 83f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang * http://www.apache.org/licenses/LICENSE-2.0 93f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang * 103f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang * Unless required by applicable law or agreed to in writing, software 113f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang * distributed under the License is distributed on an "AS IS" BASIS, 123f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang * See the License for the specific language governing permissions and 143f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang * limitations under the License. 153f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang */ 163f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang 173f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang#include <cutils/uevent.h> 183f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang 193f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang#include <errno.h> 202d55e02d0f3c27f0c99ab889ab7b73126280a21cDima Zavin#include <stdbool.h> 212d55e02d0f3c27f0c99ab889ab7b73126280a21cDima Zavin#include <string.h> 223f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang#include <strings.h> 232d55e02d0f3c27f0c99ab889ab7b73126280a21cDima Zavin#include <sys/socket.h> 242d55e02d0f3c27f0c99ab889ab7b73126280a21cDima Zavin#include <sys/un.h> 252d55e02d0f3c27f0c99ab889ab7b73126280a21cDima Zavin#include <unistd.h> 263f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang 273f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang#include <linux/netlink.h> 283f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang 293f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang/** 303f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang * Like recv(), but checks that messages actually originate from the kernel. 313f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang */ 3215621e0970e97eb2fc28f82a07620c9124a4455cGeremy Condrassize_t uevent_kernel_multicast_recv(int socket, void *buffer, size_t length) 3315621e0970e97eb2fc28f82a07620c9124a4455cGeremy Condra{ 3415621e0970e97eb2fc28f82a07620c9124a4455cGeremy Condra uid_t user = -1; 3515621e0970e97eb2fc28f82a07620c9124a4455cGeremy Condra return uevent_kernel_multicast_uid_recv(socket, buffer, length, &user); 3615621e0970e97eb2fc28f82a07620c9124a4455cGeremy Condra} 3715621e0970e97eb2fc28f82a07620c9124a4455cGeremy Condra 3815621e0970e97eb2fc28f82a07620c9124a4455cGeremy Condra/** 3915621e0970e97eb2fc28f82a07620c9124a4455cGeremy Condra * Like the above, but passes a uid_t in by reference. In the event that this 4015621e0970e97eb2fc28f82a07620c9124a4455cGeremy Condra * fails due to a bad uid check, the uid_t will be set to the uid of the 4115621e0970e97eb2fc28f82a07620c9124a4455cGeremy Condra * socket's peer. 4215621e0970e97eb2fc28f82a07620c9124a4455cGeremy Condra * 4315621e0970e97eb2fc28f82a07620c9124a4455cGeremy Condra * If this method rejects a netlink message from outside the kernel, it 4415621e0970e97eb2fc28f82a07620c9124a4455cGeremy Condra * returns -1, sets errno to EIO, and sets "user" to the UID associated with the 4515621e0970e97eb2fc28f82a07620c9124a4455cGeremy Condra * message. If the peer UID cannot be determined, "user" is set to -1." 4615621e0970e97eb2fc28f82a07620c9124a4455cGeremy Condra */ 4715621e0970e97eb2fc28f82a07620c9124a4455cGeremy Condrassize_t uevent_kernel_multicast_uid_recv(int socket, void *buffer, 4815621e0970e97eb2fc28f82a07620c9124a4455cGeremy Condra size_t length, uid_t *user) 4915621e0970e97eb2fc28f82a07620c9124a4455cGeremy Condra{ 503f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang struct iovec iov = { buffer, length }; 513f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang struct sockaddr_nl addr; 523f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang char control[CMSG_SPACE(sizeof(struct ucred))]; 533f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang struct msghdr hdr = { 543f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang &addr, 553f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang sizeof(addr), 563f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang &iov, 573f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang 1, 583f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang control, 593f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang sizeof(control), 603f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang 0, 613f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang }; 623f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang 6315621e0970e97eb2fc28f82a07620c9124a4455cGeremy Condra *user = -1; 643f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang ssize_t n = recvmsg(socket, &hdr, 0); 653f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang if (n <= 0) { 663f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang return n; 673f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang } 683f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang 693f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang struct cmsghdr *cmsg = CMSG_FIRSTHDR(&hdr); 703f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) { 713f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang /* ignoring netlink message with no sender credentials */ 723f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang goto out; 733f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang } 743f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang 753f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang struct ucred *cred = (struct ucred *)CMSG_DATA(cmsg); 7615621e0970e97eb2fc28f82a07620c9124a4455cGeremy Condra *user = cred->uid; 773f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang if (cred->uid != 0) { 783f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang /* ignoring netlink message from non-root user */ 793f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang goto out; 803f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang } 813f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang 8215621e0970e97eb2fc28f82a07620c9124a4455cGeremy Condra if (addr.nl_groups == 0 || addr.nl_pid != 0) { 8315621e0970e97eb2fc28f82a07620c9124a4455cGeremy Condra /* ignoring non-kernel or unicast netlink message */ 8415621e0970e97eb2fc28f82a07620c9124a4455cGeremy Condra goto out; 8515621e0970e97eb2fc28f82a07620c9124a4455cGeremy Condra } 8615621e0970e97eb2fc28f82a07620c9124a4455cGeremy Condra 873f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang return n; 883f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang 893f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tangout: 903f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang /* clear residual potentially malicious data */ 913f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang bzero(buffer, length); 923f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang errno = EIO; 933f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang return -1; 943f582e92f07d358f3d0941b86407b39e2e7e67ccVernon Tang} 952d55e02d0f3c27f0c99ab889ab7b73126280a21cDima Zavin 962d55e02d0f3c27f0c99ab889ab7b73126280a21cDima Zavinint uevent_open_socket(int buf_sz, bool passcred) 972d55e02d0f3c27f0c99ab889ab7b73126280a21cDima Zavin{ 982d55e02d0f3c27f0c99ab889ab7b73126280a21cDima Zavin struct sockaddr_nl addr; 992d55e02d0f3c27f0c99ab889ab7b73126280a21cDima Zavin int on = passcred; 1002d55e02d0f3c27f0c99ab889ab7b73126280a21cDima Zavin int s; 1012d55e02d0f3c27f0c99ab889ab7b73126280a21cDima Zavin 1022d55e02d0f3c27f0c99ab889ab7b73126280a21cDima Zavin memset(&addr, 0, sizeof(addr)); 1032d55e02d0f3c27f0c99ab889ab7b73126280a21cDima Zavin addr.nl_family = AF_NETLINK; 1042d55e02d0f3c27f0c99ab889ab7b73126280a21cDima Zavin addr.nl_pid = getpid(); 1052d55e02d0f3c27f0c99ab889ab7b73126280a21cDima Zavin addr.nl_groups = 0xffffffff; 1062d55e02d0f3c27f0c99ab889ab7b73126280a21cDima Zavin 1072d55e02d0f3c27f0c99ab889ab7b73126280a21cDima Zavin s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); 1082d55e02d0f3c27f0c99ab889ab7b73126280a21cDima Zavin if(s < 0) 1092d55e02d0f3c27f0c99ab889ab7b73126280a21cDima Zavin return -1; 1102d55e02d0f3c27f0c99ab889ab7b73126280a21cDima Zavin 1112d55e02d0f3c27f0c99ab889ab7b73126280a21cDima Zavin setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &buf_sz, sizeof(buf_sz)); 1122d55e02d0f3c27f0c99ab889ab7b73126280a21cDima Zavin setsockopt(s, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); 1132d55e02d0f3c27f0c99ab889ab7b73126280a21cDima Zavin 1142d55e02d0f3c27f0c99ab889ab7b73126280a21cDima Zavin if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 1152d55e02d0f3c27f0c99ab889ab7b73126280a21cDima Zavin close(s); 1162d55e02d0f3c27f0c99ab889ab7b73126280a21cDima Zavin return -1; 1172d55e02d0f3c27f0c99ab889ab7b73126280a21cDima Zavin } 1182d55e02d0f3c27f0c99ab889ab7b73126280a21cDima Zavin 1192d55e02d0f3c27f0c99ab889ab7b73126280a21cDima Zavin return s; 1202d55e02d0f3c27f0c99ab889ab7b73126280a21cDima Zavin} 121