clsync
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 */
140 static struct sock_filter filter_table[] = {
141  SECCOMP_COPY_SYSCALL_TO_ACCUM,
142  FILTER_TABLE_NONPRIV
143  FILTER_TABLE_ARCHDEPENDED
144  SECCOMP_DENY,
145 };
146 static 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 
154 int 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 
173 int ( *privileged_fork_execvp ) ( const char *file, char *const argv[] );
174 int ( *privileged_kill_child ) ( pid_t pid, int sig, char ignoreerrors );
175 
176 #ifdef CAPABILITIES_SUPPORT
177 pid_t helper_pid = 0;
178 pthread_t privileged_thread;
179 pthread_mutex_t *pthread_mutex_privileged_p;
180 pthread_mutex_t *pthread_mutex_action_signal_p;
181 pthread_mutex_t *pthread_mutex_action_entrance_p;
182 pthread_mutex_t *pthread_mutex_runner_p;
183 pthread_cond_t *pthread_cond_privileged_p;
184 pthread_cond_t *pthread_cond_action_p;
185 pthread_cond_t *pthread_cond_runner_p;
186 
187 # ifdef READWRITE_SIGNALLING
188 int priv_read_fd;
189 int priv_write_fd;
190 int nonp_read_fd;
191 int nonp_write_fd;
192 # endif
193 
194 enum 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 
221 struct pa_lstat64_arg {
222  char path_buf[PATH_MAX];
223  const char *path;
224 };
225 
226 struct 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 
234 struct pa_inotify_add_watch_arg {
235  int fd;
236  char pathname[PATH_MAX];
237  const char *pathname_p;
238  uint32_t mask;
239 };
240 
241 struct pa_inotify_rm_watch_arg {
242  int fd;
243  int wd;
244 };
245 
246 struct 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 
254 struct pa_kill_child_arg {
255  pid_t pid;
256  int signal;
257  char ignoreerrors;
258 };
259 
260 struct pa_waitpid_arg {
261  pid_t pid;
262  int status;
263  int options;
264 };
265 
266 struct 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
280 enum highload_lock_id {
281  HLLOCK_HANDLER = 0,
282 
283  HLLOCK_MAX
284 };
285 typedef enum highload_lock_id hllockid_t;
286 
287 enum 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 };
295 typedef enum highlock_lock_state hllock_state_t;
296 
297 struct 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 
317 struct 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 };
323 struct pa_ret {
324  stat64_t stat64;
325  struct pa_fts_read_ret fts_read;
326 };
327 struct 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 };
334 struct cmd_ret {
335  volatile struct pa_ret ret_buf;
336  volatile void *ret;
337  volatile int _errno;
338  volatile int processing_longcmd;
339 };
340 volatile struct cmd *cmd_p;
341 volatile struct cmd_ret *cmd_ret_p;
342 # ifdef HL_LOCKS
343 volatile struct hl_lock *hl_lock_p;
344 # endif
345 
346 # ifdef HL_LOCKS
347 static 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 
370 struct 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 
381 int ( *_privileged_lstat64 ) (
382  const char *path, stat64_t *buf
383 # ifdef HL_LOCK_TRIES_AUTO
384  , int callid
385 # endif
386 );
387 
388 FTS * ( *_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 
397 FTSENT * ( *_privileged_fts_read ) (
398  FTS *ftsp
399 # ifdef HL_LOCK_TRIES_AUTO
400  , int callid
401 # endif
402 );
403 
404 int ( *_privileged_fts_close ) (
405  FTS *ftsp
406 # ifdef HL_LOCK_TRIES_AUTO
407  , int callid
408 # endif
409 );
410 
411 int ( *_privileged_inotify_init ) ();
412 int ( *_privileged_inotify_init1 ) ( int flags );
413 
414 int ( *_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 
423 int ( *_privileged_inotify_rm_watch ) (
424  int fd,
425  int wd
426 );
427 
428 int ( *_privileged_clsync_cgroup_deinit ) ( ctx_t *ctx_p );
429 
430 pid_t ( *_privileged_waitpid ) ( pid_t pid, int *status, int options );
431 
432 int 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 
455 int 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
501 int __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 
523 int 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 
571 int 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 
656 int 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 
716 int 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 
749 static int helper_isalive_cache;
750 static 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 }
761 static 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 }
772 static inline int helper_isalive()
773 {
774  return helper_pid ? helper_isalive_proc() : helper_isalive_thread();
775 }
776 
777 int privileged_check()
778 {
779  if ( helper_pid )
780  critical_on ( !helper_isalive_proc() );
781 
782  return 0;
783 }
784 
785 # ifdef HL_LOCKS
786 
787 static inline int hl_isanswered ( int lockid )
788 {
789  return hl_lock_p->count_wait[lockid] == hl_lock_p->count_signal[lockid] + 1;
790 }
791 
792 static inline int hl_isready ( int lockid )
793 {
794  return hl_lock_p->count_wait[lockid] == hl_lock_p->count_signal[lockid];
795 }
796 
797 static inline void hl_setstate ( int lockid, hllock_state_t stateid )
798 {
799  g_atomic_int_set ( &hl_lock_p->state[lockid], stateid );
800 }
801 
802 int 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 
834 static 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 
866 static 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 
890 void 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 
908 int 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__
1275  critical_on ( !parent_isalive() );
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 
1299 static 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;
1466 privileged_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 
1480 int __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 
1500 int __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 
1520 FTS *__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 
1554 FTS *__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 
1577 FTSENT *__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 
1596 int __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 
1615 int __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 
1628 int __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 
1642 int __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 
1666 int __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 
1690 int __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
1709 int __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 
1724 int __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 
1752 int __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 
1770 int __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 
1785 pid_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 
1807 int __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)
1835 static 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)
1855 static 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)
1872 static 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)
1892 static 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 
SM_PROCESS
@ SM_PROCESS
Definition: common.h:126
ctx.h
xstrncpy
char * xstrncpy(char *dest, const char *src, size_t n)
Definition: malloc.c:94
UID
@ UID
Definition: ctx.h:52
SM_OFF
@ SM_OFF
Definition: common.h:124
FORGET_PRIVTHREAD_INFO
@ FORGET_PRIVTHREAD_INFO
Definition: ctx.h:120
CAPS_INHERIT
@ CAPS_INHERIT
Definition: ctx.h:113
syscalls.h
register_blockthread
#define register_blockthread(thread)
Definition: ctx.h:31
SHM_MPROTECT
@ SHM_MPROTECT
Definition: ctx.h:126
HL_LOCK_AUTO_K_FINISH
#define HL_LOCK_AUTO_K_FINISH
Definition: configuration.h:215
ctx
Definition: ctx.h:315
error_or_debug
#define error_or_debug(debug_level,...)
Definition: error.h:51
CAP_PRESERVE_TRY
#define CAP_PRESERVE_TRY
Definition: ctx.h:313
__privileged_kill_child_itself
int __privileged_kill_child_itself(pid_t child_pid, int signal, char ignoreerrors)
Definition: privileged.c:501
MAXARGUMENTS
#define MAXARGUMENTS
Definition: configuration.h:13
__privileged_fork_execvp_gid
gid_t __privileged_fork_execvp_gid
Definition: privileged.c:1806
synchandler_args::v
char * v[MAXARGUMENTS]
Definition: ctx.h:251
HL_LOCK_AUTO_DECELERATION
#define HL_LOCK_AUTO_DECELERATION
Definition: configuration.h:213
__privileged_fork_execvp
int __privileged_fork_execvp(const char *file, char *const argv[])
Definition: privileged.c:1807
shm_free
void shm_free(void *ptr)
Definition: malloc.c:251
SLEEP_SECONDS
#define SLEEP_SECONDS
Definition: configuration.h:113
synchandler_args::c
int c
Definition: ctx.h:252
HL_LOCK_AUTO_INTERVAL
#define HL_LOCK_AUTO_INTERVAL
Definition: configuration.h:207
argv
char ** argv
Definition: main.c:2725
privileged.h
ctx::flags
int flags[(1<< 10)]
Definition: ctx.h:338
privileged_kill_child
#define privileged_kill_child
Definition: privileged.h:147
HL_LOCK_TRIES_AUTO
#define HL_LOCK_TRIES_AUTO
Definition: configuration.h:205
CAP_PRESERVE
@ CAP_PRESERVE
Definition: ctx.h:54
pthreadex.h
ctx::gid
gid_t gid
Definition: ctx.h:322
HL_LOCK_AUTO_LIMIT_HIGH
#define HL_LOCK_AUTO_LIMIT_HIGH
Definition: configuration.h:217
CHECK_EXECVP_ARGS
@ CHECK_EXECVP_ARGS
Definition: ctx.h:114
if
if(auditd_restart())
Definition: mon_bsm.c:262
ctx::synchandler_uid
uid_t synchandler_uid
Definition: ctx.h:325
ctx::synchandler_gid
gid_t synchandler_gid
Definition: ctx.h:326
read_inf
static ssize_t read_inf(int fd, void *buf, size_t count)
Definition: syscalls.h:22
privileged_fork_execvp
#define privileged_fork_execvp
Definition: privileged.h:148
privileged_deinit
int privileged_deinit(ctx_t *ctx_p)
Definition: privileged.c:2087
clsync_cgroup_deinit
int clsync_cgroup_deinit(ctx_t *ctx_p)
Definition: cgroup.c:78
privileged_check
#define privileged_check(...)
Definition: privileged.h:120
write_inf
static ssize_t write_inf(int fd, const void *buf, size_t count)
Definition: syscalls.h:34
pthread_mutex_destroy_shared
int pthread_mutex_destroy_shared(pthread_mutex_t *mutex_p)
Definition: pthreadex.c:36
CI_DONTTOUCH
@ CI_DONTTOUCH
Definition: ctx.h:153
error
#define error(...)
Definition: error.h:36
DN_NONPRIVILEGED
@ DN_NONPRIVILEGED
Definition: ctx.h:139
ctx::label
char * label
Definition: ctx.h:344
argc
int argc
Definition: main.c:2724
parent_pid
pid_t parent_pid
Definition: main.c:386
error.h
pthread_mutex_init_shared
int pthread_mutex_init_shared(pthread_mutex_t **mutex_p)
Definition: pthreadex.c:25
pthread_cond_init_shared
int pthread_cond_init_shared(pthread_cond_t **cond_p)
Definition: pthreadex.c:44
ctx::handlerfpath
char * handlerfpath
Definition: ctx.h:382
HL_LOCK_AUTO_THREADHOLD
#define HL_LOCK_AUTO_THREADHOLD
Definition: configuration.h:211
malloc.h
SPLITTING
@ SPLITTING
Definition: ctx.h:110
debug
#define debug(debug_level,...)
Definition: error.h:50
ctx::uid
uid_t uid
Definition: ctx.h:321
GID
@ GID
Definition: ctx.h:53
SAFE
#define SAFE(code, onfail)
Definition: macros.h:56
fork_helper
pid_t fork_helper()
Definition: main.c:463
HL_LOCK_NONPRIV_TRIES
#define HL_LOCK_NONPRIV_TRIES
Definition: configuration.h:219
critical
#define critical(...)
Definition: error.h:32
parent_isalive
int parent_isalive()
Definition: main.c:415
CI_CLSYNC
@ CI_CLSYNC
Definition: ctx.h:155
HL_LOCK_TRIES_INITIAL
#define HL_LOCK_TRIES_INITIAL
Definition: configuration.h:202
PERMIT_MPROTECT
@ PERMIT_MPROTECT
Definition: ctx.h:125
__privileged_fork_execvp_uid
uid_t __privileged_fork_execvp_uid
Definition: privileged.c:1805
BUFSIZ
#define BUFSIZ
Definition: configuration.h:6
_privileged_kill_child
int(* _privileged_kill_child)(pid_t pid, int sig, char ignoreerrors)
Definition: privileged.c:174
common.h
waitpid_timed
pid_t waitpid_timed(pid_t child_pid, int *status_p, long sec, long nsec)
Definition: main.c:388
_privileged_fork_execvp
int(* _privileged_fork_execvp)(const char *file, char *const argv[])
Definition: privileged.c:173
HL_LOCK_AUTO_K
#define HL_LOCK_AUTO_K
Definition: configuration.h:209
exit_on
#define exit_on(cond)
Definition: main.h:49
main.h
ncpus
int ncpus
Definition: main.c:385
ctx::preexithookfile
char * preexithookfile
Definition: ctx.h:349
stat64_t
struct stat64 stat64_t
Definition: port-hacks.h:65
ctx::exithookfile
char * exithookfile
Definition: ctx.h:348
MAXPERMITTEDHOOKFILES
#define MAXPERMITTEDHOOKFILES
Definition: configuration.h:37
ctx::privileged_uid
uid_t privileged_uid
Definition: ctx.h:323
SHARGS_MAX
@ SHARGS_MAX
Definition: ctx.h:247
synchandler_args
Definition: ctx.h:250
SM_THREAD
@ SM_THREAD
Definition: common.h:125
ctx::synchandler_args
synchandler_args_t synchandler_args[SHARGS_MAX]
Definition: ctx.h:415
privileged_init
int privileged_init(ctx_t *ctx_p)
Definition: privileged.c:1909
critical_on
#define critical_on(cond)
Definition: error.h:33
cgroup.h
DETACH_NETWORK
@ DETACH_NETWORK
Definition: ctx.h:116
synchandler_args::isexpanded
char isexpanded[MAXARGUMENTS]
Definition: ctx.h:253
exitcode
volatile int exitcode
Definition: sync.c:547
SECCOMP_FILTER
@ SECCOMP_FILTER
Definition: ctx.h:119
ctx::privileged_gid
gid_t privileged_gid
Definition: ctx.h:324
pthread_cond_destroy_shared
int pthread_cond_destroy_shared(pthread_cond_t *cond_p)
Definition: pthreadex.c:55
shm_calloc
void * shm_calloc(size_t nmemb, size_t size)
Definition: malloc.c:236
CI_EMPTY
@ CI_EMPTY
Definition: ctx.h:156
ctx_p
ctx_t * ctx_p
Definition: mon_kqueue.c:85
CI_PERMITTED
@ CI_PERMITTED
Definition: ctx.h:154