summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuis Hector Chavez2017-11-02 16:17:43 -0500
committerLuis Hector Chavez2017-11-03 15:02:46 -0500
commite97a4b9799f25b10c50fccb20eb0af69f14fe8dc (patch)
tree5fd03695b3f1c24618f9a52f51c2ecd342685608 /libcutils
parent0d323c12df99201a341f0fb34ed543a46ec6eb86 (diff)
downloadplatform-system-core-e97a4b9799f25b10c50fccb20eb0af69f14fe8dc.tar.gz
platform-system-core-e97a4b9799f25b10c50fccb20eb0af69f14fe8dc.tar.xz
platform-system-core-e97a4b9799f25b10c50fccb20eb0af69f14fe8dc.zip
libcutils: Make uevent_kernel_* namespace-aware
This change adds user namespace-awareness to uevent_kernel_* in libcutils. Instead of assuming that root is always uid 0, it detects whether the uid 0 is mapped in the current user namespace and returns the appropriately mapped uid (or the kernel's "overflowuid" in case it is not mapped). In older kernels, or those where user namespaces are not enabled, this still uses uid 0 for root. Bug: 62378620 Test: bullhead networking still works Test: Android in Chrome OS can now receive netlink-related messages Change-Id: I7ea3454e8f38b9c70c65294d6b2a99e5a88f9d70
Diffstat (limited to 'libcutils')
-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"