mirror of
https://github.com/yarrick/iodine.git
synced 2024-11-25 09:39:20 +02:00
check capabilities, not effective user ID
Under Linux, a process may not be run under root, yet it may have a permission to do what a superuser may do given specific capabilities are granted. This commit makes iodine not depend on EUID being 0 in order to run properly. Instead, in presence of libcap-ng, the following capabilities are being checked: * `CAP_NET_BIND_SERVICES` for server to bind to a port, lower than `/proc/sys/net/ipv4/ip_unprivileged_port_start` * `CAP_NET_ADMIN` to operate on a TUN device * `CAP_SETUID` and `CAP_SETGID` in case server is configured to change the user it runs on behalf of This change is handy if iodine is being run under a non-root user, provided `AmbientCapabilities=` and `CapabilityBoundingSet=` of systemd are employed in the first place. Fixes: https://github.com/yarrick/iodine/issues/80 Signed-off-by: Oleksandr Natalenko <oleksandr@redhat.com>
This commit is contained in:
parent
11dd73a646
commit
ebf4e7ee9e
55
src/common.c
55
src/common.c
|
@ -51,6 +51,11 @@
|
||||||
# include <selinux/selinux.h>
|
# include <selinux/selinux.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBCAPNG
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <cap-ng.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
/* The raw header used when not using DNS protocol */
|
/* The raw header used when not using DNS protocol */
|
||||||
|
@ -103,12 +108,60 @@ int setgroups(int count, int *groups)
|
||||||
|
|
||||||
#ifndef WINDOWS32
|
#ifndef WINDOWS32
|
||||||
void
|
void
|
||||||
check_privileges(void)
|
check_privileges(char *username, int port)
|
||||||
{
|
{
|
||||||
|
#if defined HAVE_LIBCAPNG
|
||||||
|
bool capable = true;
|
||||||
|
|
||||||
|
if (capng_get_caps_process() == -1) {
|
||||||
|
warnx("Unable to get capabilities");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!capng_have_capability(CAPNG_EFFECTIVE, CAP_NET_ADMIN)) {
|
||||||
|
warnx("capabilities: CAP_NET_ADMIN required");
|
||||||
|
capable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (port) {
|
||||||
|
unsigned short int ip_unprivileged_port_start = 1024;
|
||||||
|
|
||||||
|
FILE *file = fopen("/proc/sys/net/ipv4/ip_unprivileged_port_start", "r");
|
||||||
|
if (!file) {
|
||||||
|
warnx("sysctl: unable to get ip_unprivileged_port_start value");
|
||||||
|
// do not bail out here in case systemd.service has ProcSubset=pid set
|
||||||
|
} else {
|
||||||
|
fscanf(file, "%hu", &ip_unprivileged_port_start);
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (port < ip_unprivileged_port_start &&
|
||||||
|
!capng_have_capability(CAPNG_EFFECTIVE, CAP_NET_BIND_SERVICE)) {
|
||||||
|
warnx("capabilities: CAP_NET_BIND_SERVICE required");
|
||||||
|
capable = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (username) {
|
||||||
|
if (!capng_have_capability(CAPNG_EFFECTIVE, CAP_SETUID)) {
|
||||||
|
warnx("capabilities: CAP_SETUID required");
|
||||||
|
capable = false;
|
||||||
|
}
|
||||||
|
if (!capng_have_capability(CAPNG_EFFECTIVE, CAP_SETGID)) {
|
||||||
|
warnx("capabilities: CAP_SETGID required");
|
||||||
|
capable = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!capable) {
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
#else
|
||||||
if (geteuid() != 0) {
|
if (geteuid() != 0) {
|
||||||
warnx("Run as root and you'll be happy.");
|
warnx("Run as root and you'll be happy.");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -105,11 +105,11 @@ enum connection {
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef WINDOWS32
|
#ifdef WINDOWS32
|
||||||
static inline void check_privileges(void)
|
static inline void check_privileges(char *, int)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
void check_privileges(void);
|
void check_privileges(char *, int);
|
||||||
#endif
|
#endif
|
||||||
char *format_addr(struct sockaddr_storage *sockaddr, int sockaddr_len);
|
char *format_addr(struct sockaddr_storage *sockaddr, int sockaddr_len);
|
||||||
int get_addr(char *, int, int, int, struct sockaddr_storage *);
|
int get_addr(char *, int, int, int, struct sockaddr_storage *);
|
||||||
|
|
|
@ -279,7 +279,7 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
check_privileges();
|
check_privileges(username, 0);
|
||||||
|
|
||||||
argc -= optind;
|
argc -= optind;
|
||||||
argv += optind;
|
argv += optind;
|
||||||
|
|
|
@ -2519,7 +2519,7 @@ main(int argc, char **argv)
|
||||||
argc -= optind;
|
argc -= optind;
|
||||||
argv += optind;
|
argv += optind;
|
||||||
|
|
||||||
check_privileges();
|
check_privileges(username, port);
|
||||||
|
|
||||||
if (argc != 2)
|
if (argc != 2)
|
||||||
usage();
|
usage();
|
||||||
|
|
|
@ -23,6 +23,7 @@ link)
|
||||||
[ -e /usr/include/selinux/selinux.h ] && FLAGS="$FLAGS -lselinux";
|
[ -e /usr/include/selinux/selinux.h ] && FLAGS="$FLAGS -lselinux";
|
||||||
"$PKG_CONFIG" --exists libsystemd-daemon && FLAGS="$FLAGS $($PKG_CONFIG --libs libsystemd-daemon)";
|
"$PKG_CONFIG" --exists libsystemd-daemon && FLAGS="$FLAGS $($PKG_CONFIG --libs libsystemd-daemon)";
|
||||||
"$PKG_CONFIG" --exists libsystemd && FLAGS="$FLAGS $($PKG_CONFIG --libs libsystemd)";
|
"$PKG_CONFIG" --exists libsystemd && FLAGS="$FLAGS $($PKG_CONFIG --libs libsystemd)";
|
||||||
|
"$PKG_CONFIG" --exists libcap-ng && FLAGS="$FLAGS $($PKG_CONFIG --libs libcap-ng)";
|
||||||
echo $FLAGS;
|
echo $FLAGS;
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
@ -43,6 +44,7 @@ cflags)
|
||||||
[ -e /usr/include/selinux/selinux.h ] && FLAGS="$FLAGS -DHAVE_SETCON";
|
[ -e /usr/include/selinux/selinux.h ] && FLAGS="$FLAGS -DHAVE_SETCON";
|
||||||
"$PKG_CONFIG" --exists libsystemd-daemon && FLAGS="$FLAGS -DHAVE_SYSTEMD";
|
"$PKG_CONFIG" --exists libsystemd-daemon && FLAGS="$FLAGS -DHAVE_SYSTEMD";
|
||||||
"$PKG_CONFIG" --exists libsystemd && FLAGS="$FLAGS -DHAVE_SYSTEMD";
|
"$PKG_CONFIG" --exists libsystemd && FLAGS="$FLAGS -DHAVE_SYSTEMD";
|
||||||
|
"$PKG_CONFIG" --exists libcap-ng && FLAGS="$FLAGS -DHAVE_LIBCAPNG";
|
||||||
echo $FLAGS;
|
echo $FLAGS;
|
||||||
;;
|
;;
|
||||||
GNU/kFreeBSD|GNU)
|
GNU/kFreeBSD|GNU)
|
||||||
|
|
Loading…
Reference in New Issue