1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
#include "config.h"
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <grp.h>
#ifdef HAVE_SYS_SYSCALL_H
#include <sys/syscall.h>
#endif
#ifdef HAVE_SYSCALL_H
#include <syscall.h>
#endif
#define NUM_THREADS 10
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
struct parm {
int id;
int ready;
};
pthread_mutex_t msg_mutex = PTHREAD_MUTEX_INITIALIZER;
static void *syscall_setreuid(void *arg)
{
long int rc;
uid_t ru;
(void) arg; /* unused */
/* This load can help with revealing race conditions. */
for (ru = 0; ru < 2048; ++ru) {
uid_t ruid, euid, suid;
rc = syscall(SYS_setreuid, -1, ru);
assert_int_equal(rc, 0);
#ifdef HAVE_GETRESUID
ruid = euid = suid = -1;
rc = getresuid(&ruid, &euid, &suid);
assert_int_equal(ruid, 0);
assert_int_equal(euid, ru);
assert_int_equal(suid, ru);
#endif
ruid = getuid();
assert_int_equal(ruid, 0);
euid = geteuid();
assert_int_equal(euid, ru);
rc = syscall(SYS_setreuid, -1, 0);
assert_int_equal(rc, 0);
#ifdef HAVE_GETRESUID
ruid = euid = suid = -1;
rc = getresuid(&ruid, &euid, &suid);
assert_int_equal(ruid, 0);
assert_int_equal(euid, 0);
assert_int_equal(suid, ru);
#endif
ruid = getuid();
assert_int_equal(ruid, 0);
euid = geteuid();
assert_int_equal(euid, 0);
}
return NULL;
}
static void *sync_setreuid(void *arg)
{
struct parm *p = (struct parm *)arg;
uid_t u;
syscall_setreuid(arg);
p->ready = 1;
pthread_mutex_lock(&msg_mutex);
u = geteuid();
assert_int_equal(u, 42);
pthread_mutex_unlock(&msg_mutex);
return NULL;
}
static void test_sync_setreuid(void **state)
{
pthread_attr_t pthread_custom_attr;
pthread_t threads[NUM_THREADS];
struct parm *p;
int rc;
int i;
(void) state; /* unused */
pthread_attr_init(&pthread_custom_attr);
p = malloc(NUM_THREADS * sizeof(struct parm));
assert_non_null(p);
pthread_mutex_lock(&msg_mutex);
for (i = 0; i < NUM_THREADS; i++) {
p[i].id = i;
p[i].ready = 0;
pthread_create(&threads[i],
&pthread_custom_attr,
sync_setreuid,
(void *)&p[i]);
}
/* wait for the threads to set euid to 0 */
for (i = 0; i < NUM_THREADS; i++) {
while (p[i].ready != 1) {
sleep(1);
}
}
rc = setreuid(-1, 42);
assert_int_equal(rc, 0);
pthread_mutex_unlock(&msg_mutex);
for (i = 0; i < NUM_THREADS; i++) {
pthread_join(threads[i], NULL);
}
pthread_attr_destroy(&pthread_custom_attr);
free(p);
}
int main(void) {
int rc;
const struct CMUnitTest thread_tests[] = {
cmocka_unit_test(test_sync_setreuid),
};
rc = cmocka_run_group_tests(thread_tests, NULL, NULL);
return rc;
}
|