Blame view

privileged.c 49.5 KB
redmine authored
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
    clsync - file tree sync utility based on inotify/kqueue
    
    Copyright (C) 2013-2014 Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

redmine authored
20 21 22
#include "common.h"			// ctx.h
#include "ctx.h"			// ctx_t
#include "error.h"			// debug()
redmine authored
23
#include "syscalls.h"			// read_inf()/write_inf()
redmine authored
24
#include "main.h"			// ncpus
redmine authored
25
#include "pthreadex.h"			// pthread_*_shared()
redmine authored
26
#include "malloc.h"			// xmalloc()
redmine authored
27

redmine authored
28
#ifdef CAPABILITIES_SUPPORT
redmine authored
29 30 31 32 33 34 35
# include <pthread.h>			// pthread_create()
# include <sys/inotify.h>		// inotify_init()
# include <sys/types.h>			// fts_open()
# include <sys/stat.h>			// fts_open()
# include <fts.h>			// fts_open()
# include <errno.h>			// errno
# include <sys/capability.h>		// capset()
redmine authored
36 37 38
# ifdef CGROUP_SUPPORT
#  include "cgroup.h"			// clsync_cgroup_deinit()
# endif
redmine authored
39 40 41
#endif

#include <unistd.h>			// execvp()
redmine authored
42
#include <glib.h>			// g_atomic_int_set()
redmine authored
43

redmine authored
44
#ifdef UNSHARE_SUPPORT
redmine authored
45
# include <sched.h>			// unshare()
redmine authored
46 47
#endif

redmine authored
48 49 50 51 52 53 54
#ifndef HL_LOCKS
# ifdef HL_LOCK_TRIES_AUTO
#  undef HL_LOCK_TRIES_AUTO
# endif
#endif

#ifdef HL_LOCK_TRIES_AUTO
redmine authored
55 56
# include <time.h>			// time()
# include <math.h>			// fabs()
redmine authored
57 58 59 60
#endif

#include "privileged.h"

redmine authored
61
#ifdef SECCOMP_SUPPORT
redmine authored
62
# include <syscall.h>			// __NR_*
redmine authored
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
# include <sys/prctl.h>			// prctl()
# include <linux/filter.h>		// struct sock_filter
# include <linux/seccomp.h>		// SECCOMP_RET_*

#define syscall_nr (offsetof(struct seccomp_data, nr))

/* Read: http://www.rawether.net/support/bpfhelp.htm */
# define SECCOMP_COPY_SYSCALL_TO_ACCUM				\
	BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_nr)

# define SECCOMP_ALLOW						\
	BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW)

# define SECCOMP_DENY						\
	BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_TRAP)

# define SECCOMP_ALLOW_ACCUM_SYSCALL(syscall)			\
	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_##syscall, 0, 1),	\
	SECCOMP_ALLOW

redmine authored
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
# define FILTER_TABLE_NONPRIV						\
	SECCOMP_ALLOW_ACCUM_SYSCALL(futex),				\
	SECCOMP_ALLOW_ACCUM_SYSCALL(inotify_init1),			\
	SECCOMP_ALLOW_ACCUM_SYSCALL(alarm),				\
	SECCOMP_ALLOW_ACCUM_SYSCALL(stat),		/* unused */	\
	SECCOMP_ALLOW_ACCUM_SYSCALL(fstat),		/* unused */	\
	SECCOMP_ALLOW_ACCUM_SYSCALL(lstat),				\
	SECCOMP_ALLOW_ACCUM_SYSCALL(open),				\
	SECCOMP_ALLOW_ACCUM_SYSCALL(write),				\
	SECCOMP_ALLOW_ACCUM_SYSCALL(close),				\
	SECCOMP_ALLOW_ACCUM_SYSCALL(wait4),				\
	SECCOMP_ALLOW_ACCUM_SYSCALL(unlink),				\
	SECCOMP_ALLOW_ACCUM_SYSCALL(tgkill),				\
	SECCOMP_ALLOW_ACCUM_SYSCALL(clock_gettime),			\
	SECCOMP_ALLOW_ACCUM_SYSCALL(rt_sigreturn),			\
	SECCOMP_ALLOW_ACCUM_SYSCALL(brk),				\
	SECCOMP_ALLOW_ACCUM_SYSCALL(mmap),				\
	SECCOMP_ALLOW_ACCUM_SYSCALL(munmap),				\
	SECCOMP_ALLOW_ACCUM_SYSCALL(wait4),				\
	SECCOMP_ALLOW_ACCUM_SYSCALL(rmdir),				\
	SECCOMP_ALLOW_ACCUM_SYSCALL(exit_group),			\
	SECCOMP_ALLOW_ACCUM_SYSCALL(select),				\
	SECCOMP_ALLOW_ACCUM_SYSCALL(read),				\
	SECCOMP_ALLOW_ACCUM_SYSCALL(rt_sigprocmask),			\
	SECCOMP_ALLOW_ACCUM_SYSCALL(rt_sigaction),			\
	SECCOMP_ALLOW_ACCUM_SYSCALL(nanosleep),				\
redmine authored
109
	SECCOMP_ALLOW_ACCUM_SYSCALL(shmdt),				\
redmine authored
110
	SECCOMP_ALLOW_ACCUM_SYSCALL(clone),		/* for --threading */		\
redmine authored
111 112 113 114
	SECCOMP_ALLOW_ACCUM_SYSCALL(set_robust_list),	/* for --threading? */		\
	SECCOMP_ALLOW_ACCUM_SYSCALL(madvise),				\
	SECCOMP_ALLOW_ACCUM_SYSCALL(exit),				\

redmine authored
115

redmine authored
116 117 118 119 120 121 122

/* Syscalls allowed to non-privileged thread */
static struct sock_filter filter_table[] = {
	SECCOMP_COPY_SYSCALL_TO_ACCUM,
	FILTER_TABLE_NONPRIV
	SECCOMP_DENY,
};
redmine authored
123 124 125 126 127 128
static struct sock_filter filter_w_mprotect_table[] = {
	SECCOMP_COPY_SYSCALL_TO_ACCUM,
	FILTER_TABLE_NONPRIV
	SECCOMP_ALLOW_ACCUM_SYSCALL(mprotect),
	SECCOMP_DENY,
};
redmine authored
129

redmine authored
130 131 132
int nonprivileged_seccomp_init(ctx_t *ctx_p) {
	struct sock_fprog *filter_p;
	struct sock_fprog filter = {
redmine authored
133 134 135
		.len = (unsigned short)(sizeof(filter_table)/sizeof(filter_table[0])),
		.filter = filter_table,
	};
redmine authored
136 137 138 139 140
	struct sock_fprog filter_w_mprotect = {
		.len = (unsigned short)(sizeof(filter_w_mprotect_table)/sizeof(filter_w_mprotect_table[0])),
		.filter = filter_w_mprotect_table,
	};

redmine authored
141 142
	debug(5, "enabling the seccomp");

redmine authored
143
	filter_p = (ctx_p->flags[PERMIT_MPROTECT] ? &filter_w_mprotect : &filter);
redmine authored
144 145

	SAFE (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0),			return -1);
redmine authored
146
	SAFE (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, filter_p),	return -1);
redmine authored
147 148 149 150 151

	return 0;
}
#endif

redmine authored
152
int (*privileged_fork_execvp)(const char *file, char *const argv[]);
redmine authored
153
int (*privileged_kill_child)(pid_t pid, int sig, char ignoreerrors);
redmine authored
154 155

#ifdef CAPABILITIES_SUPPORT
redmine authored
156
pid_t		helper_pid = 0;
redmine authored
157 158 159 160 161 162 163 164
pthread_t	privileged_thread;
pthread_mutex_t	*pthread_mutex_privileged_p;
pthread_mutex_t	*pthread_mutex_action_signal_p;
pthread_mutex_t	*pthread_mutex_action_entrance_p;
pthread_mutex_t	*pthread_mutex_runner_p;
pthread_cond_t	*pthread_cond_privileged_p;
pthread_cond_t	*pthread_cond_action_p;
pthread_cond_t	*pthread_cond_runner_p;
redmine authored
165

redmine authored
166
# ifdef READWRITE_SIGNALLING
redmine authored
167 168 169 170
int priv_read_fd;
int priv_write_fd;
int nonp_read_fd;
int nonp_write_fd;
redmine authored
171
# endif
redmine authored
172

redmine authored
173 174 175
enum privileged_action {
	PA_UNKNOWN = 0,

redmine authored
176 177
	PA_SETUP,

redmine authored
178 179 180 181 182 183 184 185 186 187 188 189 190
	PA_DIE,

	PA_FTS_OPEN,
	PA_FTS_READ,
	PA_FTS_CLOSE,

	PA_INOTIFY_INIT,
	PA_INOTIFY_INIT1,
	PA_INOTIFY_ADD_WATCH,
	PA_INOTIFY_RM_WATCH,

	PA_FORK_EXECVP,

redmine authored
191
	PA_KILL_CHILD,
redmine authored
192 193

	PA_CLSYNC_CGROUP_DEINIT,
redmine authored
194 195

	PA_WAITPID,
redmine authored
196 197
};

redmine authored
198
struct pa_fts_open_arg {
redmine authored
199 200 201
	char		_path_argv[MAXARGUMENTS+1][PATH_MAX];
	char		*path_argv[MAXARGUMENTS+1];
	char *const	*path_argv_p;
redmine authored
202 203 204
	int options;
	int (*compar)(const FTSENT **, const FTSENT **);
};
redmine authored
205

redmine authored
206 207
struct pa_inotify_add_watch_arg {
	int fd;
redmine authored
208 209
	char		 pathname[PATH_MAX];
	const char	*pathname_p;
redmine authored
210 211
	uint32_t mask;
};
redmine authored
212

redmine authored
213 214 215 216 217 218
struct pa_inotify_rm_watch_arg {
	int fd;
	int wd;
};

struct pa_fork_execvp_arg {
redmine authored
219 220 221 222 223
	char		 file[PATH_MAX];
	const char	*file_p;
	char		_argv[MAXARGUMENTS+1][BUFSIZ];
	char		*argv[MAXARGUMENTS+1];
	char *const	*argv_p;
redmine authored
224 225 226 227 228
};

struct pa_kill_child_arg {
	pid_t pid;
	int   signal;
redmine authored
229
	char  ignoreerrors;
redmine authored
230 231
};

redmine authored
232 233 234 235 236 237 238
struct pa_waitpid_arg {
	pid_t  pid;
	int    status;
	int    options;
};

struct pa_arg {
redmine authored
239 240 241 242 243
	struct pa_fts_open_arg		 fts_open;
	struct pa_inotify_add_watch_arg	 inotify_add_watch;
	struct pa_inotify_rm_watch_arg	 inotify_rm_watch;
	struct pa_fork_execvp_arg	 fork_execvp;
	struct pa_kill_child_arg	 kill_child;
redmine authored
244
	struct pa_waitpid_arg		 waitpid;
redmine authored
245 246 247 248 249 250
	void				*void_v;
	ctx_t				*ctx_p;
	uint32_t			 uint32_v;
};

# ifdef HL_LOCKS
redmine authored
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
enum highload_lock_id {
	HLLOCK_HANDLER = 0,

	HLLOCK_MAX
};
typedef enum highlock_lock_id hllockid_t;

enum highlock_lock_state {
	HLLS_UNREADY	= 0x00,
	HLLS_READY	= 0x01,
	HLLS_FALLBACK	= 0x02,
	HLLS_SIGNAL	= 0x04,
	HLLS_GOTSIGNAL	= 0x08,
	HLLS_WORKING	= 0x10,
};
typedef enum highlock_lock_state hllock_state_t;

redmine authored
268
struct hl_lock {
redmine authored
269 270 271 272 273
	volatile int			locallock_hl_setstate_ifstate;
	volatile int			enabled;
	volatile int			count_wait[HLLOCK_MAX];
	volatile int			count_signal[HLLOCK_MAX];
	volatile hllock_state_t		state[HLLOCK_MAX];
redmine authored
274
#  ifdef HL_LOCK_TRIES_AUTO
redmine authored
275 276 277 278
	volatile unsigned long		tries[PC_MAX];
	volatile unsigned long		count[PC_MAX];
	volatile unsigned long		delay[PC_MAX];
	volatile double			tries_step[PC_MAX];
redmine authored
279

redmine authored
280
#   define				tries_cur tries[callid]
redmine authored
281
#  else
redmine authored
282 283
	volatile unsigned long		tries;
#   define				tries_cur tries
redmine authored
284
#  endif
redmine authored
285
};
redmine authored
286
# endif
redmine authored
287

redmine authored
288 289 290 291 292
struct pa_fts_read_ret {
	FTSENT		ftsent;
	char		fts_accpath[PATH_MAX];
	char		fts_path[PATH_MAX];
	char		fts_name[PATH_MAX];
redmine authored
293
};
redmine authored
294
struct pa_ret {
redmine authored
295 296
	struct stat		stat;
	struct pa_fts_read_ret	fts_read;
redmine authored
297
};
redmine authored
298
struct cmd {
redmine authored
299
	volatile struct pa_arg		 arg;
redmine authored
300 301
	volatile enum privileged_action	 action;
# ifdef HL_LOCKS
redmine authored
302
	volatile unsigned long		 hl_lock_tries;
redmine authored
303
# endif
redmine authored
304
};
redmine authored
305
struct cmd_ret {
redmine authored
306
	volatile struct pa_ret		 ret_buf;
redmine authored
307 308 309 310 311 312 313 314
	volatile void			*ret;
	volatile int			 _errno;
};
volatile struct cmd		*cmd_p;
volatile struct cmd_ret		*cmd_ret_p;
# ifdef HL_LOCKS
volatile struct hl_lock		*hl_lock_p;
# endif
redmine authored
315

redmine authored
316
# ifdef HL_LOCKS
redmine authored
317 318 319
static inline void hl_lock_init(volatile struct hl_lock *hl_lock_p) {
	debug(10, "");
	hl_lock_p->enabled = 1;
redmine authored
320 321 322 323
#  ifdef HL_LOCK_TRIES_AUTO
	int i;
	i = 0;
	while (i < PC_MAX) {
redmine authored
324 325 326
		hl_lock_p->tries[i]		= HL_LOCK_TRIES_INITIAL;
		hl_lock_p->delay[i]		= ((unsigned long)~0)>>2;
		hl_lock_p->tries_step[i]	= HL_LOCK_AUTO_K;
redmine authored
327 328 329
		i++;
	}
#  else
redmine authored
330
	hl_lock_p->tries	= HL_LOCK_TRIES_INITIAL;
redmine authored
331 332 333
#  endif
	return;
}
redmine authored
334
# endif
redmine authored
335

redmine authored
336 337 338 339 340
struct pa_options {
	synchandler_args_t args[SHARGS_MAX];
	char *label;
	char *exithookfile;
	char *preexithookfile;
redmine authored
341 342
	char *permitted_hookfile[MAXPERMITTEDHOOKFILES+1];
	int   permitted_hookfiles;
redmine authored
343
	int   isprocsplitting;
redmine authored
344
	int   shm_mprotect;
redmine authored
345 346
};

redmine authored
347
FTS *(*_privileged_fts_open)		(
redmine authored
348 349 350
		char * const *path_argv,
		int options,
		int (*compar)(const FTSENT **, const FTSENT **)
redmine authored
351
# ifdef HL_LOCK_TRIES_AUTO
redmine authored
352
		, int callid
redmine authored
353
# endif
redmine authored
354 355 356 357
	);

FTSENT *(*_privileged_fts_read)		(
		FTS *ftsp
redmine authored
358
# ifdef HL_LOCK_TRIES_AUTO
redmine authored
359
		, int callid
redmine authored
360
# endif
redmine authored
361 362 363 364
	);

int (*_privileged_fts_close)		(
		FTS *ftsp
redmine authored
365
# ifdef HL_LOCK_TRIES_AUTO
redmine authored
366
		, int callid
redmine authored
367
# endif
redmine authored
368 369
	);

redmine authored
370 371
int (*_privileged_inotify_init)		();
int (*_privileged_inotify_init1)	(int flags);
redmine authored
372

redmine authored
373
int (*_privileged_inotify_add_watch)	(
redmine authored
374 375 376
		int fd,
		const char *pathname,
		uint32_t mask
redmine authored
377
# ifdef HL_LOCK_TRIES_AUTO
redmine authored
378
		, int callid
redmine authored
379
# endif
redmine authored
380 381
	);

redmine authored
382
int (*_privileged_inotify_rm_watch)	(
redmine authored
383 384 385 386
		int fd,
		int wd
	);

redmine authored
387
int (*_privileged_clsync_cgroup_deinit)	(ctx_t *ctx_p);
redmine authored
388

redmine authored
389
pid_t (*_privileged_waitpid)		(pid_t pid, int *status, int options);
redmine authored
390

redmine authored
391 392 393 394 395 396 397
int cap_enable(__u32 caps) {
	debug(1, "Enabling Linux capabilities 0x%x", caps);
	struct __user_cap_header_struct	cap_hdr = {0};
	struct __user_cap_data_struct	cap_dat = {0};

	cap_hdr.version = _LINUX_CAPABILITY_VERSION;
	if (capget(&cap_hdr, &cap_dat) < 0) {
Barak A. Pearlmutter authored
398
		error("Cannot get capabilities with capget()");
redmine authored
399 400 401 402 403 404 405 406 407 408 409 410 411 412
		return errno;
	}

	debug(3, "old: cap.eff == 0x%04x; new: cap.eff == 0x%04x", cap_dat.effective, cap_dat.effective|caps);
	cap_dat.effective |= caps;

	if (capset(&cap_hdr, &cap_dat) < 0) {
		error("Cannot set capabilities with capset().");
		return errno;
	}

	return 0;
}

redmine authored
413
int cap_drop(ctx_t *ctx_p, __u32 caps) {
Barak A. Pearlmutter authored
414
	debug(1, "Dropping all Linux capabilities but 0x%x", caps);
redmine authored
415 416 417 418 419 420

	struct __user_cap_header_struct	cap_hdr = {0};
	struct __user_cap_data_struct	cap_dat = {0};

	cap_hdr.version = _LINUX_CAPABILITY_VERSION;
	if (capget(&cap_hdr, &cap_dat) < 0) {
Barak A. Pearlmutter authored
421
		error_or_debug((ctx_p->flags[CAP_PRESERVE] != CAP_PRESERVE_TRY) ? -1 : 3, "Cannot get capabilities with capget()");
redmine authored
422 423
		return errno;
	}
redmine authored
424 425
	debug(3, "old: cap.eff == 0x%04x; cap.prm == 0x%04x; cap.inh == 0x%04x.",
		cap_dat.effective, cap_dat.permitted, cap_dat.inheritable);
redmine authored
426

redmine authored
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
	switch (ctx_p->flags[CAPS_INHERIT]) {
		case CI_PERMITTED:
			cap_dat.inheritable = cap_dat.permitted;
			break;
		case CI_DONTTOUCH:
			break;
		case CI_CLSYNC:
			cap_dat.inheritable = caps;
			break;
		case CI_EMPTY:
			cap_dat.inheritable = 0;
			break;
	}
	cap_dat.effective  = caps;
	cap_dat.permitted  = caps;
redmine authored
442

redmine authored
443
	debug(3, "new: cap.eff == 0x%04x; cap.prm == 0x%04x; cap.inh == 0x%04x.",
redmine authored
444 445 446
		cap_dat.effective, cap_dat.permitted, cap_dat.inheritable);

	if (capset(&cap_hdr, &cap_dat) < 0) {
redmine authored
447
		error_or_debug((ctx_p->flags[CAP_PRESERVE] != CAP_PRESERVE_TRY) ? -1 : 3, "Cannot set capabilities with capset().");
redmine authored
448 449 450 451 452 453
		return errno;
	}

	return 0;
}

redmine authored
454
#endif
redmine authored
455
int __privileged_kill_child_itself(pid_t child_pid, int signal, char ignoreerrors) {
redmine authored
456 457 458 459 460
	// Checking if it's a child
	if (waitpid(child_pid, NULL, WNOHANG)>=0) {
		debug(3, "Sending signal %u to child process with pid %u.",
			signal, child_pid);
		if (kill(child_pid, signal)) {
redmine authored
461 462
			if (!ignoreerrors)
				error("Got error while kill(%u, %u)", child_pid, signal);
redmine authored
463 464 465
			return errno;
		}

redmine authored
466
		waitpid_timed(child_pid, NULL, SLEEP_SECONDS, 0);
redmine authored
467 468 469 470 471
	} else
		return ENOENT;

	return 0;
}
redmine authored
472
#ifdef CAPABILITIES_SUPPORT
redmine authored
473

redmine authored
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516
int pa_strcmp(const char *s1, const char *s2, int isexpanded) {
	if (isexpanded)
		return strcmp(s1, s2);

	{
		const char *s1_start = NULL;
		const char *s2_start = NULL;
		while (1) {
			while (1) {
				if (!*s1 || !*s2) {
					if (!*s1 && s1_start != NULL)
						return 0;
					return *s1 != *s2;
				}

				if (*s1 == '%') {
					s1++;
					while (*s1 && *s1 != '%') s1++;
					s1++;
					s1_start = s1;
					s2_start = s2;
					continue;
				}

				if (*s1 != *s2)
					break;

				s1++;
				s2++;
			}

			if (s2_start == NULL)
				break;

			s2_start++;
			s1 = s1_start;
			s2 = s2_start;
		}

		return *s1 != *s2;
	}
}

redmine authored
517
int privileged_execvp_check_arguments(struct pa_options *opts, const char *u_file, char *const *u_argv) {
redmine authored
518 519
	int a_i;
	size_t u_argc;
redmine authored
520 521
	synchandler_args_t *args = opts->args;
	
redmine authored
522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538
	debug(9, "");

	// Counting the number of arguments
	u_argc = 0;
	while (u_argv[u_argc] != NULL) u_argc++;

	a_i = 0;
	do {
		int i;
		int    argc;
		char **argv;
		char  *isexpanded;

		argc       = args[a_i].c;
		argv       = args[a_i].v;
		isexpanded = args[a_i].isexpanded;

redmine authored
539
		debug(8, "Checking the number of arguments: %i <> %i", argc, u_argc);
redmine authored
540 541 542
		if (argc != u_argc)
			continue;

redmine authored
543 544
		critical_on (!argc);

redmine authored
545
		debug(8, "Checking the execution file: \"%s\" <> \"%s\"; isexpanded == %i", argv[0], u_file, isexpanded[0]);
redmine authored
546 547 548 549
		if (pa_strcmp(argv[0], u_file, isexpanded[0])) {
			debug(1, "The file to be executed didn't match (argv[0] != u_file): \"%s\" != \"%s\"", argv[0], u_file);
			break;
		}
redmine authored
550

redmine authored
551
		debug(8, "Checking arguments");
redmine authored
552 553
		i = 1;
		while (i < argc) {
redmine authored
554 555
			if (pa_strcmp(argv[i], u_argv[i], isexpanded[i])) {
				debug(1, "An argument #%i didn't match (argv[%i] != u_argv[%i]): \"%s\" != \"%s\"", argv[i], argv[i]);
redmine authored
556
				break;
redmine authored
557
			}
redmine authored
558 559 560 561 562 563 564 565 566 567
			i++;
		}

		// All arguments right?
		if (i == argc)
			break;

		// No? Ok the next "shargs".
	} while (++a_i < SHARGS_MAX);

redmine authored
568 569
	if (a_i < SHARGS_MAX)
		return 0;
redmine authored
570

redmine authored
571 572 573 574
	if (u_argc == 2) {
		int i;

		if ((opts->exithookfile != NULL) || (opts->preexithookfile != NULL)) {
redmine authored
575 576 577 578 579 580 581 582 583 584
			if (!strcmp(opts->label, u_argv[1])) {
				if (opts->exithookfile != NULL)
					if (!strcmp(opts->exithookfile,    u_file))
						return 0;
				if (opts->preexithookfile != NULL)
					if (!strcmp(opts->preexithookfile, u_file))
						return 0;
			}
		}

redmine authored
585
		i = 0;
redmine authored
586 587 588 589 590 591 592
		while (i < opts->permitted_hookfiles) {
			if (!strcmp(opts->permitted_hookfile[i], u_file))
				return 0;
			i++;
		}
	}

redmine authored
593
	debug(1, "a_i == %i; SHARGS_MAX == %i; u_argc == %i", SHARGS_MAX, a_i, u_argc);
redmine authored
594 595
	critical("Arguments are wrong. This should happend only on hacking attack.");
	return EPERM;
redmine authored
596 597
}

redmine authored
598 599
int pa_setup(struct pa_options *opts, ctx_t *ctx_p, uid_t *exec_uid_p, gid_t *exec_gid_p) {
	synchandler_args_t *args = opts->args;
redmine authored
600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616
	int a_i;

	a_i = 0;
	do {
		int i, argc_s;
		char **argv_s, **argv_d, *isex_s, *isex_d;

		argc_s = ctx_p->synchandler_args[a_i].c;
		argv_s = ctx_p->synchandler_args[a_i].v;
		isex_s = ctx_p->synchandler_args[a_i].isexpanded;
		argv_d = args[a_i].v;
		isex_d = args[a_i].isexpanded;

		if (argc_s >= MAXARGUMENTS)
			critical("Too many arguments");

		if (argc_s < 1)
redmine authored
617
			continue;
redmine authored
618

redmine authored
619
		argv_d[0] = strdup_protect(ctx_p->handlerfpath, PROT_READ);
redmine authored
620 621 622

		i = 0;
		while (i < argc_s) {
redmine authored
623
			argv_d[i+1] = strdup_protect(argv_s[i], PROT_READ);
redmine authored
624 625 626 627 628 629 630 631 632 633 634 635 636
			isex_d[i+1] = isex_s[i];
			i++;
		}
		i++;
		argv_d[i] = NULL;
		args[a_i].c = i;

		a_i++;
	} while (++a_i < SHARGS_MAX);

	*exec_uid_p = ctx_p->synchandler_uid;
	*exec_gid_p = ctx_p->synchandler_gid;

redmine authored
637
	opts->label = strdup_protect(ctx_p->label, PROT_READ);
redmine authored
638
	if (ctx_p->exithookfile != NULL)
redmine authored
639
		opts->exithookfile = strdup_protect(ctx_p->exithookfile, PROT_READ);
redmine authored
640
	if (ctx_p->preexithookfile != NULL)
redmine authored
641
		opts->preexithookfile = strdup_protect(ctx_p->preexithookfile, PROT_READ);
redmine authored
642

redmine authored
643 644 645 646
	{
		int i = 0;

		while (i < ctx_p->permitted_hookfiles) {
redmine authored
647
			opts->permitted_hookfile[i] = strdup_protect(ctx_p->permitted_hookfile[i], PROT_READ);
redmine authored
648 649 650 651 652
			i++;
		}
		opts->permitted_hookfile[i] = NULL;
		opts->permitted_hookfiles   = i;
	}
redmine authored
653

redmine authored
654 655 656
	return 0;
}

redmine authored
657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685
int pa_unsetup(struct pa_options *opts) {
	free(opts->exithookfile);
	free(opts->preexithookfile);
	free(opts->label);

	{
		int a_i = 0;
		do {
			int i;

			i = 0;
			while (i < opts->args[a_i].c) {
				free(opts->args[a_i].v[i]);
				i++;
			}
		} while(++a_i < SHARGS_MAX);
	}

	{
		int i = 0;
		while (i < opts->permitted_hookfiles) {
			free(opts->permitted_hookfile[i]);
			i++;
		}
	}

	return 0;
}

redmine authored
686
# ifdef HL_LOCKS
redmine authored
687 688

static inline int hl_isanswered(int lockid) {
redmine authored
689
	return hl_lock_p->count_wait[lockid] == hl_lock_p->count_signal[lockid]+1;
redmine authored
690 691 692
}

static inline int hl_isready(int lockid) {
redmine authored
693
	return hl_lock_p->count_wait[lockid] == hl_lock_p->count_signal[lockid];
redmine authored
694 695 696
}

static inline void hl_setstate(int lockid, hllock_state_t stateid) {
redmine authored
697
	g_atomic_int_set(&hl_lock_p->state[lockid], stateid);
redmine authored
698 699 700
}

int hl_setstate_ifstate(int lockid, hllock_state_t stateid_new, hllock_state_t stateid_old_mask) {
redmine authored
701
	volatile int *local_lock_p = &hl_lock_p->locallock_hl_setstate_ifstate;
redmine authored
702
	debug(90, "%i, 0x%o, 0x%o", lockid, stateid_new, stateid_old_mask);
redmine authored
703

redmine authored
704
	if (*local_lock_p)
redmine authored
705 706
		return 0;

redmine authored
707 708 709 710 711
	debug(92, "%i", *local_lock_p);
	g_atomic_int_inc(local_lock_p);
	debug(92, "%i", *local_lock_p);
	if (*local_lock_p != 1) {
		g_atomic_int_dec_and_test(local_lock_p);
redmine authored
712 713 714
		return 0;
	}

redmine authored
715
	if (!(hl_lock_p->state[lockid]&stateid_old_mask)) {
redmine authored
716
		g_atomic_int_dec_and_test(local_lock_p);
redmine authored
717 718 719
		return 0;
	}

redmine authored
720
	debug(50, "success");
redmine authored
721
	g_atomic_int_set(&hl_lock_p->state[lockid], stateid_new);
redmine authored
722 723
	g_atomic_int_dec_and_test(local_lock_p);
#undef local_lock
redmine authored
724 725 726
	return 1;
}

redmine authored
727 728
static inline int hl_wait(
		int lockid
redmine authored
729
#  ifdef HL_LOCK_TRIES_AUTO
redmine authored
730
		, unsigned long hl_lock_tries
redmine authored
731
#  endif
redmine authored
732
) {
redmine authored
733 734 735 736
	volatile long try = 0;

	debug(15, "");

redmine authored
737
	while (hl_lock_p->state[lockid] == HLLS_GOTSIGNAL);
redmine authored
738 739
	while (!hl_isready(lockid));
	hl_setstate(lockid, HLLS_READY);
redmine authored
740
	hl_lock_p->count_wait[lockid]++;
redmine authored
741

redmine authored
742
	while (try++ < hl_lock_tries)
redmine authored
743
		if (hl_lock_p->state[lockid] == HLLS_SIGNAL) {
redmine authored
744 745 746 747 748 749
			hl_setstate(lockid, HLLS_GOTSIGNAL);
			debug(15, "got signal");
			return 1;
		}

	while (!hl_setstate_ifstate(lockid, HLLS_FALLBACK, HLLS_READY|HLLS_SIGNAL));
redmine authored
750
	debug(14, "fallback: hl_lock_p->count_wait[%u] == %u; hl_lock_p->count_signal[%u] = %u", lockid, hl_lock_p->count_wait[lockid], lockid, hl_lock_p->count_signal[lockid]);
redmine authored
751 752 753 754 755
	return 0;
}

static inline int hl_signal(int lockid) {
	debug(15, "%u", lockid);
redmine authored
756
	hl_lock_p->count_signal[lockid]++;
redmine authored
757 758

	if (hl_setstate_ifstate(lockid, HLLS_SIGNAL, HLLS_READY)) {
redmine authored
759 760
		while (hl_lock_p->state[lockid] != HLLS_GOTSIGNAL) {
			if (hl_lock_p->state[lockid] == HLLS_FALLBACK) {
redmine authored
761 762 763
				debug(15, "fallback");
				return 0;
			}
redmine authored
764
			debug(95, "state == %i != %i, %i", hl_lock_p->state[lockid], HLLS_GOTSIGNAL, HLLS_FALLBACK);
redmine authored
765
		}
redmine authored
766 767 768 769 770 771 772 773 774
		debug(15, "the signal is sent");
		hl_setstate(lockid, HLLS_WORKING);
		return 1;
	}

	debug(15, "not ready");
	return 0;
}

redmine authored
775 776 777 778 779 780
void hl_shutdown(int lockid) {
	debug(1, "");

#  ifdef PARANOID
	critical_on (HLLOCK_MAX != 1);	// TODO: do this on compile time (not on running time)
#   ifdef HL_LOCK_TRIES_AUTO
redmine authored
781
	memset((void *)hl_lock_p->tries, 0, sizeof(hl_lock_p->tries));
redmine authored
782
#   else
redmine authored
783
	hl_lock_p->tries = 0;
redmine authored
784 785
#   endif
#  endif
redmine authored
786 787
	hl_lock_p->state[lockid]	 = HLLS_FALLBACK;
	hl_lock_p->enabled 	 = 0;
redmine authored
788 789 790 791

	return;
}

redmine authored
792
# endif
redmine authored
793

redmine authored
794
static int helper_isalive_cache;
redmine authored
795
static inline int helper_isalive_proc() {
redmine authored
796 797 798 799 800 801 802 803 804 805
	int rc;
	debug(12, "helper_pid == %u", helper_pid);

	if ((rc=waitpid(helper_pid, NULL, WNOHANG))>=0)
		return helper_isalive_cache=1;

	debug(1, "waitpid(%u, NULL, WNOHANG) => %i", helper_pid, rc);

	return helper_isalive_cache=0;
}
redmine authored
806 807 808 809 810 811 812 813 814 815 816 817 818 819
static inline int helper_isalive_thread() {
	int rc;
	debug(12, "");

	if ((rc=pthread_kill(privileged_thread, 0)))
		return helper_isalive_cache=0;

	debug(1, "pthread_kill(privileged_thread, 0) => %i", helper_pid, rc);

	return helper_isalive_cache=1;
}
static inline int helper_isalive() {
	return helper_pid ? helper_isalive_proc() : helper_isalive_thread();
}
redmine authored
820 821

int privileged_check() {
redmine authored
822 823
	if (helper_pid)
		critical_on(!helper_isalive_proc());
redmine authored
824 825 826 827
	return 0;
}

int privileged_handler(ctx_t *ctx_p)
redmine authored
828
{
redmine authored
829
# ifdef READWRITE_SIGNALLING
redmine authored
830
	char buf[1] = {0};
redmine authored
831 832
# else
	struct timespec wait_timeout = {0};
redmine authored
833
# endif
redmine authored
834

redmine authored
835
	int setup = 0;
redmine authored
836 837
	uid_t exec_uid = 65535;
	gid_t exec_gid = 65535;
redmine authored
838 839
	
	struct pa_options *opts;
redmine authored
840
	int use_args_check = 0;
redmine authored
841 842 843
	int helper_isrunning = 1;

	opts  = calloc_align(1, sizeof(*opts));
redmine authored
844 845 846 847 848 849
	opts->isprocsplitting = (ctx_p->flags[SPLITTING] == SM_PROCESS);
	opts->shm_mprotect    =  ctx_p->flags[SHM_MPROTECT];

	if (opts->isprocsplitting) {
		sigset_t sigset;
		sigemptyset(&sigset);
redmine authored
850 851 852 853

/*	Do not uncomment this. This causes handler closing on any terminal
	signal to parent process. In turn it causes: https://github.com/xaionaro/clsync/issues/104

redmine authored
854 855 856 857 858
		sigaddset(&sigset, SIGALRM);
		sigaddset(&sigset, SIGHUP);
		sigaddset(&sigset, SIGQUIT);
		sigaddset(&sigset, SIGTERM);
		sigaddset(&sigset, SIGINT);
redmine authored
859 860 861 862 863
*/
# ifndef __linux__
#  error There's no automatical mechanism that guarantees handler closing on non-linux. Don't use process splitting!
# endif

redmine authored
864
# ifdef __linux__
redmine authored
865
		sigaddset(&sigset, SIGCHLD);
redmine authored
866
# endif
redmine authored
867
		critical_on(pthread_sigmask(SIG_UNBLOCK, &sigset, NULL));
redmine authored
868 869

# ifndef __linux__
redmine authored
870
		critical_on(!parent_isalive());
redmine authored
871
# endif
redmine authored
872
	} else {
redmine authored
873
		register_blockthread();
redmine authored
874
		pthread_setname_np(pthread_self(), "clsync-helper");
redmine authored
875
	}
redmine authored
876
	cap_drop(ctx_p, ctx_p->caps);
redmine authored
877 878

	debug(2, "Syncing with the runner");
redmine authored
879
	pthread_mutex_lock(pthread_mutex_privileged_p);
redmine authored
880 881

	// Waiting for runner to get ready for signal
redmine authored
882 883
	pthread_mutex_lock(pthread_mutex_runner_p);
	pthread_mutex_unlock(pthread_mutex_runner_p);
redmine authored
884 885

	// Sending the signal that we're ready
redmine authored
886
	pthread_cond_signal(pthread_cond_runner_p);
redmine authored
887 888 889

	// The loop
	debug(2, "Running the loop");
redmine authored
890 891 892
	while (helper_isrunning) {
		errno = 0;

redmine authored
893
		// Waiting for command
redmine authored
894
		debug(10, "Waiting for command");
redmine authored
895 896 897 898
		if (opts->shm_mprotect) {
			mprotect((void *)cmd_p,		sizeof(*cmd_p),		PROT_WRITE);
			mprotect((void *)cmd_ret_p,	sizeof(*cmd_ret_p),	PROT_READ);
		}
redmine authored
899
# ifdef HL_LOCKS
redmine authored
900 901
		debug(25, "hl_lock_p->enabled == %i", hl_lock_p->enabled);
		if (!hl_lock_p->enabled || !hl_wait(
redmine authored
902
			HLLOCK_HANDLER
redmine authored
903
#  ifdef HL_LOCK_TRIES_AUTO
redmine authored
904
			, hl_lock_p->tries[HLLOCK_HANDLER]
redmine authored
905
#  endif
redmine authored
906
		)) {
redmine authored
907 908
			if (opts->isprocsplitting)
				critical_on(!parent_isalive());
redmine authored
909 910
# endif
# ifdef READWRITE_SIGNALLING
redmine authored
911
#  warning		READWRITE_SIGNALLING can cause process hanging on clsync shutdown
redmine authored
912
			read_inf(priv_read_fd, buf, 1);
redmine authored
913
# else
redmine authored
914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933
			int rc;
			while (1) {
				rc = pthread_cond_timedwait(pthread_cond_privileged_p, pthread_mutex_privileged_p, &wait_timeout);
				if (!rc)
					break;
				if (rc != ETIMEDOUT)
					critical("Got error while pthread_cond_timedwait()");
				debug(10, "pthread_cond_timedwait() timed out");

				if (opts->isprocsplitting)
					exit_on(!parent_isalive());

				{
					debug(20, "Resetting wait_timeout");
					struct timeval now;
					gettimeofday(&now, NULL);
					wait_timeout.tv_sec	= now.tv_sec  + SLEEP_SECONDS;
					wait_timeout.tv_nsec	= now.tv_usec * 1000;
				}
			}
redmine authored
934 935
# endif
# ifdef HL_LOCKS
redmine authored
936
			if (hl_lock_p->enabled)
redmine authored
937
				hl_setstate(HLLOCK_HANDLER, HLLS_WORKING);
redmine authored
938
		}
redmine authored
939
# endif
redmine authored
940 941 942 943
		if (opts->shm_mprotect) {
			mprotect((void *)cmd_p,		sizeof(*cmd_p),		PROT_READ);
			mprotect((void *)cmd_ret_p,	sizeof(*cmd_ret_p),	PROT_WRITE);
		}
redmine authored
944

redmine authored
945
		debug(10, "Got command %u (euid:egid => %i:%i)", cmd_p->action, geteuid(), getegid());
redmine authored
946

redmine authored
947
		if (!setup && cmd_p->action != PA_SETUP)
redmine authored
948 949
			critical("A try to use commands before PA_SETUP");

redmine authored
950
		switch (cmd_p->action) {
redmine authored
951
			case PA_SETUP: {
redmine authored
952
				debug(20, "PA_SETUP");
redmine authored
953 954 955
				if (setup)
					critical("Double privileged_handler setuping. It can be if somebody is trying to hack the clsync.");

redmine authored
956
				critical_on(pa_setup(opts, cmd_p->arg.ctx_p, &exec_uid, &exec_gid));
redmine authored
957
				mprotect(opts, sizeof(*opts), PROT_READ);
redmine authored
958
				use_args_check = cmd_p->arg.ctx_p->flags[CHECK_EXECVP_ARGS];
redmine authored
959
				cap_drop(ctx_p, ctx_p->caps);	// TODO: Find out why "permission denined" without this line
redmine authored
960
				setup++;
redmine authored
961
				critical_on(errno);
redmine authored
962 963 964
				break;
			}
			case PA_DIE:
redmine authored
965 966
				debug(20, "PA_DIE");
				helper_isrunning = 0;
redmine authored
967 968
				break;
			case PA_FTS_OPEN: {
redmine authored
969
				volatile struct pa_fts_open_arg *arg_p = &cmd_p->arg.fts_open;
redmine authored
970 971 972 973 974 975 976
				char *const *path_argv_p =(void *)(
						opts->isprocsplitting 	?
						arg_p->path_argv 	:
						arg_p->path_argv_p
					);

				debug(20, "PA_FTS_OPEN (%s)", *path_argv_p);
redmine authored
977
				if (arg_p->compar != NULL)
redmine authored
978
					critical("\"arg_p->compar != NULL\" (arg_p->compar == %p) is forbidden because may be used to run an arbitrary code in the privileged thread.", arg_p->compar);
redmine authored
979

redmine authored
980
				cmd_ret_p->ret = fts_open(path_argv_p, arg_p->options, NULL);
redmine authored
981
				debug(21, "/PA_FTS_OPEN => %p", cmd_ret_p->ret);
redmine authored
982 983
				break;
			}
redmine authored
984 985 986 987
			case PA_FTS_READ: {
				debug(20, "PA_FTS_READ(%p)", cmd_p->arg.void_v);
				FTSENT *ret = fts_read(cmd_p->arg.void_v);
				if (ret == NULL) {
redmine authored
988 989 990 991 992 993
					cmd_ret_p->ret = NULL;
					debug(10, "cmd_ret_p->ret == NULL");
					break;
				}
				if (!opts->isprocsplitting) {	// Is the thread-splitting?
					cmd_ret_p->ret = ret;
redmine authored
994 995 996
					break;
				}

redmine authored
997 998
				{	// Is the process splitting?
					struct pa_fts_read_ret *ret_buf = (void *)&cmd_ret_p->ret_buf.fts_read;
redmine authored
999
					memcpy(&ret_buf->ftsent, ret, sizeof(ret_buf->ftsent));
redmine authored
1000
					cmd_ret_p->ret = &ret_buf->ftsent;
redmine authored
1001 1002 1003 1004 1005 1006
					debug(25, "fts_path == <%s>", ret_buf->fts_path);
					strncpy(ret_buf->fts_accpath, ret->fts_accpath, sizeof(ret_buf->fts_accpath));
					strncpy(ret_buf->fts_path,    ret->fts_path,    sizeof(ret_buf->fts_path));
					ret_buf->ftsent.fts_accpath = ret_buf->fts_accpath;
					ret_buf->ftsent.fts_path    = ret_buf->fts_path;
				}
redmine authored
1007
				break;
redmine authored
1008
			}
redmine authored
1009
			case PA_FTS_CLOSE:
redmine authored
1010
				debug(20, "PA_FTS_CLOSE");
redmine authored
1011
				cmd_ret_p->ret = (void *)(long)fts_close(cmd_p->arg.void_v);
redmine authored
1012 1013
				break;
			case PA_INOTIFY_INIT:
redmine authored
1014
				debug(20, "PA_INOTIFY_INIT");
redmine authored
1015
				cmd_ret_p->ret = (void *)(long)inotify_init();
redmine authored
1016 1017
				break;
			case PA_INOTIFY_INIT1:
redmine authored
1018
				debug(20, "PA_INOTIFY_INIT1");
redmine authored
1019
				cmd_ret_p->ret = (void *)(long)inotify_init1(cmd_p->arg.uint32_v);
redmine authored
1020 1021
				break;
			case PA_INOTIFY_ADD_WATCH: {
redmine authored
1022
				struct pa_inotify_add_watch_arg *arg_p = (void *)&cmd_p->arg.inotify_add_watch;
redmine authored
1023 1024 1025
				const char *pathname = (opts->isprocsplitting ? arg_p->pathname : arg_p->pathname_p);
				debug(20, "PA_INOTIFY_ADD_WATCH(%u, <%s>, 0x%o)", arg_p->fd, pathname, arg_p->mask);
				cmd_ret_p->ret = (void *)(long)inotify_add_watch( arg_p->fd, pathname, arg_p->mask);
redmine authored
1026 1027 1028
				break;
			}
			case PA_INOTIFY_RM_WATCH: {
redmine authored
1029 1030
				debug(20, "PA_INOTIFY_RM_WATCH");
				struct pa_inotify_rm_watch_arg *arg_p = (void *)&cmd_p->arg.inotify_rm_watch;
redmine authored
1031
				cmd_ret_p->ret = (void *)(long)inotify_rm_watch(arg_p->fd, arg_p->wd);
redmine authored
1032 1033 1034
				break;
			}
			case PA_FORK_EXECVP: {
redmine authored
1035
				struct pa_fork_execvp_arg *arg_p = (void *)&cmd_p->arg.fork_execvp;
redmine authored
1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046
				const char *file;
				char *const *argv;

				if (opts->isprocsplitting) {
					file = arg_p->file;
					argv = arg_p->argv;
				} else {
					file = arg_p->file_p;
					argv = arg_p->argv_p;
				}

redmine authored
1047 1048
				debug(20, "PA_FORK_EXECVP (\"%s\", argv)", file);

redmine authored
1049
				if (use_args_check)
redmine authored
1050 1051
					privileged_execvp_check_arguments(opts, file, argv);

redmine authored
1052 1053 1054 1055 1056 1057
				pid_t pid = fork();
				switch (pid) {
					case -1: 
						error("Cannot fork().");
						break;
					case  0:
redmine authored
1058 1059 1060 1061 1062 1063 1064 1065 1066 1067
#ifdef ANTIPARANOID
						if (ctx_p->privileged_gid != exec_gid)
#endif
							debug(4, "setgid(%u) == %i", exec_gid, setgid(exec_gid));

#ifdef ANTIPARANOID
						if (ctx_p->privileged_uid != exec_uid)
#endif
							debug(4, "setuid(%u) == %i", exec_uid, setuid(exec_uid));

redmine authored
1068 1069
						debug(3, "execvp(\"%s\", argv)", file);
						exit(execvp(file, argv));
redmine authored
1070
				}
redmine authored
1071
				cmd_ret_p->ret = (void *)(long)pid;
redmine authored
1072
				debug(21, "/PA_FORK_EXECVP");
redmine authored
1073 1074
				break;
			}
redmine authored
1075
			case PA_KILL_CHILD: {
redmine authored
1076 1077
				debug(20, "PA_KILL_CHILD");
				struct pa_kill_child_arg *arg_p = (void *)&cmd_p->arg.kill_child;
redmine authored
1078
				cmd_ret_p->ret = (void *)(long)__privileged_kill_child_itself(arg_p->pid, arg_p->signal, arg_p->ignoreerrors);
redmine authored
1079 1080
				break;
			}
redmine authored
1081 1082
# ifdef CGROUP_SUPPORT
			case PA_CLSYNC_CGROUP_DEINIT: {
redmine authored
1083
				debug(20, "PA_CLSYNC_CGROUP_DEINIT");
redmine authored
1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099
				/*
				 * That is strange, but setuid() doesn't work
				 * without fork() in case of enabled seccomp
				 * filter. So sorry for this hacky thing.
				 *
				 * TODO: fix that.
				 */
				int status;
				pid_t pid = fork();
				switch (pid) {
					case -1: 
						error("Cannot fork().");
						break;
					case  0:
						debug(4, "setgid(0) == %i", setgid(0));
						debug(4, "setuid(0) == %i", setuid(0));
redmine authored
1100
						exit(clsync_cgroup_deinit(cmd_p->arg.void_v));
redmine authored
1101 1102 1103 1104 1105 1106 1107 1108 1109
				}

				if (waitpid(pid, &status, 0) != pid) {
					switch (errno) {
						case ECHILD:
							debug(2, "Child %u has already died.", pid);
							break;
						default:
							error("Cannot waitid().");
redmine authored
1110 1111
							cmd_ret_p->_errno = errno;
							cmd_ret_p->ret    = (void *)(long)errno;
redmine authored
1112 1113
					}
				}
redmine authored
1114

redmine authored
1115 1116 1117 1118
				// Return
				int exitcode = WEXITSTATUS(status);
				debug(3, "execution completed with exitcode %i", exitcode);

redmine authored
1119 1120
				cmd_ret_p->_errno = exitcode;
				cmd_ret_p->ret    = (void *)(long)exitcode;
redmine authored
1121

redmine authored
1122 1123 1124
				break;
			}
# endif
redmine authored
1125 1126 1127 1128 1129 1130
			case PA_WAITPID: {
				struct pa_waitpid_arg *arg_p = (void *)&cmd_p->arg.waitpid;
				debug(20, "PA_WAITPID(%u, 0x%o)", arg_p->pid, arg_p->options);
				cmd_ret_p->ret = (void *)(long)waitpid(arg_p->pid, &arg_p->status, arg_p->options);
				break;
			}
redmine authored
1131 1132 1133 1134
			default:
				critical("Unknown command type \"%u\". It's a buffer overflow (which means a security problem) or just an internal error.");
		}

redmine authored
1135 1136
		cmd_ret_p->_errno = errno;
		debug(10, "Result: %p, errno: %u. Sending the signal to non-privileged thread/process.", cmd_ret_p->ret, cmd_ret_p->_errno);
redmine authored
1137
# ifdef HL_LOCKS
redmine authored
1138
		if (!hl_lock_p->enabled) {
redmine authored
1139 1140 1141
# endif
# ifndef __linux__
			critical_on(!parent_isalive());
redmine authored
1142 1143
# endif
# ifdef READWRITE_SIGNALLING
redmine authored
1144
			write_inf(nonp_write_fd, buf, 1);
redmine authored
1145
# else
redmine authored
1146 1147 1148
			critical_on (pthread_mutex_lock(pthread_mutex_action_signal_p));
			critical_on (pthread_mutex_unlock(pthread_mutex_action_signal_p));
			critical_on (pthread_cond_signal(pthread_cond_action_p));
redmine authored
1149 1150
# endif
# ifdef HL_LOCKS
redmine authored
1151
		}
redmine authored
1152
# endif
redmine authored
1153 1154
	}

redmine authored
1155
	pa_unsetup(opts);
redmine authored
1156
# ifdef HL_LOCKS
redmine authored
1157
	hl_shutdown(HLLOCK_HANDLER);
redmine authored
1158
# endif
redmine authored
1159
	pthread_mutex_unlock(pthread_mutex_privileged_p);
redmine authored
1160 1161 1162 1163
	debug(2, "Finished");
	return 0;
}

redmine authored
1164
static inline int privileged_action(
redmine authored
1165
# ifdef HL_LOCK_TRIES_AUTO
redmine authored
1166
		int callid,
redmine authored
1167
# endif
redmine authored
1168 1169 1170 1171
		enum privileged_action action,
		void **ret_p
	)
{
redmine authored
1172 1173
	int rc = 0;

redmine authored
1174
# ifdef READWRITE_SIGNALLING
redmine authored
1175
	char buf[1] = {0};
redmine authored
1176 1177
# endif
# ifdef HL_LOCK_TRIES_AUTO
redmine authored
1178 1179 1180
	clock_t start_ticks;

	int isadjusting;
redmine authored
1181
# endif
redmine authored
1182
# ifdef HL_LOCKS
redmine authored
1183
	debug(10, "(%u, %p): %i", action, ret_p, hl_lock_p->enabled);
redmine authored
1184
# else
redmine authored
1185
	debug(10, "(%u, %p)",     action, ret_p);
redmine authored
1186
# endif
redmine authored
1187

redmine authored
1188 1189 1190
	pthread_mutex_lock(pthread_mutex_action_entrance_p);
# ifndef READWRITE_SIGNALLING
	debug(10, "Waiting the privileged thread/process to get prepared for signal");
redmine authored
1191
#  ifdef HL_LOCKS
redmine authored
1192
	if (hl_lock_p->enabled) {
redmine authored
1193
		while (!hl_isanswered(HLLOCK_HANDLER))
redmine authored
1194 1195
			if (!helper_isalive_cache) {
				debug(1, "The privileged thread/process is dead (#0). Ignoring the command.");
redmine authored
1196 1197 1198
				rc = ENOENT;
				goto privileged_action_end;
			}
redmine authored
1199
	} else {
redmine authored
1200
#  endif
redmine authored
1201 1202 1203
		critical_on(!helper_isalive_cache);
		pthread_mutex_lock(pthread_mutex_privileged_p);
		pthread_mutex_unlock(pthread_mutex_privileged_p);
redmine authored
1204
#  ifdef HL_LOCKS
redmine authored
1205
	}
redmine authored
1206
#  endif
redmine authored
1207
# endif
redmine authored
1208 1209
	if (!helper_isalive_cache) {
		debug(1, "The privileged thread/process is dead (#1). Ignoring the command.");
redmine authored
1210 1211
		rc = ENOENT;
		goto privileged_action_end;
redmine authored
1212 1213
	}

redmine authored
1214 1215
	cmd_p->action = action;
	debug(10, "Sending information (action == %i) to the privileged thread/process", action);
redmine authored
1216
# ifdef HL_LOCK_TRIES_AUTO
redmine authored
1217
	cmd_p->hl_lock_tries = hl_lock_p->tries[callid];
redmine authored
1218

redmine authored
1219 1220
	if ((isadjusting = hl_lock_p->enabled)) {
		isadjusting = hl_lock_p->tries[callid];
redmine authored
1221
		if (isadjusting) {
redmine authored
1222
			isadjusting = ((double)fabs(hl_lock_p->tries_step[callid]-1) > (double)HL_LOCK_AUTO_K_FINISH);
redmine authored
1223
			if (isadjusting) {
redmine authored
1224 1225
				isadjusting = !((++hl_lock_p->count[callid]) << (sizeof(hl_lock_p->count[callid])*CHAR_BIT - HL_LOCK_AUTO_INTERVAL));
				debug(11, "isadjusting == %u; hl_lock_p->tries_step[%i] == %lf; hl_lock_p->count[%i] == %lu", isadjusting, callid, hl_lock_p->tries_step[callid], callid, hl_lock_p->count[callid]);
redmine authored
1226 1227 1228 1229 1230
				if (isadjusting)
					start_ticks = clock();
			}
		}
	}
redmine authored
1231

redmine authored
1232 1233
# endif
# ifdef HL_LOCKS
redmine authored
1234 1235 1236
	if (action == PA_DIE)
		hl_lock_p->enabled = 0;

redmine authored
1237
	if (!hl_lock_p->enabled || !hl_signal(HLLOCK_HANDLER)) {
redmine authored
1238
# endif
redmine authored
1239
		critical_on(!helper_isalive_cache);
redmine authored
1240
# ifdef READWRITE_SIGNALLING
redmine authored
1241
		write_inf(priv_write_fd, buf, 1);
redmine authored
1242 1243
# else
#  ifdef HL_LOCKS
redmine authored
1244
		if (hl_lock_p->enabled) {
redmine authored
1245
			debug(10, "Waiting the privileged thread/process to get prepared for signal (by fallback)");
redmine authored
1246 1247
			critical_on (pthread_mutex_lock(pthread_mutex_privileged_p));
			critical_on (pthread_mutex_unlock(pthread_mutex_privileged_p));
redmine authored
1248
		} else
redmine authored
1249
#  endif
redmine authored
1250 1251
		critical_on (pthread_mutex_lock(pthread_mutex_action_signal_p));
		critical_on (pthread_cond_signal(pthread_cond_privileged_p));
redmine authored
1252 1253
# endif
# ifdef HL_LOCKS
redmine authored
1254
	}
redmine authored
1255
# endif
redmine authored
1256

redmine authored
1257 1258
	if (action == PA_DIE)
		goto privileged_action_end;
redmine authored
1259
	debug(10, "Waiting for the answer");
redmine authored
1260

redmine authored
1261
# ifdef HL_LOCKS
redmine authored
1262
	if (hl_lock_p->enabled) {
redmine authored
1263
		while (!hl_isanswered(HLLOCK_HANDLER))
redmine authored
1264 1265
			if (!helper_isalive_cache) {
				debug(1, "The privileged thread/process is dead (#2). Ignoring the command.");
redmine authored
1266 1267 1268
				rc = ENOENT;
				goto privileged_action_end;
			}
redmine authored
1269

redmine authored
1270
#  ifdef HL_LOCK_TRIES_AUTO
redmine authored
1271 1272
		if (isadjusting) {
			unsigned long delay = (long)clock() - (long)start_ticks;
redmine authored
1273
			long diff  = delay - hl_lock_p->delay[callid];
redmine authored
1274

redmine authored
1275
			debug(13, "diff == %li; hl_lock_p->delay[%i] == %lu; delay == %lu; delay*HL_LOCK_AUTO_THREADHOLD == %lu", diff, callid, hl_lock_p->delay[callid], delay, delay*HL_LOCK_AUTO_THREADHOLD)
redmine authored
1276

redmine authored
1277
			if (diff && ((unsigned long)labs(diff) > (unsigned long)delay*HL_LOCK_AUTO_THREADHOLD)) {
redmine authored
1278

redmine authored
1279
				if (diff > 0)
redmine authored
1280
					hl_lock_p->tries_step[callid] = 1/((hl_lock_p->tries_step[callid]-1)/HL_LOCK_AUTO_DECELERATION+1);
redmine authored
1281

redmine authored
1282
				hl_lock_p->delay[callid]  = delay;
redmine authored
1283

redmine authored
1284
				debug(12, "diff == %li; hl_lock_p->tries_step[%i] == %lf; hl_lock_p->delay[%i] == %lu", diff, callid, hl_lock_p->tries_step[callid], callid, hl_lock_p->delay[callid]);
redmine authored
1285
			}
redmine authored
1286
			hl_lock_p->tries[callid] *= hl_lock_p->tries_step[callid];
redmine authored
1287

redmine authored
1288 1289
			if (hl_lock_p->tries[callid] > HL_LOCK_AUTO_LIMIT_HIGH)
				hl_lock_p->tries[callid] = HL_LOCK_AUTO_LIMIT_HIGH;
redmine authored
1290

redmine authored
1291
			debug(14, "hl_lock_p->tries[%i] == %lu", callid, hl_lock_p->tries[callid]);
redmine authored
1292
		}
redmine authored
1293
#  endif
redmine authored
1294
	} else {
redmine authored
1295
# endif
redmine authored
1296
		critical_on(!helper_isalive_cache);
redmine authored
1297
# ifdef READWRITE_SIGNALLING
redmine authored
1298
		read_inf(nonp_read_fd, buf, 1);
redmine authored
1299
# else
redmine authored
1300
		critical_on (pthread_cond_wait(pthread_cond_action_p, pthread_mutex_action_signal_p));
redmine authored
1301 1302
# endif
# ifdef HL_LOCKS
redmine authored
1303
	}
redmine authored
1304
# endif
redmine authored
1305

redmine authored
1306
	if (ret_p != NULL)
redmine authored
1307 1308
		*ret_p = (void *)cmd_ret_p->ret;
	errno = cmd_ret_p->_errno;
redmine authored
1309

redmine authored
1310
privileged_action_end:
redmine authored
1311
	debug(10, "Unlocking pthread_mutex_action_*");
redmine authored
1312 1313
# ifndef READWRITE_SIGNALLING
#  ifdef HL_LOCKS
redmine authored
1314
	if (!hl_lock_p->enabled)
redmine authored
1315
#  endif
redmine authored
1316
		pthread_mutex_unlock(pthread_mutex_action_signal_p);
redmine authored
1317 1318
# endif

redmine authored
1319
	pthread_mutex_unlock(pthread_mutex_action_entrance_p);
redmine authored
1320

redmine authored
1321
	return rc;
redmine authored
1322 1323
}

redmine authored
1324
FTS *__privileged_fts_open_procsplit(
redmine authored
1325
		char *const *path_argv,
redmine authored
1326 1327
		int options,
		int (*compar)(const FTSENT **, const FTSENT **)
redmine authored
1328
# ifdef HL_LOCK_TRIES_AUTO
redmine authored
1329
		, int callid
redmine authored
1330
# endif
redmine authored
1331 1332
	)
{
redmine authored
1333
	void *ret = NULL;
redmine authored
1334
	int i;
redmine authored
1335

redmine authored
1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346
	i = 0;
	while (path_argv[i] != NULL) {
		cmd_p->arg.fts_open.path_argv[i] = (void *)cmd_p->arg.fts_open._path_argv[i];
		debug(25, "path_argv[%i] == <%s> (%p) -> %p", i, path_argv[i], path_argv[i], cmd_p->arg.fts_open.path_argv[i]);
		strncpy(cmd_p->arg.fts_open.path_argv[i], path_argv[i], sizeof(cmd_p->arg.fts_open._path_argv[i]));
		i++;
		critical_on(i >= MAXARGUMENTS);
	}
	cmd_p->arg.fts_open.path_argv[i]	= NULL;
	cmd_p->arg.fts_open.options		= options;
	cmd_p->arg.fts_open.compar		= compar;
redmine authored
1347

redmine authored
1348
	privileged_action(
redmine authored
1349
# ifdef HL_LOCK_TRIES_AUTO
redmine authored
1350
			callid,
redmine authored
1351
# endif
redmine authored
1352 1353 1354
			PA_FTS_OPEN,
			&ret
		);
redmine authored
1355 1356 1357 1358

	return ret;
}

redmine authored
1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384
FTS *__privileged_fts_open_threadsplit(
		char *const *path_argv,
		int options,
		int (*compar)(const FTSENT **, const FTSENT **)
# ifdef HL_LOCK_TRIES_AUTO
		, int callid
# endif
	)
{
	void *ret = NULL;

	cmd_p->arg.fts_open.path_argv_p		= path_argv;
	cmd_p->arg.fts_open.options		= options;
	cmd_p->arg.fts_open.compar		= compar;

	privileged_action(
# ifdef HL_LOCK_TRIES_AUTO
			callid,
# endif
			PA_FTS_OPEN,
			&ret
		);

	return ret;
}

redmine authored
1385 1386
FTSENT *__privileged_fts_read(
		FTS *ftsp
redmine authored
1387
# ifdef HL_LOCK_TRIES_AUTO
redmine authored
1388
		, int callid
redmine authored
1389
# endif
redmine authored
1390
	)
redmine authored
1391
{
redmine authored
1392
	void *ret = NULL;
redmine authored
1393
	cmd_p->arg.void_v = ftsp;
redmine authored
1394
	privileged_action(
redmine authored
1395
# ifdef HL_LOCK_TRIES_AUTO
redmine authored
1396
			callid,
redmine authored
1397
# endif
redmine authored
1398 1399 1400
			PA_FTS_READ,
			&ret
		);
redmine authored
1401 1402 1403
	return ret;
}

redmine authored
1404 1405
int __privileged_fts_close(
		FTS *ftsp
redmine authored
1406
# ifdef HL_LOCK_TRIES_AUTO
redmine authored
1407
		, int callid
redmine authored
1408
# endif
redmine authored
1409
	)
redmine authored
1410
{
redmine authored
1411
	void *ret = (void *)(long)-1;
redmine authored
1412
	cmd_p->arg.void_v = ftsp;
redmine authored
1413
	privileged_action(
redmine authored
1414
# ifdef HL_LOCK_TRIES_AUTO
redmine authored
1415
			callid,
redmine authored
1416
# endif
redmine authored
1417 1418 1419
			PA_FTS_CLOSE,
			&ret
		);
redmine authored
1420 1421 1422
	return (long)ret;
}

redmine authored
1423
int __privileged_inotify_init() {
redmine authored
1424
	void *ret = (void *)(long)-1;
redmine authored
1425
	privileged_action(
redmine authored
1426
# ifdef HL_LOCK_TRIES_AUTO
redmine authored
1427
			PC_DEFAULT,
redmine authored
1428
# endif
redmine authored
1429 1430 1431
			PA_INOTIFY_INIT,
			&ret
		);
redmine authored
1432 1433 1434
	return (long)ret;
}

redmine authored
1435
int __privileged_inotify_init1(int flags) {
redmine authored
1436
	void *ret = (void *)(long)-1;
redmine authored
1437
	cmd_p->arg.uint32_v = flags;
redmine authored
1438
	privileged_action(
redmine authored
1439
# ifdef HL_LOCK_TRIES_AUTO
redmine authored
1440
			PC_DEFAULT,
redmine authored
1441
# endif
redmine authored
1442 1443 1444
			PA_INOTIFY_INIT1,
			&ret
		);
redmine authored
1445 1446 1447
	return (long)ret;
}

redmine authored
1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475
int __privileged_inotify_add_watch_threadsplit(
		int fd,
		const char *pathname,
		uint32_t mask
# ifdef HL_LOCK_TRIES_AUTO
		, int callid
# endif
	)
{
	debug(25, "(%i, <%s>, o%o, ?)", fd, pathname, mask);
	void *ret = (void *)(long)-1;

	cmd_p->arg.inotify_add_watch.pathname_p	= pathname;
	cmd_p->arg.inotify_add_watch.fd		= fd;
	cmd_p->arg.inotify_add_watch.mask	= mask;

	privileged_action(
# ifdef HL_LOCK_TRIES_AUTO
			callid,
# endif
			PA_INOTIFY_ADD_WATCH,
			&ret
		);

	return (long)ret;
}

int __privileged_inotify_add_watch_procsplit(
redmine authored
1476 1477 1478
		int fd,
		const char *pathname,
		uint32_t mask
redmine authored
1479
# ifdef HL_LOCK_TRIES_AUTO
redmine authored
1480
		, int callid
redmine authored
1481
# endif
redmine authored
1482 1483
	)
{
redmine authored
1484
	debug(25, "(%i, <%s>, o%o, ?)", fd, pathname, mask);
redmine authored
1485
	void *ret = (void *)(long)-1;
redmine authored
1486

redmine authored
1487 1488 1489
	strncpy((void *)cmd_p->arg.inotify_add_watch.pathname, pathname, sizeof(cmd_p->arg.inotify_add_watch.pathname));
	cmd_p->arg.inotify_add_watch.fd		= fd;
	cmd_p->arg.inotify_add_watch.mask	= mask;
redmine authored
1490

redmine authored
1491
	privileged_action(
redmine authored
1492
# ifdef HL_LOCK_TRIES_AUTO
redmine authored
1493
			callid,
redmine authored
1494
# endif
redmine authored
1495 1496 1497
			PA_INOTIFY_ADD_WATCH,
			&ret
		);
redmine authored
1498 1499 1500 1501

	return (long)ret;
}

redmine authored
1502
int __privileged_inotify_rm_watch(
redmine authored
1503 1504 1505 1506
		int fd,
		int wd
	)
{
redmine authored
1507
	void *ret = (void *)(long)-1;
redmine authored
1508

redmine authored
1509 1510
	cmd_p->arg.inotify_rm_watch.fd	= fd;
	cmd_p->arg.inotify_rm_watch.wd	= wd;
redmine authored
1511

redmine authored
1512
	privileged_action(
redmine authored
1513
# ifdef HL_LOCK_TRIES_AUTO
redmine authored
1514
			PC_DEFAULT,
redmine authored
1515
# endif
redmine authored
1516 1517 1518
			PA_INOTIFY_RM_WATCH,
			&ret
		);
redmine authored
1519 1520 1521 1522

	return (long)ret;
}

redmine authored
1523
# ifdef CGROUP_SUPPORT
redmine authored
1524
int __privileged_clsync_cgroup_deinit(ctx_t *ctx_p)
redmine authored
1525 1526 1527
{
	void *ret = (void *)(long)-1;

redmine authored
1528
	cmd_p->arg.ctx_p = ctx_p;
redmine authored
1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541

	privileged_action(
#  ifdef HL_LOCK_TRIES_AUTO
			PC_DEFAULT,
#  endif
			PA_CLSYNC_CGROUP_DEINIT,
			&ret
		);

	return (long)ret;
}
# endif

redmine authored
1542
int __privileged_fork_setuid_execvp_procsplit(
redmine authored
1543 1544 1545
		const char *file,
		char *const argv[]
	)
redmine authored
1546
{
redmine authored
1547
	int i;
redmine authored
1548
	void *ret = (void *)(long)-1;
redmine authored
1549

redmine authored
1550 1551 1552 1553 1554 1555 1556 1557 1558 1559
	strncpy((void *)cmd_p->arg.fork_execvp.file, file, sizeof(cmd_p->arg.fork_execvp.file));

	i=0;
	while (argv[i] != NULL) {
		cmd_p->arg.fork_execvp.argv[i] = (void *)cmd_p->arg.fork_execvp._argv[i];
		strncpy(cmd_p->arg.fork_execvp.argv[i], argv[i], sizeof(cmd_p->arg.fork_execvp._argv[i]));
		i++;
		critical_on(i >= MAXARGUMENTS);
	}
	cmd_p->arg.fork_execvp.argv[i] = NULL;
redmine authored
1560

redmine authored
1561
	privileged_action(
redmine authored
1562
# ifdef HL_LOCK_TRIES_AUTO
redmine authored
1563
			PC_DEFAULT,
redmine authored
1564
# endif
redmine authored
1565 1566 1567
			PA_FORK_EXECVP,
			&ret
		);
redmine authored
1568 1569 1570 1571

	return (long)ret;
}

redmine authored
1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592
int __privileged_fork_setuid_execvp_threadsplit(
		const char *file,
		char *const argv[]
	)
{
	void *ret = (void *)(long)-1;

	cmd_p->arg.fork_execvp.file_p = file;
	cmd_p->arg.fork_execvp.argv_p = argv;

	privileged_action(
# ifdef HL_LOCK_TRIES_AUTO
			PC_DEFAULT,
# endif
			PA_FORK_EXECVP,
			&ret
		);

	return (long)ret;
}

redmine authored
1593
int __privileged_kill_child_wrapper(pid_t pid, int signal, char ignoreerrors)
redmine authored
1594
{
redmine authored
1595
	void *ret = (void *)(long)-1;
redmine authored
1596

redmine authored
1597 1598 1599
	cmd_p->arg.kill_child.pid          = pid;
	cmd_p->arg.kill_child.signal       = signal;
	cmd_p->arg.kill_child.ignoreerrors = ignoreerrors;
redmine authored
1600

redmine authored
1601
	privileged_action(
redmine authored
1602
# ifdef HL_LOCK_TRIES_AUTO
redmine authored
1603
			PC_DEFAULT,
redmine authored
1604
# endif
redmine authored
1605 1606
			PA_KILL_CHILD,
			&ret);
redmine authored
1607 1608 1609 1610

	return (long)ret;
}

redmine authored
1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630
pid_t __privileged_waitpid(pid_t pid, int *status, int options)
{
	void *ret = (void *)(long)-1;

	cmd_p->arg.waitpid.pid     = pid;
	cmd_p->arg.waitpid.options = options;

	privileged_action(
# ifdef HL_LOCK_TRIES_AUTO
			PC_DEFAULT,
# endif
			PA_WAITPID,
			&ret);

	if (status != NULL)
		*status = cmd_p->arg.waitpid.status;

	return (long)ret;
}

redmine authored
1631 1632
#endif

redmine authored
1633 1634 1635
uid_t __privileged_fork_execvp_uid;
gid_t __privileged_fork_execvp_gid;
int __privileged_fork_execvp(const char *file, char *const argv[])
redmine authored
1636 1637 1638 1639 1640 1641 1642 1643
{
	debug(4, "");
	pid_t pid = fork();
	switch (pid) {
		case -1: 
			error("Cannot fork().");
			return -1;
		case  0:
redmine authored
1644 1645
			debug(4, "setgid(%u) == %i", __privileged_fork_execvp_gid, setgid(__privileged_fork_execvp_gid));
			debug(4, "setuid(%u) == %i", __privileged_fork_execvp_uid, setuid(__privileged_fork_execvp_uid));
redmine authored
1646 1647 1648
			errno = 0;
			execvp(file, argv);
			exit(errno);
redmine authored
1649 1650 1651 1652 1653
	}

	return pid;
}

redmine authored
1654
#ifdef CAPABILITIES_SUPPORT
redmine authored
1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721
#define pthread_mutex_init_smart(mutex_p) _pthread_mutex_init_smart(ctx_p->flags[SPLITTING]==SM_PROCESS, mutex_p)
static inline int _pthread_mutex_init_smart(int isshared, pthread_mutex_t **mutex_p) {
	int rc;
	pthread_mutex_t *mutex, initial = PTHREAD_MUTEX_INITIALIZER;
	if (isshared)
		return pthread_mutex_init_shared(mutex_p);

	mutex = xmalloc(sizeof(*mutex));
	memcpy(mutex, &initial, sizeof(*mutex));

	rc = pthread_mutex_init(mutex, NULL);
	if (rc)
		return rc;

	*mutex_p = mutex;

	return rc;
}

#define pthread_mutex_destroy_smart(mutex_p) _pthread_mutex_destroy_smart(ctx_p->flags[SPLITTING]==SM_PROCESS, mutex_p)
static inline int _pthread_mutex_destroy_smart(int isshared, pthread_mutex_t *mutex_p) {
	int rc;
	if (isshared)
		return pthread_mutex_destroy_shared(mutex_p);

	rc = pthread_mutex_destroy(mutex_p);
	if (rc)
		return rc;

	free(mutex_p);

	return 0;
}

#define pthread_cond_init_smart(cond_p) _pthread_cond_init_smart(ctx_p->flags[SPLITTING]==SM_PROCESS, cond_p)
static inline int _pthread_cond_init_smart(int isshared, pthread_cond_t **cond_p) {
	int rc;
	pthread_cond_t *cond, initial = PTHREAD_COND_INITIALIZER;
	if (isshared)
		return pthread_cond_init_shared(cond_p);

	cond = xmalloc(sizeof(*cond));
	memcpy(cond, &initial, sizeof(*cond));

	rc = pthread_cond_init(cond, NULL);
	if (rc)
		return rc;

	*cond_p = cond;

	return rc;
}

#define pthread_cond_destroy_smart(cond_p) _pthread_cond_destroy_smart(ctx_p->flags[SPLITTING]==SM_PROCESS, cond_p)
static inline int _pthread_cond_destroy_smart(int isshared, pthread_cond_t *cond_p) {
	int rc;
	if (isshared)
		return pthread_cond_destroy_shared(cond_p);

	rc = pthread_cond_destroy(cond_p);
	if (rc)
		return rc;

	free(cond_p);

	return 0;
}
redmine authored
1722
#endif
redmine authored
1723

redmine authored
1724 1725
int privileged_init(ctx_t *ctx_p)
{
redmine authored
1726
#ifdef READWRITE_SIGNALLING
redmine authored
1727
	int pipefds[2];
redmine authored
1728
#endif
redmine authored
1729

redmine authored
1730
#ifdef CAPABILITIES_SUPPORT
redmine authored
1731
	if (ctx_p->flags[SPLITTING] == SM_OFF) {
redmine authored
1732 1733
#endif

redmine authored
1734
		_privileged_fork_execvp		= __privileged_fork_execvp;
redmine authored
1735

redmine authored
1736 1737
		__privileged_fork_execvp_uid	= ctx_p->synchandler_uid;
		__privileged_fork_execvp_gid	= ctx_p->synchandler_gid;
redmine authored