redmine

More security options.

Added options:
 --pivot-root
 --detach-network
 --detach-miscellanea
... ... @@ -7,7 +7,7 @@ bin_PROGRAMS = clsync
clsync_SOURCES = calc.c cluster.c error.c fileutils.c glibex.c \
indexes.c main.c malloc.c stringex.c sync.c privileged.c calc.h \
cluster.h fileutils.h glibex.h main.h port-hacks.h stringex.h \
sync.h common.h control.h privileged.h
sync.h common.h control.h privileged.h syscalls.h
clsync_CFLAGS = $(AM_CFLAGS)
... ... @@ -43,6 +43,12 @@ endif
if HAVE_GETMNTENT
clsync_CFLAGS += -DGETMNTENT_SUPPORT
endif
if HAVE_UNSHARE
clsync_CFLAGS += -DUNSHARE_SUPPORT
if HAVE_PIVOTROOT
clsync_CFLAGS += -DPIVOTROOT_OPT_SUPPORT
endif
endif
if SOCKET
clsync_SOURCES += socket.c control.c program.h
... ...
... ... @@ -110,6 +110,7 @@ filesz:1M\n\
#define DTRACE_PATH "dtrace"
#define PIVOT_AUTO_DIR "/dev/shm/clsync-rootfs"
#define TMPDIR_TEMPLATE "/tmp/clsync-XXXXXX"
#define SYSLOG_BUFSIZ (1<<16)
... ...
... ... @@ -129,6 +129,12 @@ AC_SEARCH_LIBS([clock_getres], [rt], [],
dnl searching for getmntent
AC_CHECK_FUNC([getmntent], [HAVE_GETMNTENT=1])
dnl searching for pivot_root
AC_CHECK_FUNC([pivot_root], [HAVE_PIVOTROOT=1])
dnl searching for unshare
AC_CHECK_FUNC([unshare], [HAVE_UNSHARE=1])
dnl capabilities check
AC_ARG_WITH(capabilities,
AS_HELP_STRING(--with-capabilities,
... ... @@ -309,6 +315,8 @@ AM_CONDITIONAL([HAVE_DTRACEPIPE], [test "x$HAVE_DTRACEPIPE" != "x"])
AM_CONDITIONAL([HAVE_BACKTRACE], [test "x$HAVE_BACKTRACE" != "x"])
AM_CONDITIONAL([HAVE_CAPABILITIES], [test "x$HAVE_CAPABILITIES" != "x"])
AM_CONDITIONAL([HAVE_GETMNTENT], [test "x$HAVE_GETMNTENT" != "x"])
AM_CONDITIONAL([HAVE_PIVOTROOT], [test "x$HAVE_PIVOTROOT" != "x"])
AM_CONDITIONAL([HAVE_UNSHARE], [test "x$HAVE_UNSHARE" != "x"])
AS_IF([test "$HAVE_KQUEUE" = '' -a "$HAVE_INOTIFY" = '' -a "$HAVE_FANOTIFY" = '' -a "$HAVE_BSM" = '' ], [AC_MSG_FAILURE([kqueue, inotify and bsm are not supported on this system])])
... ...
... ... @@ -104,9 +104,27 @@ enum flags_enum {
SYNCHANDLERGID = 28|OPTION_LONGOPTONLY,
CAPS_INHERIT = 29|OPTION_LONGOPTONLY,
CHECK_EXECVP_ARGS = 30|OPTION_LONGOPTONLY,
PIVOT_ROOT = 31|OPTION_LONGOPTONLY,
DETACH_NETWORK = 32|OPTION_LONGOPTONLY,
DETACH_MISCELLANEA = 33|OPTION_LONGOPTONLY,
};
typedef enum flags_enum flags_t;
enum detachnetwork_way {
DN_OFF = 0,
DN_NONPRIVILEGED,
DN_EVERYWHERE,
};
typedef enum detachnetwork_way detachnetwork_way_t;
enum pivotroot_way {
PW_OFF = 0,
PW_DIRECT,
PW_AUTO,
PW_AUTORO,
};
typedef enum pivotroot_way pivotroot_way_t;
enum capsinherit {
CI_DONTTOUCH = 0,
CI_PERMITTED,
... ...
... ... @@ -30,9 +30,12 @@
#include <pwd.h> // getpwnam()
#include <grp.h> // getgrnam()
#ifdef UNSHARE_SUPPORT
# include <sched.h> // unshare()
#endif
#ifdef GETMNTENT_SUPPORT
# include <mntent.h> // getmntent()
# include <sched.h> // unshare()
# include <sys/mount.h> // umount2()
#endif
... ... @@ -43,6 +46,7 @@
#include "cluster.h"
#include "fileutils.h"
#include "socket.h"
#include "syscalls.h"
//#include "revision.h"
... ... @@ -72,6 +76,13 @@ static const struct option long_options[] =
{"sync-handler-uid", required_argument, NULL, SYNCHANDLERUID},
{"sync-handler-gid", required_argument, NULL, SYNCHANDLERGID},
{"chroot", required_argument, NULL, CHROOT},
#ifdef PIVOTROOT_OPT_SUPPORT
{"pivot-root", required_argument, NULL, PIVOT_ROOT},
#endif
#ifdef UNSHARE_SUPPRT
{"detach-network", required_argument, NULL, DETACH_NETWORK},
{"detach-miscellanea", optional_argument, NULL, DETACH_MISCELLANEA},
#endif
#ifdef CAPABILITIES_SUPPORT
{"thread-splitting", optional_argument, NULL, THREADSPLITTING},
{"check-execvp-args", optional_argument, NULL, CHECK_EXECVP_ARGS},
... ... @@ -132,6 +143,25 @@ static const struct option long_options[] =
{NULL, 0, NULL, 0}
};
#ifdef UNSHARE_SUPPRT
static char *const detachnetworkways[] = {
[DN_OFF] = "off",
[DN_NONPRIVILEGED] = "non-privileged",
[DN_EVERYWHERE] = "everywhere",
NULL,
};
#endif
#ifdef PIVOTROOT_OPT_SUPPORT
static char *const pivotrootways[] = {
[PW_OFF] = "off",
[PW_DIRECT] = "direct",
[PW_AUTO] = "auto",
[PW_AUTORO] = "auto-ro",
NULL,
};
#endif
#ifdef CAPABILITIES_SUPPORT
enum x_capabilities {
... ... @@ -739,6 +769,45 @@ int parse_parameter(ctx_t *ctx_p, uint16_t param_id, char *arg, paramsource_t pa
}
ctx_p->chroot_dir = arg;
break;
#ifdef PIVOTROOT_OPT_SUPPORT
case PIVOT_ROOT: {
char *value, *arg_orig = arg;
if (!*arg) {
ctx_p->flags_set[param_id] = 0;
return 0;
}
pivotroot_way_t pivotway = getsubopt(&arg, pivotrootways, &value);
if((int)pivotway == -1) {
errno = EINVAL;
error("Invalid pivot_root use way entered: \"%s\"", arg_orig);
return EINVAL;
}
ctx_p->flags[PIVOT_ROOT] = pivotway;
break;
}
#endif
#ifdef UNSHARE_SUPPRT
case DETACH_NETWORK:
char *value, *arg_orig = arg;
if (!*arg) {
ctx_p->flags_set[param_id] = 0;
return 0;
}
detachnetwork_way_t detachnetwork_way = getsubopt(&arg, detachnetworkways, &value);
if((int)detachnetwork_way == -1) {
errno = EINVAL;
error("Invalid network detach way entered: \"%s\"", arg_orig);
return EINVAL;
}
ctx_p->flags[DETACH_NETWORK] = detachnetwork_way;
break;
#endif
#ifdef GETMNTENT_SUPPORT
case MOUNTPOINTS: {
char *ptr;
... ... @@ -1314,6 +1383,16 @@ int ctx_check(ctx_t *ctx_p) {
error("\"--socket-auth\" is useless without \"--socket\"");
}
#ifdef PIVOTROOT_OPT_SUPPORT
if ((ctx_p->flags[PIVOT_ROOT] != PW_OFF) && (ctx_p->chroot_dir == NULL)) {
ret = errno = EINVAL;
error("\"--pivot-root\" cannot be used without \"--chroot\"");
}
if ((ctx_p->flags[PIVOT_ROOT] != PW_OFF) && (ctx_p->flags[MOUNTPOINTS]))
warning("\"--mountpoints\" is set while \"--pivot-root\" is set, too");
#endif
#ifdef VERYPARANOID
if ((ctx_p->retries != 1) && ctx_p->flags[THREADING]) {
ret = errno = EINVAL;
... ... @@ -2121,17 +2200,92 @@ int main(int argc, char *argv[]) {
if (ctx_p->mountpoints) {
// Openning the file with mount list
ent_f = setmntent("/proc/mounts", "r");
if (ent_f == NULL)
if (ent_f == NULL) {
error("Got error while setmntent(\"/proc/mounts\", \"r\")");
ret = errno;
}
}
#endif
#ifdef UNSHARE_SUPPORT
#define unshare_wrapper(a) \
if (unshare(a)) {\
error("Got error from unshare("XTOSTR(a)")");\
ret = errno;\
}
if (ctx_p->flags[DETACH_MISCELLANEA]) {
unshare(CLONE_NEWIPC);
unshare(CLONE_NEWUTS);
unshare(CLONE_SYSVSEM);
}
if ((ctx_p->flags[PIVOT_ROOT] != PW_OFF) || ctx_p->flags[MOUNTPOINTS]) {
unshare_wrapper(CLONE_FILES);
unshare_wrapper(CLONE_FS);
unshare_wrapper(CLONE_NEWNS);
}
if (ctx_p->flags[DETACH_NETWORK] == DN_EVERYWHERE)
unshare_wrapper(CLONE_NEWNET);
#undef unshare_wrapper
#endif
if (ctx_p->chroot_dir != NULL) {
#ifdef PIVOTROOT_OPT_SUPPORT
switch (ctx_p->flags[PIVOT_ROOT]) {
case PW_OFF:
case PW_DIRECT:
break;
case PW_AUTO:
case PW_AUTORO: {
char *template = strdup(PIVOT_AUTO_DIR);
char *directory = mkdtemp(template);
if (directory == NULL) {
error("Got error from mkdtemp(\""PIVOT_AUTO_DIR"\")");
ret = errno;
break;
}
if (chdir(ctx_p->chroot_dir)) {
error("Got error while chdir(\"%s\")", ctx_p->chroot_dir);
ret = errno;
}
if (mkdir("old_root", 0700)) {
free(directory);
error("Got error from mkdir(\"old_root\", 0700)");
ret = errno;
break;
}
if (mkdir(directory, 0700)) {
free(directory);
error("Got error from mkdir(\"%s\", 0700)", directory);
ret = errno;
break;
}
unsigned long mount_flags = MS_BIND | MS_REC |
(ctx_p->flags[PIVOT_ROOT] == PW_AUTORO) ? MS_RDONLY : 0;
if (mount(ctx_p->chroot_dir, directory, NULL, mount_flags, NULL)) {
error("Got error while mount(\"%s\", \"%s\", NULL, %o, NULL)",
ctx_p->chroot_dir, directory, mount_flags);
ret = errno;
break;
}
ctx_p->chroot_dir = directory;
break;
}
}
#endif
debug(7, "chdir(\"%s\")", ctx_p->chroot_dir);
if (chdir(ctx_p->chroot_dir)) {
error("Got error while chdir(\"%s\")", ctx_p->chroot_dir);
ret = errno;
}
}
#ifdef GETMNTENT_SUPPORT
... ... @@ -2140,9 +2294,6 @@ int main(int argc, char *argv[]) {
size_t to_umount_count = 0;
size_t to_umount_size = 0;
// Detaching from current FS namespace
unshare(CLONE_NEWNS);
// Getting mount-points to be umounted
while (NULL != (ent = getmntent(ent_f))) {
int i;
... ... @@ -2193,11 +2344,43 @@ int main(int argc, char *argv[]) {
}
#endif
if (ctx_p->chroot_dir != NULL) {
#ifdef PIVOTROOT_OPT_SUPPORT
if (!ret) {
switch (ctx_p->flags[PIVOT_ROOT]) {
case PW_OFF:
break;
case PW_DIRECT:
case PW_AUTO:
case PW_AUTORO:
if (pivot_root(".", "old_root")) {
error("Got error while pivot_root(\".\", \"old_root\")");
ret = errno;
}
break;
}
}
#endif
debug(7, "chroot(\".\")");
if (chroot(".")) {
error("Got error while chroot(\".\")");
ret = errno;
}
#ifdef PIVOTROOT_OPT_SUPPORT
if (!ret) {
switch (ctx_p->flags[PIVOT_ROOT]) {
case PW_OFF:
break;
case PW_DIRECT:
case PW_AUTO:
case PW_AUTORO:
if (umount2("old_root", MNT_DETACH)) {
error("Got error while umount2(\"old_root\", MNT_DETACH)");
ret = errno;
}
break;
}
}
#endif
}
}
... ... @@ -2512,6 +2695,12 @@ int main(int argc, char *argv[]) {
free(ctx_p->listoutdir);
}
/*
if (ctx_p->flags[PIVOT_ROOT] == PW_AUTO || ctx_p->flags[PIVOT_ROOT] == PW_AUTORO) {
umount2("/", MNT_DETACH);
// DELETE THE DIRECTORY
}
*/
main_cleanup(ctx_p);
if (ctx_p->watchdirsize)
... ...
This diff is collapsed. Click to expand it.
... ... @@ -17,25 +17,30 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <unistd.h> // execvp()
#include "common.h" // ctx.h
#include "ctx.h" // ctx_t
#include "error.h" // debug()
#ifdef CAPABILITIES_SUPPORT
# include <pthread.h> // pthread_create()
# include <sys/inotify.h> // inotify_init()
# include <sys/types.h> // fts_open()
# include <sys/stat.h> // fts_open()
# include <fts.h> // fts_open()
# include <errno.h> // errno
# include <sys/capability.h> // capset()
#endif
#include <unistd.h> // execvp()
#ifdef UNSHARE_SUPPORT
# include <sched.h> // unshare()
#endif
int (*privileged_fork_execvp)(const char *file, char *const argv[]);
int (*privileged_kill_child)(pid_t pid, int sig);
#ifdef CAPABILITIES_SUPPORT
#include <pthread.h> // pthread_create()
#include <sys/inotify.h> // inotify_init()
#include <sys/types.h> // fts_open()
#include <sys/stat.h> // fts_open()
#include <fts.h> // fts_open()
#include <errno.h> // errno
#include <sys/capability.h> // capset()
pthread_t pthread_thread;
pthread_mutex_t pthread_mutex_privileged = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t pthread_mutex_action_signal = PTHREAD_MUTEX_INITIALIZER;
... ... @@ -707,6 +712,11 @@ int privileged_init(ctx_t *ctx_p)
error("Cannot pthread_create().");
return errno;
}
if (ctx_p->flags[DETACH_NETWORK] == DN_NONPRIVILEGED)
if (unshare(CLONE_NEWNET)) {
error("Got error from unshare(CLONE_NEWNET)");
return errno;
}
cap_drop(ctx_p, 0);
debug(4, "Waiting for the privileged thread to get prepared");
... ...
/*
clsync - file tree sync utility based on inotify/kqueue
Copyright (C) 2013-2014 Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* based on busybox's code:
* http://git.busybox.net/busybox/plain/libbb/syscalls.c?h=0_60_stable
* /
#include <sys/syscall.h>
#ifdef __NR_pivot_root
int pivot_root(const char *new_root, const char *old_root) {
return(syscall(__NR_pivot_root, new_root, put_old));
}
#else
int pivot_root(const char *new_root, const char *old_root) {
return errno=ENOSYS;
}
#endif
*/
... ...
/*
clsync - file tree sync utility based on inotify/kqueue
Copyright (C) 2013-2014 Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
extern int pivot_root(const char *new_root, const char *old_root);
... ...