(root)/
glibc-2.38/
sysdeps/
pthread/
tst-setuid3.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 <stdio.h>
      19  #include <errno.h>
      20  #include <pthread.h>
      21  #include <stdbool.h>
      22  #include <unistd.h>
      23  
      24  /* The test must run under a non-privileged user ID.  */
      25  static const uid_t test_uid = 1;
      26  
      27  static pthread_barrier_t barrier1;
      28  static pthread_barrier_t barrier2;
      29  
      30  #define FAIL(fmt, ...) \
      31    do { printf ("FAIL: " fmt "\n", __VA_ARGS__); _exit (1); } while (0)
      32  
      33  #define FAIL_ERR(fmt, ...) \
      34    do { printf ("FAIL: " fmt ": %m\n", __VA_ARGS__); _exit (1); } while (0)
      35  
      36  /* True if x is not a successful return code from pthread_barrier_wait.  */
      37  static inline bool
      38  is_invalid_barrier_ret (int x)
      39  {
      40    return x != 0 && x != PTHREAD_BARRIER_SERIAL_THREAD;
      41  }
      42  
      43  static void *
      44  thread_func (void *ctx __attribute__ ((unused)))
      45  {
      46    int ret = pthread_barrier_wait (&barrier1);
      47    if (is_invalid_barrier_ret (ret))
      48      FAIL ("pthread_barrier_wait (barrier1) (on thread): %d", ret);
      49    ret = pthread_barrier_wait (&barrier2);
      50    if (is_invalid_barrier_ret (ret))
      51      FAIL ("pthread_barrier_wait (barrier2) (on thread): %d", ret);
      52    return NULL;
      53  }
      54  
      55  static void
      56  setuid_failure (int phase)
      57  {
      58    int ret = setuid (0);
      59    switch (ret)
      60      {
      61      case 0:
      62        FAIL ("setuid succeeded unexpectedly in phase %d", phase);
      63      case -1:
      64        if (errno != EPERM)
      65  	FAIL_ERR ("setuid phase %d", phase);
      66        break;
      67      default:
      68        FAIL ("invalid setuid return value in phase %d: %d", phase, ret);
      69      }
      70  }
      71  
      72  static int
      73  do_test (void)
      74  {
      75    if (getuid () == 0)
      76      if (setuid (test_uid) != 0)
      77        FAIL_ERR ("setuid (%u)", (unsigned) test_uid);
      78    if (setuid (getuid ()))
      79      FAIL_ERR ("setuid (%s)", "getuid ()");
      80    setuid_failure (1);
      81  
      82    int ret = pthread_barrier_init (&barrier1, NULL, 2);
      83    if (ret != 0)
      84      FAIL ("pthread_barrier_init (barrier1): %d", ret);
      85    ret = pthread_barrier_init (&barrier2, NULL, 2);
      86    if (ret != 0)
      87      FAIL ("pthread_barrier_init (barrier2): %d", ret);
      88  
      89    pthread_t thread;
      90    ret = pthread_create (&thread, NULL, thread_func, NULL);
      91    if (ret != 0)
      92      FAIL ("pthread_create: %d", ret);
      93  
      94    /* Ensure that the thread is running properly.  */
      95    ret = pthread_barrier_wait (&barrier1);
      96    if (is_invalid_barrier_ret (ret))
      97      FAIL ("pthread_barrier_wait (barrier1): %d", ret);
      98  
      99    setuid_failure (2);
     100  
     101    /* Check success case. */
     102    if (setuid (getuid ()) != 0)
     103      FAIL_ERR ("setuid (%s)", "getuid ()");
     104  
     105    /* Shutdown.  */
     106    ret = pthread_barrier_wait (&barrier2);
     107    if (is_invalid_barrier_ret (ret))
     108      FAIL ("pthread_barrier_wait (barrier2): %d", ret);
     109  
     110    ret = pthread_join (thread, NULL);
     111    if (ret != 0)
     112      FAIL ("pthread_join: %d", ret);
     113  
     114    return 0;
     115  }
     116  
     117  #define TEST_FUNCTION do_test ()
     118  #include "../test-skeleton.c"