aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorElliott Hughes2014-12-18 15:36:25 -0600
committerElliott Hughes2014-12-18 17:01:10 -0600
commit7874f1d7182d80eb72c699eaa9ab8cc4cfec95ab (patch)
tree4348cc097c742280038ff78b454d6cd513cd619e
parent9dd5ab46194a3ef7992b0c08d18f2e30551f9331 (diff)
downloadplatform-bionic-7874f1d7182d80eb72c699eaa9ab8cc4cfec95ab.tar.gz
platform-bionic-7874f1d7182d80eb72c699eaa9ab8cc4cfec95ab.tar.xz
platform-bionic-7874f1d7182d80eb72c699eaa9ab8cc4cfec95ab.zip
Split the shared group data from the shared passwd data.
Found by the toybox id(1) which calls both getpwuid(3) and getgrgid(3) before looking at either result. The use of a shared buffer in this code meant that even on a single thread, the data for any of the passwd functions would be clobbered by the data for any of the group functions (or vice versa). This might seem like an insufficient fix, but POSIX explicitly says (for getpwnam) that the result "might be overwritten by a subsequent call to getpwent(), getpwnam(), or getpwuid()" and likewise for other members of that group, plus equivalent text for the group-related functions. Change-Id: I2272f47e91f72e043fdaf7c169fa9f6978ff4370
-rw-r--r--libc/bionic/stubs.cpp82
-rw-r--r--libc/private/bionic_tls.h5
2 files changed, 50 insertions, 37 deletions
diff --git a/libc/bionic/stubs.cpp b/libc/bionic/stubs.cpp
index 88e5ac5e..ab679355 100644
--- a/libc/bionic/stubs.cpp
+++ b/libc/bionic/stubs.cpp
@@ -42,18 +42,44 @@
42#include "private/libc_logging.h" 42#include "private/libc_logging.h"
43#include "private/ThreadLocalBuffer.h" 43#include "private/ThreadLocalBuffer.h"
44 44
45GLOBAL_INIT_THREAD_LOCAL_BUFFER(stubs); 45// POSIX seems to envisage an implementation where the <pwd.h> functions are
46// implemented by brute-force searching with getpwent(3), and the <grp.h>
47// functions are implemented similarly with getgrent(3). This means that it's
48// okay for all the <grp.h> functions to share state, and all the <passwd.h>
49// functions to share state, but <grp.h> functions can't clobber <passwd.h>
50// functions' state and vice versa.
46 51
47struct stubs_state_t { 52GLOBAL_INIT_THREAD_LOCAL_BUFFER(group);
48 passwd passwd_; 53
54struct group_state_t {
49 group group_; 55 group group_;
50 char* group_members_[2]; 56 char* group_members_[2];
51 char app_name_buffer_[32];
52 char group_name_buffer_[32]; 57 char group_name_buffer_[32];
58};
59
60static group_state_t* __group_state() {
61 LOCAL_INIT_THREAD_LOCAL_BUFFER(group_state_t*, group, sizeof(group_state_t));
62 if (group_tls_buffer != NULL) {
63 memset(group_tls_buffer, 0, sizeof(group_state_t));
64 group_tls_buffer->group_.gr_mem = group_tls_buffer->group_members_;
65 }
66 return group_tls_buffer;
67}
68
69GLOBAL_INIT_THREAD_LOCAL_BUFFER(passwd);
70
71struct passwd_state_t {
72 passwd passwd_;
73 char app_name_buffer_[32];
53 char dir_buffer_[32]; 74 char dir_buffer_[32];
54 char sh_buffer_[32]; 75 char sh_buffer_[32];
55}; 76};
56 77
78static passwd_state_t* __passwd_state() {
79 LOCAL_INIT_THREAD_LOCAL_BUFFER(passwd_state_t*, passwd, sizeof(passwd_state_t));
80 return passwd_tls_buffer;
81}
82
57static int do_getpw_r(int by_name, const char* name, uid_t uid, 83static int do_getpw_r(int by_name, const char* name, uid_t uid,
58 passwd* dst, char* buf, size_t byte_count, 84 passwd* dst, char* buf, size_t byte_count,
59 passwd** result) { 85 passwd** result) {
@@ -91,7 +117,7 @@ static int do_getpw_r(int by_name, const char* name, uid_t uid,
91 117
92 // pw_passwd and pw_gecos are non-POSIX and unused (always NULL) in bionic. 118 // pw_passwd and pw_gecos are non-POSIX and unused (always NULL) in bionic.
93 dst->pw_passwd = NULL; 119 dst->pw_passwd = NULL;
94#ifdef __LP64__ 120#if defined(__LP64__)
95 dst->pw_gecos = NULL; 121 dst->pw_gecos = NULL;
96#endif 122#endif
97 123
@@ -113,17 +139,7 @@ int getpwuid_r(uid_t uid, passwd* pwd,
113 return do_getpw_r(0, NULL, uid, pwd, buf, byte_count, result); 139 return do_getpw_r(0, NULL, uid, pwd, buf, byte_count, result);
114} 140}
115 141
116static stubs_state_t* __stubs_state() { 142static passwd* android_iinfo_to_passwd(passwd_state_t* state,
117 LOCAL_INIT_THREAD_LOCAL_BUFFER(stubs_state_t*, stubs, sizeof(stubs_state_t));
118
119 if (stubs_tls_buffer != NULL) {
120 memset(stubs_tls_buffer, 0, sizeof(stubs_state_t));
121 stubs_tls_buffer->group_.gr_mem = stubs_tls_buffer->group_members_;
122 }
123 return stubs_tls_buffer;
124}
125
126static passwd* android_iinfo_to_passwd(stubs_state_t* state,
127 const android_id_info* iinfo) { 143 const android_id_info* iinfo) {
128 snprintf(state->dir_buffer_, sizeof(state->dir_buffer_), "/"); 144 snprintf(state->dir_buffer_, sizeof(state->dir_buffer_), "/");
129 snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/system/bin/sh"); 145 snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/system/bin/sh");
@@ -145,7 +161,7 @@ static group* android_iinfo_to_group(group* gr,
145 return gr; 161 return gr;
146} 162}
147 163
148static passwd* android_id_to_passwd(stubs_state_t* state, unsigned id) { 164static passwd* android_id_to_passwd(passwd_state_t* state, unsigned id) {
149 for (size_t n = 0; n < android_id_count; ++n) { 165 for (size_t n = 0; n < android_id_count; ++n) {
150 if (android_ids[n].aid == id) { 166 if (android_ids[n].aid == id) {
151 return android_iinfo_to_passwd(state, android_ids + n); 167 return android_iinfo_to_passwd(state, android_ids + n);
@@ -154,7 +170,7 @@ static passwd* android_id_to_passwd(stubs_state_t* state, unsigned id) {
154 return NULL; 170 return NULL;
155} 171}
156 172
157static passwd* android_name_to_passwd(stubs_state_t* state, const char* name) { 173static passwd* android_name_to_passwd(passwd_state_t* state, const char* name) {
158 for (size_t n = 0; n < android_id_count; ++n) { 174 for (size_t n = 0; n < android_id_count; ++n) {
159 if (!strcmp(android_ids[n].name, name)) { 175 if (!strcmp(android_ids[n].name, name)) {
160 return android_iinfo_to_passwd(state, android_ids + n); 176 return android_iinfo_to_passwd(state, android_ids + n);
@@ -297,9 +313,7 @@ static void print_app_name_from_gid(const gid_t gid, char* buffer, const int buf
297// AID_ISOLATED_START to AID_USER-1 -> u0_i1234 313// AID_ISOLATED_START to AID_USER-1 -> u0_i1234
298// AID_USER+ -> u1_radio, u1_a1234, u2_i1234, etc. 314// AID_USER+ -> u1_radio, u1_a1234, u2_i1234, etc.
299// returns a passwd structure (sets errno to ENOENT on failure). 315// returns a passwd structure (sets errno to ENOENT on failure).
300static passwd* app_id_to_passwd(uid_t uid, stubs_state_t* state) { 316static passwd* app_id_to_passwd(uid_t uid, passwd_state_t* state) {
301 passwd* pw = &state->passwd_;
302
303 if (uid < AID_APP) { 317 if (uid < AID_APP) {
304 errno = ENOENT; 318 errno = ENOENT;
305 return NULL; 319 return NULL;
@@ -316,18 +330,18 @@ static passwd* app_id_to_passwd(uid_t uid, stubs_state_t* state) {
316 330
317 snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/system/bin/sh"); 331 snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/system/bin/sh");
318 332
333 passwd* pw = &state->passwd_;
319 pw->pw_name = state->app_name_buffer_; 334 pw->pw_name = state->app_name_buffer_;
320 pw->pw_dir = state->dir_buffer_; 335 pw->pw_dir = state->dir_buffer_;
321 pw->pw_shell = state->sh_buffer_; 336 pw->pw_shell = state->sh_buffer_;
322 pw->pw_uid = uid; 337 pw->pw_uid = uid;
323 pw->pw_gid = uid; 338 pw->pw_gid = uid;
324
325 return pw; 339 return pw;
326} 340}
327 341
328// Translate a gid into the corresponding app_<gid> 342// Translate a gid into the corresponding app_<gid>
329// group structure (sets errno to ENOENT on failure). 343// group structure (sets errno to ENOENT on failure).
330static group* app_id_to_group(gid_t gid, stubs_state_t* state) { 344static group* app_id_to_group(gid_t gid, group_state_t* state) {
331 if (gid < AID_APP) { 345 if (gid < AID_APP) {
332 errno = ENOENT; 346 errno = ENOENT;
333 return NULL; 347 return NULL;
@@ -339,13 +353,11 @@ static group* app_id_to_group(gid_t gid, stubs_state_t* state) {
339 gr->gr_name = state->group_name_buffer_; 353 gr->gr_name = state->group_name_buffer_;
340 gr->gr_gid = gid; 354 gr->gr_gid = gid;
341 gr->gr_mem[0] = gr->gr_name; 355 gr->gr_mem[0] = gr->gr_name;
342
343 return gr; 356 return gr;
344} 357}
345 358
346
347passwd* getpwuid(uid_t uid) { // NOLINT: implementing bad function. 359passwd* getpwuid(uid_t uid) { // NOLINT: implementing bad function.
348 stubs_state_t* state = __stubs_state(); 360 passwd_state_t* state = __passwd_state();
349 if (state == NULL) { 361 if (state == NULL) {
350 return NULL; 362 return NULL;
351 } 363 }
@@ -358,7 +370,7 @@ passwd* getpwuid(uid_t uid) { // NOLINT: implementing bad function.
358} 370}
359 371
360passwd* getpwnam(const char* login) { // NOLINT: implementing bad function. 372passwd* getpwnam(const char* login) { // NOLINT: implementing bad function.
361 stubs_state_t* state = __stubs_state(); 373 passwd_state_t* state = __passwd_state();
362 if (state == NULL) { 374 if (state == NULL) {
363 return NULL; 375 return NULL;
364 } 376 }
@@ -372,12 +384,12 @@ passwd* getpwnam(const char* login) { // NOLINT: implementing bad function.
372 384
373// All users are in just one group, the one passed in. 385// All users are in just one group, the one passed in.
374int getgrouplist(const char* /*user*/, gid_t group, gid_t* groups, int* ngroups) { 386int getgrouplist(const char* /*user*/, gid_t group, gid_t* groups, int* ngroups) {
375 if (*ngroups < 1) { 387 if (*ngroups < 1) {
376 *ngroups = 1; 388 *ngroups = 1;
377 return -1; 389 return -1;
378 } 390 }
379 groups[0] = group; 391 groups[0] = group;
380 return (*ngroups = 1); 392 return (*ngroups = 1);
381} 393}
382 394
383char* getlogin() { // NOLINT: implementing bad function. 395char* getlogin() { // NOLINT: implementing bad function.
@@ -386,7 +398,7 @@ char* getlogin() { // NOLINT: implementing bad function.
386} 398}
387 399
388group* getgrgid(gid_t gid) { // NOLINT: implementing bad function. 400group* getgrgid(gid_t gid) { // NOLINT: implementing bad function.
389 stubs_state_t* state = __stubs_state(); 401 group_state_t* state = __group_state();
390 if (state == NULL) { 402 if (state == NULL) {
391 return NULL; 403 return NULL;
392 } 404 }
@@ -399,7 +411,7 @@ group* getgrgid(gid_t gid) { // NOLINT: implementing bad function.
399} 411}
400 412
401group* getgrnam(const char* name) { // NOLINT: implementing bad function. 413group* getgrnam(const char* name) { // NOLINT: implementing bad function.
402 stubs_state_t* state = __stubs_state(); 414 group_state_t* state = __group_state();
403 if (state == NULL) { 415 if (state == NULL) {
404 return NULL; 416 return NULL;
405 } 417 }
diff --git a/libc/private/bionic_tls.h b/libc/private/bionic_tls.h
index 4a351668..944f9579 100644
--- a/libc/private/bionic_tls.h
+++ b/libc/private/bionic_tls.h
@@ -85,7 +85,8 @@ enum {
85 * ttyname libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER) 85 * ttyname libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
86 * strerror libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER) 86 * strerror libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
87 * strsignal libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER) 87 * strsignal libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
88 * stubs libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER) 88 * passwd libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
89 * group libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
89 * _res_key libc 90 * _res_key libc
90 * je_thread_allocated_tsd jemalloc 91 * je_thread_allocated_tsd jemalloc
91 * je_arenas_tsd jemalloc 92 * je_arenas_tsd jemalloc
@@ -95,7 +96,7 @@ enum {
95 * 96 *
96 */ 97 */
97 98
98#define LIBC_TLS_RESERVED_SLOTS 11 99#define LIBC_TLS_RESERVED_SLOTS 12
99 100
100#if defined(USE_JEMALLOC) 101#if defined(USE_JEMALLOC)
101/* jemalloc uses 5 keys for itself. */ 102/* jemalloc uses 5 keys for itself. */