Use getpwuid_r() instead of getpwuid()
In the Netopeer2 test suite, two threads were calling getpwuid(), which
is not a reentrant function. Here's a trace from TSAN:
WARNING: ThreadSanitizer: data race (pid=3803971)
Write of size 8 at 0x7fc95e073f40 by thread T2:
#0 getpwuid <null> (test_parallel_sessions+0x4367d4)
#1 nc_connect_unix libnetconf2/src/session_client.c:1270:10 (libnetconf2.so.2+0x1ba34)
#2 send_get_rpc Netopeer2/tests/test_parallel_sessions.c:68:15 (test_parallel_sessions+0x4ea807)
Previous write of size 8 at 0x7fc95e073f40 by thread T1:
#0 getpwuid <null> (test_parallel_sessions+0x4367d4)
#1 nc_connect_unix libnetconf2/src/session_client.c:1270:10 (libnetconf2.so.2+0x1ba34)
#2 send_get_rpc Netopeer2/tests/test_parallel_sessions.c:68:15 (test_parallel_sessions+0x4ea807)
Location is global 'resbuf.11357' of size 48 at 0x7fc95e073f40 (libc.so.6+0x1bcf40)
Thread T2 (tid=3807449, running) created by main thread at:
#0 pthread_create <null> (test_parallel_sessions+0x469032)
#1 test_first Netopeer2/tests/test_parallel_sessions.c:115:9 (test_parallel_sessions+0x4ea6c2)
#2 cmocka_run_one_test_or_fixture <null> (libcmocka.so.0+0x630e)
Thread T1 (tid=3807448, running) created by main thread at:
#0 pthread_create <null> (test_parallel_sessions+0x469032)
#1 test_first Netopeer2/tests/test_parallel_sessions.c:115:9 (test_parallel_sessions+0x4ea6ad)
#2 cmocka_run_one_test_or_fixture <null> (libcmocka.so.0+0x630e)
SUMMARY: ThreadSanitizer: data race (Netopeer2/tests/test_parallel_sessions+0x4367d4) in __interceptor_getpwuid
Fix that by switching to getpwuid_r(). The code is very similar to the
auth_password_getpwnam() wrapper from session_server_ssh.c. I chose to
put this into io.c even though it is not really an IO function, but the
existing nc_realloc() is in that file as well.
diff --git a/src/io.c b/src/io.c
index 97ad40a..7048430 100644
--- a/src/io.c
+++ b/src/io.c
@@ -17,10 +17,12 @@
#include <errno.h>
#include <inttypes.h>
#include <poll.h>
+#include <pwd.h>
#include <signal.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/types.h>
#include <time.h>
#include <unistd.h>
@@ -1158,3 +1160,39 @@
return ret;
}
+
+struct passwd *
+nc_getpwuid(uid_t uid, struct passwd *pwd_buf, char **buf, size_t *buf_size)
+{
+ struct passwd *pwd = NULL;
+ char *mem;
+ int r = 0;
+
+ do {
+ r = getpwuid_r(uid, pwd_buf, *buf, *buf_size, &pwd);
+ if (pwd) {
+ break;
+ }
+
+ if (r == ERANGE) {
+ if (!*buf_size) {
+ ssize_t size = sysconf(_SC_GETPW_R_SIZE_MAX);
+ if (size == -1) {
+ *buf_size = 256;
+ } else {
+ *buf_size = size;
+ }
+ } else {
+ *buf_size <<= 2;
+ }
+ mem = realloc(*buf, *buf_size);
+ if (!mem) {
+ ERRMEM;
+ return NULL;
+ }
+ *buf = mem;
+ }
+ } while (r == ERANGE);
+
+ return pwd;
+}