From c4786d366b11ed81165d43ee7f23e0d4965fc00f Mon Sep 17 00:00:00 2001 From: Yabin Cui Date: Mon, 20 Jul 2015 19:46:26 -0700 Subject: [PATCH] Add getgrgid_r/getgrnam_r. Bug: 22568551 Change-Id: I3c0772d119d6041063c6be53f5bcc5ea1768f0d5 --- libc/bionic/stubs.cpp | 59 ++++++++++++++++++++++++----- libc/libc.map | 8 +++- tests/stubs_test.cpp | 88 +++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 142 insertions(+), 13 deletions(-) diff --git a/libc/bionic/stubs.cpp b/libc/bionic/stubs.cpp index b57aedab4..41c78bc99 100644 --- a/libc/bionic/stubs.cpp +++ b/libc/bionic/stubs.cpp @@ -39,6 +39,7 @@ #include #include "private/android_filesystem_config.h" +#include "private/bionic_macros.h" #include "private/ErrnoRestorer.h" #include "private/libc_logging.h" #include "private/ThreadLocalBuffer.h" @@ -66,11 +67,15 @@ struct passwd_state_t { static ThreadLocalBuffer g_group_tls_buffer; static ThreadLocalBuffer g_passwd_tls_buffer; +static void init_group_state(group_state_t* state) { + memset(state, 0, sizeof(group_state_t)); + state->group_.gr_mem = state->group_members_; +} + static group_state_t* __group_state() { group_state_t* result = g_group_tls_buffer.get(); if (result != nullptr) { - memset(result, 0, sizeof(group_state_t)); - result->group_.gr_mem = result->group_members_; + init_group_state(result); } return result; } @@ -397,17 +402,28 @@ char* getlogin() { // NOLINT: implementing bad function. return (pw != NULL) ? pw->pw_name : NULL; } +static group* getgrgid_internal(gid_t gid, group_state_t* state) { + group* grp = android_id_to_group(state, gid); + if (grp != NULL) { + return grp; + } + return app_id_to_group(gid, state); +} + group* getgrgid(gid_t gid) { // NOLINT: implementing bad function. group_state_t* state = __group_state(); if (state == NULL) { return NULL; } + return getgrgid_internal(gid, state); +} - group* gr = android_id_to_group(state, gid); - if (gr != NULL) { - return gr; +static group* getgrnam_internal(const char* name, group_state_t* state) { + group* grp = android_name_to_group(state, name); + if (grp != NULL) { + return grp; } - return app_id_to_group(gid, state); + return app_id_to_group(app_id_from_name(name, true), state); } group* getgrnam(const char* name) { // NOLINT: implementing bad function. @@ -415,11 +431,36 @@ group* getgrnam(const char* name) { // NOLINT: implementing bad function. if (state == NULL) { return NULL; } + return getgrnam_internal(name, state); +} - if (android_name_to_group(state, name) != 0) { - return &state->group_; +static int getgroup_r(bool by_name, const char* name, gid_t gid, struct group* grp, char* buf, + size_t buflen, struct group** result) { + ErrnoRestorer errno_restorer; + *result = NULL; + char* p = reinterpret_cast( + BIONIC_ALIGN(reinterpret_cast(buf), sizeof(uintptr_t))); + if (p + sizeof(group_state_t) > buf + buflen) { + return ERANGE; } - return app_id_to_group(app_id_from_name(name, true), state); + group_state_t* state = reinterpret_cast(p); + init_group_state(state); + group* retval = (by_name ? getgrnam_internal(name, state) : getgrgid_internal(gid, state)); + if (retval != NULL) { + *grp = *retval; + *result = grp; + return 0; + } + return errno; +} + +int getgrgid_r(gid_t gid, struct group* grp, char* buf, size_t buflen, struct group** result) { + return getgroup_r(false, NULL, gid, grp, buf, buflen, result); +} + +int getgrnam_r(const char* name, struct group* grp, char* buf, size_t buflen, + struct group **result) { + return getgroup_r(true, name, 0, grp, buf, buflen, result); } // We don't have an /etc/networks, so all inputs return NULL. diff --git a/libc/libc.map b/libc/libc.map index 47c52a40f..ffbd29ccf 100644 --- a/libc/libc.map +++ b/libc/libc.map @@ -1332,6 +1332,12 @@ LIBC { *; }; +LIBC_N { + global: + getgrgid_r; + getgrnam_r; +} LIBC; + LIBC_PRIVATE { global: ___Unwind_Backtrace; # arm @@ -1453,4 +1459,4 @@ LIBC_PRIVATE { SHA1Init; # arm x86 mips SHA1Transform; # arm x86 mips SHA1Update; # arm x86 mips -} LIBC; +} LIBC_N; diff --git a/tests/stubs_test.cpp b/tests/stubs_test.cpp index 89d67cbb8..2d1bdeee6 100644 --- a/tests/stubs_test.cpp +++ b/tests/stubs_test.cpp @@ -163,8 +163,6 @@ TEST(getpwnam, app_id_u1_i0) { check_get_passwd("u1_i0", 199000, TYPE_APP); } -#if defined(__BIONIC__) - static void check_group(const group* grp, const char* group_name, gid_t gid) { ASSERT_TRUE(grp != NULL); ASSERT_STREQ(group_name, grp->gr_name); @@ -174,6 +172,8 @@ static void check_group(const group* grp, const char* group_name, gid_t gid) { ASSERT_TRUE(grp->gr_mem[1] == NULL); } +#if defined(__BIONIC__) + static void check_getgrgid(const char* group_name, gid_t gid) { errno = 0; group* grp = getgrgid(gid); @@ -190,17 +190,49 @@ static void check_getgrnam(const char* group_name, gid_t gid) { check_group(grp, group_name, gid); } +static void check_getgrgid_r(const char* group_name, gid_t gid) { + group grp_storage; + char buf[512]; + group* grp; + + errno = 0; + int result = getgrgid_r(gid, &grp_storage, buf, sizeof(buf), &grp); + ASSERT_EQ(0, result); + ASSERT_EQ(0, errno); + SCOPED_TRACE("getgrgid_r"); + check_group(grp, group_name, gid); +} + +static void check_getgrnam_r(const char* group_name, gid_t gid) { + group grp_storage; + char buf[512]; + group* grp; + + errno = 0; + int result = getgrnam_r(group_name, &grp_storage, buf, sizeof(buf), &grp); + ASSERT_EQ(0, result); + ASSERT_EQ(0, errno); + SCOPED_TRACE("getgrnam_r"); + check_group(grp, group_name, gid); +} + static void check_get_group(const char* group_name, gid_t gid) { check_getgrgid(group_name, gid); check_getgrnam(group_name, gid); + check_getgrgid_r(group_name, gid); + check_getgrnam_r(group_name, gid); } #else // !defined(__BIONIC__) -static void check_get_group(const char* /* group_name */, gid_t /* gid */) { +static void print_no_getgrnam_test_info() { GTEST_LOG_(INFO) << "This test is about gid/group_name translation for Android, which does nothing on libc other than bionic.\n"; } +static void check_get_group(const char*, gid_t) { + print_no_getgrnam_test_info(); +} + #endif TEST(getgrnam, system_id_root) { @@ -259,3 +291,53 @@ TEST(getgrnam, app_id_u1_a40000) { TEST(getgrnam, app_id_u1_i0) { check_get_group("u1_i0", 199000); } + +TEST(getgrnam_r, reentrancy) { +#if defined(__BIONIC__) + group grp_storage[2]; + char buf[2][512]; + group* grp[3]; + int result = getgrnam_r("root", &grp_storage[0], buf[0], sizeof(buf[0]), &grp[0]); + ASSERT_EQ(0, result); + check_group(grp[0], "root", 0); + grp[1] = getgrnam("system"); + check_group(grp[1], "system", 1000); + result = getgrnam_r("radio", &grp_storage[1], buf[1], sizeof(buf[1]), &grp[2]); + ASSERT_EQ(0, result); + check_group(grp[2], "radio", 1001); + check_group(grp[0], "root", 0); + check_group(grp[1], "system", 1000); +#else + print_no_getgrnam_test_info(); +#endif +} + +TEST(getgrgid_r, reentrancy) { +#if defined(__BIONIC__) + group grp_storage[2]; + char buf[2][512]; + group* grp[3]; + int result = getgrgid_r(0, &grp_storage[0], buf[0], sizeof(buf[0]), &grp[0]); + ASSERT_EQ(0, result); + check_group(grp[0], "root", 0); + grp[1] = getgrgid(1000); + check_group(grp[1], "system", 1000); + result = getgrgid_r(1001, &grp_storage[1], buf[1], sizeof(buf[1]), &grp[2]); + ASSERT_EQ(0, result); + check_group(grp[2], "radio", 1001); + check_group(grp[0], "root", 0); + check_group(grp[1], "system", 1000); +#else + print_no_getgrnam_test_info(); +#endif +} + +TEST(getgrnam_r, large_enough_suggested_buffer_size) { + long size = sysconf(_SC_GETGR_R_SIZE_MAX); + ASSERT_GT(size, 0); + char buf[size]; + group grp_storage; + group* grp; + ASSERT_EQ(0, getgrnam_r("root", &grp_storage, buf, size, &grp)); + check_group(grp, "root", 0); +}