summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libcutils/Android.bp2
-rw-r--r--libcutils/include/private/android_filesystem_config.h8
-rw-r--r--libcutils/uevent.cpp (renamed from libcutils/uevent.c)90
3 files changed, 76 insertions, 24 deletions
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index cfe8d2931..f48330867 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -112,7 +112,7 @@ cc_library {
112 "properties.cpp", 112 "properties.cpp",
113 "qtaguid.c", 113 "qtaguid.c",
114 "trace-dev.c", 114 "trace-dev.c",
115 "uevent.c", 115 "uevent.cpp",
116 ], 116 ],
117 sanitize: { 117 sanitize: {
118 misc_undefined: ["integer"], 118 misc_undefined: ["integer"],
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index 55ece54a5..2ecf5bce6 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -170,6 +170,14 @@
170#define AID_SHARED_GID_START 50000 /* start of gids for apps in each user to share */ 170#define AID_SHARED_GID_START 50000 /* start of gids for apps in each user to share */
171#define AID_SHARED_GID_END 59999 /* end of gids for apps in each user to share */ 171#define AID_SHARED_GID_END 59999 /* end of gids for apps in each user to share */
172 172
173/*
174 * This is a magic number in the kernel and not something that was picked
175 * arbitrarily. This value is returned whenever a uid that has no mapping in the
176 * user namespace is returned to userspace:
177 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/linux/highuid.h?h=v4.4#n40
178 */
179#define AID_OVERFLOWUID 65534 /* unmapped user in the user namespace */
180
173#define AID_ISOLATED_START 99000 /* start of uids for fully isolated sandboxed processes */ 181#define AID_ISOLATED_START 99000 /* start of uids for fully isolated sandboxed processes */
174#define AID_ISOLATED_END 99999 /* end of uids for fully isolated sandboxed processes */ 182#define AID_ISOLATED_END 99999 /* end of uids for fully isolated sandboxed processes */
175 183
diff --git a/libcutils/uevent.c b/libcutils/uevent.cpp
index f548dca2f..a84e5b000 100644
--- a/libcutils/uevent.c
+++ b/libcutils/uevent.cpp
@@ -17,7 +17,8 @@
17#include <cutils/uevent.h> 17#include <cutils/uevent.h>
18 18
19#include <errno.h> 19#include <errno.h>
20#include <stdbool.h> 20#include <stdint.h>
21#include <stdio.h>
21#include <string.h> 22#include <string.h>
22#include <strings.h> 23#include <strings.h>
23#include <sys/socket.h> 24#include <sys/socket.h>
@@ -26,11 +27,60 @@
26 27
27#include <linux/netlink.h> 28#include <linux/netlink.h>
28 29
30#include <fstream>
31
32#include <private/android_filesystem_config.h>
33
34namespace {
35
36// Returns the uid of root in the current user namespace.
37// Returns AID_OVERFLOWUID if the root user is not mapped in the current
38// namespace.
39// Returns 0 if the kernel is not user namespace-aware (for backwards
40// compatibility) or if AID_OVERFLOWUID could not be validated to match what the
41// kernel would return.
42uid_t GetRootUid() {
43 constexpr uid_t kParentRootUid = 0;
44
45 std::ifstream uid_map_file("/proc/self/uid_map");
46 if (!uid_map_file) {
47 // The kernel does not support user namespaces.
48 return kParentRootUid;
49 }
50
51 uid_t current_namespace_uid, parent_namespace_uid;
52 uint32_t length;
53 while (uid_map_file >> current_namespace_uid >> parent_namespace_uid >> length) {
54 // Since kParentRootUid is 0, it should be the first entry in the mapped
55 // range.
56 if (parent_namespace_uid != kParentRootUid || length < 1) continue;
57 return current_namespace_uid;
58 }
59
60 // Sanity check: verify that the overflow UID is the one to be returned by
61 // the kernel.
62 std::ifstream overflowuid_file("/proc/sys/kernel/overflowuid");
63 if (!overflowuid_file) {
64 // It's better to return 0 in case we cannot make sure that the overflow
65 // UID matches.
66 return kParentRootUid;
67 }
68 uid_t kernel_overflow_uid;
69 if (!(overflowuid_file >> kernel_overflow_uid) || kernel_overflow_uid != AID_OVERFLOWUID)
70 return kParentRootUid;
71
72 // root is unmapped, use the kernel "overflow" uid.
73 return AID_OVERFLOWUID;
74}
75
76} // namespace
77
78extern "C" {
79
29/** 80/**
30 * Like recv(), but checks that messages actually originate from the kernel. 81 * Like recv(), but checks that messages actually originate from the kernel.
31 */ 82 */
32ssize_t uevent_kernel_multicast_recv(int socket, void *buffer, size_t length) 83ssize_t uevent_kernel_multicast_recv(int socket, void* buffer, size_t length) {
33{
34 uid_t uid = -1; 84 uid_t uid = -1;
35 return uevent_kernel_multicast_uid_recv(socket, buffer, length, &uid); 85 return uevent_kernel_multicast_uid_recv(socket, buffer, length, &uid);
36} 86}
@@ -44,25 +94,19 @@ ssize_t uevent_kernel_multicast_recv(int socket, void *buffer, size_t length)
44 * returns -1, sets errno to EIO, and sets "user" to the UID associated with the 94 * returns -1, sets errno to EIO, and sets "user" to the UID associated with the
45 * message. If the peer UID cannot be determined, "user" is set to -1." 95 * message. If the peer UID cannot be determined, "user" is set to -1."
46 */ 96 */
47ssize_t uevent_kernel_multicast_uid_recv(int socket, void *buffer, size_t length, uid_t *uid) 97ssize_t uevent_kernel_multicast_uid_recv(int socket, void* buffer, size_t length, uid_t* uid) {
48{
49 return uevent_kernel_recv(socket, buffer, length, true, uid); 98 return uevent_kernel_recv(socket, buffer, length, true, uid);
50} 99}
51 100
52ssize_t uevent_kernel_recv(int socket, void *buffer, size_t length, bool require_group, uid_t *uid) 101ssize_t uevent_kernel_recv(int socket, void* buffer, size_t length, bool require_group, uid_t* uid) {
53{ 102 static const uid_t root_uid = GetRootUid();
54 struct iovec iov = { buffer, length }; 103 struct iovec iov = {buffer, length};
55 struct sockaddr_nl addr; 104 struct sockaddr_nl addr;
56 char control[CMSG_SPACE(sizeof(struct ucred))]; 105 char control[CMSG_SPACE(sizeof(struct ucred))];
57 struct msghdr hdr = { 106 struct msghdr hdr = {
58 &addr, 107 &addr, sizeof(addr), &iov, 1, control, sizeof(control), 0,
59 sizeof(addr),
60 &iov,
61 1,
62 control,
63 sizeof(control),
64 0,
65 }; 108 };
109 struct ucred* cred;
66 110
67 *uid = -1; 111 *uid = -1;
68 ssize_t n = recvmsg(socket, &hdr, 0); 112 ssize_t n = recvmsg(socket, &hdr, 0);
@@ -70,15 +114,15 @@ ssize_t uevent_kernel_recv(int socket, void *buffer, size_t length, bool require
70 return n; 114 return n;
71 } 115 }
72 116
73 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&hdr); 117 struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
74 if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) { 118 if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
75 /* ignoring netlink message with no sender credentials */ 119 /* ignoring netlink message with no sender credentials */
76 goto out; 120 goto out;
77 } 121 }
78 122
79 struct ucred *cred = (struct ucred *)CMSG_DATA(cmsg); 123 cred = (struct ucred*)CMSG_DATA(cmsg);
80 *uid = cred->uid; 124 *uid = cred->uid;
81 if (cred->uid != 0) { 125 if (cred->uid != root_uid) {
82 /* ignoring netlink message from non-root user */ 126 /* ignoring netlink message from non-root user */
83 goto out; 127 goto out;
84 } 128 }
@@ -101,8 +145,7 @@ out:
101 return -1; 145 return -1;
102} 146}
103 147
104int uevent_open_socket(int buf_sz, bool passcred) 148int uevent_open_socket(int buf_sz, bool passcred) {
105{
106 struct sockaddr_nl addr; 149 struct sockaddr_nl addr;
107 int on = passcred; 150 int on = passcred;
108 int s; 151 int s;
@@ -113,8 +156,7 @@ int uevent_open_socket(int buf_sz, bool passcred)
113 addr.nl_groups = 0xffffffff; 156 addr.nl_groups = 0xffffffff;
114 157
115 s = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT); 158 s = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT);
116 if(s < 0) 159 if (s < 0) return -1;
117 return -1;
118 160
119 /* buf_sz should be less than net.core.rmem_max for this to succeed */ 161 /* buf_sz should be less than net.core.rmem_max for this to succeed */
120 if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &buf_sz, sizeof(buf_sz)) < 0) { 162 if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &buf_sz, sizeof(buf_sz)) < 0) {
@@ -124,10 +166,12 @@ int uevent_open_socket(int buf_sz, bool passcred)
124 166
125 setsockopt(s, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); 167 setsockopt(s, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
126 168
127 if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 169 if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
128 close(s); 170 close(s);
129 return -1; 171 return -1;
130 } 172 }
131 173
132 return s; 174 return s;
133} 175}
176
177} // extern "C"