On 25/11/2013 14:56, Petr Salinger wrote: > The getlogin_r is not thread safe, as it uses the same buffer as getlogin.
This should fix it, I think. It still updates the buffer (for the sake of getlogin) but doesn't rely on it. Also, I think the ERANGE check can be removed when we drop support for pre-9.2. -- Robert Millan
Index: getlogin_r.c =================================================================== --- getlogin_r.c (revision 5163) +++ getlogin_r.c (working copy) @@ -25,11 +25,9 @@ #include <sys/param.h> #include <sysdep.h> -/* Cache the system call's return value. */ -char *__getlogin_cache; -/* The kernel never returns more than MAXLOGNAME bytes, therefore we don't - need more than that either. */ -char __getlogin_cache_room[MAXLOGNAME]; +/* Defined in getlogin.c. */ +extern char *__getlogin_cache; +extern char __getlogin_cache_room[MAXLOGNAME]; extern int __syscall_getlogin (char *__name, size_t __name_len); libc_hidden_proto (__syscall_getlogin) @@ -45,20 +43,28 @@ { size_t len; - if (__getlogin_cache == NULL) - { - if (INLINE_SYSCALL (getlogin, 2, __getlogin_cache_room, MAXLOGNAME) < 0) + if (INLINE_SYSCALL (getlogin, 2, name, name_len) < 0) return errno; /* The system call should return a NULL terminated name. */ - if (__memchr (__getlogin_cache_room, '\0', MAXLOGNAME) == NULL) + if (__memchr (name, '\0', name_len) == NULL) abort (); - __getlogin_cache = __getlogin_cache_room; - } - len = strlen (__getlogin_cache); + len = strlen (name); + + /* FIXME: recent kernels (r243021) already check this (and set ERANGE). */ if (__builtin_expect (len < name_len, 1)) { - memcpy (name, __getlogin_cache, len + 1); + /* We update the cache only for the sake of getlogin.c. We can't use it + ourselves since it would break thread-safety. */ + + /* Upstream has increased MAXLOGNAME in the kernel before (r243023). + Be safe rather than sorry. */ + if (len + 1 <= sizeof (__getlogin_cache_room)) + { + /* Not thread-safe, but the only consumer (getlogin.c) doesn't care. */ + memcpy (__getlogin_cache, name, len + 1); + __getlogin_cache = __getlogin_cache_room; + } return 0; } else Index: getlogin.c =================================================================== --- getlogin.c (revision 5151) +++ getlogin.c (working copy) @@ -24,9 +24,11 @@ #include <sys/param.h> #include <sysdep.h> -/* Defined in getlogin_r.c. */ -extern char *__getlogin_cache; -extern char __getlogin_cache_room[MAXLOGNAME]; +/* Cache the system call's return value. */ +char *__getlogin_cache; +/* The kernel never returns more than MAXLOGNAME bytes, therefore we don't + need more than that either. */ +char __getlogin_cache_room[MAXLOGNAME]; extern int __syscall_getlogin (char *__name, size_t __name_len); libc_hidden_proto (__syscall_getlogin)