pwd/grp: fix pwd _r reentrancy, new tests, clean up
getpwnam_r() and getpwuid_r() clobber the storage used by getpwnam() and getpwuid(). This isn't likely to be a big issue, but since we do this right for the group functions, fix this as well as add a test. Both use more space in buf than is actually required, but well below their sysconf() suggested values, so we accept that to keep the code concise. Add tests for dealing with unaligned input buffers, particularly for getgrnam_r() and getgrgid_r(), as they require alignment but this wasn't being tested. Refactor common initialization code for both passwd and group state structs. Remove extraneous null pointer checks; the values they were testing were offsets of a previous pointer, so guaranteed to never actually be null. If the underlying pointer is actually null, we're beyond repair anyway, so accept that we'll crash. Test: pwd/grp unit tests Change-Id: I60c4d00e9ab3cf55daf8314c5029fd914025b696
This commit is contained in:
parent
84c29cc446
commit
c57c5bdb7f
|
@ -58,85 +58,31 @@ static GroupFile vendor_group("/vendor/etc/group", "vendor_");
|
||||||
// functions to share state, but <grp.h> functions can't clobber <passwd.h>
|
// functions to share state, but <grp.h> functions can't clobber <passwd.h>
|
||||||
// functions' state and vice versa.
|
// functions' state and vice versa.
|
||||||
#include "bionic/pthread_internal.h"
|
#include "bionic/pthread_internal.h"
|
||||||
static group_state_t* get_group_tls_buffer() {
|
|
||||||
return &__get_bionic_tls().group;
|
|
||||||
}
|
|
||||||
|
|
||||||
static passwd_state_t* get_passwd_tls_buffer() {
|
|
||||||
return &__get_bionic_tls().passwd;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void init_group_state(group_state_t* state) {
|
static void init_group_state(group_state_t* state) {
|
||||||
memset(state, 0, sizeof(group_state_t) - sizeof(state->getgrent_idx));
|
memset(state, 0, sizeof(group_state_t) - sizeof(state->getgrent_idx));
|
||||||
|
state->group_.gr_name = state->group_name_buffer_;
|
||||||
state->group_.gr_mem = state->group_members_;
|
state->group_.gr_mem = state->group_members_;
|
||||||
|
state->group_.gr_mem[0] = state->group_.gr_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
static group_state_t* __group_state() {
|
static group_state_t* get_group_tls_buffer() {
|
||||||
group_state_t* result = get_group_tls_buffer();
|
auto result = &__get_bionic_tls().group;
|
||||||
if (result != nullptr) {
|
init_group_state(result);
|
||||||
init_group_state(result);
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_getpw_r(int by_name, const char* name, uid_t uid,
|
static void init_passwd_state(passwd_state_t* state) {
|
||||||
passwd* dst, char* buf, size_t byte_count,
|
memset(state, 0, sizeof(passwd_state_t) - sizeof(state->getpwent_idx));
|
||||||
passwd** result) {
|
state->passwd_.pw_name = state->name_buffer_;
|
||||||
// getpwnam_r and getpwuid_r don't modify errno, but library calls we
|
state->passwd_.pw_dir = state->dir_buffer_;
|
||||||
// make might.
|
state->passwd_.pw_shell = state->sh_buffer_;
|
||||||
ErrnoRestorer errno_restorer;
|
|
||||||
*result = nullptr;
|
|
||||||
|
|
||||||
// Our implementation of getpwnam(3) and getpwuid(3) use thread-local
|
|
||||||
// storage, so we can call them as long as we copy everything out
|
|
||||||
// before returning.
|
|
||||||
const passwd* src = by_name ? getpwnam(name) : getpwuid(uid); // NOLINT: see above.
|
|
||||||
|
|
||||||
// POSIX allows failure to find a match to be considered a non-error.
|
|
||||||
// Reporting success (0) but with *result NULL is glibc's behavior.
|
|
||||||
if (src == nullptr) {
|
|
||||||
return (errno == ENOENT) ? 0 : errno;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Work out where our strings will go in 'buf', and whether we've got
|
|
||||||
// enough space.
|
|
||||||
size_t required_byte_count = 0;
|
|
||||||
dst->pw_name = buf;
|
|
||||||
required_byte_count += strlen(src->pw_name) + 1;
|
|
||||||
dst->pw_dir = buf + required_byte_count;
|
|
||||||
required_byte_count += strlen(src->pw_dir) + 1;
|
|
||||||
dst->pw_shell = buf + required_byte_count;
|
|
||||||
required_byte_count += strlen(src->pw_shell) + 1;
|
|
||||||
if (byte_count < required_byte_count) {
|
|
||||||
return ERANGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy the strings.
|
|
||||||
snprintf(buf, byte_count, "%s%c%s%c%s", src->pw_name, 0, src->pw_dir, 0, src->pw_shell);
|
|
||||||
|
|
||||||
// pw_passwd and pw_gecos are non-POSIX and unused (always NULL) in bionic.
|
|
||||||
// Note: On LP32, we define pw_gecos to pw_passwd since they're both NULL.
|
|
||||||
dst->pw_passwd = nullptr;
|
|
||||||
#if defined(__LP64__)
|
|
||||||
dst->pw_gecos = nullptr;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Copy the integral fields.
|
|
||||||
dst->pw_gid = src->pw_gid;
|
|
||||||
dst->pw_uid = src->pw_uid;
|
|
||||||
|
|
||||||
*result = dst;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int getpwnam_r(const char* name, passwd* pwd,
|
static passwd_state_t* get_passwd_tls_buffer() {
|
||||||
char* buf, size_t byte_count, passwd** result) {
|
auto result = &__get_bionic_tls().passwd;
|
||||||
return do_getpw_r(1, name, -1, pwd, buf, byte_count, result);
|
init_passwd_state(result);
|
||||||
}
|
return result;
|
||||||
|
|
||||||
int getpwuid_r(uid_t uid, passwd* pwd,
|
|
||||||
char* buf, size_t byte_count, passwd** result) {
|
|
||||||
return do_getpw_r(0, nullptr, uid, pwd, buf, byte_count, result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static passwd* android_iinfo_to_passwd(passwd_state_t* state,
|
static passwd* android_iinfo_to_passwd(passwd_state_t* state,
|
||||||
|
@ -146,11 +92,8 @@ static passwd* android_iinfo_to_passwd(passwd_state_t* state,
|
||||||
snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/system/bin/sh");
|
snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/system/bin/sh");
|
||||||
|
|
||||||
passwd* pw = &state->passwd_;
|
passwd* pw = &state->passwd_;
|
||||||
pw->pw_name = state->name_buffer_;
|
|
||||||
pw->pw_uid = iinfo->aid;
|
pw->pw_uid = iinfo->aid;
|
||||||
pw->pw_gid = iinfo->aid;
|
pw->pw_gid = iinfo->aid;
|
||||||
pw->pw_dir = state->dir_buffer_;
|
|
||||||
pw->pw_shell = state->sh_buffer_;
|
|
||||||
return pw;
|
return pw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,9 +102,7 @@ static group* android_iinfo_to_group(group_state_t* state,
|
||||||
snprintf(state->group_name_buffer_, sizeof(state->group_name_buffer_), "%s", iinfo->name);
|
snprintf(state->group_name_buffer_, sizeof(state->group_name_buffer_), "%s", iinfo->name);
|
||||||
|
|
||||||
group* gr = &state->group_;
|
group* gr = &state->group_;
|
||||||
gr->gr_name = state->group_name_buffer_;
|
gr->gr_gid = iinfo->aid;
|
||||||
gr->gr_gid = iinfo->aid;
|
|
||||||
gr->gr_mem[0] = gr->gr_name;
|
|
||||||
return gr;
|
return gr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -435,9 +376,6 @@ static passwd* oem_id_to_passwd(uid_t uid, passwd_state_t* state) {
|
||||||
snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/vendor/bin/sh");
|
snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/vendor/bin/sh");
|
||||||
|
|
||||||
passwd* pw = &state->passwd_;
|
passwd* pw = &state->passwd_;
|
||||||
pw->pw_name = state->name_buffer_;
|
|
||||||
pw->pw_dir = state->dir_buffer_;
|
|
||||||
pw->pw_shell = state->sh_buffer_;
|
|
||||||
pw->pw_uid = uid;
|
pw->pw_uid = uid;
|
||||||
pw->pw_gid = uid;
|
pw->pw_gid = uid;
|
||||||
return pw;
|
return pw;
|
||||||
|
@ -456,9 +394,7 @@ static group* oem_id_to_group(gid_t gid, group_state_t* state) {
|
||||||
"oem_%u", gid);
|
"oem_%u", gid);
|
||||||
|
|
||||||
group* gr = &state->group_;
|
group* gr = &state->group_;
|
||||||
gr->gr_name = state->group_name_buffer_;
|
gr->gr_gid = gid;
|
||||||
gr->gr_gid = gid;
|
|
||||||
gr->gr_mem[0] = gr->gr_name;
|
|
||||||
return gr;
|
return gr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -486,9 +422,6 @@ static passwd* app_id_to_passwd(uid_t uid, passwd_state_t* state) {
|
||||||
snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/system/bin/sh");
|
snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/system/bin/sh");
|
||||||
|
|
||||||
passwd* pw = &state->passwd_;
|
passwd* pw = &state->passwd_;
|
||||||
pw->pw_name = state->name_buffer_;
|
|
||||||
pw->pw_dir = state->dir_buffer_;
|
|
||||||
pw->pw_shell = state->sh_buffer_;
|
|
||||||
pw->pw_uid = uid;
|
pw->pw_uid = uid;
|
||||||
pw->pw_gid = uid;
|
pw->pw_gid = uid;
|
||||||
return pw;
|
return pw;
|
||||||
|
@ -505,18 +438,11 @@ static group* app_id_to_group(gid_t gid, group_state_t* state) {
|
||||||
print_app_name_from_gid(gid, state->group_name_buffer_, sizeof(state->group_name_buffer_));
|
print_app_name_from_gid(gid, state->group_name_buffer_, sizeof(state->group_name_buffer_));
|
||||||
|
|
||||||
group* gr = &state->group_;
|
group* gr = &state->group_;
|
||||||
gr->gr_name = state->group_name_buffer_;
|
gr->gr_gid = gid;
|
||||||
gr->gr_gid = gid;
|
|
||||||
gr->gr_mem[0] = gr->gr_name;
|
|
||||||
return gr;
|
return gr;
|
||||||
}
|
}
|
||||||
|
|
||||||
passwd* getpwuid(uid_t uid) { // NOLINT: implementing bad function.
|
passwd* getpwuid_internal(uid_t uid, passwd_state_t* state) {
|
||||||
passwd_state_t* state = get_passwd_tls_buffer();
|
|
||||||
if (state == nullptr) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auto* android_id_info = find_android_id_info(uid); android_id_info != nullptr) {
|
if (auto* android_id_info = find_android_id_info(uid); android_id_info != nullptr) {
|
||||||
return android_iinfo_to_passwd(state, android_id_info);
|
return android_iinfo_to_passwd(state, android_id_info);
|
||||||
}
|
}
|
||||||
|
@ -529,12 +455,12 @@ passwd* getpwuid(uid_t uid) { // NOLINT: implementing bad function.
|
||||||
return app_id_to_passwd(uid, state);
|
return app_id_to_passwd(uid, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
passwd* getpwnam(const char* login) { // NOLINT: implementing bad function.
|
passwd* getpwuid(uid_t uid) { // NOLINT: implementing bad function.
|
||||||
passwd_state_t* state = get_passwd_tls_buffer();
|
passwd_state_t* state = get_passwd_tls_buffer();
|
||||||
if (state == nullptr) {
|
return getpwuid_internal(uid, state);
|
||||||
return nullptr;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
passwd* getpwnam_internal(const char* login, passwd_state_t* state) {
|
||||||
if (auto* android_id_info = find_android_id_info(login); android_id_info != nullptr) {
|
if (auto* android_id_info = find_android_id_info(login); android_id_info != nullptr) {
|
||||||
return android_iinfo_to_passwd(state, android_id_info);
|
return android_iinfo_to_passwd(state, android_id_info);
|
||||||
}
|
}
|
||||||
|
@ -553,6 +479,39 @@ passwd* getpwnam(const char* login) { // NOLINT: implementing bad function.
|
||||||
return app_id_to_passwd(app_id_from_name(login, false), state);
|
return app_id_to_passwd(app_id_from_name(login, false), state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
passwd* getpwnam(const char* login) { // NOLINT: implementing bad function.
|
||||||
|
passwd_state_t* state = get_passwd_tls_buffer();
|
||||||
|
return getpwnam_internal(login, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getpasswd_r(bool by_name, const char* name, uid_t uid, struct passwd* pwd, char* buf,
|
||||||
|
size_t buflen, struct passwd** result) {
|
||||||
|
ErrnoRestorer errno_restorer;
|
||||||
|
*result = nullptr;
|
||||||
|
char* p =
|
||||||
|
reinterpret_cast<char*>(__BIONIC_ALIGN(reinterpret_cast<uintptr_t>(buf), sizeof(uintptr_t)));
|
||||||
|
if (p + sizeof(passwd_state_t) > buf + buflen) {
|
||||||
|
return ERANGE;
|
||||||
|
}
|
||||||
|
passwd_state_t* state = reinterpret_cast<passwd_state_t*>(p);
|
||||||
|
init_passwd_state(state);
|
||||||
|
passwd* retval = (by_name ? getpwnam_internal(name, state) : getpwuid_internal(uid, state));
|
||||||
|
if (retval != nullptr) {
|
||||||
|
*pwd = *retval;
|
||||||
|
*result = pwd;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getpwnam_r(const char* name, passwd* pwd, char* buf, size_t byte_count, passwd** result) {
|
||||||
|
return getpasswd_r(true, name, -1, pwd, buf, byte_count, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
int getpwuid_r(uid_t uid, passwd* pwd, char* buf, size_t byte_count, passwd** result) {
|
||||||
|
return getpasswd_r(false, nullptr, uid, pwd, buf, byte_count, result);
|
||||||
|
}
|
||||||
|
|
||||||
// All users are in just one group, the one passed in.
|
// All users are in just one group, the one passed in.
|
||||||
int getgrouplist(const char* /*user*/, gid_t group, gid_t* groups, int* ngroups) {
|
int getgrouplist(const char* /*user*/, gid_t group, gid_t* groups, int* ngroups) {
|
||||||
if (*ngroups < 1) {
|
if (*ngroups < 1) {
|
||||||
|
@ -590,9 +549,6 @@ void endpwent() {
|
||||||
|
|
||||||
passwd* getpwent() {
|
passwd* getpwent() {
|
||||||
passwd_state_t* state = get_passwd_tls_buffer();
|
passwd_state_t* state = get_passwd_tls_buffer();
|
||||||
if (state == nullptr) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
if (state->getpwent_idx < 0) {
|
if (state->getpwent_idx < 0) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -643,10 +599,7 @@ static group* getgrgid_internal(gid_t gid, group_state_t* state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
group* getgrgid(gid_t gid) { // NOLINT: implementing bad function.
|
group* getgrgid(gid_t gid) { // NOLINT: implementing bad function.
|
||||||
group_state_t* state = __group_state();
|
group_state_t* state = get_group_tls_buffer();
|
||||||
if (state == nullptr) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return getgrgid_internal(gid, state);
|
return getgrgid_internal(gid, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -670,10 +623,7 @@ static group* getgrnam_internal(const char* name, group_state_t* state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
group* getgrnam(const char* name) { // NOLINT: implementing bad function.
|
group* getgrnam(const char* name) { // NOLINT: implementing bad function.
|
||||||
group_state_t* state = __group_state();
|
group_state_t* state = get_group_tls_buffer();
|
||||||
if (state == nullptr) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return getgrnam_internal(name, state);
|
return getgrnam_internal(name, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -719,9 +669,6 @@ void endgrent() {
|
||||||
|
|
||||||
group* getgrent() {
|
group* getgrent() {
|
||||||
group_state_t* state = get_group_tls_buffer();
|
group_state_t* state = get_group_tls_buffer();
|
||||||
if (state == nullptr) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
if (state->getgrent_idx < 0) {
|
if (state->getgrent_idx < 0) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -729,7 +676,6 @@ group* getgrent() {
|
||||||
size_t start = 0;
|
size_t start = 0;
|
||||||
ssize_t end = android_id_count;
|
ssize_t end = android_id_count;
|
||||||
if (state->getgrent_idx < end) {
|
if (state->getgrent_idx < end) {
|
||||||
init_group_state(state);
|
|
||||||
return android_iinfo_to_group(state, android_ids + state->getgrent_idx++);
|
return android_iinfo_to_group(state, android_ids + state->getgrent_idx++);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -737,7 +683,6 @@ group* getgrent() {
|
||||||
end += AID_OEM_RESERVED_END - AID_OEM_RESERVED_START + 1;
|
end += AID_OEM_RESERVED_END - AID_OEM_RESERVED_START + 1;
|
||||||
|
|
||||||
if (state->getgrent_idx < end) {
|
if (state->getgrent_idx < end) {
|
||||||
init_group_state(state);
|
|
||||||
return oem_id_to_group(
|
return oem_id_to_group(
|
||||||
state->getgrent_idx++ - start + AID_OEM_RESERVED_START, state);
|
state->getgrent_idx++ - start + AID_OEM_RESERVED_START, state);
|
||||||
}
|
}
|
||||||
|
@ -746,7 +691,6 @@ group* getgrent() {
|
||||||
end += AID_OEM_RESERVED_2_END - AID_OEM_RESERVED_2_START + 1;
|
end += AID_OEM_RESERVED_2_END - AID_OEM_RESERVED_2_START + 1;
|
||||||
|
|
||||||
if (state->getgrent_idx < end) {
|
if (state->getgrent_idx < end) {
|
||||||
init_group_state(state);
|
|
||||||
return oem_id_to_group(
|
return oem_id_to_group(
|
||||||
state->getgrent_idx++ - start + AID_OEM_RESERVED_2_START, state);
|
state->getgrent_idx++ - start + AID_OEM_RESERVED_2_START, state);
|
||||||
}
|
}
|
||||||
|
|
|
@ -217,6 +217,89 @@ TEST(pwd, getpwnam_app_id_u1_a40000) {
|
||||||
TEST(pwd, getpwnam_app_id_u1_i0) {
|
TEST(pwd, getpwnam_app_id_u1_i0) {
|
||||||
check_get_passwd("u1_i0", 190000, TYPE_APP);
|
check_get_passwd("u1_i0", 190000, TYPE_APP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(pwd, getpwnam_r_alignment) {
|
||||||
|
#if defined(__BIONIC__)
|
||||||
|
passwd pwd_storage;
|
||||||
|
alignas(16) char buf[512];
|
||||||
|
passwd* pwd;
|
||||||
|
int result = getpwnam_r("root", &pwd_storage, buf + 1, sizeof(buf) - 1, &pwd);
|
||||||
|
ASSERT_EQ(0, result);
|
||||||
|
check_passwd(pwd, "root", 0, TYPE_SYSTEM, true);
|
||||||
|
#else
|
||||||
|
GTEST_SKIP() << "bionic-only test";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(pwd, getpwuid_r_alignment) {
|
||||||
|
#if defined(__BIONIC__)
|
||||||
|
passwd pwd_storage;
|
||||||
|
alignas(16) char buf[512];
|
||||||
|
passwd* pwd;
|
||||||
|
int result = getpwuid_r(0, &pwd_storage, buf + 1, sizeof(buf) - 1, &pwd);
|
||||||
|
ASSERT_EQ(0, result);
|
||||||
|
check_passwd(pwd, "root", 0, TYPE_SYSTEM, true);
|
||||||
|
#else
|
||||||
|
GTEST_SKIP() << "bionic-only test";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(pwd, getpwnam_r_reentrancy) {
|
||||||
|
#if defined(__BIONIC__)
|
||||||
|
passwd pwd_storage[2];
|
||||||
|
char buf[2][512];
|
||||||
|
passwd* pwd[3];
|
||||||
|
int result = getpwnam_r("root", &pwd_storage[0], buf[0], sizeof(buf[0]), &pwd[0]);
|
||||||
|
ASSERT_EQ(0, result);
|
||||||
|
check_passwd(pwd[0], "root", 0, TYPE_SYSTEM, true);
|
||||||
|
pwd[1] = getpwnam("system");
|
||||||
|
ASSERT_NE(nullptr, pwd[1]);
|
||||||
|
check_passwd(pwd[1], "system", 1000, TYPE_SYSTEM, true);
|
||||||
|
result = getpwnam_r("radio", &pwd_storage[1], buf[1], sizeof(buf[1]), &pwd[2]);
|
||||||
|
ASSERT_EQ(0, result);
|
||||||
|
check_passwd(pwd[2], "radio", 1001, TYPE_SYSTEM, true);
|
||||||
|
check_passwd(pwd[0], "root", 0, TYPE_SYSTEM, true);
|
||||||
|
check_passwd(pwd[1], "system", 1000, TYPE_SYSTEM, true);
|
||||||
|
#else
|
||||||
|
GTEST_SKIP() << "bionic-only test";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(pwd, getpwuid_r_reentrancy) {
|
||||||
|
#if defined(__BIONIC__)
|
||||||
|
passwd pwd_storage[2];
|
||||||
|
char buf[2][512];
|
||||||
|
passwd* pwd[3];
|
||||||
|
int result = getpwuid_r(0, &pwd_storage[0], buf[0], sizeof(buf[0]), &pwd[0]);
|
||||||
|
ASSERT_EQ(0, result);
|
||||||
|
check_passwd(pwd[0], "root", 0, TYPE_SYSTEM, true);
|
||||||
|
pwd[1] = getpwuid(1000);
|
||||||
|
ASSERT_NE(nullptr, pwd[1]);
|
||||||
|
check_passwd(pwd[1], "system", 1000, TYPE_SYSTEM, true);
|
||||||
|
result = getpwuid_r(1001, &pwd_storage[1], buf[1], sizeof(buf[1]), &pwd[2]);
|
||||||
|
ASSERT_EQ(0, result);
|
||||||
|
check_passwd(pwd[2], "radio", 1001, TYPE_SYSTEM, true);
|
||||||
|
check_passwd(pwd[0], "root", 0, TYPE_SYSTEM, true);
|
||||||
|
check_passwd(pwd[1], "system", 1000, TYPE_SYSTEM, true);
|
||||||
|
#else
|
||||||
|
GTEST_SKIP() << "bionic-only test";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(pwd, getpwnam_r_large_enough_suggested_buffer_size) {
|
||||||
|
#if defined(__BIONIC__)
|
||||||
|
long size = sysconf(_SC_GETPW_R_SIZE_MAX);
|
||||||
|
ASSERT_GT(size, 0);
|
||||||
|
char buf[size];
|
||||||
|
passwd pwd_storage;
|
||||||
|
passwd* pwd;
|
||||||
|
ASSERT_EQ(0, getpwnam_r("root", &pwd_storage, buf, size, &pwd));
|
||||||
|
check_passwd(pwd, "root", 0, TYPE_SYSTEM, true);
|
||||||
|
#else
|
||||||
|
GTEST_SKIP() << "bionic-only test";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(__BIONIC__)
|
#if defined(__BIONIC__)
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static void expect_ids(const T& ids) {
|
static void expect_ids(const T& ids) {
|
||||||
|
@ -477,6 +560,32 @@ TEST(grp, getgrnam_app_id_u1_i0) {
|
||||||
check_get_group("u1_i0", 190000);
|
check_get_group("u1_i0", 190000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(grp, getgrnam_r_alignment) {
|
||||||
|
#if defined(__BIONIC__)
|
||||||
|
group grp_storage;
|
||||||
|
alignas(16) char buf[512];
|
||||||
|
group* grp;
|
||||||
|
int result = getgrnam_r("root", &grp_storage, buf + 1, sizeof(buf) - 1, &grp);
|
||||||
|
ASSERT_EQ(0, result);
|
||||||
|
check_group(grp, "root", 0);
|
||||||
|
#else
|
||||||
|
GTEST_SKIP() << "bionic-only test";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(grp, getgrgid_r_alignment) {
|
||||||
|
#if defined(__BIONIC__)
|
||||||
|
group grp_storage;
|
||||||
|
alignas(16) char buf[512];
|
||||||
|
group* grp;
|
||||||
|
int result = getgrgid_r(0, &grp_storage, buf + 1, sizeof(buf) - 1, &grp);
|
||||||
|
ASSERT_EQ(0, result);
|
||||||
|
check_group(grp, "root", 0);
|
||||||
|
#else
|
||||||
|
GTEST_SKIP() << "bionic-only test";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
TEST(grp, getgrnam_r_reentrancy) {
|
TEST(grp, getgrnam_r_reentrancy) {
|
||||||
#if defined(__BIONIC__)
|
#if defined(__BIONIC__)
|
||||||
group grp_storage[2];
|
group grp_storage[2];
|
||||||
|
|
Loading…
Reference in New Issue