aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@aleksander.es>2017-10-16 22:55:02 +0200
committerAleksander Morgado <aleksander@aleksander.es>2017-12-05 10:58:29 +0100
commitee570d44dc117dc69f23e83313dd877f76c5e3e0 (patch)
tree360a1d17e37ab1569cb82153c19bc835e92a0b63 /src
parent33583ca4dea8dd14e9090fc011986577b14b8ede (diff)
filter: new automatic whitelisting rules and strict/paranoid policies
The 'default' filter policy was based on blacklisting as much as possible and otherwise allow. The new 'strict' filter policy will be based on whitelisting as much as much as possible, using custom defined rules, and otherwise forbid the ports. The new 'paranoid' filter policy is equivalent to the 'strict' filter after having applied the blacklist rules from the 'default' filter.
Diffstat (limited to 'src')
-rw-r--r--src/mm-base-manager.c4
-rw-r--r--src/mm-context.c12
-rw-r--r--src/mm-filter.c78
-rw-r--r--src/mm-filter.h77
4 files changed, 142 insertions, 29 deletions
diff --git a/src/mm-base-manager.c b/src/mm-base-manager.c
index a77b4f1b..6961ca90 100644
--- a/src/mm-base-manager.c
+++ b/src/mm-base-manager.c
@@ -1139,7 +1139,9 @@ initable_init (GInitable *initable,
#endif
/* Create filter */
- priv->filter = mm_filter_new (priv->filter_policy);
+ priv->filter = mm_filter_new (priv->filter_policy, error);
+ if (!priv->filter)
+ return FALSE;
/* Create plugin manager */
priv->plugin_manager = mm_plugin_manager_new (priv->plugin_dir, error);
diff --git a/src/mm-context.c b/src/mm-context.c
index 3dac3903..88d71384 100644
--- a/src/mm-context.c
+++ b/src/mm-context.c
@@ -58,6 +58,16 @@ filter_policy_option_arg (const gchar *option_name,
return TRUE;
}
+ if (!g_ascii_strcasecmp (value, "strict")) {
+ filter_policy = MM_FILTER_POLICY_STRICT;
+ return TRUE;
+ }
+
+ if (!g_ascii_strcasecmp (value, "paranoid")) {
+ filter_policy = MM_FILTER_POLICY_PARANOID;
+ return TRUE;
+ }
+
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
"Invalid filter policy value given: %s",
value);
@@ -67,7 +77,7 @@ filter_policy_option_arg (const gchar *option_name,
static const GOptionEntry entries[] = {
{
"filter-policy", 0, 0, G_OPTION_ARG_CALLBACK, filter_policy_option_arg,
- "Filter policy: one of DEFAULT, WHITELIST-ONLY",
+ "Filter policy: one of DEFAULT, WHITELIST-ONLY, STRICT, PARANOID",
"[POLICY]"
},
{
diff --git a/src/mm-filter.c b/src/mm-filter.c
index 50a7dffa..087166f0 100644
--- a/src/mm-filter.c
+++ b/src/mm-filter.c
@@ -81,6 +81,9 @@ mm_filter_port (MMFilter *self,
if ((self->priv->enabled_rules & MM_FILTER_RULE_TTY) &&
(g_strcmp0 (subsystem, "tty") == 0)) {
const gchar *physdev_subsystem;
+ const gchar *driver;
+
+ /* Blacklist rules first */
/* Ignore blacklisted tty devices. */
if ((self->priv->enabled_rules & MM_FILTER_RULE_TTY_BLACKLIST) &&
@@ -97,6 +100,8 @@ mm_filter_port (MMFilter *self,
return FALSE;
}
+ /* Mixed blacklist/whitelist rules */
+
/* If the physdev is a 'platform' or 'pnp' device that's not whitelisted, ignore it */
physdev_subsystem = mm_kernel_device_get_physdev_subsystem (port);
if ((self->priv->enabled_rules & MM_FILTER_RULE_TTY_PLATFORM_DRIVER) &&
@@ -109,8 +114,41 @@ mm_filter_port (MMFilter *self,
return TRUE;
}
- /* Otherwise, TTY probed */
- return TRUE;
+ /* Default allowed? */
+ if (self->priv->enabled_rules & MM_FILTER_RULE_TTY_DEFAULT_ALLOWED) {
+ mm_dbg ("[filter] (%s/%s) port allowed", subsystem, name);
+ return TRUE;
+ }
+
+ /* Whitelist rules last */
+
+ /* If the TTY kernel driver is one expected modem kernel driver, allow it */
+ driver = mm_kernel_device_get_driver (port);
+ if ((self->priv->enabled_rules & MM_FILTER_RULE_TTY_DRIVER) &&
+ (!g_strcmp0 (driver, "option") ||
+ !g_strcmp0 (driver, "qcserial") ||
+ !g_strcmp0 (driver, "sierra"))) {
+ mm_dbg ("[filter] (%s/%s): port allowed: modem-specific kernel driver detected", subsystem, name);
+ return TRUE;
+ }
+
+ /* If the TTY kernel driver is cdc-acm and the interface is class=2/subclass=2/protocol=1, allow it */
+ if ((self->priv->enabled_rules & MM_FILTER_RULE_TTY_ACM_INTERFACE) &&
+ (!g_strcmp0 (driver, "cdc_acm")) &&
+ (mm_kernel_device_get_interface_class (port) == 2) &&
+ (mm_kernel_device_get_interface_subclass (port) == 2) &&
+ (mm_kernel_device_get_interface_protocol (port) == 1)) {
+ mm_dbg ("[filter] (%s/%s): port allowed: cdc-acm interface reported AT-capable", subsystem, name);
+ return TRUE;
+ }
+
+ /* Default forbidden? */
+ if (self->priv->enabled_rules & MM_FILTER_RULE_TTY_DEFAULT_FORBIDDEN) {
+ mm_dbg ("[filter] (%s/%s) port forbidden", subsystem, name);
+ return FALSE;
+ }
+
+ g_assert_not_reached ();
}
/* Otherwise forbidden */
@@ -157,13 +195,30 @@ filter_rule_env_process (MMFilterRule enabled_rules)
/*****************************************************************************/
+/* If TTY rule enabled, either DEFAULT_ALLOWED or DEFAULT_FORBIDDEN must be set. */
+#define VALIDATE_RULE_TTY(rules) (!(rules & MM_FILTER_RULE_TTY) || \
+ ((rules & (MM_FILTER_RULE_TTY_DEFAULT_ALLOWED | MM_FILTER_RULE_TTY_DEFAULT_FORBIDDEN)) && \
+ ((rules & (MM_FILTER_RULE_TTY_DEFAULT_ALLOWED | MM_FILTER_RULE_TTY_DEFAULT_FORBIDDEN)) != \
+ (MM_FILTER_RULE_TTY_DEFAULT_ALLOWED | MM_FILTER_RULE_TTY_DEFAULT_FORBIDDEN))))
+
MMFilter *
-mm_filter_new (MMFilterRule enabled_rules)
+mm_filter_new (MMFilterRule enabled_rules,
+ GError **error)
{
- MMFilter *self;
+ MMFilter *self;
+ MMFilterRule updated_rules;
+
+ /* The input enabled rules are coming from predefined filter profiles. */
+ g_assert (VALIDATE_RULE_TTY (enabled_rules));
+ updated_rules = filter_rule_env_process (enabled_rules);
+ if (!VALIDATE_RULE_TTY (updated_rules)) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
+ "Invalid rules after processing envvars");
+ return NULL;
+ }
self = g_object_new (MM_TYPE_FILTER,
- MM_FILTER_ENABLED_RULES, filter_rule_env_process (enabled_rules),
+ MM_FILTER_ENABLED_RULES, updated_rules,
NULL);
#define RULE_ENABLED_STR(flag) ((self->priv->enabled_rules & flag) ? "yes" : "no")
@@ -173,12 +228,21 @@ mm_filter_new (MMFilterRule enabled_rules)
mm_dbg ("[filter] virtual devices forbidden: %s", RULE_ENABLED_STR (MM_FILTER_RULE_VIRTUAL));
mm_dbg ("[filter] net devices allowed: %s", RULE_ENABLED_STR (MM_FILTER_RULE_NET));
mm_dbg ("[filter] cdc-wdm devices allowed: %s", RULE_ENABLED_STR (MM_FILTER_RULE_CDC_WDM));
- mm_dbg ("[filter] tty devices allowed: %s", RULE_ENABLED_STR (MM_FILTER_RULE_TTY));
if (self->priv->enabled_rules & MM_FILTER_RULE_TTY) {
+ mm_dbg ("[filter] tty devices:");
mm_dbg ("[filter] blacklist applied: %s", RULE_ENABLED_STR (MM_FILTER_RULE_TTY_BLACKLIST));
mm_dbg ("[filter] manual scan only applied: %s", RULE_ENABLED_STR (MM_FILTER_RULE_TTY_MANUAL_SCAN_ONLY));
mm_dbg ("[filter] platform driver check: %s", RULE_ENABLED_STR (MM_FILTER_RULE_TTY_PLATFORM_DRIVER));
- }
+ mm_dbg ("[filter] driver check: %s", RULE_ENABLED_STR (MM_FILTER_RULE_TTY_DRIVER));
+ mm_dbg ("[filter] cdc-acm interface check: %s", RULE_ENABLED_STR (MM_FILTER_RULE_TTY_ACM_INTERFACE));
+ if (self->priv->enabled_rules & MM_FILTER_RULE_TTY_DEFAULT_ALLOWED)
+ mm_dbg ("[filter] default: allowed");
+ else if (self->priv->enabled_rules & MM_FILTER_RULE_TTY_DEFAULT_FORBIDDEN)
+ mm_dbg ("[filter] default: forbidden");
+ else
+ g_assert_not_reached ();
+ } else
+ mm_dbg ("[filter] tty devices: no");
#undef RULE_ENABLED_STR
diff --git a/src/mm-filter.h b/src/mm-filter.h
index ba8afdbe..6c4e7e49 100644
--- a/src/mm-filter.h
+++ b/src/mm-filter.h
@@ -44,26 +44,33 @@ typedef struct {
GType mm_filter_get_type (void);
typedef enum { /*< underscore_name=mm_filter_rule >*/
- MM_FILTER_RULE_NONE = 0,
- MM_FILTER_RULE_EXPLICIT_WHITELIST = 1 << 0,
- MM_FILTER_RULE_VIRTUAL = 1 << 1,
- MM_FILTER_RULE_NET = 1 << 2,
- MM_FILTER_RULE_CDC_WDM = 1 << 3,
- MM_FILTER_RULE_TTY = 1 << 4,
- MM_FILTER_RULE_TTY_BLACKLIST = 1 << 5,
- MM_FILTER_RULE_TTY_MANUAL_SCAN_ONLY = 1 << 6,
- MM_FILTER_RULE_TTY_PLATFORM_DRIVER = 1 << 7,
+ MM_FILTER_RULE_NONE = 0,
+ MM_FILTER_RULE_EXPLICIT_WHITELIST = 1 << 0,
+ MM_FILTER_RULE_VIRTUAL = 1 << 1,
+ MM_FILTER_RULE_NET = 1 << 2,
+ MM_FILTER_RULE_CDC_WDM = 1 << 3,
+ MM_FILTER_RULE_TTY = 1 << 4,
+ MM_FILTER_RULE_TTY_BLACKLIST = 1 << 5,
+ MM_FILTER_RULE_TTY_MANUAL_SCAN_ONLY = 1 << 6,
+ MM_FILTER_RULE_TTY_PLATFORM_DRIVER = 1 << 7,
+ MM_FILTER_RULE_TTY_DEFAULT_ALLOWED = 1 << 8,
+ MM_FILTER_RULE_TTY_DRIVER = 1 << 9,
+ MM_FILTER_RULE_TTY_ACM_INTERFACE = 1 << 10,
+ MM_FILTER_RULE_TTY_DEFAULT_FORBIDDEN = 1 << 11,
} MMFilterRule;
-#define MM_FILTER_RULE_ALL \
- (MM_FILTER_RULE_EXPLICIT_WHITELIST | \
- MM_FILTER_RULE_VIRTUAL | \
- MM_FILTER_RULE_NET | \
- MM_FILTER_RULE_CDC_WDM | \
- MM_FILTER_RULE_TTY | \
- MM_FILTER_RULE_TTY_BLACKLIST | \
- MM_FILTER_RULE_TTY_MANUAL_SCAN_ONLY | \
- MM_FILTER_RULE_TTY_PLATFORM_DRIVER)
+#define MM_FILTER_RULE_ALL \
+ (MM_FILTER_RULE_EXPLICIT_WHITELIST | \
+ MM_FILTER_RULE_VIRTUAL | \
+ MM_FILTER_RULE_NET | \
+ MM_FILTER_RULE_CDC_WDM | \
+ MM_FILTER_RULE_TTY | \
+ MM_FILTER_RULE_TTY_BLACKLIST | \
+ MM_FILTER_RULE_TTY_MANUAL_SCAN_ONLY | \
+ MM_FILTER_RULE_TTY_PLATFORM_DRIVER | \
+ MM_FILTER_RULE_TTY_DEFAULT_ALLOWED | \
+ MM_FILTER_RULE_TTY_DRIVER | \
+ MM_FILTER_RULE_TTY_DEFAULT_FORBIDDEN)
/* This is the default ModemManager policy that tries to automatically probe
* device ports unless they're blacklisted in some way or another. */
@@ -75,13 +82,43 @@ typedef enum { /*< underscore_name=mm_filter_rule >*/
MM_FILTER_RULE_TTY | \
MM_FILTER_RULE_TTY_BLACKLIST | \
MM_FILTER_RULE_TTY_MANUAL_SCAN_ONLY | \
- MM_FILTER_RULE_TTY_PLATFORM_DRIVER)
+ MM_FILTER_RULE_TTY_PLATFORM_DRIVER | \
+ MM_FILTER_RULE_TTY_DEFAULT_ALLOWED)
+
+/* This is a stricter policy which will only automatically probe device ports
+ * if they are allowed by any of the automatic whitelist rules. */
+#define MM_FILTER_POLICY_STRICT \
+ (MM_FILTER_RULE_EXPLICIT_WHITELIST | \
+ MM_FILTER_RULE_VIRTUAL | \
+ MM_FILTER_RULE_NET | \
+ MM_FILTER_RULE_CDC_WDM | \
+ MM_FILTER_RULE_TTY | \
+ MM_FILTER_RULE_TTY_PLATFORM_DRIVER | \
+ MM_FILTER_RULE_TTY_DRIVER | \
+ MM_FILTER_RULE_TTY_ACM_INTERFACE | \
+ MM_FILTER_RULE_TTY_DEFAULT_FORBIDDEN)
+
+/* This is equivalent to the strict policy, but also applying the device
+ * blacklists explicitly */
+#define MM_FILTER_POLICY_PARANOID \
+ (MM_FILTER_RULE_EXPLICIT_WHITELIST | \
+ MM_FILTER_RULE_VIRTUAL | \
+ MM_FILTER_RULE_NET | \
+ MM_FILTER_RULE_CDC_WDM | \
+ MM_FILTER_RULE_TTY | \
+ MM_FILTER_RULE_TTY_BLACKLIST | \
+ MM_FILTER_RULE_TTY_MANUAL_SCAN_ONLY | \
+ MM_FILTER_RULE_TTY_PLATFORM_DRIVER | \
+ MM_FILTER_RULE_TTY_DRIVER | \
+ MM_FILTER_RULE_TTY_ACM_INTERFACE | \
+ MM_FILTER_RULE_TTY_DEFAULT_FORBIDDEN)
/* This policy only allows using device ports explicitly whitelisted via
* udev rules. i.e. ModemManager won't do any kind of automatic probing. */
#define MM_FILTER_POLICY_WHITELIST_ONLY MM_FILTER_RULE_EXPLICIT_WHITELIST
-MMFilter *mm_filter_new (MMFilterRule enabled_rules);
+MMFilter *mm_filter_new (MMFilterRule enabled_rules,
+ GError **error);
gboolean mm_filter_port (MMFilter *self,
MMKernelDevice *port,