(root)/
glibc-2.38/
nptl/
tst-setuid2.c
       1  /* Copyright (C) 2014-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <errno.h>
      19  #include <pthread.h>
      20  #include <signal.h>
      21  #include <stdbool.h>
      22  #include <stdio.h>
      23  #include <support/xthread.h>
      24  #include <sys/syscall.h>
      25  #include <unistd.h>
      26  
      27  /* Check that a partial setuid failure aborts the process. */
      28  
      29  static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
      30  static pthread_cond_t cond_send;
      31  static void (*func_sent) (void);
      32  static pthread_cond_t cond_recv;
      33  
      34  #define FAIL(fmt, ...) \
      35    do { printf ("FAIL: " fmt "\n", __VA_ARGS__); _exit (1); } while (0)
      36  
      37  static void *
      38  thread_func (void *ctx __attribute__ ((unused)))
      39  {
      40    xpthread_mutex_lock (&mutex);
      41    while (true)
      42      {
      43        if (func_sent != NULL)
      44  	{
      45  	  void (*func) (void) = func_sent;
      46  	  xpthread_mutex_unlock (&mutex);
      47  
      48  	  func ();
      49  
      50  	  xpthread_mutex_lock (&mutex);
      51  	  func_sent = NULL;
      52  	  xpthread_cond_signal (&cond_recv);
      53  	}
      54        xpthread_cond_wait (&cond_send, &mutex);
      55      }
      56    return NULL;
      57  }
      58  
      59  static void
      60  run_on_thread (void (*func) (void))
      61  {
      62    xpthread_mutex_lock (&mutex);
      63    func_sent = func;
      64    xpthread_mutex_unlock (&mutex);
      65  
      66    xpthread_cond_signal (&cond_send);
      67  
      68    xpthread_mutex_lock (&mutex);
      69    while (func_sent != NULL)
      70      {
      71        xpthread_cond_wait (&cond_recv, &mutex);
      72      }
      73    xpthread_mutex_unlock (&mutex);
      74  }
      75  
      76  static void
      77  change_thread_ids (void)
      78  {
      79    long ret = syscall (__NR_setresuid, 2001, 2002, 2003);
      80    if (ret != 0)
      81      FAIL ("setresuid (2001, 2002, 2003): %ld", ret);
      82  }
      83  
      84  static uid_t ruid, euid, suid;
      85  
      86  static void
      87  get_thread_ids (void)
      88  {
      89    if (getresuid (&ruid, &euid, &suid) < 0)
      90      FAIL ("getresuid: %m (%d)", errno);
      91  }
      92  
      93  static void
      94  abort_expected (int signal __attribute__ ((unused)))
      95  {
      96    _exit (0);
      97  }
      98  
      99  static int
     100  do_test (void)
     101  {
     102    pthread_t thread;
     103    int ret = pthread_create (&thread, NULL, thread_func, NULL);
     104    if (ret != 0)
     105      FAIL ("pthread_create: %d", ret);
     106  
     107    run_on_thread (change_thread_ids);
     108  
     109    signal (SIGABRT, &abort_expected);
     110    /* This should abort the process.  */
     111    if (setresuid (1001, 1002, 1003) < 0)
     112      FAIL ("setresuid: %m (%d)", errno);
     113    signal (SIGABRT, SIG_DFL);
     114  
     115    /* If we get here, check that the kernel did the right thing. */
     116    run_on_thread (get_thread_ids);
     117    if (ruid != 1001 || euid != 1002 || suid != 1003)
     118      FAIL ("unexpected UIDs after setuid: %ld, %ld, %ld",
     119  	  (long) ruid, (long) euid, (long) suid);
     120    return 0;
     121  }
     122  
     123  #include <support/test-driver.c>