262 lines
8.4 KiB
Diff
262 lines
8.4 KiB
Diff
diff --git a/configure.ac b/configure.ac
|
|
index 9f73a708d0..958c26245e 100644
|
|
--- a/configure.ac
|
|
+++ b/configure.ac
|
|
@@ -377,6 +377,28 @@ AC_ARG_ENABLE(fmhash,
|
|
[enable_fmhash=yes]
|
|
)
|
|
|
|
+AC_ARG_ENABLE(libcap-ng,
|
|
+ [AS_HELP_STRING([--enable-libcap-ng],[Enable dropping capabilities to only the necessary set @<:@default=no@:>@])],
|
|
+ [case "${enableval}" in
|
|
+ yes) enable_libcapng="yes" ;;
|
|
+ no) enable_libcapng="no" ;;
|
|
+ *) AC_MSG_ERROR(bad value ${enableval} for --enable_libcapng) ;;
|
|
+ esac],
|
|
+ [enable_libcapng=no]
|
|
+)
|
|
+
|
|
+if test "$enable_libcapng" = "yes"; then
|
|
+ PKG_CHECK_MODULES(
|
|
+ [LIBCAPNG],
|
|
+ [libcap-ng >= 0.8.2],
|
|
+ [AC_DEFINE([ENABLE_LIBCAPNG], [1], [Indicator that libcap-ng is present])],
|
|
+ [AC_MSG_ERROR(libcap-ng is not present.)]
|
|
+ )
|
|
+ CFLAGS="$CFLAGS $LIBCAPNG_CFLAGS"
|
|
+ LIBS="$LIBS $LIBCAPNG_LIBS"
|
|
+fi
|
|
+
|
|
+
|
|
AC_ARG_ENABLE(fmhash-xxhash,
|
|
[AS_HELP_STRING([--enable-fmhash-xxhash],[Enable xxhash in fmhash support @<:@default=no@:>@])],
|
|
[case "${enableval}" in
|
|
@@ -2820,6 +2842,8 @@ echo " liblogging-stdlog support enabled: $enable_liblogging_stdlog"
|
|
echo " libsystemd enabled: $enable_libsystemd"
|
|
echo " kafka static linking enabled: $enable_kafka_static"
|
|
echo " atomic operations enabled: $enable_atomic_operations"
|
|
+echo " libcap-ng support enabled: $enable_libcapng"
|
|
+
|
|
echo
|
|
echo "---{ input plugins }---"
|
|
if test "$unamestr" != "AIX"; then
|
|
diff --git a/runtime/debug.c b/runtime/debug.c
|
|
index a655bc2e4e..6e6c9fd38f 100644
|
|
--- a/runtime/debug.c
|
|
+++ b/runtime/debug.c
|
|
@@ -250,7 +250,7 @@ r_dbgoprint( const char *srcname, obj_t *pObj, const char *fmt, ...)
|
|
|
|
if(!(Debug && debugging_on))
|
|
return;
|
|
-
|
|
+
|
|
if(!checkDbgFile(srcname)) {
|
|
return;
|
|
}
|
|
@@ -435,7 +435,7 @@ rsRetVal dbgClassInit(void)
|
|
{
|
|
rsRetVal iRet; /* do not use DEFiRet, as this makes calls into the debug system! */
|
|
|
|
-
|
|
+
|
|
(void) pthread_key_create(&keyThrdName, dbgThrdNameDestruct);
|
|
|
|
/* while we try not to use any of the real rsyslog code (to avoid infinite loops), we
|
|
diff --git a/runtime/modules.c b/runtime/modules.c
|
|
index 810b2e9b52..b39bd9f066 100644
|
|
--- a/runtime/modules.c
|
|
+++ b/runtime/modules.c
|
|
@@ -595,7 +595,7 @@ doModInit(pModInit_t modInit, uchar *name, void *pModHdlr, modInfo_t **pNewModul
|
|
CHKiRet((*pNew->modQueryEtryPt)((uchar*)"getKeepType", &modGetKeepType));
|
|
CHKiRet((*modGetKeepType)(&pNew->eKeepType));
|
|
dbgprintf("module %s of type %d being loaded (keepType=%d).\n", name, pNew->eType, pNew->eKeepType);
|
|
-
|
|
+
|
|
/* OK, we know we can successfully work with the module. So we now fill the
|
|
* rest of the data elements. First we load the interfaces common to all
|
|
* module types.
|
|
@@ -1242,7 +1242,7 @@ Load(uchar *const pModName, const sbool bConfLoad, struct nvlst *const lst)
|
|
}
|
|
|
|
iLoadCnt++;
|
|
-
|
|
+
|
|
} while(pModHdlr == NULL && *pModName != '/' && pModDirNext);
|
|
|
|
if(load_err_msg != NULL) {
|
|
@@ -1323,7 +1323,7 @@ modulesProcessCnf(struct cnfobj *o)
|
|
|
|
cnfModName = (uchar*)es_str2cstr(pvals[typeIdx].val.d.estr, NULL);
|
|
iRet = Load(cnfModName, 1, o->nvlst);
|
|
-
|
|
+
|
|
finalize_it:
|
|
free(cnfModName);
|
|
cnfparamvalsDestruct(pvals, &pblk);
|
|
diff --git a/runtime/rsconf.c b/runtime/rsconf.c
|
|
index 4620ff8d13..de2a21b406 100644
|
|
--- a/runtime/rsconf.c
|
|
+++ b/runtime/rsconf.c
|
|
@@ -34,6 +34,10 @@
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/socket.h>
|
|
+#ifdef ENABLE_LIBCAPNG
|
|
+ #include <cap-ng.h>
|
|
+#endif
|
|
+
|
|
|
|
#include "rsyslog.h"
|
|
#include "obj.h"
|
|
@@ -656,6 +660,7 @@ rsRetVal doDropPrivGid(rsconf_t *cnf)
|
|
uchar szBuf[1024];
|
|
DEFiRet;
|
|
|
|
+#ifndef ENABLE_LIBCAPNG
|
|
if(!cnf->globals.gidDropPrivKeepSupplemental) {
|
|
res = setgroups(0, NULL); /* remove all supplemental group IDs */
|
|
if(res) {
|
|
@@ -668,9 +673,19 @@ rsRetVal doDropPrivGid(rsconf_t *cnf)
|
|
res = setgid(cnf->globals.gidDropPriv);
|
|
if(res) {
|
|
LogError(errno, RS_RET_ERR_DROP_PRIV,
|
|
- "could not set requested group id %d", cnf->globals.gidDropPriv);
|
|
+ "could not set requested group id %d via setgid()", cnf->globals.gidDropPriv);
|
|
ABORT_FINALIZE(RS_RET_ERR_DROP_PRIV);
|
|
}
|
|
+#else
|
|
+ int capng_flags = cnf->globals.gidDropPrivKeepSupplemental ? CAPNG_NO_FLAG : CAPNG_DROP_SUPP_GRP;
|
|
+ res = capng_change_id(-1, cnf->globals.gidDropPriv, capng_flags);
|
|
+ if (res) {
|
|
+ LogError(0, RS_RET_LIBCAPNG_ERR,
|
|
+ "could not set requested group id %d via capng_change_id()", cnf->globals.gidDropPriv);
|
|
+ ABORT_FINALIZE(RS_RET_LIBCAPNG_ERR);
|
|
+ }
|
|
+#endif
|
|
+
|
|
DBGPRINTF("setgid(%d): %d\n", cnf->globals.gidDropPriv, res);
|
|
snprintf((char*)szBuf, sizeof(szBuf), "rsyslogd's groupid changed to %d",
|
|
cnf->globals.gidDropPriv);
|
|
@@ -705,12 +720,18 @@ static void doDropPrivUid(rsconf_t *cnf)
|
|
cnf->globals.uidDropPriv);
|
|
}
|
|
|
|
+#ifndef ENABLE_LIBCAPNG
|
|
res = setuid(cnf->globals.uidDropPriv);
|
|
+#else
|
|
+ int capng_flags = cnf->globals.gidDropPrivKeepSupplemental ? CAPNG_NO_FLAG : CAPNG_DROP_SUPP_GRP;
|
|
+ res = capng_change_id(cnf->globals.uidDropPriv, -1, capng_flags);
|
|
+#endif
|
|
if(res) {
|
|
/* if we can not set the userid, this is fatal, so let's unconditionally abort */
|
|
perror("could not set requested userid");
|
|
exit(1);
|
|
}
|
|
+
|
|
DBGPRINTF("setuid(%d): %d\n", cnf->globals.uidDropPriv, res);
|
|
snprintf((char*)szBuf, sizeof(szBuf), "rsyslogd's userid changed to %d", cnf->globals.uidDropPriv);
|
|
logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, szBuf, 0);
|
|
@@ -739,6 +760,29 @@ dropPrivileges(rsconf_t *cnf)
|
|
cnf->globals.uidDropPriv);
|
|
}
|
|
|
|
+#ifdef ENABLE_LIBCAPNG
|
|
+ /* In case privileges were dropped, do not allow bypassing
|
|
+ * file read, write, and execute permission checks
|
|
+ */
|
|
+ if (cnf->globals.gidDropPriv != 0 || cnf->globals.uidDropPriv != 0) {
|
|
+ int capng_rc;
|
|
+ if ((capng_rc = capng_update(CAPNG_DROP, CAPNG_EFFECTIVE|CAPNG_PERMITTED, CAP_DAC_OVERRIDE)) != 0) {
|
|
+ LogError(0, RS_RET_LIBCAPNG_ERR,
|
|
+ "could not update the internal posix capabilities settings "
|
|
+ "based on the options passed to it, capng_update=%d\n", capng_rc);
|
|
+ exit(-1);
|
|
+ }
|
|
+
|
|
+ if ((capng_rc = capng_apply(CAPNG_SELECT_BOTH)) != 0) {
|
|
+ LogError(0, RS_RET_LIBCAPNG_ERR,
|
|
+ "could not transfer the specified internal posix capabilities "
|
|
+ "settings to the kernel, capng_apply=%d\n", capng_rc);
|
|
+ exit(-1);
|
|
+ }
|
|
+ }
|
|
+
|
|
+#endif
|
|
+
|
|
finalize_it:
|
|
RETiRet;
|
|
}
|
|
diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h
|
|
index 908e5e7b73..01616d8f7d 100644
|
|
--- a/runtime/rsyslog.h
|
|
+++ b/runtime/rsyslog.h
|
|
@@ -604,6 +604,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
|
|
RS_RET_REDIS_ERROR = -2452, /**< redis-specific error. See message foe details. */
|
|
RS_RET_REDIS_AUTH_FAILED = -2453, /**< redis authentication failure */
|
|
RS_RET_FAUP_INIT_OPTIONS_FAILED = -2454, /**< could not initialize faup options */
|
|
+ RS_RET_LIBCAPNG_ERR = -2455, /**< error during dropping the capabilities */
|
|
|
|
/* RainerScript error messages (range 1000.. 1999) */
|
|
RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */
|
|
diff --git a/tools/rsyslogd.c b/tools/rsyslogd.c
|
|
index 31b91a1bd1..77d814b482 100644
|
|
--- a/tools/rsyslogd.c
|
|
+++ b/tools/rsyslogd.c
|
|
@@ -37,6 +37,9 @@
|
|
#ifdef HAVE_LIBSYSTEMD
|
|
# include <systemd/sd-daemon.h>
|
|
#endif
|
|
+#ifdef ENABLE_LIBCAPNG
|
|
+ #include <cap-ng.h>
|
|
+#endif
|
|
|
|
#include "rsyslog.h"
|
|
#include "wti.h"
|
|
@@ -2167,6 +2170,46 @@ main(int argc, char **argv)
|
|
fjson_global_do_case_sensitive_comparison(0);
|
|
|
|
dbgClassInit();
|
|
+
|
|
+#ifdef ENABLE_LIBCAPNG
|
|
+ /*
|
|
+ * Drop capabilities to the necessary set
|
|
+ */
|
|
+ int capng_rc;
|
|
+ capng_clear(CAPNG_SELECT_BOTH);
|
|
+
|
|
+ if ((capng_rc = capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED,
|
|
+ CAP_BLOCK_SUSPEND,
|
|
+ CAP_CHOWN,
|
|
+ CAP_IPC_LOCK,
|
|
+ CAP_LEASE,
|
|
+ CAP_NET_ADMIN,
|
|
+ CAP_NET_BIND_SERVICE,
|
|
+ CAP_DAC_OVERRIDE,
|
|
+ CAP_SETGID,
|
|
+ CAP_SETUID,
|
|
+ CAP_SETPCAP,
|
|
+ CAP_SYS_ADMIN,
|
|
+ CAP_SYS_CHROOT,
|
|
+ CAP_SYS_RESOURCE,
|
|
+ CAP_SYSLOG,
|
|
+ -1
|
|
+ )) != 0) {
|
|
+ LogError(0, RS_RET_LIBCAPNG_ERR,
|
|
+ "could not update the internal posix capabilities settings "
|
|
+ "based on the options passed to it, capng_updatev=%d\n", capng_rc);
|
|
+ exit(-1);
|
|
+ }
|
|
+
|
|
+ if ((capng_rc = capng_apply(CAPNG_SELECT_BOTH)) != 0) {
|
|
+ LogError(0, RS_RET_LIBCAPNG_ERR,
|
|
+ "could not transfer the specified internal posix capabilities "
|
|
+ "settings to the kernel, capng_apply=%d\n", capng_rc);
|
|
+ exit(-1);
|
|
+ }
|
|
+ DBGPRINTF("Capabilities were dropped successfully\n");
|
|
+#endif
|
|
+
|
|
initAll(argc, argv);
|
|
#ifdef HAVE_LIBSYSTEMD
|
|
sd_notify(0, "READY=1");
|