clsync
Loading...
Searching...
No Matches
privileged.c
Go to the documentation of this file.
1/*
2 clsync - file tree sync utility based on inotify/kqueue
3
4 Copyright (C) 2013-2014 Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "common.h" // ctx.h
21#include "ctx.h" // ctx_t
22#include "error.h" // debug()
23#include "syscalls.h" // read_inf()/write_inf()
24#include "main.h" // ncpus
25#include "pthreadex.h" // pthread_*_shared()
26#include "malloc.h" // xmalloc()
27
28#ifdef CAPABILITIES_SUPPORT
29# include <pthread.h> // pthread_create()
30# include <sys/inotify.h> // inotify_init()
31# include <sys/types.h> // fts_open()
32# include <sys/stat.h> // fts_open()
33# include <fts.h> // fts_open()
34# include <errno.h> // errno
35# include <sys/capability.h> // capset()
36# ifdef CGROUP_SUPPORT
37# include "cgroup.h" // clsync_cgroup_deinit()
38# endif
39#endif
40
41#include <unistd.h> // execvp()
42#include <glib.h> // g_atomic_int_set()
43
44#ifdef UNSHARE_SUPPORT
45# include <sched.h> // unshare()
46#endif
47
48#ifndef HL_LOCKS
49# ifdef HL_LOCK_TRIES_AUTO
50# undef HL_LOCK_TRIES_AUTO
51# endif
52#endif
53
54#ifdef HL_LOCK_TRIES_AUTO
55# include <time.h> // time()
56# include <math.h> // fabs()
57#endif
58
59#include "privileged.h"
60
61#ifdef SECCOMP_SUPPORT
62# include <syscall.h> // __NR_*
63# include <sys/prctl.h> // prctl()
64# include <linux/filter.h> // struct sock_filter
65# include <linux/seccomp.h> // SECCOMP_RET_*
66
67# ifndef __NR_shmdt
68# ifdef __i386__
69# warning [security] Caution! __NR_shmdt is not defined. Setting it to -222.
70# define __NR_shmdt -222
71# endif
72# endif
73
74
75# define syscall_nr (offsetof(struct seccomp_data, nr))
76
77/* Read: http://www.rawether.net/support/bpfhelp.htm */
78# define SECCOMP_COPY_SYSCALL_TO_ACCUM \
79 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_nr)
80
81# define SECCOMP_ALLOW \
82 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW)
83
84# define SECCOMP_DENY \
85 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_TRAP)
86
87# define SECCOMP_ALLOW_ACCUM_SYSCALL(syscall) \
88 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_##syscall, 0, 1), \
89 SECCOMP_ALLOW
90
91# define FILTER_TABLE_NONPRIV \
92 SECCOMP_ALLOW_ACCUM_SYSCALL(futex), \
93 SECCOMP_ALLOW_ACCUM_SYSCALL(inotify_init1), \
94 SECCOMP_ALLOW_ACCUM_SYSCALL(alarm), \
95 SECCOMP_ALLOW_ACCUM_SYSCALL(open), \
96 SECCOMP_ALLOW_ACCUM_SYSCALL(write), \
97 SECCOMP_ALLOW_ACCUM_SYSCALL(close), \
98 SECCOMP_ALLOW_ACCUM_SYSCALL(wait4), \
99 SECCOMP_ALLOW_ACCUM_SYSCALL(unlink), \
100 SECCOMP_ALLOW_ACCUM_SYSCALL(tgkill), \
101 SECCOMP_ALLOW_ACCUM_SYSCALL(rt_sigreturn), \
102 SECCOMP_ALLOW_ACCUM_SYSCALL(brk), \
103 SECCOMP_ALLOW_ACCUM_SYSCALL(munmap), \
104 SECCOMP_ALLOW_ACCUM_SYSCALL(wait4), \
105 SECCOMP_ALLOW_ACCUM_SYSCALL(rmdir), \
106 SECCOMP_ALLOW_ACCUM_SYSCALL(exit_group), \
107 SECCOMP_ALLOW_ACCUM_SYSCALL(select), \
108 SECCOMP_ALLOW_ACCUM_SYSCALL(read), \
109 SECCOMP_ALLOW_ACCUM_SYSCALL(rt_sigprocmask), \
110 SECCOMP_ALLOW_ACCUM_SYSCALL(rt_sigaction), \
111 SECCOMP_ALLOW_ACCUM_SYSCALL(nanosleep), \
112 SECCOMP_ALLOW_ACCUM_SYSCALL(shmdt), \
113 SECCOMP_ALLOW_ACCUM_SYSCALL(clone), /* for --threading */ \
114 SECCOMP_ALLOW_ACCUM_SYSCALL(set_robust_list), /* for --threading? */ \
115 SECCOMP_ALLOW_ACCUM_SYSCALL(madvise), \
116 SECCOMP_ALLOW_ACCUM_SYSCALL(exit), \
117 SECCOMP_ALLOW_ACCUM_SYSCALL(clock_gettime), \
118
119# ifdef __i386__
120# define FILTER_TABLE_ARCHDEPENDED /* unused */ \
121 SECCOMP_ALLOW_ACCUM_SYSCALL(fstat64), \
122 SECCOMP_ALLOW_ACCUM_SYSCALL(lstat64), \
123 SECCOMP_ALLOW_ACCUM_SYSCALL(stat64), \
124 SECCOMP_ALLOW_ACCUM_SYSCALL(time), \
125 SECCOMP_ALLOW_ACCUM_SYSCALL(mmap2), \
126 SECCOMP_ALLOW_ACCUM_SYSCALL(gettimeofday), \
127 SECCOMP_ALLOW_ACCUM_SYSCALL(_newselect), \
128
129# else
130# define FILTER_TABLE_ARCHDEPENDED \
131 SECCOMP_ALLOW_ACCUM_SYSCALL(fstat), /* unused */ \
132 SECCOMP_ALLOW_ACCUM_SYSCALL(lstat), \
133 SECCOMP_ALLOW_ACCUM_SYSCALL(stat), /* unused */ \
134 SECCOMP_ALLOW_ACCUM_SYSCALL(mmap), \
135
136# endif
137
138
139/* Syscalls allowed to non-privileged thread */
140static struct sock_filter filter_table[] = {
141 SECCOMP_COPY_SYSCALL_TO_ACCUM,
142 FILTER_TABLE_NONPRIV
143 FILTER_TABLE_ARCHDEPENDED
144 SECCOMP_DENY,
145};
146static struct sock_filter filter_w_mprotect_table[] = {
147 SECCOMP_COPY_SYSCALL_TO_ACCUM,
148 FILTER_TABLE_NONPRIV
149 FILTER_TABLE_ARCHDEPENDED
150 SECCOMP_ALLOW_ACCUM_SYSCALL ( mprotect ),
151 SECCOMP_DENY,
152};
153
154int nonprivileged_seccomp_init ( ctx_t *ctx_p )
155{
156 struct sock_fprog *filter_p;
157 struct sock_fprog filter = {
158 .len = ( unsigned short ) ( sizeof ( filter_table ) / sizeof ( filter_table[0] ) ),
159 .filter = filter_table,
160 };
161 struct sock_fprog filter_w_mprotect = {
162 .len = ( unsigned short ) ( sizeof ( filter_w_mprotect_table ) / sizeof ( filter_w_mprotect_table[0] ) ),
163 .filter = filter_w_mprotect_table,
164 };
165 debug ( 5, "enabling the seccomp" );
166 filter_p = ( ctx_p->flags[PERMIT_MPROTECT] ? &filter_w_mprotect : &filter );
167 SAFE ( prctl ( PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0 ), return -1 );
168 SAFE ( prctl ( PR_SET_SECCOMP, SECCOMP_MODE_FILTER, filter_p ), return -1 );
169 return 0;
170}
171#endif
172
173int ( *privileged_fork_execvp ) ( const char *file, char *const argv[] );
174int ( *privileged_kill_child ) ( pid_t pid, int sig, char ignoreerrors );
175
176#ifdef CAPABILITIES_SUPPORT
177pid_t helper_pid = 0;
178pthread_t privileged_thread;
179pthread_mutex_t *pthread_mutex_privileged_p;
180pthread_mutex_t *pthread_mutex_action_signal_p;
181pthread_mutex_t *pthread_mutex_action_entrance_p;
182pthread_mutex_t *pthread_mutex_runner_p;
183pthread_cond_t *pthread_cond_privileged_p;
184pthread_cond_t *pthread_cond_action_p;
185pthread_cond_t *pthread_cond_runner_p;
186
187# ifdef READWRITE_SIGNALLING
188int priv_read_fd;
189int priv_write_fd;
190int nonp_read_fd;
191int nonp_write_fd;
192# endif
193
194enum privileged_action {
195 PA_UNKNOWN = 0,
196
197 PA_SETUP,
198
199 PA_DIE,
200
201 PA_LSTAT64,
202
203 PA_FTS_OPEN,
204 PA_FTS_READ,
205 PA_FTS_CLOSE,
206
207 PA_INOTIFY_INIT,
208 PA_INOTIFY_INIT1,
209 PA_INOTIFY_ADD_WATCH,
210 PA_INOTIFY_RM_WATCH,
211
212 PA_FORK_EXECVP,
213
214 PA_KILL_CHILD,
215
216 PA_CLSYNC_CGROUP_DEINIT,
217
218 PA_WAITPID,
219};
220
221struct pa_lstat64_arg {
222 char path_buf[PATH_MAX];
223 const char *path;
224};
225
226struct pa_fts_open_arg {
227 char _path_argv[MAXARGUMENTS + 1][PATH_MAX];
228 char *path_argv[MAXARGUMENTS + 1];
229 char *const *path_argv_p;
230 int options;
231 int ( *compar ) ( const FTSENT **, const FTSENT ** );
232};
233
234struct pa_inotify_add_watch_arg {
235 int fd;
236 char pathname[PATH_MAX];
237 const char *pathname_p;
238 uint32_t mask;
239};
240
241struct pa_inotify_rm_watch_arg {
242 int fd;
243 int wd;
244};
245
246struct pa_fork_execvp_arg {
247 char file[PATH_MAX];
248 const char *file_p;
249 char _argv[MAXARGUMENTS + 1][BUFSIZ];
250 char *argv[MAXARGUMENTS + 1];
251 char *const *argv_p;
252};
253
254struct pa_kill_child_arg {
255 pid_t pid;
256 int signal;
257 char ignoreerrors;
258};
259
260struct pa_waitpid_arg {
261 pid_t pid;
262 int status;
263 int options;
264};
265
266struct pa_arg {
267 struct pa_lstat64_arg lstat64;
268 struct pa_fts_open_arg fts_open;
269 struct pa_inotify_add_watch_arg inotify_add_watch;
270 struct pa_inotify_rm_watch_arg inotify_rm_watch;
271 struct pa_fork_execvp_arg fork_execvp;
272 struct pa_kill_child_arg kill_child;
273 struct pa_waitpid_arg waitpid;
274 void *void_v;
275 ctx_t *ctx_p;
276 uint32_t uint32_v;
277};
278
279# ifdef HL_LOCKS
280enum highload_lock_id {
281 HLLOCK_HANDLER = 0,
282
283 HLLOCK_MAX
284};
285typedef enum highload_lock_id hllockid_t;
286
287enum highlock_lock_state {
288 HLLS_UNREADY = 0x00,
289 HLLS_READY = 0x01,
290 HLLS_FALLBACK = 0x02,
291 HLLS_SIGNAL = 0x04,
292 HLLS_GOTSIGNAL = 0x08,
293 HLLS_WORKING = 0x10,
294};
295typedef enum highlock_lock_state hllock_state_t;
296
297struct hl_lock {
298 volatile int locallock_hl_setstate_ifstate;
299 volatile int enabled;
300 volatile int count_wait[HLLOCK_MAX];
301 volatile int count_signal[HLLOCK_MAX];
302 volatile hllock_state_t state[HLLOCK_MAX];
303# ifdef HL_LOCK_TRIES_AUTO
304 volatile unsigned long tries[PC_MAX];
305 volatile unsigned long count[PC_MAX];
306 volatile unsigned long delay[PC_MAX];
307 volatile double tries_step[PC_MAX];
308
309# define tries_cur tries[callid]
310# else
311 volatile unsigned long tries;
312# define tries_cur tries
313# endif
314};
315# endif
316
317struct pa_fts_read_ret {
318 FTSENT ftsent;
319 char fts_accpath[PATH_MAX];
320 char fts_path[PATH_MAX];
321 char fts_name[PATH_MAX];
322};
323struct pa_ret {
324 stat64_t stat64;
325 struct pa_fts_read_ret fts_read;
326};
327struct cmd {
328 volatile struct pa_arg arg;
329 volatile enum privileged_action action;
330# ifdef HL_LOCKS
331 volatile unsigned long hl_lock_tries;
332# endif
333};
334struct cmd_ret {
335 volatile struct pa_ret ret_buf;
336 volatile void *ret;
337 volatile int _errno;
338 volatile int processing_longcmd;
339};
340volatile struct cmd *cmd_p;
341volatile struct cmd_ret *cmd_ret_p;
342# ifdef HL_LOCKS
343volatile struct hl_lock *hl_lock_p;
344# endif
345
346# ifdef HL_LOCKS
347static inline void hl_lock_init ( volatile struct hl_lock *hl_lock_p )
348{
349 debug ( 10, "" );
350 hl_lock_p->enabled = 1;
351 hl_lock_p->locallock_hl_setstate_ifstate = 1;
352# ifdef HL_LOCK_TRIES_AUTO
353 int i;
354 i = 0;
355
356 while ( i < PC_MAX ) {
357 hl_lock_p->tries[i] = HL_LOCK_TRIES_INITIAL;
358 hl_lock_p->delay[i] = ( ( unsigned long ) ~0 ) >> 2;
359 hl_lock_p->tries_step[i] = HL_LOCK_AUTO_K;
360 i++;
361 }
362
363# else
364 hl_lock_p->tries = HL_LOCK_TRIES_INITIAL;
365# endif
366 return;
367}
368# endif
369
370struct pa_options {
372 char *label;
373 char *exithookfile;
374 char *preexithookfile;
375 char *permitted_hookfile[MAXPERMITTEDHOOKFILES + 1];
376 int permitted_hookfiles;
377 int isprocsplitting;
378 int shm_mprotect;
379};
380
381int ( *_privileged_lstat64 ) (
382 const char *path, stat64_t *buf
383# ifdef HL_LOCK_TRIES_AUTO
384 , int callid
385# endif
386);
387
388FTS * ( *_privileged_fts_open ) (
389 char * const *path_argv,
390 int options,
391 int ( *compar ) ( const FTSENT **, const FTSENT ** )
392# ifdef HL_LOCK_TRIES_AUTO
393 , int callid
394# endif
395);
396
397FTSENT * ( *_privileged_fts_read ) (
398 FTS *ftsp
399# ifdef HL_LOCK_TRIES_AUTO
400 , int callid
401# endif
402);
403
404int ( *_privileged_fts_close ) (
405 FTS *ftsp
406# ifdef HL_LOCK_TRIES_AUTO
407 , int callid
408# endif
409);
410
411int ( *_privileged_inotify_init ) ();
412int ( *_privileged_inotify_init1 ) ( int flags );
413
414int ( *_privileged_inotify_add_watch ) (
415 int fd,
416 const char *pathname,
417 uint32_t mask
418# ifdef HL_LOCK_TRIES_AUTO
419 , int callid
420# endif
421);
422
423int ( *_privileged_inotify_rm_watch ) (
424 int fd,
425 int wd
426);
427
428int ( *_privileged_clsync_cgroup_deinit ) ( ctx_t *ctx_p );
429
430pid_t ( *_privileged_waitpid ) ( pid_t pid, int *status, int options );
431
432int cap_enable ( __u32 caps )
433{
434 debug ( 1, "Enabling Linux capabilities 0x%x", caps );
435 struct __user_cap_header_struct cap_hdr = {0};
436 struct __user_cap_data_struct cap_dat = {0};
437 cap_hdr.version = _LINUX_CAPABILITY_VERSION;
438
439 if ( capget ( &cap_hdr, &cap_dat ) < 0 ) {
440 error ( "Cannot get capabilities with capget()" );
441 return errno;
442 }
443
444 debug ( 3, "old: cap.eff == 0x%04x; new: cap.eff == 0x%04x", cap_dat.effective, cap_dat.effective | caps );
445 cap_dat.effective |= caps;
446
447 if ( capset ( &cap_hdr, &cap_dat ) < 0 ) {
448 error ( "Cannot set capabilities with capset()." );
449 return errno;
450 }
451
452 return 0;
453}
454
455int cap_drop ( ctx_t *ctx_p, __u32 caps )
456{
457 debug ( 1, "Dropping all Linux capabilities but 0x%x", caps );
458 struct __user_cap_header_struct cap_hdr = {0};
459 struct __user_cap_data_struct cap_dat = {0};
460 cap_hdr.version = _LINUX_CAPABILITY_VERSION;
461
462 if ( capget ( &cap_hdr, &cap_dat ) < 0 ) {
463 error_or_debug ( ( ctx_p->flags[CAP_PRESERVE] != CAP_PRESERVE_TRY ) ? -1 : 3, "Cannot get capabilities with capget()" );
464 return errno;
465 }
466
467 debug ( 3, "old: cap.eff == 0x%04x; cap.prm == 0x%04x; cap.inh == 0x%04x.",
468 cap_dat.effective, cap_dat.permitted, cap_dat.inheritable );
469
470 switch ( ctx_p->flags[CAPS_INHERIT] ) {
471 case CI_PERMITTED:
472 cap_dat.inheritable = cap_dat.permitted;
473 break;
474
475 case CI_DONTTOUCH:
476 break;
477
478 case CI_CLSYNC:
479 cap_dat.inheritable = caps;
480 break;
481
482 case CI_EMPTY:
483 cap_dat.inheritable = 0;
484 break;
485 }
486
487 cap_dat.effective = caps;
488 cap_dat.permitted = caps;
489 debug ( 3, "new: cap.eff == 0x%04x; cap.prm == 0x%04x; cap.inh == 0x%04x.",
490 cap_dat.effective, cap_dat.permitted, cap_dat.inheritable );
491
492 if ( capset ( &cap_hdr, &cap_dat ) < 0 ) {
493 error_or_debug ( ( ctx_p->flags[CAP_PRESERVE] != CAP_PRESERVE_TRY ) ? -1 : 3, "Cannot set capabilities with capset()." );
494 return errno;
495 }
496
497 return 0;
498}
499
500#endif
501int __privileged_kill_child_itself ( pid_t child_pid, int signal, char ignoreerrors )
502{
503 // Checking if it's a child
504 if ( waitpid ( child_pid, NULL, WNOHANG ) >= 0 ) {
505 debug ( 3, "Sending signal %u to child process with pid %u.",
506 signal, child_pid );
507
508 if ( kill ( child_pid, signal ) ) {
509 if ( !ignoreerrors )
510 error ( "Got error while kill(%u, %u)", child_pid, signal );
511
512 return errno;
513 }
514
515 waitpid_timed ( child_pid, NULL, SLEEP_SECONDS, 0 );
516 } else
517 return ENOENT;
518
519 return 0;
520}
521#ifdef CAPABILITIES_SUPPORT
522
523int pa_strcmp ( const char *s1, const char *s2, int isexpanded )
524{
525 if ( isexpanded )
526 return strcmp ( s1, s2 );
527
528 {
529 const char *s1_start = NULL;
530 const char *s2_start = NULL;
531
532 while ( 1 ) {
533 while ( 1 ) {
534 if ( !*s1 || !*s2 ) {
535 if ( !*s1 && s1_start != NULL )
536 return 0;
537
538 return *s1 != *s2;
539 }
540
541 if ( *s1 == '%' ) {
542 s1++;
543
544 while ( *s1 && *s1 != '%' ) s1++;
545
546 s1++;
547 s1_start = s1;
548 s2_start = s2;
549 continue;
550 }
551
552 if ( *s1 != *s2 )
553 break;
554
555 s1++;
556 s2++;
557 }
558
559 if ( s2_start == NULL )
560 break;
561
562 s2_start++;
563 s1 = s1_start;
564 s2 = s2_start;
565 }
566
567 return *s1 != *s2;
568 }
569}
570
571int privileged_execvp_check_arguments ( struct pa_options *opts, const char *u_file, char *const *u_argv )
572{
573 int a_i;
574 size_t u_argc;
575 synchandler_args_t *args = opts->args;
576 debug ( 9, "" );
577 // Counting the number of arguments
578 u_argc = 0;
579
580 while ( u_argv[u_argc] != NULL ) u_argc++;
581
582 a_i = 0;
583
584 do {
585 size_t argc, i;
586 char **argv;
587 char *isexpanded;
588 argc = args[a_i].c;
589 argv = args[a_i].v;
590 isexpanded = args[a_i].isexpanded;
591 debug ( 8, "Checking the number of arguments: %i <> %i", argc, u_argc );
592
593 if ( argc != u_argc )
594 continue;
595
596 critical_on ( !argc );
597 debug ( 8, "Checking the execution file: \"%s\" <> \"%s\"; isexpanded == %i", argv[0], u_file, isexpanded[0] );
598
599 if ( pa_strcmp ( argv[0], u_file, isexpanded[0] ) ) {
600 debug ( 1, "The file to be executed didn't match (argv[0] != u_file): \"%s\" != \"%s\"", argv[0], u_file );
601 break;
602 }
603
604 debug ( 8, "Checking arguments" );
605 i = 1;
606
607 while ( i < argc ) {
608 if ( pa_strcmp ( argv[i], u_argv[i], isexpanded[i] ) ) {
609 debug ( 1, "An argument #%i didn't match (argv[%i] != u_argv[%i]): \"%s\" != \"%s\"", argv[i], argv[i] );
610 break;
611 }
612
613 i++;
614 }
615
616 // All arguments right?
617 if ( i == argc )
618 break;
619
620 // No? Ok the next "shargs".
621 } while ( ++a_i < SHARGS_MAX );
622
623 if ( a_i < SHARGS_MAX )
624 return 0;
625
626 if ( u_argc == 2 ) {
627 int i;
628
629 if ( ( opts->exithookfile != NULL ) || ( opts->preexithookfile != NULL ) ) {
630 if ( !strcmp ( opts->label, u_argv[1] ) ) {
631 if ( opts->exithookfile != NULL )
632 if ( !strcmp ( opts->exithookfile, u_file ) )
633 return 0;
634
635 if ( opts->preexithookfile != NULL )
636 if ( !strcmp ( opts->preexithookfile, u_file ) )
637 return 0;
638 }
639 }
640
641 i = 0;
642
643 while ( i < opts->permitted_hookfiles ) {
644 if ( !strcmp ( opts->permitted_hookfile[i], u_file ) )
645 return 0;
646
647 i++;
648 }
649 }
650
651 debug ( 1, "a_i == %i; SHARGS_MAX == %i; u_argc == %i", SHARGS_MAX, a_i, u_argc );
652 critical ( "Arguments are wrong. This should happen only on hacking attack." );
653 return EPERM;
654}
655
656int pa_setup ( struct pa_options *opts, ctx_t *ctx_p, uid_t *exec_uid_p, gid_t *exec_gid_p )
657{
658 synchandler_args_t *args = opts->args;
659 int a_i;
660 a_i = 0;
661
662 do {
663 int i, argc_s;
664 char **argv_s, **argv_d, *isex_s, *isex_d;
665 argc_s = ctx_p->synchandler_args[a_i].c;
666 argv_s = ctx_p->synchandler_args[a_i].v;
667 isex_s = ctx_p->synchandler_args[a_i].isexpanded;
668 argv_d = args[a_i].v;
669 isex_d = args[a_i].isexpanded;
670
671 if ( argc_s >= MAXARGUMENTS )
672 critical ( "Too many arguments" );
673
674 if ( argc_s < 1 )
675 continue;
676
677 argv_d[0] = strdup_protect ( ctx_p->handlerfpath, PROT_READ );
678 i = 0;
679
680 while ( i < argc_s ) {
681 argv_d[i + 1] = strdup_protect ( argv_s[i], PROT_READ );
682 isex_d[i + 1] = isex_s[i];
683 i++;
684 }
685
686 i++;
687 argv_d[i] = NULL;
688 args[a_i].c = i;
689 a_i++;
690 } while ( ++a_i < SHARGS_MAX );
691
692 *exec_uid_p = ctx_p->synchandler_uid;
693 *exec_gid_p = ctx_p->synchandler_gid;
694 opts->label = strdup_protect ( ctx_p->label, PROT_READ );
695
696 if ( ctx_p->exithookfile != NULL )
697 opts->exithookfile = strdup_protect ( ctx_p->exithookfile, PROT_READ );
698
699 if ( ctx_p->preexithookfile != NULL )
700 opts->preexithookfile = strdup_protect ( ctx_p->preexithookfile, PROT_READ );
701
702 {
703 int i = 0;
704
705 while ( i < ctx_p->permitted_hookfiles ) {
706 opts->permitted_hookfile[i] = strdup_protect ( ctx_p->permitted_hookfile[i], PROT_READ );
707 i++;
708 }
709
710 opts->permitted_hookfile[i] = NULL;
711 opts->permitted_hookfiles = i;
712 }
713 return 0;
714}
715
716int pa_unsetup ( struct pa_options *opts )
717{
718 ( void ) opts;
719#ifdef TODO_FIX
720 // segfaults: gdb --args clsync -K lxc-brother-atomic-sync -l jabber --pre-exit-hook wlxc-stop --chroot= --pivot-root=off -d9 -b0 -Ystderr
721 free ( opts->exithookfile );
722 free ( opts->preexithookfile );
723 free ( opts->label );
724 {
725 int a_i = 0;
726
727 do {
728 int i;
729 i = 0;
730
731 while ( i < opts->args[a_i].c ) {
732 free ( opts->args[a_i].v[i] );
733 i++;
734 }
735 } while ( ++a_i < SHARGS_MAX );
736 }
737 {
738 int i = 0;
739
740 while ( i < opts->permitted_hookfiles ) {
741 free ( opts->permitted_hookfile[i] );
742 i++;
743 }
744 }
745#endif
746 return 0;
747}
748
749static int helper_isalive_cache;
750static inline int helper_isalive_proc()
751{
752 int rc;
753 debug ( 12, "helper_pid == %u", helper_pid );
754
755 if ( ( rc = waitpid ( helper_pid, NULL, WNOHANG ) ) >= 0 )
756 return helper_isalive_cache = 1;
757
758 debug ( 1, "waitpid(%u, NULL, WNOHANG) => %i", helper_pid, rc );
759 return helper_isalive_cache = 0;
760}
761static inline int helper_isalive_thread()
762{
763 int rc;
764 debug ( 12, "" );
765
766 if ( ( rc = pthread_kill ( privileged_thread, 0 ) ) )
767 return helper_isalive_cache = 0;
768
769 debug ( 1, "pthread_kill(privileged_thread, 0) => %i", helper_pid, rc );
770 return helper_isalive_cache = 1;
771}
772static inline int helper_isalive()
773{
774 return helper_pid ? helper_isalive_proc() : helper_isalive_thread();
775}
776
778{
779 if ( helper_pid )
780 critical_on ( !helper_isalive_proc() );
781
782 return 0;
783}
784
785# ifdef HL_LOCKS
786
787static inline int hl_isanswered ( int lockid )
788{
789 return hl_lock_p->count_wait[lockid] == hl_lock_p->count_signal[lockid] + 1;
790}
791
792static inline int hl_isready ( int lockid )
793{
794 return hl_lock_p->count_wait[lockid] == hl_lock_p->count_signal[lockid];
795}
796
797static inline void hl_setstate ( int lockid, hllock_state_t stateid )
798{
799 g_atomic_int_set ( &hl_lock_p->state[lockid], stateid );
800}
801
802int hl_setstate_ifstate ( int lockid, hllock_state_t stateid_new, hllock_state_t stateid_old_mask )
803{
804 static long long counter = 0;
805 volatile int *local_lock_p = &hl_lock_p->locallock_hl_setstate_ifstate;
806 debug ( 90, "%i, 0x%o, 0x%o", lockid, stateid_new, stateid_old_mask );
807
808 if ( helper_pid || parent_pid ) {
809 if ( ( ( ++counter ) & 0xffffff ) == 0 ) {
810 if ( helper_pid ) {
811 critical_on ( !helper_isalive_proc() );
812 } else {
814 }
815 }
816 }
817
818 if ( !g_atomic_int_dec_and_test ( local_lock_p ) ) {
819 g_atomic_int_inc ( local_lock_p );
820 return 0;
821 }
822
823 if ( ! ( hl_lock_p->state[lockid]&stateid_old_mask ) ) {
824 g_atomic_int_inc ( local_lock_p );
825 return 0;
826 }
827
828 debug ( 50, "success" );
829 g_atomic_int_set ( &hl_lock_p->state[lockid], stateid_new );
830 g_atomic_int_inc ( local_lock_p );
831 return 1;
832}
833
834static inline int hl_wait (
835 int lockid
836# ifdef HL_LOCK_TRIES_AUTO
837 , unsigned long hl_lock_tries
838# endif
839)
840{
841
842 volatile unsigned long try = 0;
843
844 debug ( 15, "" );
845
846 while ( hl_lock_p->state[lockid] == HLLS_GOTSIGNAL );
847
848 while ( !hl_isready ( lockid ) );
849
850 hl_setstate ( lockid, HLLS_READY );
851 hl_lock_p->count_wait[lockid]++;
852
853 while ( try++ < hl_lock_tries )
854 if ( hl_lock_p->state[lockid] == HLLS_SIGNAL ) {
855 hl_setstate ( lockid, HLLS_GOTSIGNAL );
856 debug ( 15, "got signal" );
857 return 1;
858 }
859
860 while ( !hl_setstate_ifstate ( lockid, HLLS_FALLBACK, HLLS_READY | HLLS_SIGNAL ) );
861
862 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] );
863 return 0;
864}
865
866static inline int hl_signal ( int lockid )
867{
868 debug ( 15, "%u", lockid );
869 hl_lock_p->count_signal[lockid]++;
870
871 if ( hl_setstate_ifstate ( lockid, HLLS_SIGNAL, HLLS_READY ) ) {
872 while ( hl_lock_p->state[lockid] != HLLS_GOTSIGNAL ) {
873 if ( hl_lock_p->state[lockid] == HLLS_FALLBACK ) {
874 debug ( 15, "fallback" );
875 return 0;
876 }
877
878 debug ( 95, "state == %i != %i, %i", hl_lock_p->state[lockid], HLLS_GOTSIGNAL, HLLS_FALLBACK );
879 }
880
881 debug ( 15, "the signal is sent" );
882 hl_setstate ( lockid, HLLS_WORKING );
883 return 1;
884 }
885
886 debug ( 15, "not ready" );
887 return 0;
888}
889
890void hl_shutdown ( int lockid )
891{
892 debug ( 1, "" );
893# ifdef PARANOID
894 critical_on ( HLLOCK_MAX != 1 ); // TODO: do this on compile time (not on running time)
895# ifdef HL_LOCK_TRIES_AUTO
896 memset ( ( void * ) hl_lock_p->tries, 0, sizeof ( hl_lock_p->tries ) );
897# else
898 hl_lock_p->tries = 0;
899# endif
900# endif
901 hl_lock_p->state[lockid] = HLLS_FALLBACK;
902 hl_lock_p->enabled = 0;
903 return;
904}
905
906# endif
907
908int privileged_handler ( ctx_t *ctx_p )
909{
910# ifdef READWRITE_SIGNALLING
911 char buf[1] = {0};
912# else
913 struct timespec wait_timeout = {0};
914# endif
915 int setup = 0;
916 uid_t exec_uid = 65535;
917 gid_t exec_gid = 65535;
918 struct pa_options *opts;
919 int use_args_check = 0;
920 int helper_isrunning = 1;
921 opts = calloc_align ( 1, sizeof ( *opts ) );
922 opts->isprocsplitting = ( ctx_p->flags[SPLITTING] == SM_PROCESS );
923 opts->shm_mprotect = ctx_p->flags[SHM_MPROTECT];
924
925 if ( opts->isprocsplitting ) {
926 sigset_t sigset;
927 sigemptyset ( &sigset );
928 /* Do not uncomment this. This causes handler closing on any terminal
929 signal to parent process. In turn it causes: https://github.com/clsync/clsync/issues/104
930
931 sigaddset(&sigset, SIGALRM);
932 sigaddset(&sigset, SIGHUP);
933 sigaddset(&sigset, SIGQUIT);
934 sigaddset(&sigset, SIGTERM);
935 sigaddset(&sigset, SIGINT);
936 */
937# ifndef __linux__
938# error There's no automatical mechanism that guarantees handler closing on non-linux. Don't use process splitting!
939# endif
940# ifdef __linux__
941 sigaddset ( &sigset, SIGCHLD );
942# endif
943 critical_on ( pthread_sigmask ( SIG_UNBLOCK, &sigset, NULL ) );
944# ifndef __linux__
946# endif
947 } else {
949 pthread_setname_np ( pthread_self(), "clsync-helper" );
950 }
951
952 cap_drop ( ctx_p, ctx_p->caps );
953 debug ( 2, "Syncing with the runner" );
954 pthread_mutex_lock ( pthread_mutex_privileged_p );
955 // Waiting for runner to get ready for signal
956 pthread_mutex_lock ( pthread_mutex_runner_p );
957 pthread_mutex_unlock ( pthread_mutex_runner_p );
958 // Sending the signal that we're ready
959 pthread_cond_signal ( pthread_cond_runner_p );
960 // The loop
961 debug ( 2, "Running the loop" );
962
963 while ( helper_isrunning ) {
964 errno = 0;
965 // Waiting for command
966 debug ( 10, "Waiting for command" );
967
968 if ( opts->shm_mprotect ) {
969 mprotect ( ( void * ) cmd_p, sizeof ( *cmd_p ), PROT_WRITE );
970 mprotect ( ( void * ) cmd_ret_p, sizeof ( *cmd_ret_p ), PROT_READ );
971 }
972
973# ifdef HL_LOCKS
974 debug ( 25, "hl_lock_p->enabled == %i", hl_lock_p->enabled );
975
976 if ( !hl_lock_p->enabled || !hl_wait (
977 HLLOCK_HANDLER
978# ifdef HL_LOCK_TRIES_AUTO
979 , hl_lock_p->tries[HLLOCK_HANDLER]
980# endif
981 ) ) {
982 if ( opts->isprocsplitting )
984
985# endif
986# ifdef READWRITE_SIGNALLING
987# warning READWRITE_SIGNALLING can cause process hanging on clsync shutdown
988 read_inf ( priv_read_fd, buf, 1 );
989# else
990 int rc;
991
992 while ( 1 ) {
993 rc = pthread_cond_timedwait ( pthread_cond_privileged_p, pthread_mutex_privileged_p, &wait_timeout );
994
995 if ( !rc )
996 break;
997
998 if ( rc != ETIMEDOUT )
999 critical ( "Got error while pthread_cond_timedwait()" );
1000
1001 debug ( 10, "pthread_cond_timedwait() timed out" );
1002
1003 if ( opts->isprocsplitting )
1004 exit_on ( !parent_isalive() );
1005
1006 {
1007 debug ( 20, "Resetting wait_timeout" );
1008 struct timeval now;
1009 gettimeofday ( &now, NULL );
1010 wait_timeout.tv_sec = now.tv_sec + SLEEP_SECONDS;
1011 wait_timeout.tv_nsec = now.tv_usec * 1000;
1012 }
1013 }
1014
1015# endif
1016# ifdef HL_LOCKS
1017
1018 if ( hl_lock_p->enabled )
1019 hl_setstate ( HLLOCK_HANDLER, HLLS_WORKING );
1020 }
1021
1022# endif
1023
1024 if ( opts->shm_mprotect ) {
1025 mprotect ( ( void * ) cmd_p, sizeof ( *cmd_p ), PROT_READ );
1026 mprotect ( ( void * ) cmd_ret_p, sizeof ( *cmd_ret_p ), PROT_WRITE );
1027 }
1028
1029 debug ( 10, "Got command %u (euid:egid => %i:%i)", cmd_p->action, geteuid(), getegid() );
1030
1031 if ( !setup && cmd_p->action != PA_SETUP )
1032 critical ( "A try to use commands before PA_SETUP" );
1033
1034 switch ( cmd_p->action ) {
1035 case PA_SETUP: {
1036 debug ( 20, "PA_SETUP" );
1037
1038 if ( setup )
1039 critical ( "Double privileged_handler setuping. It can be if somebody is trying to hack the clsync." );
1040
1041 critical_on ( pa_setup ( opts, cmd_p->arg.ctx_p, &exec_uid, &exec_gid ) );
1042 mprotect ( opts, sizeof ( *opts ), PROT_READ );
1043 use_args_check = cmd_p->arg.ctx_p->flags[CHECK_EXECVP_ARGS];
1044 cap_drop ( ctx_p, ctx_p->caps ); // TODO: Find out why "permission denined" without this line
1045 setup++;
1046 critical_on ( errno );
1047 break;
1048 }
1049
1050 case PA_DIE:
1051 debug ( 20, "PA_DIE" );
1052 helper_isrunning = 0;
1053 break;
1054
1055 case PA_LSTAT64: {
1056 volatile struct pa_lstat64_arg *arg_p = &cmd_p->arg.lstat64;
1057 stat64_t *ret_buf = ( void * ) &cmd_ret_p->ret_buf.stat64;
1058 volatile const char *path = opts->isprocsplitting ?
1059 arg_p->path_buf :
1060 arg_p->path;
1061 debug ( 20, "PA_LSTAT64 (%s)", path );
1062 cmd_ret_p->ret = ( void * ) ( long ) lstat64 ( ( const char * ) path, ret_buf );
1063 debug ( 21, "/PA_LSTAT64 => %i", ( int ) ( long ) cmd_ret_p->ret );
1064 break;
1065 }
1066
1067 case PA_FTS_OPEN: {
1068 volatile struct pa_fts_open_arg *arg_p = &cmd_p->arg.fts_open;
1069 char *const *path_argv_p = ( void * ) (
1070 opts->isprocsplitting ?
1071 arg_p->path_argv :
1072 arg_p->path_argv_p
1073 );
1074 debug ( 20, "PA_FTS_OPEN (%s)", *path_argv_p );
1075
1076 if ( arg_p->compar != NULL )
1077 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 );
1078
1079 cmd_ret_p->ret = fts_open ( path_argv_p, arg_p->options, NULL );
1080 debug ( 21, "/PA_FTS_OPEN => %p", cmd_ret_p->ret );
1081 break;
1082 }
1083
1084 case PA_FTS_READ: {
1085 debug ( 20, "PA_FTS_READ(%p)", cmd_p->arg.void_v );
1086 FTSENT *ret = fts_read ( cmd_p->arg.void_v );
1087
1088 if ( ret == NULL ) {
1089 cmd_ret_p->ret = NULL;
1090 debug ( 10, "cmd_ret_p->ret == NULL" );
1091 break;
1092 }
1093
1094 if ( !opts->isprocsplitting ) { // Is the thread-splitting?
1095 cmd_ret_p->ret = ret;
1096 break;
1097 }
1098
1099 {
1100 // Is the process splitting?
1101 struct pa_fts_read_ret *ret_buf = ( void * ) &cmd_ret_p->ret_buf.fts_read;
1102 memcpy ( &ret_buf->ftsent, ret, sizeof ( ret_buf->ftsent ) );
1103 cmd_ret_p->ret = &ret_buf->ftsent;
1104 debug ( 25, "fts_path == <%s>", ret_buf->fts_path );
1105 xstrncpy ( ret_buf->fts_accpath, ret->fts_accpath, sizeof ( ret_buf->fts_accpath ) );
1106 xstrncpy ( ret_buf->fts_path, ret->fts_path, sizeof ( ret_buf->fts_path ) );
1107 ret_buf->ftsent.fts_accpath = ret_buf->fts_accpath;
1108 ret_buf->ftsent.fts_path = ret_buf->fts_path;
1109 }
1110
1111 break;
1112 }
1113
1114 case PA_FTS_CLOSE:
1115 debug ( 20, "PA_FTS_CLOSE" );
1116 cmd_ret_p->ret = ( void * ) ( long ) fts_close ( cmd_p->arg.void_v );
1117 break;
1118
1119 case PA_INOTIFY_INIT:
1120 debug ( 20, "PA_INOTIFY_INIT" );
1121 cmd_ret_p->ret = ( void * ) ( long ) inotify_init();
1122 break;
1123
1124 case PA_INOTIFY_INIT1:
1125 debug ( 20, "PA_INOTIFY_INIT1" );
1126 cmd_ret_p->ret = ( void * ) ( long ) inotify_init1 ( cmd_p->arg.uint32_v );
1127 break;
1128
1129 case PA_INOTIFY_ADD_WATCH: {
1130 struct pa_inotify_add_watch_arg *arg_p = ( void * ) &cmd_p->arg.inotify_add_watch;
1131 const char *pathname = ( opts->isprocsplitting ? arg_p->pathname : arg_p->pathname_p );
1132 debug ( 20, "PA_INOTIFY_ADD_WATCH(%u, <%s>, 0x%o)", arg_p->fd, pathname, arg_p->mask );
1133 cmd_ret_p->ret = ( void * ) ( long ) inotify_add_watch ( arg_p->fd, pathname, arg_p->mask );
1134 break;
1135 }
1136
1137 case PA_INOTIFY_RM_WATCH: {
1138 debug ( 20, "PA_INOTIFY_RM_WATCH" );
1139 struct pa_inotify_rm_watch_arg *arg_p = ( void * ) &cmd_p->arg.inotify_rm_watch;
1140 cmd_ret_p->ret = ( void * ) ( long ) inotify_rm_watch ( arg_p->fd, arg_p->wd );
1141 break;
1142 }
1143
1144 case PA_FORK_EXECVP: {
1145 struct pa_fork_execvp_arg *arg_p = ( void * ) &cmd_p->arg.fork_execvp;
1146 const char *file;
1147 char *const *argv;
1148
1149 if ( opts->isprocsplitting ) {
1150 file = arg_p->file;
1151 argv = arg_p->argv;
1152 } else {
1153 file = arg_p->file_p;
1154 argv = arg_p->argv_p;
1155 }
1156
1157 debug ( 20, "PA_FORK_EXECVP (\"%s\", argv)", file );
1158
1159 if ( use_args_check )
1160 privileged_execvp_check_arguments ( opts, file, argv );
1161
1162 pid_t pid = fork();
1163
1164 switch ( pid ) {
1165 case -1:
1166 error ( "Cannot fork()." );
1167 break;
1168
1169 case 0: {
1170 int rc;
1171 ( void ) rc; // anti-warning on ./configure --enable-debug=no
1172#ifdef ANTIPARANOID
1173
1174 if ( ctx_p->privileged_gid != exec_gid )
1175#endif
1176 {
1177 rc = setgid ( exec_gid );
1178 debug ( 4, "setgid(%u) == %i", exec_gid, rc );
1179 }
1180
1181#ifdef ANTIPARANOID
1182
1183 if ( ctx_p->privileged_uid != exec_uid )
1184#endif
1185 {
1186 rc = setuid ( exec_uid );
1187 debug ( 4, "setuid(%u) == %i", exec_uid, rc );
1188 }
1189
1190 debug ( 3, "execvp(\"%s\", argv)", file );
1191 exit ( execvp ( file, argv ) );
1192 }
1193 }
1194
1195 cmd_ret_p->ret = ( void * ) ( long ) pid;
1196 debug ( 21, "/PA_FORK_EXECVP" );
1197 break;
1198 }
1199
1200 case PA_KILL_CHILD: {
1201 debug ( 20, "PA_KILL_CHILD" );
1202 struct pa_kill_child_arg *arg_p = ( void * ) &cmd_p->arg.kill_child;
1203 cmd_ret_p->ret = ( void * ) ( long ) __privileged_kill_child_itself ( arg_p->pid, arg_p->signal, arg_p->ignoreerrors );
1204 break;
1205 }
1206
1207# ifdef CGROUP_SUPPORT
1208
1209 case PA_CLSYNC_CGROUP_DEINIT: {
1210 debug ( 20, "PA_CLSYNC_CGROUP_DEINIT" );
1211 /*
1212 * That is strange, but setuid() doesn't work
1213 * without fork() in case of enabled seccomp
1214 * filter. So sorry for this hacky thing.
1215 *
1216 * TODO: fix that.
1217 */
1218 int status;
1219 pid_t pid = fork();
1220
1221 switch ( pid ) {
1222 case -1:
1223 error ( "Cannot fork()." );
1224 break;
1225
1226 case 0:
1227 debug ( 4, "setgid(0) == %i", setgid ( 0 ) );
1228 debug ( 4, "setuid(0) == %i", setuid ( 0 ) );
1229 exit ( clsync_cgroup_deinit ( cmd_p->arg.void_v ) );
1230 }
1231
1232 if ( waitpid ( pid, &status, 0 ) != pid ) {
1233 switch ( errno ) {
1234 case ECHILD:
1235 debug ( 2, "Child %u has already died.", pid );
1236 break;
1237
1238 default:
1239 error ( "Cannot waitid()." );
1240 cmd_ret_p->_errno = errno;
1241 cmd_ret_p->ret = ( void * ) ( long ) errno;
1242 }
1243 }
1244
1245 // Return
1246 int exitcode = WEXITSTATUS ( status );
1247 debug ( 3, "execution completed with exitcode %i", exitcode );
1248 cmd_ret_p->_errno = exitcode;
1249 cmd_ret_p->ret = ( void * ) ( long ) exitcode;
1250 break;
1251 }
1252
1253# endif
1254
1255 case PA_WAITPID: {
1256 struct pa_waitpid_arg *arg_p = ( void * ) &cmd_p->arg.waitpid;
1257 debug ( 20, "PA_WAITPID(%u, 0x%o)", arg_p->pid, arg_p->options );
1258 cmd_ret_p->processing_longcmd = 1;
1259 cmd_ret_p->ret = ( void * ) ( long ) waitpid ( arg_p->pid, &arg_p->status, arg_p->options );
1260 cmd_ret_p->processing_longcmd = 0;
1261 break;
1262 }
1263
1264 default:
1265 critical ( "Unknown command type \"%u\". It's a buffer overflow (which means a security problem) or just an internal error." );
1266 }
1267
1268 cmd_ret_p->_errno = errno;
1269 debug ( 10, "Result: %p, errno: %u. Sending the signal to non-privileged thread/process.", cmd_ret_p->ret, cmd_ret_p->_errno );
1270# ifdef HL_LOCKS
1271
1272 if ( !hl_lock_p->enabled ) {
1273# endif
1274# ifndef __linux__
1276# endif
1277# ifdef READWRITE_SIGNALLING
1278 write_inf ( nonp_write_fd, buf, 1 );
1279# else
1280 critical_on ( pthread_mutex_lock ( pthread_mutex_action_signal_p ) );
1281 critical_on ( pthread_mutex_unlock ( pthread_mutex_action_signal_p ) );
1282 critical_on ( pthread_cond_signal ( pthread_cond_action_p ) );
1283# endif
1284# ifdef HL_LOCKS
1285 }
1286
1287# endif
1288 }
1289
1290 pa_unsetup ( opts );
1291# ifdef HL_LOCKS
1292 hl_shutdown ( HLLOCK_HANDLER );
1293# endif
1294 pthread_mutex_unlock ( pthread_mutex_privileged_p );
1295 debug ( 2, "Finished" );
1296 return 0;
1297}
1298
1299static inline int privileged_action (
1300# ifdef HL_LOCK_TRIES_AUTO
1301 int callid,
1302# endif
1303 enum privileged_action action,
1304 void **ret_p
1305)
1306{
1307 int rc = 0;
1308# ifdef READWRITE_SIGNALLING
1309 char buf[1] = {0};
1310# endif
1311# ifdef HL_LOCK_TRIES_AUTO
1312 clock_t start_ticks;
1313 int isadjusting;
1314# endif
1315# ifdef HL_LOCKS
1316 debug ( 10, "(%u, %p): %i", action, ret_p, hl_lock_p->enabled );
1317# else
1318 debug ( 10, "(%u, %p)", action, ret_p );
1319# endif
1320 pthread_mutex_lock ( pthread_mutex_action_entrance_p );
1321# ifndef READWRITE_SIGNALLING
1322 debug ( 10, "Waiting the privileged thread/process to get prepared for signal" );
1323# ifdef HL_LOCKS
1324
1325 if ( hl_lock_p->enabled ) {
1326 long long counter = 0;
1327
1328 while ( !hl_isanswered ( HLLOCK_HANDLER ) ) {
1329 if ( !helper_isalive_cache ) {
1330 debug ( 1, "The privileged thread/process is dead (#0). Ignoring the command." );
1331 rc = ENOENT;
1332 goto privileged_action_end;
1333 }
1334
1335 if ( cmd_ret_p->processing_longcmd && ++counter > HL_LOCK_NONPRIV_TRIES )
1336 sleep ( SLEEP_SECONDS );
1337 }
1338 } else {
1339# endif
1340 critical_on ( !helper_isalive_cache );
1341 pthread_mutex_lock ( pthread_mutex_privileged_p );
1342 pthread_mutex_unlock ( pthread_mutex_privileged_p );
1343# ifdef HL_LOCKS
1344 }
1345
1346# endif
1347# endif
1348
1349 if ( !helper_isalive_cache ) {
1350 debug ( 1, "The privileged thread/process is dead (#1). Ignoring the command." );
1351 rc = ENOENT;
1352 goto privileged_action_end;
1353 }
1354
1355 cmd_p->action = action;
1356 debug ( 10, "Sending information (action == %i) to the privileged thread/process", action );
1357# ifdef HL_LOCK_TRIES_AUTO
1358 cmd_p->hl_lock_tries = hl_lock_p->tries[callid];
1359
1360 if ( ( isadjusting = hl_lock_p->enabled ) ) {
1361 isadjusting = hl_lock_p->tries[callid];
1362
1363 if ( isadjusting ) {
1364 isadjusting = ( ( double ) fabs ( hl_lock_p->tries_step[callid] - 1 ) > ( double ) HL_LOCK_AUTO_K_FINISH );
1365
1366 if ( isadjusting ) {
1367 isadjusting = ! ( ( ++hl_lock_p->count[callid] ) << ( sizeof ( hl_lock_p->count[callid] ) * CHAR_BIT - HL_LOCK_AUTO_INTERVAL ) );
1368 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] );
1369
1370 if ( isadjusting )
1371 start_ticks = clock();
1372 }
1373 }
1374 }
1375
1376# endif
1377# ifdef HL_LOCKS
1378
1379 if ( action == PA_DIE )
1380 hl_lock_p->enabled = 0;
1381
1382 if ( !hl_lock_p->enabled || !hl_signal ( HLLOCK_HANDLER ) ) {
1383# endif
1384 critical_on ( !helper_isalive_cache );
1385# ifdef READWRITE_SIGNALLING
1386 write_inf ( priv_write_fd, buf, 1 );
1387# else
1388# ifdef HL_LOCKS
1389
1390 if ( hl_lock_p->enabled ) {
1391 debug ( 10, "Waiting the privileged thread/process to get prepared for signal (by fallback)" );
1392 critical_on ( pthread_mutex_lock ( pthread_mutex_privileged_p ) );
1393 critical_on ( pthread_mutex_unlock ( pthread_mutex_privileged_p ) );
1394 } else
1395# endif
1396 critical_on ( pthread_mutex_lock ( pthread_mutex_action_signal_p ) );
1397
1398 critical_on ( pthread_cond_signal ( pthread_cond_privileged_p ) );
1399# endif
1400# ifdef HL_LOCKS
1401 }
1402
1403# endif
1404
1405 if ( action == PA_DIE )
1406 goto privileged_action_end;
1407
1408 debug ( 10, "Waiting for the answer" );
1409# ifdef HL_LOCKS
1410
1411 if ( hl_lock_p->enabled ) {
1412 long long counter = 0;
1413
1414 while ( !hl_isanswered ( HLLOCK_HANDLER ) ) {
1415 if ( !helper_isalive_cache ) {
1416 debug ( 1, "The privileged thread/process is dead (#2). Ignoring the command." );
1417 rc = ENOENT;
1418 goto privileged_action_end;
1419 }
1420
1421 if ( cmd_ret_p->processing_longcmd && ++counter > HL_LOCK_NONPRIV_TRIES )
1422 sleep ( SLEEP_SECONDS );
1423 }
1424
1425# ifdef HL_LOCK_TRIES_AUTO
1426
1427 if ( isadjusting ) {
1428 unsigned long delay = ( long ) clock() - ( long ) start_ticks;
1429 long diff = delay - hl_lock_p->delay[callid];
1430 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 )
1431
1432 if ( diff && ( ( unsigned long ) labs ( diff ) > ( unsigned long ) delay * HL_LOCK_AUTO_THREADHOLD ) ) {
1433 if ( diff > 0 )
1434 hl_lock_p->tries_step[callid] = 1 / ( ( hl_lock_p->tries_step[callid] - 1 ) / HL_LOCK_AUTO_DECELERATION + 1 );
1435
1436 hl_lock_p->delay[callid] = delay;
1437 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] );
1438 }
1439
1440 hl_lock_p->tries[callid] *= hl_lock_p->tries_step[callid];
1441
1442 if ( hl_lock_p->tries[callid] > HL_LOCK_AUTO_LIMIT_HIGH )
1443 hl_lock_p->tries[callid] = HL_LOCK_AUTO_LIMIT_HIGH;
1444
1445 debug ( 14, "hl_lock_p->tries[%i] == %lu", callid, hl_lock_p->tries[callid] );
1446 }
1447
1448# endif
1449 } else {
1450# endif
1451 critical_on ( !helper_isalive_cache );
1452# ifdef READWRITE_SIGNALLING
1453 read_inf ( nonp_read_fd, buf, 1 );
1454# else
1455 critical_on ( pthread_cond_wait ( pthread_cond_action_p, pthread_mutex_action_signal_p ) );
1456# endif
1457# ifdef HL_LOCKS
1458 }
1459
1460# endif
1461
1462 if ( ret_p != NULL )
1463 *ret_p = ( void * ) cmd_ret_p->ret;
1464
1465 errno = cmd_ret_p->_errno;
1466privileged_action_end:
1467 debug ( 10, "Unlocking pthread_mutex_action_*" );
1468# ifndef READWRITE_SIGNALLING
1469# ifdef HL_LOCKS
1470
1471 if ( !hl_lock_p->enabled )
1472# endif
1473 pthread_mutex_unlock ( pthread_mutex_action_signal_p );
1474
1475# endif
1476 pthread_mutex_unlock ( pthread_mutex_action_entrance_p );
1477 return rc;
1478}
1479
1480int __privileged_lstat64_procsplit (
1481 const char *path, stat64_t *buf
1482# ifdef HL_LOCK_TRIES_AUTO
1483 , int callid
1484# endif
1485)
1486{
1487 void *ret = ( void * ) ( long ) - 1;
1488 xstrncpy ( ( char * ) cmd_p->arg.lstat64.path_buf, path, PATH_MAX );
1489 privileged_action (
1490# ifdef HL_LOCK_TRIES_AUTO
1491 callid,
1492# endif
1493 PA_LSTAT64,
1494 &ret
1495 );
1496 memcpy ( buf, ( void * ) &cmd_ret_p->ret_buf.stat64, sizeof ( stat64_t ) );
1497 return ( long ) ret;
1498}
1499
1500int __privileged_lstat64_threadsplit (
1501 const char *path, stat64_t *buf
1502# ifdef HL_LOCK_TRIES_AUTO
1503 , int callid
1504# endif
1505)
1506{
1507 void *ret = ( void * ) ( long ) - 1;
1508 cmd_p->arg.lstat64.path = path;
1509 privileged_action (
1510# ifdef HL_LOCK_TRIES_AUTO
1511 callid,
1512# endif
1513 PA_LSTAT64,
1514 &ret
1515 );
1516 memcpy ( buf, ( void * ) &cmd_ret_p->ret_buf.stat64, sizeof ( stat64_t ) );
1517 return ( long ) ret;
1518}
1519
1520FTS *__privileged_fts_open_procsplit (
1521 char *const *path_argv,
1522 int options,
1523 int ( *compar ) ( const FTSENT **, const FTSENT ** )
1524# ifdef HL_LOCK_TRIES_AUTO
1525 , int callid
1526# endif
1527)
1528{
1529 void *ret = NULL;
1530 int i;
1531 i = 0;
1532
1533 while ( path_argv[i] != NULL ) {
1534 cmd_p->arg.fts_open.path_argv[i] = ( void * ) cmd_p->arg.fts_open._path_argv[i];
1535 debug ( 25, "path_argv[%i] == <%s> (%p) -> %p", i, path_argv[i], path_argv[i], cmd_p->arg.fts_open.path_argv[i] );
1536 xstrncpy ( cmd_p->arg.fts_open.path_argv[i], path_argv[i], sizeof ( cmd_p->arg.fts_open._path_argv[i] ) );
1537 i++;
1538 critical_on ( i >= MAXARGUMENTS );
1539 }
1540
1541 cmd_p->arg.fts_open.path_argv[i] = NULL;
1542 cmd_p->arg.fts_open.options = options;
1543 cmd_p->arg.fts_open.compar = compar;
1544 privileged_action (
1545# ifdef HL_LOCK_TRIES_AUTO
1546 callid,
1547# endif
1548 PA_FTS_OPEN,
1549 &ret
1550 );
1551 return ret;
1552}
1553
1554FTS *__privileged_fts_open_threadsplit (
1555 char *const *path_argv,
1556 int options,
1557 int ( *compar ) ( const FTSENT **, const FTSENT ** )
1558# ifdef HL_LOCK_TRIES_AUTO
1559 , int callid
1560# endif
1561)
1562{
1563 void *ret = NULL;
1564 cmd_p->arg.fts_open.path_argv_p = path_argv;
1565 cmd_p->arg.fts_open.options = options;
1566 cmd_p->arg.fts_open.compar = compar;
1567 privileged_action (
1568# ifdef HL_LOCK_TRIES_AUTO
1569 callid,
1570# endif
1571 PA_FTS_OPEN,
1572 &ret
1573 );
1574 return ret;
1575}
1576
1577FTSENT *__privileged_fts_read (
1578 FTS *ftsp
1579# ifdef HL_LOCK_TRIES_AUTO
1580 , int callid
1581# endif
1582)
1583{
1584 void *ret = NULL;
1585 cmd_p->arg.void_v = ftsp;
1586 privileged_action (
1587# ifdef HL_LOCK_TRIES_AUTO
1588 callid,
1589# endif
1590 PA_FTS_READ,
1591 &ret
1592 );
1593 return ret;
1594}
1595
1596int __privileged_fts_close (
1597 FTS *ftsp
1598# ifdef HL_LOCK_TRIES_AUTO
1599 , int callid
1600# endif
1601)
1602{
1603 void *ret = ( void * ) ( long ) - 1;
1604 cmd_p->arg.void_v = ftsp;
1605 privileged_action (
1606# ifdef HL_LOCK_TRIES_AUTO
1607 callid,
1608# endif
1609 PA_FTS_CLOSE,
1610 &ret
1611 );
1612 return ( long ) ret;
1613}
1614
1615int __privileged_inotify_init()
1616{
1617 void *ret = ( void * ) ( long ) - 1;
1618 privileged_action (
1619# ifdef HL_LOCK_TRIES_AUTO
1620 PC_DEFAULT,
1621# endif
1622 PA_INOTIFY_INIT,
1623 &ret
1624 );
1625 return ( long ) ret;
1626}
1627
1628int __privileged_inotify_init1 ( int flags )
1629{
1630 void *ret = ( void * ) ( long ) - 1;
1631 cmd_p->arg.uint32_v = flags;
1632 privileged_action (
1633# ifdef HL_LOCK_TRIES_AUTO
1634 PC_DEFAULT,
1635# endif
1636 PA_INOTIFY_INIT1,
1637 &ret
1638 );
1639 return ( long ) ret;
1640}
1641
1642int __privileged_inotify_add_watch_threadsplit (
1643 int fd,
1644 const char *pathname,
1645 uint32_t mask
1646# ifdef HL_LOCK_TRIES_AUTO
1647 , int callid
1648# endif
1649)
1650{
1651 debug ( 25, "(%i, <%s>, o%o, ?)", fd, pathname, mask );
1652 void *ret = ( void * ) ( long ) - 1;
1653 cmd_p->arg.inotify_add_watch.pathname_p = pathname;
1654 cmd_p->arg.inotify_add_watch.fd = fd;
1655 cmd_p->arg.inotify_add_watch.mask = mask;
1656 privileged_action (
1657# ifdef HL_LOCK_TRIES_AUTO
1658 callid,
1659# endif
1660 PA_INOTIFY_ADD_WATCH,
1661 &ret
1662 );
1663 return ( long ) ret;
1664}
1665
1666int __privileged_inotify_add_watch_procsplit (
1667 int fd,
1668 const char *pathname,
1669 uint32_t mask
1670# ifdef HL_LOCK_TRIES_AUTO
1671 , int callid
1672# endif
1673)
1674{
1675 debug ( 25, "(%i, <%s>, o%o, ?)", fd, pathname, mask );
1676 void *ret = ( void * ) ( long ) - 1;
1677 xstrncpy ( ( void * ) cmd_p->arg.inotify_add_watch.pathname, pathname, sizeof ( cmd_p->arg.inotify_add_watch.pathname ) );
1678 cmd_p->arg.inotify_add_watch.fd = fd;
1679 cmd_p->arg.inotify_add_watch.mask = mask;
1680 privileged_action (
1681# ifdef HL_LOCK_TRIES_AUTO
1682 callid,
1683# endif
1684 PA_INOTIFY_ADD_WATCH,
1685 &ret
1686 );
1687 return ( long ) ret;
1688}
1689
1690int __privileged_inotify_rm_watch (
1691 int fd,
1692 int wd
1693)
1694{
1695 void *ret = ( void * ) ( long ) - 1;
1696 cmd_p->arg.inotify_rm_watch.fd = fd;
1697 cmd_p->arg.inotify_rm_watch.wd = wd;
1698 privileged_action (
1699# ifdef HL_LOCK_TRIES_AUTO
1700 PC_DEFAULT,
1701# endif
1702 PA_INOTIFY_RM_WATCH,
1703 &ret
1704 );
1705 return ( long ) ret;
1706}
1707
1708# ifdef CGROUP_SUPPORT
1709int __privileged_clsync_cgroup_deinit ( ctx_t *ctx_p )
1710{
1711 void *ret = ( void * ) ( long ) - 1;
1712 cmd_p->arg.ctx_p = ctx_p;
1713 privileged_action (
1714# ifdef HL_LOCK_TRIES_AUTO
1715 PC_DEFAULT,
1716# endif
1717 PA_CLSYNC_CGROUP_DEINIT,
1718 &ret
1719 );
1720 return ( long ) ret;
1721}
1722# endif
1723
1724int __privileged_fork_setuid_execvp_procsplit (
1725 const char *file,
1726 char *const argv[]
1727)
1728{
1729 int i;
1730 void *ret = ( void * ) ( long ) - 1;
1731 xstrncpy ( ( void * ) cmd_p->arg.fork_execvp.file, file, sizeof ( cmd_p->arg.fork_execvp.file ) );
1732 i = 0;
1733
1734 while ( argv[i] != NULL ) {
1735 cmd_p->arg.fork_execvp.argv[i] = ( void * ) cmd_p->arg.fork_execvp._argv[i];
1736 xstrncpy ( cmd_p->arg.fork_execvp.argv[i], argv[i], sizeof ( cmd_p->arg.fork_execvp._argv[i] ) );
1737 i++;
1738 critical_on ( i >= MAXARGUMENTS );
1739 }
1740
1741 cmd_p->arg.fork_execvp.argv[i] = NULL;
1742 privileged_action (
1743# ifdef HL_LOCK_TRIES_AUTO
1744 PC_DEFAULT,
1745# endif
1746 PA_FORK_EXECVP,
1747 &ret
1748 );
1749 return ( long ) ret;
1750}
1751
1752int __privileged_fork_setuid_execvp_threadsplit (
1753 const char *file,
1754 char *const argv[]
1755)
1756{
1757 void *ret = ( void * ) ( long ) - 1;
1758 cmd_p->arg.fork_execvp.file_p = file;
1759 cmd_p->arg.fork_execvp.argv_p = argv;
1760 privileged_action (
1761# ifdef HL_LOCK_TRIES_AUTO
1762 PC_DEFAULT,
1763# endif
1764 PA_FORK_EXECVP,
1765 &ret
1766 );
1767 return ( long ) ret;
1768}
1769
1770int __privileged_kill_child_wrapper ( pid_t pid, int signal, char ignoreerrors )
1771{
1772 void *ret = ( void * ) ( long ) - 1;
1773 cmd_p->arg.kill_child.pid = pid;
1774 cmd_p->arg.kill_child.signal = signal;
1775 cmd_p->arg.kill_child.ignoreerrors = ignoreerrors;
1776 privileged_action (
1777# ifdef HL_LOCK_TRIES_AUTO
1778 PC_DEFAULT,
1779# endif
1780 PA_KILL_CHILD,
1781 &ret );
1782 return ( long ) ret;
1783}
1784
1785pid_t __privileged_waitpid ( pid_t pid, int *status, int options )
1786{
1787 void *ret = ( void * ) ( long ) - 1;
1788 cmd_p->arg.waitpid.pid = pid;
1789 cmd_p->arg.waitpid.options = options;
1790 privileged_action (
1791# ifdef HL_LOCK_TRIES_AUTO
1792 PC_DEFAULT,
1793# endif
1794 PA_WAITPID,
1795 &ret );
1796
1797 if ( status != NULL )
1798 *status = cmd_p->arg.waitpid.status;
1799
1800 return ( long ) ret;
1801}
1802
1803#endif
1804
1807int __privileged_fork_execvp ( const char *file, char *const argv[] )
1808{
1809 debug ( 4, "" );
1810 pid_t pid = fork();
1811
1812 switch ( pid ) {
1813 case -1:
1814 error ( "Cannot fork()." );
1815 return -1;
1816
1817 case 0: {
1818 int rc;
1819 ( void ) rc; // anti-warning on ./configure --enable-debug=no
1820 rc = setgid ( __privileged_fork_execvp_gid );
1821 debug ( 4, "setgid(%u) == %i", __privileged_fork_execvp_gid, rc );
1822 rc = setuid ( __privileged_fork_execvp_uid );
1823 debug ( 4, "setuid(%u) == %i", __privileged_fork_execvp_uid, rc );
1824 errno = 0;
1825 execvp ( file, argv );
1826 exit ( errno );
1827 }
1828 }
1829
1830 return pid;
1831}
1832
1833#ifdef CAPABILITIES_SUPPORT
1834#define pthread_mutex_init_smart(mutex_p) _pthread_mutex_init_smart(ctx_p->flags[SPLITTING]==SM_PROCESS, mutex_p)
1835static inline int _pthread_mutex_init_smart ( int isshared, pthread_mutex_t **mutex_p )
1836{
1837 int rc;
1838 pthread_mutex_t *mutex, initial = PTHREAD_MUTEX_INITIALIZER;
1839
1840 if ( isshared )
1841 return pthread_mutex_init_shared ( mutex_p );
1842
1843 mutex = xmalloc ( sizeof ( *mutex ) );
1844 memcpy ( mutex, &initial, sizeof ( *mutex ) );
1845 rc = pthread_mutex_init ( mutex, NULL );
1846
1847 if ( rc )
1848 return rc;
1849
1850 *mutex_p = mutex;
1851 return rc;
1852}
1853
1854#define pthread_mutex_destroy_smart(mutex_p) _pthread_mutex_destroy_smart(ctx_p->flags[SPLITTING]==SM_PROCESS, mutex_p)
1855static inline int _pthread_mutex_destroy_smart ( int isshared, pthread_mutex_t *mutex_p )
1856{
1857 int rc;
1858
1859 if ( isshared )
1860 return pthread_mutex_destroy_shared ( mutex_p );
1861
1862 rc = pthread_mutex_destroy ( mutex_p );
1863
1864 if ( rc )
1865 return rc;
1866
1867 free ( mutex_p );
1868 return 0;
1869}
1870
1871#define pthread_cond_init_smart(cond_p) _pthread_cond_init_smart(ctx_p->flags[SPLITTING]==SM_PROCESS, cond_p)
1872static inline int _pthread_cond_init_smart ( int isshared, pthread_cond_t **cond_p )
1873{
1874 int rc;
1875 pthread_cond_t *cond, initial = PTHREAD_COND_INITIALIZER;
1876
1877 if ( isshared )
1878 return pthread_cond_init_shared ( cond_p );
1879
1880 cond = xmalloc ( sizeof ( *cond ) );
1881 memcpy ( cond, &initial, sizeof ( *cond ) );
1882 rc = pthread_cond_init ( cond, NULL );
1883
1884 if ( rc )
1885 return rc;
1886
1887 *cond_p = cond;
1888 return rc;
1889}
1890
1891#define pthread_cond_destroy_smart(cond_p) _pthread_cond_destroy_smart(ctx_p->flags[SPLITTING]==SM_PROCESS, cond_p)
1892static inline int _pthread_cond_destroy_smart ( int isshared, pthread_cond_t *cond_p )
1893{
1894 int rc;
1895
1896 if ( isshared )
1897 return pthread_cond_destroy_shared ( cond_p );
1898
1899 rc = pthread_cond_destroy ( cond_p );
1900
1901 if ( rc )
1902 return rc;
1903
1904 free ( cond_p );
1905 return 0;
1906}
1907#endif
1908
1910{
1911#ifdef READWRITE_SIGNALLING
1912 int pipefds[2];
1913#endif
1914#ifdef CAPABILITIES_SUPPORT
1915
1916 if ( ctx_p->flags[SPLITTING] == SM_OFF ) {
1917#endif
1921 debug ( 5, "uid == %d; gid == %d", __privileged_fork_execvp_uid, __privileged_fork_execvp_gid );
1923#ifdef CAPABILITIES_SUPPORT
1924 _privileged_lstat64 = ( typeof ( _privileged_lstat64 ) ) lstat64;
1925 _privileged_fts_open = ( typeof ( _privileged_fts_open ) ) fts_open;
1926 _privileged_fts_read = ( typeof ( _privileged_fts_read ) ) fts_read;
1927 _privileged_fts_close = ( typeof ( _privileged_fts_close ) ) fts_close;
1928 _privileged_inotify_init = ( typeof ( _privileged_inotify_init ) ) inotify_init;
1929 _privileged_inotify_init1 = ( typeof ( _privileged_inotify_init1 ) ) inotify_init1;
1930 _privileged_inotify_add_watch = ( typeof ( _privileged_inotify_add_watch ) ) inotify_add_watch;
1931 _privileged_inotify_rm_watch = ( typeof ( _privileged_inotify_rm_watch ) ) inotify_rm_watch;
1932# ifdef CGROUP_SUPPORT
1933 _privileged_clsync_cgroup_deinit = ( typeof ( _privileged_clsync_cgroup_deinit ) ) clsync_cgroup_deinit;
1934# endif
1935 _privileged_waitpid = ( typeof ( _privileged_waitpid ) ) waitpid;
1936 cap_drop ( ctx_p, ctx_p->caps );
1937#endif
1938 return 0;
1939#ifdef CAPABILITIES_SUPPORT
1940 }
1941
1942 _privileged_fts_read = __privileged_fts_read;
1943 _privileged_fts_close = __privileged_fts_close;
1944 _privileged_inotify_init = __privileged_inotify_init;
1945 _privileged_inotify_init1 = __privileged_inotify_init1;
1946 _privileged_inotify_rm_watch = __privileged_inotify_rm_watch;
1947 _privileged_kill_child = __privileged_kill_child_wrapper;
1948# ifdef CGROUP_SUPPORT
1949 _privileged_clsync_cgroup_deinit = __privileged_clsync_cgroup_deinit;
1950# endif
1951 _privileged_waitpid = __privileged_waitpid;
1952 SAFE ( pthread_mutex_init_smart ( &pthread_mutex_privileged_p ), return errno; );
1953 SAFE ( pthread_mutex_init_smart ( &pthread_mutex_action_entrance_p ), return errno; );
1954 SAFE ( pthread_mutex_init_smart ( &pthread_mutex_action_signal_p ), return errno; );
1955 SAFE ( pthread_mutex_init_smart ( &pthread_mutex_runner_p ), return errno; );
1956 SAFE ( pthread_cond_init_smart ( &pthread_cond_privileged_p ), return errno; );
1957 SAFE ( pthread_cond_init_smart ( &pthread_cond_action_p ), return errno; );
1958 SAFE ( pthread_cond_init_smart ( &pthread_cond_runner_p ), return errno; );
1959# ifdef READWRITE_SIGNALLING
1960 SAFE ( pipe2 ( pipefds, O_CLOEXEC ), return errno; );
1961 priv_read_fd = pipefds[0];
1962 priv_write_fd = pipefds[1];
1963 SAFE ( pipe2 ( pipefds, O_CLOEXEC ), return errno; );
1964 nonp_read_fd = pipefds[0];
1965 nonp_write_fd = pipefds[1];
1966# endif
1967 SAFE ( pthread_mutex_lock ( pthread_mutex_runner_p ), return errno; );
1968# ifdef UNSHARE_SUPPORT
1969 unshare ( CLONE_NEWIPC );
1970# endif
1971
1972 switch ( ctx_p->flags[SPLITTING] ) {
1973 case SM_THREAD: {
1974 _privileged_lstat64 = __privileged_lstat64_threadsplit;
1975 _privileged_fts_open = __privileged_fts_open_threadsplit;
1976 _privileged_inotify_add_watch = __privileged_inotify_add_watch_threadsplit;
1977 _privileged_fork_execvp = __privileged_fork_setuid_execvp_threadsplit;
1978 cmd_p = calloc_align ( 1, sizeof ( *cmd_p ) );
1979 cmd_ret_p = calloc_align ( 1, sizeof ( *cmd_ret_p ) );
1980# ifdef HL_LOCKS
1981 hl_lock_p = calloc_align ( 1, sizeof ( *hl_lock_p ) );
1982 hl_lock_init ( hl_lock_p );
1983# endif
1984 // Running the privileged thread
1985 SAFE ( pthread_create ( &privileged_thread, NULL, ( void * ( * ) ( void * ) ) privileged_handler, ctx_p ), return errno );
1986
1988 privileged_thread = 0;
1989
1990 break;
1991 }
1992
1993 case SM_PROCESS: {
1994 _privileged_lstat64 = __privileged_lstat64_procsplit;
1995 _privileged_fts_open = __privileged_fts_open_procsplit;
1996 _privileged_inotify_add_watch = __privileged_inotify_add_watch_procsplit;
1997 _privileged_fork_execvp = __privileged_fork_setuid_execvp_procsplit;
1998 cmd_p = shm_calloc ( 1, sizeof ( *cmd_p ) );
1999 cmd_ret_p = shm_calloc ( 1, sizeof ( *cmd_ret_p ) );
2000# ifdef HL_LOCKS
2001 hl_lock_p = shm_calloc ( 1, sizeof ( *hl_lock_p ) );
2002 hl_lock_init ( hl_lock_p );
2003# endif
2004 // Running the privileged helper
2005 SAFE ( ( helper_pid = fork_helper() ) == -1, return errno );
2006
2007 if ( !helper_pid ) {
2008 if ( ctx_p->privileged_gid != ctx_p->gid ) {
2009// SAFE ( cap_enable(CAP_TO_MASK(CAP_SETGID)), return errno; );
2010 debug ( 3, "[privileged] Trying to set real gid to %i (ctx_p->privileged_gid)", ctx_p->privileged_gid );
2011 SAFE ( setgid ( ctx_p->privileged_gid ), return errno );
2012 }
2013
2014 if ( ctx_p->privileged_uid != ctx_p->uid ) {
2015// SAFE ( cap_enable(CAP_TO_MASK(CAP_SETUID)), return errno; );
2016 debug ( 3, "[privileged] Trying to set real uid to %i (ctx_p->privileged_uid)", ctx_p->privileged_uid );
2017 SAFE ( setuid ( ctx_p->privileged_uid ), return errno );
2018 }
2019
2020 exit ( privileged_handler ( ctx_p ) );
2021 }
2022
2023 break;
2024 }
2025
2026 default:
2027 critical ( "Invalid ctx_p->flags[SPLITTING]: %i", ctx_p->flags[SPLITTING] );
2028 }
2029
2030 if ( ctx_p->flags[GID] || ctx_p->flags[UID] )
2031 SAFE ( seteuid ( 0 ), {error ( "Not enough permission to start a privileged thread/fork" ); return errno;} );
2032
2033 if ( ctx_p->flags[GID] ) {
2034 SAFE ( setegid ( 0 ), return errno );
2035 debug ( 3, "[non-privileged] Trying to drop real gid %i (ctx_p->gid)", getgid(), ctx_p->gid );
2036 SAFE ( setgid ( ctx_p->gid ), return errno );
2037 }
2038
2039 if ( ctx_p->flags[UID] ) {
2040 debug ( 3, "[non-privileged] Trying to drop real uid %i (ctx_p->uid)", getuid(), ctx_p->uid );
2041 SAFE ( setuid ( ctx_p->uid ), return errno );
2042 }
2043
2044# ifdef HL_LOCKS
2045
2046 if ( ncpus == 1 )
2047 hl_shutdown ( HLLOCK_HANDLER );
2048
2049# endif
2050 critical_on ( !helper_isalive() );
2051# ifdef UNSHARE_SUPPORT
2052
2053 // The rest routines
2055 SAFE ( cap_enable ( CAP_TO_MASK ( CAP_SYS_ADMIN ) ), return errno; );
2056 SAFE ( unshare ( CLONE_NEWNET ), return errno; );
2057 }
2058
2059# endif
2060 SAFE ( cap_drop ( ctx_p, 0 ), return errno; );
2061 debug ( 4, "Waiting for the privileged thread to get prepared" );
2062 pthread_cond_wait ( pthread_cond_runner_p, pthread_mutex_runner_p );
2063 pthread_mutex_unlock ( pthread_mutex_runner_p );
2064 debug ( 4, "Sending the settings (exec_uid == %u; exec_gid == %u)", ctx_p->synchandler_uid, ctx_p->synchandler_gid );
2065 cmd_p->arg.ctx_p = ctx_p;
2066 privileged_action (
2067# ifdef HL_LOCK_TRIES_AUTO
2068 PC_DEFAULT,
2069# endif
2070 PA_SETUP,
2071 NULL
2072 );
2073 SAFE ( pthread_mutex_destroy_smart ( pthread_mutex_runner_p ), return errno; );
2074 SAFE ( pthread_cond_destroy_smart ( pthread_cond_runner_p ), return errno; );
2075# ifdef SECCOMP_SUPPORT
2076
2077 if ( ctx_p->flags[SECCOMP_FILTER] )
2078 nonprivileged_seccomp_init ( ctx_p );
2079
2080# endif
2081 debug ( 5, "Finish" );
2082 return 0;
2083#endif
2084}
2085
2086
2088{
2089 int ret = 0;
2090#ifdef CAPABILITIES_SUPPORT
2091
2092 if ( ctx_p->flags[SPLITTING] == SM_OFF )
2093 return 0;
2094
2095# ifdef HL_LOCK_TRIES_AUTO
2096# define ARGS PC_DEFAULT, PA_DIE, NULL
2097# else
2098# define ARGS PA_DIE, NULL
2099# endif
2100 SAFE ( privileged_action ( ARGS ), ret = errno );
2101# ifdef HL_LOCK_TRIES_AUTO
2102 {
2103 int i = 0;
2104
2105 while ( i < PC_MAX ) {
2106 debug ( 1, "hl_lock_p->tries[%i] == %lu", i, hl_lock_p->tries[i] );
2107 i++;
2108 }
2109 }
2110# endif
2111# ifdef HL_LOCKS
2112 hl_shutdown ( HLLOCK_HANDLER );
2113# endif
2114
2115 switch ( ctx_p->flags[SPLITTING] ) {
2116 case SM_THREAD: {
2118 pthread_mutex_lock ( pthread_mutex_privileged_p );
2119 pthread_mutex_unlock ( pthread_mutex_privileged_p );
2120 } else {
2121 SAFE ( pthread_join ( privileged_thread, NULL ), ret = errno );
2122 }
2123
2124 free ( ( void * ) cmd_p );
2125 free ( ( void * ) cmd_ret_p );
2126# ifdef HL_LOCKS
2127 free ( ( void * ) hl_lock_p );
2128# endif
2129 break;
2130 }
2131
2132 case SM_PROCESS: {
2133 int status;
2134
2135 if ( !ctx_p->flags[SECCOMP_FILTER] ) {
2136 if ( !__privileged_kill_child_itself ( helper_pid, SIGKILL, 1 ) ) {
2137 debug ( 9, "waitpid(%u, ...)", helper_pid );
2138 waitpid ( helper_pid, &status, 0 );
2139 }
2140 }
2141
2142 shm_free ( ( void * ) cmd_p );
2143 shm_free ( ( void * ) cmd_ret_p );
2144# ifdef HL_LOCKS
2145 shm_free ( ( void * ) hl_lock_p );
2146# endif
2147 break;
2148 }
2149 }
2150
2151 /*
2152 SAFE ( pthread_mutex_destroy_smart(pthread_mutex_privileged_p), ret = errno );
2153 SAFE ( pthread_mutex_destroy_smart(pthread_mutex_action_entrance_p), ret = errno );
2154 SAFE ( pthread_mutex_destroy_smart(pthread_mutex_action_signal_p), ret = errno );
2155 SAFE ( pthread_cond_destroy_smart(pthread_cond_privileged_p), ret = errno );
2156 SAFE ( pthread_cond_destroy_smart(pthread_cond_action_p), ret = errno );
2157 */
2158#endif
2159 debug ( 2, "endof privileged_deinit()" );
2160 return ret;
2161}
2162
2163
int clsync_cgroup_deinit(ctx_t *ctx_p)
Definition cgroup.c:78
@ SM_PROCESS
Definition common.h:126
@ SM_OFF
Definition common.h:124
@ SM_THREAD
Definition common.h:125
#define MAXARGUMENTS
#define HL_LOCK_AUTO_K_FINISH
#define HL_LOCK_TRIES_AUTO
#define HL_LOCK_NONPRIV_TRIES
#define HL_LOCK_TRIES_INITIAL
#define HL_LOCK_AUTO_K
#define BUFSIZ
#define HL_LOCK_AUTO_LIMIT_HIGH
#define SLEEP_SECONDS
#define HL_LOCK_AUTO_THREADHOLD
#define MAXPERMITTEDHOOKFILES
#define HL_LOCK_AUTO_DECELERATION
#define HL_LOCK_AUTO_INTERVAL
#define CAP_PRESERVE_TRY
Definition ctx.h:313
@ GID
Definition ctx.h:53
@ FORGET_PRIVTHREAD_INFO
Definition ctx.h:120
@ PERMIT_MPROTECT
Definition ctx.h:125
@ UID
Definition ctx.h:52
@ SECCOMP_FILTER
Definition ctx.h:119
@ SHM_MPROTECT
Definition ctx.h:126
@ DETACH_NETWORK
Definition ctx.h:116
@ CHECK_EXECVP_ARGS
Definition ctx.h:114
@ CAP_PRESERVE
Definition ctx.h:54
@ CAPS_INHERIT
Definition ctx.h:113
@ SPLITTING
Definition ctx.h:110
@ SHARGS_MAX
Definition ctx.h:247
@ CI_CLSYNC
Definition ctx.h:155
@ CI_DONTTOUCH
Definition ctx.h:153
@ CI_EMPTY
Definition ctx.h:156
@ CI_PERMITTED
Definition ctx.h:154
@ DN_NONPRIVILEGED
Definition ctx.h:139
#define register_blockthread(thread)
Definition ctx.h:31
#define error_or_debug(debug_level,...)
Definition error.h:51
#define critical(...)
Definition error.h:32
#define error(...)
Definition error.h:36
#define debug(debug_level,...)
Definition error.h:50
#define critical_on(cond)
Definition error.h:33
#define SAFE(code, onfail)
Definition macros.h:56
pid_t fork_helper()
Definition main.c:463
int ncpus
Definition main.c:385
pid_t parent_pid
Definition main.c:386
int parent_isalive()
Definition main.c:415
pid_t waitpid_timed(pid_t child_pid, int *status_p, long sec, long nsec)
Definition main.c:388
int argc
Definition main.c:2724
char ** argv
Definition main.c:2725
#define exit_on(cond)
Definition main.h:49
void shm_free(void *ptr)
Definition malloc.c:251
void * shm_calloc(size_t nmemb, size_t size)
Definition malloc.c:236
char * xstrncpy(char *dest, const char *src, size_t n)
Definition malloc.c:94
ctx_t * ctx_p
Definition mon_kqueue.c:85
struct stat64 stat64_t
Definition port-hacks.h:65
int(* _privileged_fork_execvp)(const char *file, char *const argv[])
Definition privileged.c:173
int privileged_init(ctx_t *ctx_p)
int __privileged_fork_execvp(const char *file, char *const argv[])
int privileged_deinit(ctx_t *ctx_p)
gid_t __privileged_fork_execvp_gid
int(* _privileged_kill_child)(pid_t pid, int sig, char ignoreerrors)
Definition privileged.c:174
uid_t __privileged_fork_execvp_uid
int __privileged_kill_child_itself(pid_t child_pid, int signal, char ignoreerrors)
Definition privileged.c:501
#define privileged_check(...)
Definition privileged.h:120
#define privileged_kill_child
Definition privileged.h:147
#define privileged_fork_execvp
Definition privileged.h:148
int pthread_mutex_init_shared(pthread_mutex_t **mutex_p)
Definition pthreadex.c:25
int pthread_cond_destroy_shared(pthread_cond_t *cond_p)
Definition pthreadex.c:55
int pthread_mutex_destroy_shared(pthread_mutex_t *mutex_p)
Definition pthreadex.c:36
int pthread_cond_init_shared(pthread_cond_t **cond_p)
Definition pthreadex.c:44
Definition ctx.h:315
char * handlerfpath
Definition ctx.h:382
char * preexithookfile
Definition ctx.h:349
char * exithookfile
Definition ctx.h:348
gid_t synchandler_gid
Definition ctx.h:326
char * label
Definition ctx.h:344
uid_t uid
Definition ctx.h:321
uid_t synchandler_uid
Definition ctx.h:325
int flags[(1<< 10)]
Definition ctx.h:338
gid_t privileged_gid
Definition ctx.h:324
synchandler_args_t synchandler_args[SHARGS_MAX]
Definition ctx.h:415
uid_t privileged_uid
Definition ctx.h:323
gid_t gid
Definition ctx.h:322
char isexpanded[MAXARGUMENTS]
Definition ctx.h:253
char * v[MAXARGUMENTS]
Definition ctx.h:251
volatile int exitcode
Definition sync.c:547
static ssize_t read_inf(int fd, void *buf, size_t count)
Definition syscalls.h:22
static ssize_t write_inf(int fd, const void *buf, size_t count)
Definition syscalls.h:34