diff --git a/server/Makefile b/server/Makefile index e1e70a444..9a2504f8e 100644 --- a/server/Makefile +++ b/server/Makefile @@ -3,7 +3,7 @@ TARGETS = server send random receive test # Common objs OBJS = path.o node.o hooks.o msg.o cfg.o stats.o # Helper libs -OBJS += utils.o list.o hist.o log.o timing.o +OBJS += utils.o list.o hist.o log.o timing.o checks.o # Node types OBJS += file.o @@ -66,7 +66,7 @@ receive: receive.o $(OBJS) test: test.o $(OBJS) random: random.o msg.o utils.o timing.o log.o -protected: CFLAGS += -DPROTECT -DVALID_UNTIL=$(shell date -d "now +5months" +%s) -s -O3 -fvisibility=hidden +protected: CFLAGS += -DLICENSE -DLICENSE_VALID=$(shell date -d "now +5months" +%s) -s -O3 -fvisibility=hidden protected: clean strip strip: $(TARGETS) diff --git a/server/include/checks.h b/server/include/checks.h new file mode 100644 index 000000000..b9df6731f --- /dev/null +++ b/server/include/checks.h @@ -0,0 +1,58 @@ +/** Check system requirements. + * + * @author Steffen Vogel + * @copyright 2014-2015, Institute for Automation of Complex Power Systems, EONERC + * This file is part of S2SS. All Rights Reserved. Proprietary and confidential. + * Unauthorized copying of this file, via any medium is strictly prohibited. + *********************************************************************************/ + +#ifndef _CHECKS_H_ +#define _CHECKS_H_ + +/** Checks for realtime (RT_PREEMPT) patched kernel. + * + * See https://rt.wiki.kernel.org + * + * @retval 0 Kernel is patched. + * @reval <>0 Kernel is not patched. + */ +int check_kernel_rtpreempt(); + +/** Check if kernel command line contains "isolcpus=" option. + * + * See https://www.kernel.org/doc/Documentation/kernel-parameters.txt + * + * @retval 0 Kernel has isolated cores. + * @reval <>0 Kernel has no isolated cores. + */ +int check_kernel_cmdline(); + +/** Check if kernel is version is sufficient + * + * @retval 0 Kernel version is sufficient. + * @reval <>0 Kernel version is not sufficient. + */ +int check_kernel_version(); + +/** Check if program is running with super user (root) privileges. + * + * + * @retval 0 Permissions are sufficient. + * @reval <>0 Permissions are not sufficient. + */ +int check_root(); + +/** Simple copy protection. + * + * This function checks several machine IDs for predefined values. + * + * @retval 0 The machine is allowed to run this program. + * @reval <>0 The machine is not allowed to run this program. + */ +int check_license_ids(); + +int check_license_time(); + +int check_license_trace(); + +#endif diff --git a/server/include/config.h b/server/include/config.h index b6a3cc30e..aaaecad51 100644 --- a/server/include/config.h +++ b/server/include/config.h @@ -36,6 +36,16 @@ #define IPPROTO_S2SS 137 #define ETH_P_S2SS 0xBABE +/* Checks */ +#define KERNEL_VERSION_MAJ 3 +#define KERNEL_VERSION_MIN 4 + +#define LICENSE_CHECKS \ + { { "/sys/class/dmi/id/product_uuid", "5002E503-4904-EB05-7406-0C0700080009" }, \ + { "/sys/class/net/eth0/address" , "50:e5:49:eb:74:0c" }, \ + { "/etc/machine-id", "0d8399d0216314f083b9ed2053a354a8" }, \ + { "/dev/sda2", "\x53\xf6\xb5\xeb\x8b\x16\x46\xdc\x8d\x8f\x5b\x70\xb8\xc9\x1a\x2a", 0x468 } } + /* Hook function configuration */ #define HOOK_FIR_INDEX 1 /**< The first value of message should be filtered. */ #define HOOK_TS_INDEX -1 /**< The last value of message should be overwritten by a timestamp. */ diff --git a/server/include/license.h b/server/include/license.h deleted file mode 100644 index 51fb1ec31..000000000 --- a/server/include/license.h +++ /dev/null @@ -1,64 +0,0 @@ -/** Simple copy protection - * - * @file - * @author Steffen Vogel - * @copyright 2014-2015, Institute for Automation of Complex Power Systems, EONERC - * This file is part of S2SS. All Rights Reserved. Proprietary and confidential. - * Unauthorized copying of this file, via any medium is strictly prohibited. - *********************************************************************************/ - -#ifdef PROTECT - -#include -#include -#include -#include - -/** Simple copy protection. - * - * This function does: - * - checks several machine IDs for predefined values. - * - checks if program is debugged / traced - * - * This function shall be executed during program startup to - * check if this host is allowed to execute S2SS. - */ -static inline __attribute__((always_inline)) int check_license() -{ - const struct { - char *file, *content; - off_t offset; - } checks[] = { - { "/sys/class/dmi/id/product_uuid", "5002E503-4904-EB05-7406-0C0700080009" }, - { "/sys/class/net/eth0/address" , "50:e5:49:eb:74:0c" }, - { "/etc/machine-id", "0d8399d0216314f083b9ed2053a354a8" }, - { "/dev/sda2", "\x53\xf6\xb5\xeb\x8b\x16\x46\xdc\x8d\x8f\x5b\x70\xb8\xc9\x1a\x2a", 0x468 }, /* EXT4 UUID */ - }; - - if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) - return -1; - - if (time(NULL) > VALID_UNTIL) - return -1; - - FILE *f; - char buf[128]; - - for (int i = 0; i < ARRAY_LEN(checks); i++) { - f = fopen(checks[i].file, "r"); - if (!f) - return -1; - - fseek(f, checks[i].offset, SEEK_SET); - fgets(buf, sizeof(buf), f); - fclose(f); - - if (strncmp(buf, checks[i].content, strlen(checks[i].content))) - return -1; - } - - return 0; -} -#else - #define check_license() (0) -#endif diff --git a/server/include/utils.h b/server/include/utils.h index c0bff7f4c..7298cbf84 100644 --- a/server/include/utils.h +++ b/server/include/utils.h @@ -114,6 +114,18 @@ int system2(const char* cmd, ...); /** Call quit() in the main thread. */ void die(); +/** Used by version_parse(), version_compare() */ +struct version { + int major; + int minor; +}; + +/** Compare two versions. */ +int version_compare(struct version *a, struct version *b); + +/** Parse a dotted version string. */ +int version_parse(const char *s, struct version *v); + /** Check assertion and exit if failed. */ #define assert(exp) do { \ if (!EXPECT(exp, 0)) \ diff --git a/server/src/checks.c b/server/src/checks.c new file mode 100644 index 000000000..b52c2f235 --- /dev/null +++ b/server/src/checks.c @@ -0,0 +1,96 @@ +/** Check system requirements. + * + * @author Steffen Vogel + * @copyright 2014-2015, Institute for Automation of Complex Power Systems, EONERC + * This file is part of S2SS. All Rights Reserved. Proprietary and confidential. + * Unauthorized copying of this file, via any medium is strictly prohibited. + *********************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" +#include "config.h" + +int check_kernel_version() +{ + struct utsname uts; + struct version current; + struct version required = { KERNEL_VERSION_MAJ, KERNEL_VERSION_MIN }; + + if (uname(&uts) < 0) + return -1; + + if (version_parse(uts.release, ¤t)) + return -1; + + return version_compare(¤t, &required) < 0; +} + +int check_kernel_rtpreempt() +{ + return access("/sys/kernel/realtime", R_OK); +} + +int check_kernel_cmdline() +{ + char cmd[512]; + + FILE *f = fopen("/proc/cmdline", "r"); + if (!f) + return -1; + + if (!fgets(cmd, sizeof(cmd), f)) + return -1; + + return strstr(cmd, "isolcpus=") ? 0 : -1; +} + +int check_root() +{ + return getuid(); +} + +int check_license_time() +{ + return time(NULL) > LICENSE_VALID; +} + +int check_license_trace() +{ + return ptrace(PTRACE_TRACEME, 0, 0, 0) < 0; +} + +int check_license_ids() +{ + const struct { + char *file, *content; + off_t offset; + } checks[] = LICENSE_CHECKS; + + FILE *f; + char buf[128]; + + for (int i = 0; i < ARRAY_LEN(checks); i++) { + f = fopen(checks[i].file, "r"); + if (!f) + return -1; + + fseek(f, checks[i].offset, SEEK_SET); + fgets(buf, sizeof(buf), f); + fclose(f); + + if (strncmp(buf, checks[i].content, strlen(checks[i].content))) + return -1; + } + + return 0; +} + diff --git a/server/src/server.c b/server/src/server.c index 4f6a9a114..3ab5aa0ab 100644 --- a/server/src/server.c +++ b/server/src/server.c @@ -6,7 +6,6 @@ * Unauthorized copying of this file, via any medium is strictly prohibited. *********************************************************************************/ - #include #include @@ -21,7 +20,7 @@ #include "path.h" #include "node.h" #include "stats.h" -#include "license.h" +#include "checks.h" #ifdef ENABLE_OPAL_ASYNC #include "opal.h" @@ -142,12 +141,23 @@ int main(int argc, char *argv[]) info("This is Simulator2Simulator Server (S2SS) %s (built on %s, %s)", BLD(YEL(VERSION)), BLD(MAG(__DATE__)), BLD(MAG(__TIME__))); - /* Check priviledges */ - if (getuid() != 0) + /* Checks system requirements*/ + if (check_root()) error("The server requires superuser privileges!"); - - if (check_license()) - error("You're not allowed to use this software!"); +#ifdef LICENSE + if (check_license_trace()) + error("This software should not be traced!"); + if (check_license_time()) + error("Your license expired"); + if (check_license_ids()) + error("This version is compiled for a different machine!"); +#endif + if (check_kernel_version()) + error("Your kernel version is to old: required >= %u.%u", KERNEL_VERSION_MAJ, KERNEL_VERSION_MIN); + if (check_kernel_cmdline()) + warn("You should reserve some cores for the server (see 'isolcpus')"); + if (check_kernel_rtpreempt()) + warn("We recommend to use an RT_PREEMPT patched kernel!"); /* Initialize lists */ list_init(&nodes, (dtor_cb_t) node_destroy); diff --git a/server/src/utils.c b/server/src/utils.c index 168318f0d..5b5598a0a 100644 --- a/server/src/utils.c +++ b/server/src/utils.c @@ -19,6 +19,18 @@ #include "cfg.h" #include "utils.h" +int version_parse(const char *s, struct version *v) +{ + return sscanf(s, "%u.%u", &v->major, &v->minor) != 2; +} + +int version_compare(struct version *a, struct version *b) { + int major = a->major - b->major; + int minor = a->minor - b->minor; + + return major ? major : minor; +} + double box_muller(float m, float s) { double x1, x2, y1;