redmine

Testing variant of process slitting

... ... @@ -290,7 +290,7 @@ Russian:
LVEE (Russian):
- [clsync - live sync utility (abstract)](http://lvee.org/en/abstracts/118) [presentation](http://lvee.org/uploads/image_upload/file/337/winter_2014_15_clsync.pdf)
- [clsync progress: security and porting to freebsd](http://lvee.org/en/abstracts/138)
14. See also
------------
... ...
... ... @@ -196,3 +196,4 @@ filesz:1M\n\
}
#define DEFAULT_CG_GROUPNAME "clsync/%PID%"
... ...
... ... @@ -99,7 +99,7 @@ enum flags_enum {
CUSTOMSIGNALS = 23|OPTION_LONGOPTONLY,
CHROOT = 24|OPTION_LONGOPTONLY,
MOUNTPOINTS = 25|OPTION_LONGOPTONLY,
THREADSPLITTING = 26|OPTION_LONGOPTONLY,
PROCESSSPLITTING = 26|OPTION_LONGOPTONLY,
SYNCHANDLERUID = 27|OPTION_LONGOPTONLY,
SYNCHANDLERGID = 28|OPTION_LONGOPTONLY,
CAPS_INHERIT = 29|OPTION_LONGOPTONLY,
... ... @@ -109,8 +109,7 @@ enum flags_enum {
DETACH_MISCELLANEA = 33|OPTION_LONGOPTONLY,
ADDPERMITTEDHOOKFILES = 34|OPTION_LONGOPTONLY,
SECCOMP_FILTER = 35|OPTION_LONGOPTONLY,
FORGET_PRIVTHREAD_INFO = 36|OPTION_LONGOPTONLY,
SECURETHREADSPLITTING = 37|OPTION_LONGOPTONLY,
SECUREPROCESSSPLITTING = 37|OPTION_LONGOPTONLY,
FTS_EXPERIMENTAL_OPTIMIZATION = 38|OPTION_LONGOPTONLY,
FORBIDDEVICES = 39|OPTION_LONGOPTONLY,
CG_GROUPNAME = 40|OPTION_LONGOPTONLY,
... ...
... ... @@ -176,8 +176,9 @@ void _critical(const char *const function_name, const char *fmt, ...) {
{
va_list args;
pthread_t thread = pthread_self();
pid_t pid = getpid();
outfunct[method]("Critical (thread %p): %s(): ", thread, function_name);
outfunct[method]("Critical (pid: %u; thread: %p): %s(): ", pid, thread, function_name);
va_start(args, fmt);
voutfunct[method](fmt, args);
va_end(args);
... ... @@ -225,9 +226,10 @@ void _error(const char *const function_name, const char *fmt, ...) {
pthread_mutex_lock(&error_mutex);
pthread_t thread = pthread_self();
pid_t pid = getpid();
outputmethod_t method = *outputmethod;
outfunct[method](*debug ? "Error (thread %p): %s(): " : "Error: ", thread, function_name);
outfunct[method](*debug ? "Error (pid: %u; thread: %p): %s(): " : "Error: ", pid, thread, function_name);
va_start(args, fmt);
voutfunct[method](fmt, args);
va_end(args);
... ... @@ -251,9 +253,10 @@ void _info(const char *const function_name, const char *fmt, ...) {
pthread_mutex_lock(&error_mutex);
pthread_t thread = pthread_self();
pid_t pid = getpid();
outputmethod_t method = *outputmethod;
outfunct[method](*debug ? "Info (thread %p): %s(): " : "Info: ", thread, function_name);
outfunct[method](*debug ? "Info (pid: %u; thread: %p): %s(): " : "Info: ", pid, thread, function_name);
va_start(args, fmt);
voutfunct[method](fmt, args);
va_end(args);
... ... @@ -275,9 +278,10 @@ void _warning(const char *const function_name, const char *fmt, ...) {
pthread_mutex_lock(&error_mutex);
pthread_t thread = pthread_self();
pid_t pid = getpid();
outputmethod_t method = *outputmethod;
outfunct[method](*debug ? "Warning (thread %p): %s(): " : "Warning: ", thread, function_name);
outfunct[method](*debug ? "Warning (pid: %u; thread: %p): %s(): " : "Warning: ", pid, thread, function_name);
va_start(args, fmt);
voutfunct[method](fmt, args);
va_end(args);
... ... @@ -300,9 +304,10 @@ void _debug(int debug_level, const char *const function_name, const char *fmt, .
pthread_mutex_lock(&error_mutex);
pthread_t thread = pthread_self();
pid_t pid = getpid();
outputmethod_t method = *outputmethod;
outfunct[method]("Debug%u (thread %p): %s(): ", debug_level, thread, function_name);
outfunct[method]("Debug%u (pid: %u; thread: %p): %s(): ", debug_level, pid, thread, function_name);
va_start(args, fmt);
voutfunct[method](fmt, args);
va_end(args);
... ...
... ... @@ -89,15 +89,14 @@ static const struct option long_options[] =
#endif
#ifdef CAPABILITIES_SUPPORT
# ifdef SECCOMP_SUPPORT
{"secure-thread-splitting",optional_argument, NULL, SECURETHREADSPLITTING},
{"secure-process-splitting",optional_argument, NULL, SECUREPROCESSSPLITTING},
# endif
{"thread-splitting", optional_argument, NULL, THREADSPLITTING},
{"process-splitting", optional_argument, NULL, PROCESSSPLITTING},
{"check-execvp-args", optional_argument, NULL, CHECK_EXECVP_ARGS},
{"add-permitted-hook-files",required_argument, NULL, ADDPERMITTEDHOOKFILES},
# ifdef SECCOMP_SUPPORT
{"seccomp-filter", optional_argument, NULL, SECCOMP_FILTER},
# endif
{"forget-privthread-info",optional_argument, NULL, FORGET_PRIVTHREAD_INFO},
#endif
#ifdef GETMNTENT_SUPPORT
{"mountpoints", required_argument, NULL, MOUNTPOINTS},
... ... @@ -291,6 +290,21 @@ int syntax() {
}
int ncpus;
pid_t parent_pid;
pid_t myfork() {
pid_t pid = fork();
if (!pid) {
parent_pid = getppid();
# ifdef __linux__
prctl(PR_SET_PDEATHSIG, SIGCHLD);
# endif
debug(20, "parent_pid == %u", parent_pid);
}
return pid;
}
int version() {
info(PROGRAM" v%i.%i"REVISION"\n\t"AUTHOR"\n\nCompiled with options"
... ... @@ -777,11 +791,11 @@ int parse_parameter(ctx_t *ctx_p, uint16_t param_id, char *arg, paramsource_t pa
}
#ifdef CAPABILITIES_SUPPORT
# ifdef SECCOMP_SUPPORT
case SECURETHREADSPLITTING: {
ctx_p->flags[THREADSPLITTING]++;
case SECUREPROCESSSPLITTING: {
ctx_p->flags[PROCESSSPLITTING]++;
ctx_p->flags[CHECK_EXECVP_ARGS]++;
ctx_p->flags[SECCOMP_FILTER]++;
ctx_p->flags[FORGET_PRIVTHREAD_INFO]++;
ctx_p->flags[FORBIDDEVICES]++;
break;
}
# endif
... ...
... ... @@ -18,6 +18,7 @@
*/
extern int ncpus;
extern pid_t parent_pid;
extern int main_rehash(ctx_t *ctx_p);
extern int main_status_update(ctx_t *ctx_p);
... ... @@ -33,3 +34,4 @@ extern char *parameter_expand(
const char *(*parameter_get)(const char *variable_name, void *arg),
void *parameter_get_arg
);
extern pid_t myfork();
... ...
... ... @@ -28,6 +28,10 @@
# endif
#endif
#include <sys/ipc.h> // shmget()
#include <sys/shm.h> // shmget()
#include "common.h"
#include "malloc.h"
#include "error.h"
#include "configuration.h"
... ... @@ -185,3 +189,30 @@ int memory_init() {
return 0;
}
void *shm_malloc(size_t size) {
void *ret;
int privileged_shmid = shmget(0, size, IPC_PRIVATE|IPC_CREAT|0600);
struct shmid_ds shmid_ds;
critical_on (privileged_shmid == -1)
ret = shmat(privileged_shmid, NULL, 0);
critical_on((long)ret == -1);
debug(15, "ret == %p", ret);
// Forbidding access for others to the pointer
shmctl(privileged_shmid, IPC_STAT, &shmid_ds);
shmid_ds.shm_perm.mode = 0;
shmctl(privileged_shmid, IPC_SET, &shmid_ds);
// Checking that nobody else attached to the shared memory before access forbidding
shmctl(privileged_shmid, IPC_STAT, &shmid_ds);
if (shmid_ds.shm_lpid != shmid_ds.shm_cpid)
critical("A process (pid %u) attached to my shared memory. It's a security problem. Emergency exit.");
return ret;
}
void shm_free(void *ptr) {
debug(25, "(%p)", ptr);
shmdt(ptr);
}
... ...
... ... @@ -30,6 +30,8 @@ extern char *strdup_protect(const char *src, int prot);
extern int is_protected(void *addr);
# endif
#endif
extern void *shm_malloc(size_t size);
extern void shm_free(void *ptr);
extern int memory_init();
... ...
... ... @@ -1052,10 +1052,10 @@ Is set to "clsync/%PID%" by default.
.SH SECURITY OPTIONS
.B \-\-secure\-thread\-splitting
.B \-\-secure\-process\-splitting
.RS
Implies "\-\-thread\-splitting \-\-check\-execvp\-arguments \-\-seccomp\-filter
\-\-forget\-privthread\-info".
Implies "\-\-process\-splitting \-\-check\-execvp\-arguments \-\-seccomp\-filter
\-\-forbid\-devices"
.RE
.B \-u, \-\-uid
... ... @@ -1124,7 +1124,7 @@ and
.BR prctl (2)
to preserve "CAP_DAC_READ_SEARCH", "CAP_SETUID" or/and "CAP_SETGID" [see
.BR capabilities (7)]
Linux capability for thread using
Linux capability for process using
.BR fts "(3), " inotify "(7) and " execve "(2)."
This allows to preserve enough FS privileges to watch a file tree and execute
the
... ... @@ -1216,11 +1216,11 @@ Reset all capabilities
The default value is "empty".
.RE
.B \-\-thread\-splitting
.B \-\-process\-splitting
.RS
.B [Linux only, requires capabilities]
Split the main thread to privileged and non-privileged. This's an additional
Split the process to privileged and non-privileged. This's an additional
way to secure your system from any bug in
.B clsync
while running it with capabilities or root privileges. But
... ... @@ -1240,22 +1240,14 @@ too. Otherwise in case of
security bug a hacker will be able to use execvp() with any arguments
with root privileges.
But there's an ability to change a code of the privileged thread from
non\-privileged. To prevent it use
.B \-\-seccomp\-filter
option. It will forbid call of
.BR mprotect (2)
syscall, so the non\-privileged will be unable to drop protection from memory
ages.
Is not set by default.
.RE
.B \-\-check\-execvp\-arguments
.RS
.B [Requires \-\-thread\-splitting]
.B [Requires \-\-process\-splitting]
Enables execvp() arguments recheck in the privileged thread (in case of their
Enables execvp() arguments recheck in the privileged process (in case of their
substitution to any exploit-given arguments).
This option doesn't utilize a lot of CPU resources but forbids run-time
... ... @@ -1288,7 +1280,7 @@ Use
.B seccomp
filter to forbid syscalls that shouldn't be used by clsync.
Forbid all syscalls for non-privileged thread, but
Forbid all syscalls for non-privileged process, but
.RS
futex
inotify_init1
... ... @@ -1315,6 +1307,7 @@ read
rt_sigprocmask
rt_sigaction
nanosleep
mprotect
.RE
This option requires
... ... @@ -1328,14 +1321,6 @@ function.
Is not set by default.
.RE
.B \-\-forget\-privthread\-info
.RS
Just sets pthread_t variable for the privileged thread to zero. It complicates
attack on the privileged thread, but makes call of
.BR pthread_join (3)
on a privileged thread end impossible.
.RE
.B \-\-chroot
.I chroot\-directory
.RS
... ... @@ -1442,12 +1427,12 @@ Possible values:
.RS
.B everywhere
.RS
Removes network for all threads.
Removes network for all processes.
.RE
.B non\-privileged
.RS
Removes network from non\-privileged threads if option
.B \-\-thread\-splitting
Removes network from non\-privileged process if option
.B \-\-process\-splitting
is enabled, otherwise doesn't do anything.
.RE
.B off
... ...
This diff is collapsed. Click to expand it.
... ... @@ -82,6 +82,8 @@ extern int (*_privileged_inotify_rm_watch) (
extern int (*_privileged_clsync_cgroup_deinit) (ctx_t *ctx_p);
#endif
extern int privileged_check();
# ifdef HL_LOCK_TRIES_AUTO
# define privileged_fts_open(a,b,c,d) _privileged_fts_open(a,b,c,d)
# define privileged_fts_read(a,b) _privileged_fts_read(a,b)
... ... @@ -101,6 +103,8 @@ extern int (*_privileged_clsync_cgroup_deinit) (ctx_t *ctx_p);
#else
# define privileged_check(...) {}
# define privileged_fts_open(a,b,c,d) fts_open(a,b,c)
# define privileged_fts_read(a,b) fts_read(a)
# define privileged_fts_close(a,b) fts_close(a)
... ...
... ... @@ -1686,7 +1686,7 @@ int sync_mark_walk(ctx_t *ctx_p, const char *dirpath, indexes_t *indexes_p) {
int fts_opts = FTS_NOCHDIR|FTS_PHYSICAL|FTS_NOSTAT|(ctx_p->flags[ONEFILESYSTEM]?FTS_XDEV:0);
debug(3, "fts_opts == %p", (void *)(long)fts_opts);
tree = privileged_fts_open((char *const *)&rootpaths, fts_opts, NULL, PC_SYNC_MARK_WALK_FTS_OPEN);
tree = privileged_fts_open((char *const *)rootpaths, fts_opts, NULL, PC_SYNC_MARK_WALK_FTS_OPEN);
if (tree == NULL) {
error_or_debug((ctx_p->state == STATE_STARTING) ?-1:2, "Cannot privileged_fts_open() on \"%s\".", dirpath);
... ... @@ -1796,9 +1796,9 @@ int sync_notify_init(ctx_t *ctx_p) {
#ifdef INOTIFY_SUPPORT
case NE_INOTIFY: {
#if INOTIFY_OLD
ctx_p->fsmondata = (void *)(long)inotify_init();
ctx_p->fsmondata = (void *)(long)privileged_inotify_init();
#else
ctx_p->fsmondata = (void *)(long)inotify_init1(INOTIFY_FLAGS);
ctx_p->fsmondata = (void *)(long)privileged_inotify_init1(INOTIFY_FLAGS);
#endif
if ((long)ctx_p->fsmondata == -1) {
error("cannot inotify_init(%i).", INOTIFY_FLAGS);
... ... @@ -3462,6 +3462,7 @@ int sync_sighandler(sighandler_arg_t *sighandler_arg_p) {
case SIGQUIT:
case SIGTERM:
case SIGINT:
case SIGCHLD:
// TODO: remove the exit() from here. Main thread should exit itself
exit(*exitcode_p);
break;
... ... @@ -3517,6 +3518,9 @@ int sync_sighandler(sighandler_arg_t *sighandler_arg_p) {
case SIGHUP:
sync_switch_state(pthread_parent, STATE_REHASH);
break;
case SIGCHLD:
privileged_check();
break;
case SIGUSR_THREAD_GC:
sync_switch_state(pthread_parent, STATE_THREAD_GC);
break;
... ... @@ -3560,6 +3564,7 @@ int sync_run(ctx_t *ctx_p) {
sigaddset(&sigset_sighandler, SIGQUIT);
sigaddset(&sigset_sighandler, SIGTERM);
sigaddset(&sigset_sighandler, SIGINT);
sigaddset(&sigset_sighandler, SIGCHLD);
sigaddset(&sigset_sighandler, SIGUSR_THREAD_GC);
sigaddset(&sigset_sighandler, SIGUSR_INITSYNC);
sigaddset(&sigset_sighandler, SIGUSR_DUMP);
... ...