daemon: implemented blacklisting/whitelisting of plugins.
authorKrisztian Litkey <kli@iki.fi>
Wed, 20 Nov 2013 22:45:26 +0000 (00:45 +0200)
committerKrisztian Litkey <kli@iki.fi>
Thu, 21 Nov 2013 11:14:28 +0000 (13:14 +0200)
Currently plugins can only be blacklisted/whitelisted on the
command line. You can specify blacklists and whitelists separately
for builtin plugins, dynamic plugins, and plugins of either type.
You can use the special tokens '*' and 'all' as wildcards which
match all tokens. Using wildcards you can easily blacklist or
whitelist all plugins of any or a certain kind then puch holes
on the whiltelists or blacklists.

Examples:
  - to blacklist all builtin plugins, use:
        murphyd --blacklist-builtin '*'

  - to blacklist all builtin plugins except lua and resource-native, use:
        murphyd --blacklist-builtin '*' --whitelist-builtin lua,resource-native

  - to consider all external plugins untrusted and blacklist them, use:
        murphyd --blacklist-dynamic '*'

  - to disable the console:
        murphyd --blacklist console,wrt-console

Note that only the names of builtin plugins can be (somewhat) trusted
and even those cannot be trusted if you don't have any extra mechanisms
for the integrity protection of binaries and libraries. External plugins
can always be copied/moved under a different name, so disabling any
specific external plugin by name should not be considered secure by any
means. One typical usage of these options is to disable loading of any
external plugins.

src/core/context.h
src/core/plugin.c
src/daemon/config.c
src/daemon/daemon.c

index b472baf..01999e7 100644 (file)
@@ -60,6 +60,13 @@ struct mrp_context_s {
 
     char       *resolver_ruleset;          /* resolver ruleset file */
 
+    const char *blacklist_plugins;         /* blacklisted plugins */
+    const char *blacklist_builtin;         /* blacklisted builtin plugins */
+    const char *blacklist_dynamic;         /* blacklisted dynamic plugins */
+    const char *whitelist_plugins;         /* whitelisted plugins */
+    const char *whitelist_builtin;         /* whitelisted builtin plugins */
+    const char *whitelist_dynamic;         /* whitelisted dynamic plugins */
+
     /* actual runtime context data */
     int              state;                /* context/daemon state */
     mrp_mainloop_t  *ml;                   /* mainloop */
index f72b7b1..75988eb 100644 (file)
 #include <murphy/core/event.h>
 #include <murphy/core/plugin.h>
 
-
 #define PLUGIN_PREFIX "plugin-"
+#define BUILTIN TRUE
+#define DYNAMIC FALSE
 
-static mrp_plugin_descr_t *open_builtin(const char *name);
-static mrp_plugin_descr_t *open_dynamic(const char *path, void **handle);
+static mrp_plugin_descr_t *open_builtin(mrp_context_t *ctx, const char *name);
+static mrp_plugin_descr_t *open_dynamic(mrp_context_t *ctx, const char *name,
+                                        void **handle);
 static mrp_plugin_t *find_plugin(mrp_context_t *ctx, char *name);
 static mrp_plugin_t *find_plugin_instance(mrp_context_t *ctx,
                                           const char *instance);
@@ -90,6 +92,115 @@ MRP_REGISTER_EVENTS(events,
                     { MRP_PLUGIN_EVENT_UNLOADED, PLUGIN_EVENT_UNLOADED });
 
 
+static inline int is_listed(const char *list,  const char *name)
+{
+    const char *b, *n, *e;
+
+    if (list == NULL || name == NULL)
+        return FALSE;
+
+    if ((list[0] == '*' && list[1] == '\0') || (!strcmp(list, "all")))
+        return TRUE;
+
+    b = list;
+    while (b && *b) {
+        while (*b == ' ' || *b == '\t' || *b == ',')
+            b++;
+
+        if ((e = n = strchr(b, ',')) != NULL) {
+            while (e > b && (*e == ' ' || *e == '\t' || *e == ','))
+                e--;
+        }
+
+        if ((e != NULL && e > b && !strncmp(b, name, e - b)) ||
+            (e == NULL &&          !strcmp (b, name)))
+            return TRUE;
+
+        if ((b[0] == '*' && (b[1] == ',' ||
+                             b[1] == ' ' || b[1] == '\t' ||
+                             b[1] == '\0')) ||
+            (b[0] == 'a' && b[1] == 'l' && b[2] == 'l' &&
+             (b[1] == ',' ||
+              b[1] == ' ' || b[1] == '\t' ||
+              b[1] == '\0'))) {
+            mrp_log_warning("Wildcard entry in blacklist/whitelist '%s'", list);
+            return TRUE;
+        }
+
+        b = n ? n + 1 : NULL;
+    }
+
+    return FALSE;
+}
+
+
+static inline int is_blacklisted(mrp_context_t *ctx, const char *name,
+                                 int builtin)
+{
+#define IS_WILDCARD(l) \
+    (((l) != NULL && (l)[0] == '*' && (l)[1] == '\0') ||        \
+     ((l) != NULL && !strcmp((l), "all")))
+
+    const char *bl, *wl, *type_bl, *type_wl;
+    int         b, w, tb, tw, blacklist;
+
+    mrp_debug("checking if %s plugin %s is blacklisted",
+              builtin ? "builtin" : "dynamic", name);
+
+    bl = ctx->blacklist_plugins;
+    wl = ctx->whitelist_plugins;
+    b  = is_listed(bl, name);
+    w  = is_listed(wl, name);
+
+    if (builtin) {
+        type_bl = ctx->blacklist_builtin;
+        type_wl = ctx->whitelist_builtin;
+    }
+    else {
+        type_bl = ctx->blacklist_dynamic;
+        type_wl = ctx->whitelist_dynamic;
+    }
+
+    tb = is_listed(type_bl, name);
+    tw = is_listed(type_wl, name);
+
+    mrp_debug("%s: b:(%s,%s), w:(%s,%s)", name,
+              b ? "true" : "false", tb ? "true" : "false",
+              w ? "true" : "false", tw ? "true" : "false");
+
+    if (IS_WILDCARD(bl) || IS_WILDCARD(type_bl)) {
+        if (w || tw)
+            blacklist = FALSE;
+         else
+            blacklist = TRUE;
+
+        goto verdict;
+    }
+
+    if (IS_WILDCARD(wl) || IS_WILDCARD(type_wl)) {
+        if (b || tb)
+            blacklist = TRUE;
+        else
+            blacklist = FALSE;
+
+        goto verdict;
+    }
+
+    blacklist = (( is_listed(bl, name) || is_listed(type_bl, name)) &&
+                 !(is_listed(wl, name) || is_listed(type_wl, name)));
+
+
+ verdict:
+    if (blacklist)
+        mrp_log_warning("%s plugin '%s' is blacklisted.",
+                        builtin ? "Builtin" : "Dynamic", name);
+
+    mrp_debug("%s: %sblacklisted", name, blacklist ? "" : "not ");
+
+    return blacklist;
+}
+
+
 static int emit_plugin_event(int idx, mrp_plugin_t *plugin)
 {
     uint16_t name = MRP_PLUGIN_TAG_PLUGIN;
@@ -129,9 +240,12 @@ int mrp_plugin_exists(mrp_context_t *ctx, const char *name)
     struct stat st;
     char        path[PATH_MAX];
 
-    if (open_builtin(name))
+    if (open_builtin(ctx, name))
         return TRUE;
     else {
+        if (is_blacklisted(ctx, name, DYNAMIC))
+            return FALSE;
+
         snprintf(path, sizeof(path), "%s/%s%s.so", ctx->plugin_dir,
                  PLUGIN_PREFIX, name);
         if (stat(path, &st) == 0)
@@ -199,8 +313,8 @@ mrp_plugin_t *mrp_load_plugin(mrp_context_t *ctx, const char *name,
     snprintf(path, sizeof(path), "%s/%s%s.so", ctx->plugin_dir,
              PLUGIN_PREFIX, name);
 
-    dynamic = open_dynamic(path, &handle);
-    builtin = open_builtin(name);
+    dynamic = open_dynamic(ctx, name, &handle);
+    builtin = open_builtin(ctx, name);
 
     if (dynamic != NULL) {
         if (builtin != NULL)
@@ -334,7 +448,6 @@ int mrp_load_all_plugins(mrp_context_t *ctx)
     pattern = PLUGIN_PREFIX".*\\.so$";
     mrp_scan_dir(ctx->plugin_dir, pattern, type, load_plugin_cb, ctx);
 
-
     mrp_list_foreach(&builtin_plugins, p, n) {
         plugin = mrp_list_entry(p, typeof(*plugin), hook);
 
@@ -556,11 +669,19 @@ static mrp_plugin_t *find_plugin(mrp_context_t *ctx, char *name)
 }
 
 
-static mrp_plugin_descr_t *open_dynamic(const char *path, void **handle)
+static mrp_plugin_descr_t *open_dynamic(mrp_context_t *ctx, const char *name,
+                                        void **handle)
 {
     mrp_plugin_descr_t *(*describe)(void);
     mrp_plugin_descr_t   *d;
     void                 *h;
+    char                  path[PATH_MAX];
+
+    snprintf(path, sizeof(path), "%s/%s%s.so", ctx->plugin_dir,
+             PLUGIN_PREFIX, name);
+
+    if (is_blacklisted(ctx, name, DYNAMIC))
+        return NULL;
 
     if ((h = dlopen(path, RTLD_LAZY | RTLD_LOCAL)) != NULL) {
         if ((describe = dlsym(h, "mrp_get_plugin_descriptor")) != NULL) {
@@ -601,11 +722,14 @@ static mrp_plugin_descr_t *open_dynamic(const char *path, void **handle)
 }
 
 
-static mrp_plugin_descr_t *open_builtin(const char *name)
+static mrp_plugin_descr_t *open_builtin(mrp_context_t *ctx, const char *name)
 {
     mrp_list_hook_t *p, *n;
     mrp_plugin_t    *plugin;
 
+    if (is_blacklisted(ctx, name, BUILTIN))
+        return NULL;
+
     mrp_list_foreach(&builtin_plugins, p, n) {
         plugin = mrp_list_entry(p, typeof(*plugin), hook);
 
index 3776025..6c45dfc 100644 (file)
@@ -87,6 +87,12 @@ static void print_usage(mrp_context_t *ctx, const char *argv0, int exit_code,
            "  -h, --help                     show help on usage\n"
            "  -q, --query-plugins            show detailed information about\n"
            "                                 all the available plugins\n"
+           "  -B, --blacklist-plugins <list> disable list of plugins\n"
+           "  -I, --blacklist-builtin <list> disable list of builtin plugins\n"
+           "  -E, --blacklist-dynamic <list> disable list of dynamic plugins\n"
+           "  -w, --whitelist-plugins <list> disable list of plugins\n"
+           "  -i, --whitelist-builtin <list> disable list of builtin plugins\n"
+           "  -e, --whitelist-dynamic <list> disable list of dynamic plugins\n"
            "  -V, --valgrind                 run through valgrind\n",
            argv0, ctx->config_file, ctx->config_dir, ctx->plugin_dir);
 
@@ -220,21 +226,29 @@ static void config_set_defaults(mrp_context_t *ctx, char *argv0)
 
 void mrp_parse_cmdline(mrp_context_t *ctx, int argc, char **argv, char **envp)
 {
-#   define OPTIONS "c:C:l:t:fP:a:vd:DhHqV"
+#   define OPTIONS "c:C:l:t:fP:a:vd:DhHqB:I:E:w:i:e:V"
     struct option options[] = {
-        { "config-file"  , required_argument, NULL, 'c' },
-        { "config-dir"   , required_argument, NULL, 'C' },
-        { "plugin-dir"   , required_argument, NULL, 'P' },
-        { "log-level"    , required_argument, NULL, 'l' },
-        { "log-target"   , required_argument, NULL, 't' },
-        { "verbose"      , optional_argument, NULL, 'v' },
-        { "debug"        , required_argument, NULL, 'd' },
-        { "list-debug"   , no_argument      , NULL, 'D' },
-        { "foreground"   , no_argument      , NULL, 'f' },
-        { "help"         , no_argument      , NULL, 'h' },
-        { "more-help"    , no_argument      , NULL, 'H' },
-        { "query-plugins", no_argument      , NULL, 'q' },
-        { "valgrind"     , optional_argument, NULL, 'V' },
+        { "config-file"      , required_argument, NULL, 'c' },
+        { "config-dir"       , required_argument, NULL, 'C' },
+        { "plugin-dir"       , required_argument, NULL, 'P' },
+        { "log-level"        , required_argument, NULL, 'l' },
+        { "log-target"       , required_argument, NULL, 't' },
+        { "verbose"          , optional_argument, NULL, 'v' },
+        { "debug"            , required_argument, NULL, 'd' },
+        { "list-debug"       , no_argument      , NULL, 'D' },
+        { "foreground"       , no_argument      , NULL, 'f' },
+        { "help"             , no_argument      , NULL, 'h' },
+        { "more-help"        , no_argument      , NULL, 'H' },
+        { "query-plugins"    , no_argument      , NULL, 'q' },
+        { "blacklist"        , required_argument, NULL, 'B' },
+        { "blacklist-plugins", required_argument, NULL, 'B' },
+        { "blacklist-builtin", required_argument, NULL, 'I' },
+        { "blacklist-dynamic", required_argument, NULL, 'E' },
+        { "whitelist"        , required_argument, NULL, 'w' },
+        { "whitelist-plugins", required_argument, NULL, 'w' },
+        { "whitelist-builtin", required_argument, NULL, 'i' },
+        { "whitelist-dynamic", required_argument, NULL, 'e' },
+        { "valgrind"         , optional_argument, NULL, 'V' },
         { NULL, 0, NULL, 0 }
     };
 
@@ -334,6 +348,48 @@ void mrp_parse_cmdline(mrp_context_t *ctx, int argc, char **argv, char **envp)
             print_plugin_help(ctx, TRUE);
             break;
 
+        case 'B':
+            if (ctx->blacklist_plugins != NULL)
+                print_usage(ctx, argv[0], EINVAL,
+                            "blacklist option given multiple times");
+            SAVE_OPTARG("-B", optarg);
+            ctx->blacklist_plugins = optarg;
+            break;
+        case 'I':
+            if (ctx->blacklist_builtin != NULL)
+                print_usage(ctx, argv[0], EINVAL,
+                            "builtin blacklist option given multiple times");
+            SAVE_OPTARG("-I", optarg);
+            ctx->blacklist_builtin = optarg;
+            break;
+        case 'E':
+            if (ctx->blacklist_dynamic != NULL)
+                print_usage(ctx, argv[0], EINVAL,
+                            "dynamic blacklist option given multiple times");
+            SAVE_OPTARG("-E", optarg);
+            ctx->blacklist_dynamic = optarg;
+            break;
+        case 'w':
+            if (ctx->whitelist_plugins != NULL)
+                print_usage(ctx, argv[0], EINVAL,
+                            "whitelist option given multiple times");
+            SAVE_OPTARG("-w", optarg);
+            ctx->whitelist_plugins = optarg;
+            break;
+        case 'i':
+            if (ctx->whitelist_builtin != NULL)
+                print_usage(ctx, argv[0], EINVAL,
+                            "builtin whitelist option given multiple times");
+            SAVE_OPTARG("-i", optarg);
+            ctx->whitelist_builtin = optarg;
+            break;
+        case 'e':
+            if (ctx->whitelist_dynamic != NULL)
+                print_usage(ctx, argv[0], EINVAL,
+                            "dynamic whitelist option given multiple times");
+            SAVE_OPTARG("-e", optarg);
+            ctx->whitelist_dynamic = optarg;
+            break;
         case 'V':
             valgrind(optarg, argc, argv, optind, saved_argc, saved_argv, envp);
             break;
index e292be7..27931c4 100644 (file)
@@ -129,6 +129,19 @@ static void load_configuration(mrp_context_t *ctx)
     cfg = mrp_parse_cfgfile(ctx->config_file);
 
     if (cfg != NULL) {
+        mrp_log_info("Blacklisted plugins of any type: %s",
+                     ctx->blacklist_plugins ? ctx->blacklist_plugins:"<none>");
+        mrp_log_info("Blacklisted builtin plugins: %s",
+                     ctx->blacklist_builtin ? ctx->blacklist_builtin:"<none>");
+        mrp_log_info("Blacklisted dynamic plugins: %s",
+                     ctx->blacklist_dynamic ? ctx->blacklist_dynamic:"<none>");
+        mrp_log_info("Whitelisted plugins of any type: %s",
+                     ctx->whitelist_plugins ? ctx->whitelist_plugins:"<none>");
+        mrp_log_info("Whitelisted builtin plugins: %s",
+                     ctx->whitelist_builtin ? ctx->whitelist_builtin:"<none>");
+        mrp_log_info("Whitelisted dynamic plugins: %s",
+                     ctx->whitelist_dynamic ? ctx->whitelist_dynamic:"<none>");
+
         if (!mrp_exec_cfgfile(ctx, cfg)) {
             mrp_log_error("Failed to execute configuration.");
             exit(1);