src/uid_wrapper.c: check for uid_wrapper related syscall numbers before uid_wrapper_e...
authorStefan Metzmacher <metze@samba.org>
Mon, 16 Jan 2023 10:27:32 +0000 (11:27 +0100)
committerAndreas Schneider <asn@samba.org>
Tue, 17 Jan 2023 13:27:50 +0000 (14:27 +0100)
On FreeBSD syscall() is called after the pthread_atfork() 'prepare'
hooks. So we need to avoid calling uid_wrapper_enabled() as it would
deadlock.

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
src/uid_wrapper.c

index 54bc15fe338fb0c8534f93fa622d0d3ce22754c3..9246546be7d4c79b7baac997d5e137ca1c3a82f0 100644 (file)
@@ -2255,6 +2255,118 @@ int __getgroups_chk(int size, gid_t *list, size_t listlen)
 
 #if (defined(HAVE_SYS_SYSCALL_H) || defined(HAVE_SYSCALL_H)) \
     && (defined(SYS_setreuid) || defined(SYS_setreuid32))
+static bool uwrap_is_uwrap_related_syscall(long int sysno)
+{
+       switch (sysno) {
+       /* gid */
+#ifdef __alpha__
+       case SYS_getxgid:
+               return true;
+#else
+       case SYS_getgid:
+               return true;
+#endif
+#ifdef HAVE_LINUX_32BIT_SYSCALLS
+       case SYS_getgid32:
+               return true;
+#endif
+#ifdef SYS_getegid
+       case SYS_getegid:
+               return true;
+#ifdef HAVE_LINUX_32BIT_SYSCALLS
+       case SYS_getegid32:
+               return true;
+#endif
+#endif /* SYS_getegid */
+       case SYS_setgid:
+               return true;
+#ifdef HAVE_LINUX_32BIT_SYSCALLS
+       case SYS_setgid32:
+               return true;
+#endif
+       case SYS_setregid:
+               return true;
+#ifdef HAVE_LINUX_32BIT_SYSCALLS
+       case SYS_setregid32:
+               return true;
+#endif
+#ifdef SYS_setresgid
+       case SYS_setresgid:
+               return true;
+#ifdef HAVE_LINUX_32BIT_SYSCALLS
+       case SYS_setresgid32:
+               return true;
+#endif
+#endif /* SYS_setresgid */
+#if defined(SYS_getresgid) && defined(HAVE_GETRESGID)
+       case SYS_getresgid:
+               return true;
+#ifdef HAVE_LINUX_32BIT_SYSCALLS
+       case SYS_getresgid32:
+               return true;
+#endif
+#endif /* SYS_getresgid && HAVE_GETRESGID */
+
+       /* uid */
+#ifdef __alpha__
+       case SYS_getxuid:
+               return true;
+#else
+       case SYS_getuid:
+               return true;
+#endif
+#ifdef HAVE_LINUX_32BIT_SYSCALLS
+       case SYS_getuid32:
+               return true;
+#endif
+#ifdef SYS_geteuid
+       case SYS_geteuid:
+               return true;
+#ifdef HAVE_LINUX_32BIT_SYSCALLS
+       case SYS_geteuid32:
+               return true;
+#endif
+#endif /* SYS_geteuid */
+       case SYS_setuid:
+               return true;
+#ifdef HAVE_LINUX_32BIT_SYSCALLS
+       case SYS_setuid32:
+               return true;
+#endif
+       case SYS_setreuid:
+               return true;
+#ifdef HAVE_LINUX_32BIT_SYSCALLS
+       case SYS_setreuid32:
+               return true;
+#endif
+#ifdef SYS_setresuid
+       case SYS_setresuid:
+               return true;
+#ifdef HAVE_LINUX_32BIT_SYSCALLS
+       case SYS_setresuid32:
+               return true;
+#endif
+#endif /* SYS_setresuid */
+#if defined(SYS_getresuid) && defined(HAVE_GETRESUID)
+       case SYS_getresuid:
+               return true;
+#ifdef HAVE_LINUX_32BIT_SYSCALLS
+       case SYS_getresuid32:
+               return true;
+#endif
+#endif /* SYS_getresuid && HAVE_GETRESUID*/
+       /* groups */
+       case SYS_setgroups:
+               return true;
+#ifdef HAVE_LINUX_32BIT_SYSCALLS
+       case SYS_setgroups32:
+               return true;
+#endif
+       default:
+               return false;
+       }
+}
+
 static long int uwrap_syscall (long int sysno, va_list vp)
 {
        long int rc;
@@ -2418,11 +2530,8 @@ static long int uwrap_syscall (long int sysno, va_list vp)
                        }
                        break;
                default:
-                       UWRAP_LOG(UWRAP_LOG_DEBUG,
-                                 "UID_WRAPPER calling non-wrapped syscall %lu",
-                                 sysno);
-
-                       rc = libc_vsyscall(sysno, vp);
+                       rc = -1;
+                       errno = ENOSYS;
                        break;
        }
 
@@ -2445,6 +2554,17 @@ long int syscall (long int sysno, ...)
 
        va_start(va, sysno);
 
+       /*
+        * We need to check for uwrap related syscall numbers before calling
+        * uid_wrapper_enabled() otherwise we'd deadlock during the freebsd libc
+        * fork() which calls syscall() after invoking uwrap_thread_prepare().
+        */
+       if (!uwrap_is_uwrap_related_syscall(sysno)) {
+               rc = libc_vsyscall(sysno, va);
+               va_end(va);
+               return rc;
+       }
+
        if (!uid_wrapper_enabled()) {
                rc = libc_vsyscall(sysno, va);
                va_end(va);