linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC 0/4] cfg80211: in-kernel regulatory database
@ 2017-09-15 10:18 Johannes Berg
  2017-09-15 10:18 ` [RFC 1/4] cfg80211: support loading regulatory database as firmware file Johannes Berg
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Johannes Berg @ 2017-09-15 10:18 UTC (permalink / raw)
  To: linux-wireless

I've been sitting on these patches for pretty much 2 years, waiting
for the firmware loader to gain signature checking abilities. This
hasn't happened, and even the suggested code from AKASHI Takahiro
doesn't fulfill all requirements, notably having extra keys/keyring.

I'm not sure building the keys into the module really is the best
option, but then again, that's the same way it's done with crda.

Additionally, we've not been able to extend the regulatory database
format, and for even longer we've been wanting to do that, e.g. to
add spectral density power limits and DFS configuration. Since the
new database format is easily extensible (variable size on all of
the structures used, with only the minimum size being required), the
extensions can finally be done with this.

johannes

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [RFC 1/4] cfg80211: support loading regulatory database as firmware file
  2017-09-15 10:18 [RFC 0/4] cfg80211: in-kernel regulatory database Johannes Berg
@ 2017-09-15 10:18 ` Johannes Berg
  2017-09-15 10:18 ` [RFC 2/4] cfg80211: support reloading regulatory database Johannes Berg
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 6+ messages in thread
From: Johannes Berg @ 2017-09-15 10:18 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

As the current regulatory database is only about 4k big, and already
difficult to extend, we decided that overall it would be better to
get rid of the complications with CRDA and load the database into the
kernel directly, but in a new format that is extensible.

The new file format can be extended since it carries a length field
on all the structs that need to be extensible.

In order to be able to request firmware when the module initializes,
move cfg80211 from subsys_initcall() to the later fs_initcall(); the
firmware loader is at the same level but linked earlier, so it can
be called from there. Otherwise, when both the firmware loader and
cfg80211 are built-in, the request will crash the kernel. We also
need to be before device_initcall() so that cfg80211 is available
for devices when they initialize.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 Documentation/networking/regulatory.txt |   8 +
 net/wireless/Kconfig                    |   4 +-
 net/wireless/core.c                     |   2 +-
 net/wireless/reg.c                      | 265 +++++++++++++++++++++++++++++---
 4 files changed, 255 insertions(+), 24 deletions(-)

diff --git a/Documentation/networking/regulatory.txt b/Documentation/networking/regulatory.txt
index 7818b5fe448b..46c8d8b1cc66 100644
--- a/Documentation/networking/regulatory.txt
+++ b/Documentation/networking/regulatory.txt
@@ -19,6 +19,14 @@ core regulatory domain all wireless devices should adhere to.
 How to get regulatory domains to the kernel
 -------------------------------------------
 
+When the regulatory domain is first set up, the kernel will request a
+database file (regulatory.db) containing all the regulatory rules. It
+will then use that database when it needs to look up the rules for a
+given country.
+
+How to get regulatory domains to the kernel (old CRDA solution)
+---------------------------------------------------------------
+
 Userspace gets a regulatory domain in the kernel by having
 a userspace agent build it and send it via nl80211. Only
 expected regulatory domains will be respected by the kernel.
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index 6c606120abfe..24eec5516649 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -19,6 +19,7 @@ config WEXT_PRIV
 config CFG80211
 	tristate "cfg80211 - wireless configuration API"
 	depends on RFKILL || !RFKILL
+	select FW_LOADER
 	---help---
 	  cfg80211 is the Linux wireless LAN (802.11) configuration API.
 	  Enable this if you have a wireless device.
@@ -167,7 +168,8 @@ config CFG80211_CRDA_SUPPORT
 	depends on CFG80211
 	help
 	  You should enable this option unless you know for sure you have no
-	  need for it, for example when using internal regdb (above.)
+	  need for it, for example when using internal regdb (above) or the
+	  database loaded as a firmware file.
 
 	  If unsure, say Y.
 
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 7b33e8c366bc..fdde0d98fde1 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -1384,7 +1384,7 @@ static int __init cfg80211_init(void)
 out_fail_pernet:
 	return err;
 }
-subsys_initcall(cfg80211_init);
+fs_initcall(cfg80211_init);
 
 static void __exit cfg80211_exit(void)
 {
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 5fae296a6a58..7a1d6cda64f3 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -53,6 +53,7 @@
 #include <linux/nl80211.h>
 #include <linux/platform_device.h>
 #include <linux/moduleparam.h>
+#include <linux/firmware.h>
 #include <net/cfg80211.h>
 #include "core.h"
 #include "reg.h"
@@ -99,7 +100,7 @@ static struct regulatory_request core_request_world = {
 static struct regulatory_request __rcu *last_request =
 	(void __force __rcu *)&core_request_world;
 
-/* To trigger userspace events */
+/* To trigger userspace events and load firmware */
 static struct platform_device *reg_pdev;
 
 /*
@@ -442,7 +443,6 @@ reg_copy_regd(const struct ieee80211_regdomain *src_regd)
 	return regd;
 }
 
-#ifdef CONFIG_CFG80211_INTERNAL_REGDB
 struct reg_regdb_apply_request {
 	struct list_head list;
 	const struct ieee80211_regdomain *regdom;
@@ -474,41 +474,44 @@ static void reg_regdb_apply(struct work_struct *work)
 
 static DECLARE_WORK(reg_regdb_work, reg_regdb_apply);
 
-static int reg_query_builtin(const char *alpha2)
+static int reg_schedule_apply(const struct ieee80211_regdomain *regdom)
 {
-	const struct ieee80211_regdomain *regdom = NULL;
 	struct reg_regdb_apply_request *request;
-	unsigned int i;
-
-	for (i = 0; i < reg_regdb_size; i++) {
-		if (alpha2_equal(alpha2, reg_regdb[i]->alpha2)) {
-			regdom = reg_regdb[i];
-			break;
-		}
-	}
-
-	if (!regdom)
-		return -ENODATA;
 
 	request = kzalloc(sizeof(struct reg_regdb_apply_request), GFP_KERNEL);
-	if (!request)
-		return -ENOMEM;
-
-	request->regdom = reg_copy_regd(regdom);
-	if (IS_ERR_OR_NULL(request->regdom)) {
-		kfree(request);
+	if (!request) {
+		kfree(regdom);
 		return -ENOMEM;
 	}
 
+	request->regdom = regdom;
+
 	mutex_lock(&reg_regdb_apply_mutex);
 	list_add_tail(&request->list, &reg_regdb_apply_list);
 	mutex_unlock(&reg_regdb_apply_mutex);
 
 	schedule_work(&reg_regdb_work);
-
 	return 0;
 }
 
+#ifdef CONFIG_CFG80211_INTERNAL_REGDB
+static int reg_query_builtin(const char *alpha2)
+{
+	const struct ieee80211_regdomain *regdom = NULL;
+	unsigned int i;
+
+	for (i = 0; i < reg_regdb_size; i++) {
+		if (alpha2_equal(alpha2, reg_regdb[i]->alpha2)) {
+			regdom = reg_copy_regd(reg_regdb[i]);
+			break;
+		}
+	}
+	if (!regdom)
+		return -ENODATA;
+
+	return reg_schedule_apply(regdom);
+}
+
 /* Feel free to add any other sanity checks here */
 static void reg_regdb_size_check(void)
 {
@@ -598,12 +601,227 @@ static inline int call_crda(const char *alpha2)
 }
 #endif /* CONFIG_CFG80211_CRDA_SUPPORT */
 
+/* code to directly load a firmware database through request_firmware */
+static const struct firmware *regdb;
+static unsigned int fwregdb_attempts = 10;
+
+struct fwdb_country {
+	u8 alpha2[2];
+	__be16 coll_ptr;
+} __packed __aligned(4);
+
+struct fwdb_collection {
+	__be16 len;
+	__be16 n_rules;
+	u8 dfs_region;
+	u8 pad_reserved;
+	__be16 rules_ptr[];
+} __packed __aligned(4);
+
+struct fwdb_rule {
+	__be16 len;
+	__be16 flags;
+	__be32 start, end, max_bw;
+	__be32 cac_timeout;
+	__be16 max_ant_gain;
+	__be16 max_eirp;
+} __packed __aligned(4);
+
+#define FWDB_MAGIC 0x52474442
+#define FWDB_VERSION 20
+
+struct fwdb_header {
+	__be32 magic;
+	__be32 version;
+	struct fwdb_country country[];
+} __packed __aligned(4);
+
+static bool valid_rule(const struct firmware *db, u16 rule_ptr)
+{
+	struct fwdb_rule *rule = (void *)(db->data + (rule_ptr << 2));
+
+	if ((u8 *)rule + sizeof(rule->len) > db->data + db->size)
+		return false;
+
+	/* mandatory fields */
+	if (be16_to_cpu(rule->len) < offsetofend(struct fwdb_rule, max_eirp))
+		return false;
+
+	return true;
+}
+
+static bool valid_country(const struct firmware *db,
+			  const struct fwdb_country *country)
+{
+	unsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
+	struct fwdb_collection *coll = (void *)(db->data + ptr);
+	unsigned int i;
+
+	if ((u8 *)coll + sizeof(coll->len) > db->data + db->size)
+		return false;
+
+	if ((u8 *)coll + be16_to_cpu(coll->len) > db->data + db->size)
+		return false;
+
+	/* mandatory fields */
+	if (be16_to_cpu(coll->len) < offsetof(struct fwdb_collection,
+					      rules_ptr))
+		return false;
+
+	if (be16_to_cpu(coll->len) < offsetof(struct fwdb_collection,
+					      rules_ptr) +
+				     be16_to_cpu(coll->n_rules) *
+					sizeof(coll->rules_ptr[0]))
+		return false;
+
+	for (i = 0; i < be16_to_cpu(coll->n_rules); i++) {
+		u16 rule_ptr = be16_to_cpu(coll->rules_ptr[i]);
+
+		if (!valid_rule(db, rule_ptr))
+			return false;
+	}
+
+	return true;
+}
+
+static bool valid_regdb(const struct firmware *db)
+{
+	const struct fwdb_header *hdr = (void *)db->data;
+	const struct fwdb_country *country;
+
+	if (db->size < sizeof(*hdr))
+		return false;
+
+	if (hdr->magic != cpu_to_be32(FWDB_MAGIC))
+		return false;
+
+	if (hdr->version != cpu_to_be32(FWDB_VERSION))
+		return false;
+
+	country = &hdr->country[0];
+	while ((u8 *)(country + 1) <= db->data + db->size) {
+		if (!country->coll_ptr)
+			break;
+		if (!valid_country(db, country))
+			return false;
+		country++;
+	}
+
+	return true;
+}
+
+static int regdb_query_country(const struct firmware *db,
+			       const struct fwdb_country *country)
+{
+	unsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
+	struct fwdb_collection *coll = (void *)(db->data + ptr);
+	struct ieee80211_regdomain *regdom;
+	unsigned int size_of_regd;
+	unsigned int i;
+
+	size_of_regd =
+		sizeof(struct ieee80211_regdomain) +
+		be16_to_cpu(coll->n_rules) * sizeof(struct ieee80211_reg_rule);
+
+	regdom = kzalloc(size_of_regd, GFP_KERNEL);
+	if (!regdom)
+		return -ENOMEM;
+
+	regdom->n_reg_rules = be16_to_cpu(coll->n_rules);
+	regdom->alpha2[0] = country->alpha2[0];
+	regdom->alpha2[1] = country->alpha2[1];
+	regdom->dfs_region = coll->dfs_region;
+
+	for (i = 0; i < regdom->n_reg_rules; i++) {
+		unsigned int rule_ptr = be16_to_cpu(coll->rules_ptr[i]) << 2;
+		struct fwdb_rule *rule = (void *)(db->data + rule_ptr);
+		struct ieee80211_reg_rule *rrule = &regdom->reg_rules[i];
+
+		rrule->freq_range.start_freq_khz = be32_to_cpu(rule->start);
+		rrule->freq_range.end_freq_khz = be32_to_cpu(rule->end);
+		rrule->freq_range.max_bandwidth_khz = be32_to_cpu(rule->max_bw);
+
+		rrule->power_rule.max_antenna_gain =
+			be16_to_cpu(rule->max_ant_gain);
+		rrule->power_rule.max_eirp = be16_to_cpu(rule->max_eirp);
+
+		rrule->flags = be16_to_cpu(rule->flags);
+		rrule->dfs_cac_ms = be32_to_cpu(rule->cac_timeout);
+	}
+
+	return reg_schedule_apply(regdom);
+}
+
+static int query_regdb(const char *alpha2)
+{
+	const struct fwdb_header *hdr;
+	const struct fwdb_country *country;
+
+	if (IS_ERR(regdb))
+		return PTR_ERR(regdb);
+
+	hdr = (void *)regdb->data;
+	country = &hdr->country[0];
+	while (country->coll_ptr) {
+		if (alpha2_equal(alpha2, country->alpha2))
+			return regdb_query_country(regdb, country);
+		country++;
+	}
+
+	return -ENODATA;
+}
+
+static void regdb_fw_cb(const struct firmware *fw, void *context)
+{
+	if (!fw) {
+		pr_info("failed to load regulatory.db\n");
+		if (fwregdb_attempts-- == 0)
+			regdb = ERR_PTR(-ENODATA);
+		goto restore;
+	}
+
+	if (!valid_regdb(fw)) {
+		pr_info("loaded regulatory.db is malformed\n");
+		release_firmware(fw);
+		regdb = ERR_PTR(-EINVAL);
+		goto restore;
+	}
+
+	regdb = fw;
+	if (query_regdb(context))
+		goto restore;
+	goto free;
+ restore:
+	rtnl_lock();
+	restore_regulatory_settings(true);
+	rtnl_unlock();
+ free:
+	kfree(context);
+}
+
+static int query_regdb_file(const char *alpha2)
+{
+	if (regdb)
+		return query_regdb(alpha2);
+
+	alpha2 = kmemdup(alpha2, 2, GFP_KERNEL);
+	if (!alpha2)
+		return -ENOMEM;
+
+	return request_firmware_nowait(THIS_MODULE, true, "regulatory.db",
+				       &reg_pdev->dev, GFP_KERNEL,
+				       (void *)alpha2, regdb_fw_cb);
+}
+
 static bool reg_query_database(struct regulatory_request *request)
 {
 	/* query internal regulatory database (if it exists) */
 	if (reg_query_builtin(request->alpha2) == 0)
 		return true;
 
+	if (query_regdb_file(request->alpha2) == 0)
+		return true;
+
 	if (call_crda(request->alpha2) == 0)
 		return true;
 
@@ -3344,4 +3562,7 @@ void regulatory_exit(void)
 		list_del(&reg_request->list);
 		kfree(reg_request);
 	}
+
+	if (!IS_ERR_OR_NULL(regdb))
+		release_firmware(regdb);
 }
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [RFC 2/4] cfg80211: support reloading regulatory database
  2017-09-15 10:18 [RFC 0/4] cfg80211: in-kernel regulatory database Johannes Berg
  2017-09-15 10:18 ` [RFC 1/4] cfg80211: support loading regulatory database as firmware file Johannes Berg
@ 2017-09-15 10:18 ` Johannes Berg
  2017-09-15 10:18 ` [RFC 3/4] cfg80211: reg: remove support for built-in regdb Johannes Berg
  2017-09-15 10:18 ` [RFC 4/4] cfg80211: implement regdb signature checking Johannes Berg
  3 siblings, 0 replies; 6+ messages in thread
From: Johannes Berg @ 2017-09-15 10:18 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

If the regulatory database is loaded, and then updated, it may
be necessary to reload it. Add an nl80211 command to do this,
and RCU-ify the pointer to the regdb "firmware" to allow it to
be replaced at runtime.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 include/uapi/linux/nl80211.h |  4 +++
 net/wireless/nl80211.c       | 11 ++++++
 net/wireless/reg.c           | 84 ++++++++++++++++++++++++++++++++++++--------
 net/wireless/reg.h           |  6 ++++
 4 files changed, 90 insertions(+), 15 deletions(-)

diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 51626b4175c0..926eb92cb4a8 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -983,6 +983,8 @@
  *	configured PMK for the authenticator address identified by
  *	&NL80211_ATTR_MAC.
  *
+ * @NL80211_CMD_RELOAD_REGDB: Request that the regdb firmware file is reloaded.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -1185,6 +1187,8 @@ enum nl80211_commands {
 	NL80211_CMD_SET_PMK,
 	NL80211_CMD_DEL_PMK,
 
+	NL80211_CMD_RELOAD_REGDB,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 8ce85420ecb0..ee902ea13833 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5669,6 +5669,11 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
 	}
 }
 
+static int nl80211_reload_regdb(struct sk_buff *skb, struct genl_info *info)
+{
+	return reg_reload_regdb();
+}
+
 static int nl80211_get_mesh_config(struct sk_buff *skb,
 				   struct genl_info *info)
 {
@@ -12668,6 +12673,12 @@ static const struct genl_ops nl80211_ops[] = {
 		.policy = nl80211_policy,
 		.flags = GENL_ADMIN_PERM,
 	},
+	{
+		.cmd = NL80211_CMD_RELOAD_REGDB,
+		.doit = nl80211_reload_regdb,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
 	{
 		.cmd = NL80211_CMD_GET_MESH_CONFIG,
 		.doit = nl80211_get_mesh_config,
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 7a1d6cda64f3..8d366738c08a 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -602,7 +602,7 @@ static inline int call_crda(const char *alpha2)
 #endif /* CONFIG_CFG80211_CRDA_SUPPORT */
 
 /* code to directly load a firmware database through request_firmware */
-static const struct firmware *regdb;
+static const struct firmware __rcu *regdb;
 static unsigned int fwregdb_attempts = 10;
 
 struct fwdb_country {
@@ -756,47 +756,76 @@ static int query_regdb(const char *alpha2)
 {
 	const struct fwdb_header *hdr;
 	const struct fwdb_country *country;
+	const struct firmware *db;
+	int err;
 
-	if (IS_ERR(regdb))
-		return PTR_ERR(regdb);
+	rcu_read_lock();
+	db = rcu_dereference(regdb);
 
-	hdr = (void *)regdb->data;
+	if (IS_ERR(db)) {
+		err = PTR_ERR(db);
+		goto out;
+	}
+
+	hdr = (void *)db->data;
 	country = &hdr->country[0];
 	while (country->coll_ptr) {
-		if (alpha2_equal(alpha2, country->alpha2))
-			return regdb_query_country(regdb, country);
+		if (alpha2_equal(alpha2, country->alpha2)) {
+			err = regdb_query_country(db, country);
+			goto out;
+		}
 		country++;
 	}
 
-	return -ENODATA;
+	err = -ENODATA;
+ out:
+	rcu_read_unlock();
+	return err;
 }
 
 static void regdb_fw_cb(const struct firmware *fw, void *context)
 {
+	const struct firmware *db;
+
+	rtnl_lock();
+
+	db = rcu_dereference_protected(regdb, lockdep_rtnl_is_held());
+
+	if (WARN_ON(db)) {
+		release_firmware(fw);
+		goto out;
+	}
+
 	if (!fw) {
 		pr_info("failed to load regulatory.db\n");
 		if (fwregdb_attempts-- == 0)
-			regdb = ERR_PTR(-ENODATA);
+			rcu_assign_pointer(regdb, ERR_PTR(-ENODATA));
 		goto restore;
 	}
 
 	if (!valid_regdb(fw)) {
 		pr_info("loaded regulatory.db is malformed\n");
 		release_firmware(fw);
-		regdb = ERR_PTR(-EINVAL);
+		rcu_assign_pointer(regdb, ERR_PTR(-EINVAL));
 		goto restore;
 	}
 
-	regdb = fw;
-	if (query_regdb(context))
+	rcu_assign_pointer(regdb, fw);
+
+	if (context && query_regdb(context))
 		goto restore;
-	goto free;
+	goto out;
+
  restore:
-	rtnl_lock();
 	restore_regulatory_settings(true);
+ out:
 	rtnl_unlock();
- free:
 	kfree(context);
+
+	if (!IS_ERR_OR_NULL(db)) {
+		synchronize_rcu();
+		release_firmware(db);
+	}
 }
 
 static int query_regdb_file(const char *alpha2)
@@ -813,6 +842,31 @@ static int query_regdb_file(const char *alpha2)
 				       (void *)alpha2, regdb_fw_cb);
 }
 
+int reg_reload_regdb(void)
+{
+	const struct firmware *db, *old;
+	int err;
+
+	err = request_firmware(&db, "regulatory.db", &reg_pdev->dev);
+	if (err)
+		return err;
+
+	if (!valid_regdb(db))
+		return -ENODATA;
+
+	rtnl_lock();
+	old = rcu_dereference_protected(regdb, lockdep_rtnl_is_held());
+	rcu_assign_pointer(regdb, db);
+	rtnl_unlock();
+
+	if (!IS_ERR_OR_NULL(old)) {
+		synchronize_rcu();
+		release_firmware(old);
+	}
+
+	return 0;
+}
+
 static bool reg_query_database(struct regulatory_request *request)
 {
 	/* query internal regulatory database (if it exists) */
@@ -3564,5 +3618,5 @@ void regulatory_exit(void)
 	}
 
 	if (!IS_ERR_OR_NULL(regdb))
-		release_firmware(regdb);
+		release_firmware(rcu_access_pointer(regdb));
 }
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index ca7fedf2e7a1..9529c522611a 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -179,4 +179,10 @@ void regulatory_propagate_dfs_state(struct wiphy *wiphy,
  * @wiphy2 - wiphy it's dfs_region to be checked against that of wiphy1
  */
 bool reg_dfs_domain_same(struct wiphy *wiphy1, struct wiphy *wiphy2);
+
+/**
+ * reg_reload_regdb - reload the regulatory.db firmware file
+ */
+int reg_reload_regdb(void);
+
 #endif  /* __NET_WIRELESS_REG_H */
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [RFC 3/4] cfg80211: reg: remove support for built-in regdb
  2017-09-15 10:18 [RFC 0/4] cfg80211: in-kernel regulatory database Johannes Berg
  2017-09-15 10:18 ` [RFC 1/4] cfg80211: support loading regulatory database as firmware file Johannes Berg
  2017-09-15 10:18 ` [RFC 2/4] cfg80211: support reloading regulatory database Johannes Berg
@ 2017-09-15 10:18 ` Johannes Berg
  2017-09-15 10:18 ` [RFC 4/4] cfg80211: implement regdb signature checking Johannes Berg
  3 siblings, 0 replies; 6+ messages in thread
From: Johannes Berg @ 2017-09-15 10:18 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

Parsing and building C structures from a regdb is no longer needed
since the "firmware" file (regulatory.db) can be linked into the
kernel image to achieve the same effect.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 Documentation/networking/regulatory.txt |  22 +----
 net/wireless/Kconfig                    |  24 +----
 net/wireless/Makefile                   |   6 --
 net/wireless/db.txt                     |  17 ----
 net/wireless/genregdb.awk               | 158 --------------------------------
 net/wireless/reg.c                      |  38 --------
 6 files changed, 3 insertions(+), 262 deletions(-)
 delete mode 100644 net/wireless/db.txt
 delete mode 100644 net/wireless/genregdb.awk

diff --git a/Documentation/networking/regulatory.txt b/Documentation/networking/regulatory.txt
index 46c8d8b1cc66..381e5b23d61d 100644
--- a/Documentation/networking/regulatory.txt
+++ b/Documentation/networking/regulatory.txt
@@ -200,23 +200,5 @@ Then in some part of your code after your wiphy has been registered:
 Statically compiled regulatory database
 ---------------------------------------
 
-In most situations the userland solution using CRDA as described
-above is the preferred solution.  However in some cases a set of
-rules built into the kernel itself may be desirable.  To account
-for this situation, a configuration option has been provided
-(i.e. CONFIG_CFG80211_INTERNAL_REGDB).  With this option enabled,
-the wireless database information contained in net/wireless/db.txt is
-used to generate a data structure encoded in net/wireless/regdb.c.
-That option also enables code in net/wireless/reg.c which queries
-the data in regdb.c as an alternative to using CRDA.
-
-The file net/wireless/db.txt should be kept up-to-date with the db.txt
-file available in the git repository here:
-
-    git://git.kernel.org/pub/scm/linux/kernel/git/sforshee/wireless-regdb.git
-
-Again, most users in most situations should be using the CRDA package
-provided with their distribution, and in most other situations users
-should be building and using CRDA on their own rather than using
-this option.  If you are not absolutely sure that you should be using
-CONFIG_CFG80211_INTERNAL_REGDB then _DO_NOT_USE_IT_.
+When a database should be fixed into the kernel, it can be provided as a
+firmware file at build time that is then linked into the kernel.
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index 24eec5516649..f050030055c5 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -140,30 +140,8 @@ config CFG80211_DEBUGFS
 
 	  If unsure, say N.
 
-config CFG80211_INTERNAL_REGDB
-	bool "use statically compiled regulatory rules database" if EXPERT
-	default n
-	depends on CFG80211
-	---help---
-	  This option generates an internal data structure representing
-	  the wireless regulatory rules described in net/wireless/db.txt
-	  and includes code to query that database. This is an alternative
-	  to using CRDA for defining regulatory rules for the kernel.
-
-	  Using this option requires some parsing of the db.txt at build time,
-	  the parser will be upkept with the latest wireless-regdb updates but
-	  older wireless-regdb formats will be ignored. The parser may later
-	  be replaced to avoid issues with conflicts on versions of
-	  wireless-regdb.
-
-	  For details see:
-
-	  http://wireless.kernel.org/en/developers/Regulatory
-
-	  Most distributions have a CRDA package. So if unsure, say N.
-
 config CFG80211_CRDA_SUPPORT
-	bool "support CRDA" if CFG80211_INTERNAL_REGDB
+	bool "support CRDA" if EXPERT
 	default y
 	depends on CFG80211
 	help
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index d06e5015751a..5f20dac5d8c6 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -14,11 +14,5 @@ cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o trace.o ocb.o
 cfg80211-$(CONFIG_OF) += of.o
 cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
 cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o
-cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o
 
 CFLAGS_trace.o := -I$(src)
-
-$(obj)/regdb.c: $(src)/db.txt $(src)/genregdb.awk
-	@$(AWK) -f $(srctree)/$(src)/genregdb.awk < $< > $@
-
-clean-files := regdb.c
diff --git a/net/wireless/db.txt b/net/wireless/db.txt
deleted file mode 100644
index a2fc3a09ccdc..000000000000
--- a/net/wireless/db.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# This file is a placeholder to prevent accidental build breakage if someone
-# enables CONFIG_CFG80211_INTERNAL_REGDB.  Almost no one actually needs to
-# enable that build option.
-#
-# You should be using CRDA instead.  It is even better if you use the CRDA
-# package provided by your distribution, since they will probably keep it
-# up-to-date on your behalf.
-#
-# If you _really_ intend to use CONFIG_CFG80211_INTERNAL_REGDB then you will
-# need to replace this file with one containing appropriately formatted
-# regulatory rules that cover the regulatory domains you will be using.  Your
-# best option is to extract the db.txt file from the wireless-regdb git
-# repository:
-#
-#   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-regdb.git
-#
diff --git a/net/wireless/genregdb.awk b/net/wireless/genregdb.awk
deleted file mode 100644
index baf2426b555a..000000000000
--- a/net/wireless/genregdb.awk
+++ /dev/null
@@ -1,158 +0,0 @@
-#!/usr/bin/awk -f
-#
-# genregdb.awk -- generate regdb.c from db.txt
-#
-# Actually, it reads from stdin (presumed to be db.txt) and writes
-# to stdout (presumed to be regdb.c), but close enough...
-#
-# Copyright 2009 John W. Linville <linville@tuxdriver.com>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-BEGIN {
-	active = 0
-	rules = 0;
-	print "/*"
-	print " * DO NOT EDIT -- file generated from data in db.txt"
-	print " */"
-	print ""
-	print "#include <linux/nl80211.h>"
-	print "#include <net/cfg80211.h>"
-	print "#include \"regdb.h\""
-	print ""
-	regdb = "const struct ieee80211_regdomain *reg_regdb[] = {\n"
-}
-
-function parse_country_head() {
-	country=$2
-	sub(/:/, "", country)
-	printf "static const struct ieee80211_regdomain regdom_%s = {\n", country
-	printf "\t.alpha2 = \"%s\",\n", country
-	if ($NF ~ /DFS-ETSI/)
-		printf "\t.dfs_region = NL80211_DFS_ETSI,\n"
-	else if ($NF ~ /DFS-FCC/)
-		printf "\t.dfs_region = NL80211_DFS_FCC,\n"
-	else if ($NF ~ /DFS-JP/)
-		printf "\t.dfs_region = NL80211_DFS_JP,\n"
-	printf "\t.reg_rules = {\n"
-	active = 1
-	regdb = regdb "\t&regdom_" country ",\n"
-}
-
-function parse_reg_rule()
-{
-	flag_starts_at = 7
-
-	start = $1
-	sub(/\(/, "", start)
-	end = $3
-	bw = $5
-	sub(/\),/, "", bw)
-	gain = 0
-	power = $6
-	# power might be in mW...
-	units = $7
-	dfs_cac = 0
-
-	sub(/\(/, "", power)
-	sub(/\),/, "", power)
-	sub(/\),/, "", units)
-	sub(/\)/, "", units)
-
-	if (units == "mW") {
-		flag_starts_at = 8
-		power = 10 * log(power)/log(10)
-		if ($8 ~ /[[:digit:]]/) {
-			flag_starts_at = 9
-			dfs_cac = $8
-		}
-	} else {
-		if ($7 ~ /[[:digit:]]/) {
-			flag_starts_at = 8
-			dfs_cac = $7
-		}
-	}
-	sub(/\(/, "", dfs_cac)
-	sub(/\),/, "", dfs_cac)
-	flagstr = ""
-	for (i=flag_starts_at; i<=NF; i++)
-		flagstr = flagstr $i
-	split(flagstr, flagarray, ",")
-	flags = ""
-	for (arg in flagarray) {
-		if (flagarray[arg] == "NO-OFDM") {
-			flags = flags "\n\t\t\tNL80211_RRF_NO_OFDM | "
-		} else if (flagarray[arg] == "NO-CCK") {
-			flags = flags "\n\t\t\tNL80211_RRF_NO_CCK | "
-		} else if (flagarray[arg] == "NO-INDOOR") {
-			flags = flags "\n\t\t\tNL80211_RRF_NO_INDOOR | "
-		} else if (flagarray[arg] == "NO-OUTDOOR") {
-			flags = flags "\n\t\t\tNL80211_RRF_NO_OUTDOOR | "
-		} else if (flagarray[arg] == "DFS") {
-			flags = flags "\n\t\t\tNL80211_RRF_DFS | "
-		} else if (flagarray[arg] == "PTP-ONLY") {
-			flags = flags "\n\t\t\tNL80211_RRF_PTP_ONLY | "
-		} else if (flagarray[arg] == "PTMP-ONLY") {
-			flags = flags "\n\t\t\tNL80211_RRF_PTMP_ONLY | "
-		} else if (flagarray[arg] == "PASSIVE-SCAN") {
-			flags = flags "\n\t\t\tNL80211_RRF_NO_IR | "
-		} else if (flagarray[arg] == "NO-IBSS") {
-			flags = flags "\n\t\t\tNL80211_RRF_NO_IR | "
-		} else if (flagarray[arg] == "NO-IR") {
-			flags = flags "\n\t\t\tNL80211_RRF_NO_IR | "
-		} else if (flagarray[arg] == "AUTO-BW") {
-			flags = flags "\n\t\t\tNL80211_RRF_AUTO_BW | "
-		}
-
-	}
-	flags = flags "0"
-	printf "\t\tREG_RULE_EXT(%d, %d, %d, %d, %.0f, %d, %s),\n", start, end, bw, gain, power, dfs_cac, flags
-	rules++
-}
-
-function print_tail_country()
-{
-	active = 0
-	printf "\t},\n"
-	printf "\t.n_reg_rules = %d\n", rules
-	printf "};\n\n"
-	rules = 0;
-}
-
-/^[ \t]*#/ {
-	# Ignore
-}
-
-!active && /^[ \t]*$/ {
-	# Ignore
-}
-
-!active && /country/ {
-	parse_country_head()
-}
-
-active && /^[ \t]*\(/ {
-	parse_reg_rule()
-}
-
-active && /^[ \t]*$/ {
-	print_tail_country()
-}
-
-END {
-	if (active)
-		print_tail_country()
-	print regdb "};"
-	print ""
-	print "int reg_regdb_size = ARRAY_SIZE(reg_regdb);"
-}
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 8d366738c08a..5dd453bdad3a 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -494,38 +494,6 @@ static int reg_schedule_apply(const struct ieee80211_regdomain *regdom)
 	return 0;
 }
 
-#ifdef CONFIG_CFG80211_INTERNAL_REGDB
-static int reg_query_builtin(const char *alpha2)
-{
-	const struct ieee80211_regdomain *regdom = NULL;
-	unsigned int i;
-
-	for (i = 0; i < reg_regdb_size; i++) {
-		if (alpha2_equal(alpha2, reg_regdb[i]->alpha2)) {
-			regdom = reg_copy_regd(reg_regdb[i]);
-			break;
-		}
-	}
-	if (!regdom)
-		return -ENODATA;
-
-	return reg_schedule_apply(regdom);
-}
-
-/* Feel free to add any other sanity checks here */
-static void reg_regdb_size_check(void)
-{
-	/* We should ideally BUILD_BUG_ON() but then random builds would fail */
-	WARN_ONCE(!reg_regdb_size, "db.txt is empty, you should update it...");
-}
-#else
-static inline void reg_regdb_size_check(void) {}
-static inline int reg_query_builtin(const char *alpha2)
-{
-	return -ENODATA;
-}
-#endif /* CONFIG_CFG80211_INTERNAL_REGDB */
-
 #ifdef CONFIG_CFG80211_CRDA_SUPPORT
 /* Max number of consecutive attempts to communicate with CRDA  */
 #define REG_MAX_CRDA_TIMEOUTS 10
@@ -869,10 +837,6 @@ int reg_reload_regdb(void)
 
 static bool reg_query_database(struct regulatory_request *request)
 {
-	/* query internal regulatory database (if it exists) */
-	if (reg_query_builtin(request->alpha2) == 0)
-		return true;
-
 	if (query_regdb_file(request->alpha2) == 0)
 		return true;
 
@@ -3549,8 +3513,6 @@ int __init regulatory_init(void)
 	spin_lock_init(&reg_pending_beacons_lock);
 	spin_lock_init(&reg_indoor_lock);
 
-	reg_regdb_size_check();
-
 	rcu_assign_pointer(cfg80211_regdomain, cfg80211_world_regdom);
 
 	user_alpha2[0] = '9';
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [RFC 4/4] cfg80211: implement regdb signature checking
  2017-09-15 10:18 [RFC 0/4] cfg80211: in-kernel regulatory database Johannes Berg
                   ` (2 preceding siblings ...)
  2017-09-15 10:18 ` [RFC 3/4] cfg80211: reg: remove support for built-in regdb Johannes Berg
@ 2017-09-15 10:18 ` Johannes Berg
  2017-09-15 10:20   ` Johannes Berg
  3 siblings, 1 reply; 6+ messages in thread
From: Johannes Berg @ 2017-09-15 10:18 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

Currently CRDA implements the signature checking, and the previous
commits added the ability to load the whole regulatory database
into the kernel.

However, we really can't lose the signature checking, so implement
it in the kernel by loading a detached signature (regulatory.db.p7s)
and check it against built-in keys.

TODO
 - add a Kconfig option to specify extra keys, rather than requiring
   them to be dropped into the right directory
 - should anything be able to modify the keyring? I guess not?
 - add Seth's key, obviously

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 net/wireless/Kconfig         |  10 ++++
 net/wireless/Makefile        |  10 ++++
 net/wireless/certs/none.x509 |   0
 net/wireless/reg.c           | 109 +++++++++++++++++++++++++++++++++++++++++++
 net/wireless/reg.h           |   6 +++
 5 files changed, 135 insertions(+)
 create mode 100644 net/wireless/certs/none.x509

diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index f050030055c5..8ac8fda93cfe 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -83,6 +83,16 @@ config CFG80211_CERTIFICATION_ONUS
 	  you are a wireless researcher and are working in a controlled
 	  and approved environment by your local regulatory agency.
 
+config CFG80211_REQUIRE_SIGNED_REGDB
+	bool "require regdb signature" if CFG80211_CERTIFICATION_ONUS
+	default y
+	select SYSTEM_DATA_VERIFICATION
+	help
+	  Require that in addition to the "regulatory.db" file a
+	  "regulatory.db.p7s" can be loaded with a valid PKCS#7
+	  signature for the regulatory.db file made by one of the
+	  keys in the certs/ directory.
+
 config CFG80211_REG_CELLULAR_HINTS
 	bool "cfg80211 regulatory support for cellular base station hints"
 	depends on CFG80211_CERTIFICATION_ONUS
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index 5f20dac5d8c6..20994876d42a 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -16,3 +16,13 @@ cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
 cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o
 
 CFLAGS_trace.o := -I$(src)
+
+cfg80211-$(CONFIG_CFG80211_REQUIRE_SIGNED_REGDB) += certs.o
+
+$(obj)/certs.c: $(wildcard $(srctree)/$(src)/certs/*.x509)
+	@echo "  GEN     $@"
+	@echo '#include "reg.h"' > $@
+	@echo 'const u8 regdb_certs[] = {' >> $@
+	@hexdump -v -e '1/1 "0x%.2x," "\n"' < $< >> $@
+	@echo '};' >> $@
+	@echo 'unsigned int regdb_certs_len = sizeof(regdb_certs);' >> $@
diff --git a/net/wireless/certs/none.x509 b/net/wireless/certs/none.x509
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 5dd453bdad3a..2a04118c500a 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -52,6 +52,7 @@
 #include <linux/ctype.h>
 #include <linux/nl80211.h>
 #include <linux/platform_device.h>
+#include <linux/verification.h>
 #include <linux/moduleparam.h>
 #include <linux/firmware.h>
 #include <net/cfg80211.h>
@@ -652,6 +653,105 @@ static bool valid_country(const struct firmware *db,
 	return true;
 }
 
+#ifdef CONFIG_CFG80211_REQUIRE_SIGNED_REGDB
+static struct key *builtin_regdb_keys;
+
+static int load_builtin_regdb_keys(void)
+{
+	key_ref_t key;
+	const u8 *p, *end;
+	size_t plen;
+
+	builtin_regdb_keys =
+		keyring_alloc(".builtin_regdb_keys",
+			      KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
+			      ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
+			      KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH),
+			      KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
+	if (IS_ERR(builtin_regdb_keys))
+		return PTR_ERR(builtin_regdb_keys);
+
+	pr_notice("Loading compiled-in X.509 certificates\n");
+
+	p = regdb_certs;
+	end = p + regdb_certs_len;
+	while (p < end) {
+		/* Each cert begins with an ASN.1 SEQUENCE tag and must be more
+		 * than 256 bytes in size.
+		 */
+		if (end - p < 4)
+			goto dodgy_cert;
+		if (p[0] != 0x30 &&
+		    p[1] != 0x82)
+			goto dodgy_cert;
+		plen = (p[2] << 8) | p[3];
+		plen += 4;
+		if (plen > end - p)
+			goto dodgy_cert;
+
+		key = key_create_or_update(make_key_ref(builtin_regdb_keys, 1),
+					   "asymmetric",
+					   NULL,
+					   p,
+					   plen,
+					   ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
+					   KEY_USR_VIEW | KEY_USR_READ),
+					   KEY_ALLOC_NOT_IN_QUOTA |
+					   KEY_ALLOC_BUILT_IN |
+					   KEY_ALLOC_BYPASS_RESTRICTION);
+		if (IS_ERR(key)) {
+			pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
+			       PTR_ERR(key));
+		} else {
+			pr_notice("Loaded X.509 cert '%s'\n",
+				  key_ref_to_ptr(key)->description);
+			key_ref_put(key);
+		}
+		p += plen;
+	}
+
+	return 0;
+
+dodgy_cert:
+	pr_err("Problem parsing in-kernel X.509 certificate list\n");
+	return 0;
+}
+
+static bool regdb_has_valid_signature(const struct firmware *db)
+{
+	const struct firmware *sig;
+
+	if (request_firmware(&sig, "regulatory.db.p7s", &reg_pdev->dev))
+		return false;
+
+	if (verify_pkcs7_signature(db->data, db->size, sig->data, sig->size,
+				   builtin_regdb_keys,
+				   VERIFYING_UNSPECIFIED_SIGNATURE, NULL, NULL))
+		return false;
+
+	return true;
+}
+
+static void free_regdb_keyring(void)
+{
+	key_put(builtin_regdb_keys);
+}
+#else
+static int load_builtin_regdb_keys(void)
+{
+	return 0;
+}
+
+static bool regdb_has_valid_signature(const struct firmware *db)
+{
+	return true;
+}
+
+static void free_regdb_keyring(void)
+{
+}
+#endif /* CONFIG_CFG80211_REQUIRE_SIGNED_REGDB */
+
 static bool valid_regdb(const struct firmware *db)
 {
 	const struct fwdb_header *hdr = (void *)db->data;
@@ -666,6 +766,9 @@ static bool valid_regdb(const struct firmware *db)
 	if (hdr->version != cpu_to_be32(FWDB_VERSION))
 		return false;
 
+	if (!regdb_has_valid_signature(db))
+		return false;
+
 	country = &hdr->country[0];
 	while ((u8 *)(country + 1) <= db->data + db->size) {
 		if (!country->coll_ptr)
@@ -3505,6 +3608,10 @@ int __init regulatory_init(void)
 {
 	int err = 0;
 
+	err = load_builtin_regdb_keys();
+	if (err)
+		return err;
+
 	reg_pdev = platform_device_register_simple("regulatory", 0, NULL, 0);
 	if (IS_ERR(reg_pdev))
 		return PTR_ERR(reg_pdev);
@@ -3581,4 +3688,6 @@ void regulatory_exit(void)
 
 	if (!IS_ERR_OR_NULL(regdb))
 		release_firmware(rcu_access_pointer(regdb));
+
+	free_regdb_keyring();
 }
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index 9529c522611a..a520a8261d1a 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -1,5 +1,8 @@
 #ifndef __NET_WIRELESS_REG_H
 #define __NET_WIRELESS_REG_H
+
+#include <net/cfg80211.h>
+
 /*
  * Copyright 2008-2011	Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
  *
@@ -185,4 +188,7 @@ bool reg_dfs_domain_same(struct wiphy *wiphy1, struct wiphy *wiphy2);
  */
 int reg_reload_regdb(void);
 
+extern const u8 regdb_certs[];
+extern unsigned int regdb_certs_len;
+
 #endif  /* __NET_WIRELESS_REG_H */
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [RFC 4/4] cfg80211: implement regdb signature checking
  2017-09-15 10:18 ` [RFC 4/4] cfg80211: implement regdb signature checking Johannes Berg
@ 2017-09-15 10:20   ` Johannes Berg
  0 siblings, 0 replies; 6+ messages in thread
From: Johannes Berg @ 2017-09-15 10:20 UTC (permalink / raw)
  To: linux-wireless

On Fri, 2017-09-15 at 12:18 +0200, Johannes Berg wrote:
> 
> +config CFG80211_REQUIRE_SIGNED_REGDB
> +	bool "require regdb signature" if
> CFG80211_CERTIFICATION_ONUS
> +	default y
> +	select SYSTEM_DATA_VERIFICATION

Note that this will not be easy to backport, however, the code only
needs relatively self-contained functionality, namely this:

> +       builtin_regdb_keys =
> +               keyring_alloc(".builtin_regdb_keys",
> +                             KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
> +                             ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
> +                             KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH),
> +                             KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);

> +               key = key_create_or_update(make_key_ref(builtin_regdb_keys, 1),
> +                                          "asymmetric",
> +                                          NULL,
> +                                          p,
> +                                          plen,
> +                                          ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
> +                                          KEY_USR_VIEW | KEY_USR_READ),
> +                                          KEY_ALLOC_NOT_IN_QUOTA |
> +                                          KEY_ALLOC_BUILT_IN |
> +                                          KEY_ALLOC_BYPASS_RESTRICTION);

> +       if (verify_pkcs7_signature(db->data, db->size, sig->data, sig->size,
> +                                  builtin_regdb_keys,
> +                                  VERIFYING_UNSPECIFIED_SIGNATURE, NULL, NULL))

so I'm hoping it won't be too difficult, since we don't really need the
ability to manipulate keyrings etc.

johannes

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2017-09-15 10:21 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-09-15 10:18 [RFC 0/4] cfg80211: in-kernel regulatory database Johannes Berg
2017-09-15 10:18 ` [RFC 1/4] cfg80211: support loading regulatory database as firmware file Johannes Berg
2017-09-15 10:18 ` [RFC 2/4] cfg80211: support reloading regulatory database Johannes Berg
2017-09-15 10:18 ` [RFC 3/4] cfg80211: reg: remove support for built-in regdb Johannes Berg
2017-09-15 10:18 ` [RFC 4/4] cfg80211: implement regdb signature checking Johannes Berg
2017-09-15 10:20   ` Johannes Berg

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).