All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH V3 0/8] Add password protected lock/unlock support for SD/MMC
@ 2015-05-19 23:11 Al Cooper
  2015-05-19 23:11 ` [PATCH V3 1/8] mmc: lock: Use the kernel "KEYS" subsystem to get a card's password Al Cooper
                   ` (8 more replies)
  0 siblings, 9 replies; 12+ messages in thread
From: Al Cooper @ 2015-05-19 23:11 UTC (permalink / raw)
  To: ulf.hansson, linux-mmc, pgynther; +Cc: Al Cooper

This set of patches adds support for password protected locking
and unlocking of MMC and SD devices. It uses the LOCK/UNLOCK command
(CMD42) available in both the MMC and SD command sets.

Some of this code was based on a patch set submitted in 2006 by
Anderson Briglia "Add MMC Password Protection (lock/unlock)". This
patch set never made it into mainline.

By default, a card with no password assigned is always in "unlocked"
state. After password assignment, in the next power cycle the card
switches to a "locked" state where only the "basic" and "lock card"
command classes are accepted by the card. Only after unlocking it with
the correct password can the card be used for normal operations like
block I/O.

Password management and caching is done through the "Kernel Key
Retention Service" mechanism and the sysfs filesystem. Two new sysfs
attributes were added. The "lock" attribute is used to lock, unlock,
assign a password, clear a password and force erase a card. The
"unlock_retry" attribute is used to retry an unlock that failed
during boot because the rootfs was not yet available with the password.

The user space software needed to test this new feature
is available on GitHub at:
https://github.com/alcooper/mmc-password-utils
See the README for a detailed description of the user space layer
and how to use this feature.

Changed for V3:
  - Ported the V2 patch set submitted Aug. 2013 to the latest mainline
    (v4.1-rc4).
  - Created a GitHub project for the user space layer.
  - Change the lock command (CMD42) to round up the data buffer
    size to 512 for SD but leave exact size for eMMC based on the
    SD and eMMC specs.


Changed for V2:
The V2 changes were not functional and were just general cleanup.
  - Use stub functions to reduce the number of CONFIG ifdefs.
  - Add static to a few functions that were local.
  - Use pr_warn instead of pr_warning.
  - Improve a few variable names and messages.


Abbas Raza (1):
  According to SD Physical Layer Specifications: Locked cards respond to
    (and execute) all commands in the "basic" command class (class 0),
    ACMD41, CMD16 and "lock card" command class. Thus, the host is
    allowed to reset, initialize, select, query for status, etc., but
    not to access data on the card.

Al Cooper (7):
  mmc: lock: Use the kernel "KEYS" subsystem to get a card's password
  mmc: lock: Add low level LOCK_UNLOCK command
  mmc: lock: Add function to unlock a password locked card
  mmc: lock: Add card lock/unlock maintenance commands
  mmc: lock: Change SD init functionality to handle locked SD cards
  mmc: lock: Prevent partition table read for locked cards.
  mmc: lock: Change MMC init to handle locked cards.

 drivers/mmc/card/block.c   |  14 ++++
 drivers/mmc/core/Kconfig   |   8 +++
 drivers/mmc/core/core.c    | 120 +++++++++++++++++++++++++++++++++
 drivers/mmc/core/core.h    |  14 +++-
 drivers/mmc/core/mmc.c     | 123 ++++++++++++++++++++++++++++++++++
 drivers/mmc/core/mmc_ops.c | 150 +++++++++++++++++++++++++++++++++++++++++
 drivers/mmc/core/mmc_ops.h |  13 ++++
 drivers/mmc/core/sd.c      | 161 +++++++++++++++++++++++++++++++--------------
 include/linux/mmc/card.h   |   6 ++
 9 files changed, 560 insertions(+), 49 deletions(-)

-- 
1.9.0.138.g2de3478


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

* [PATCH V3 1/8] mmc: lock: Use the kernel "KEYS" subsystem to get a card's password
  2015-05-19 23:11 [PATCH V3 0/8] Add password protected lock/unlock support for SD/MMC Al Cooper
@ 2015-05-19 23:11 ` Al Cooper
  2015-05-19 23:11 ` [PATCH V3 2/8] mmc: lock: Add low level LOCK_UNLOCK command Al Cooper
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Al Cooper @ 2015-05-19 23:11 UTC (permalink / raw)
  To: ulf.hansson, linux-mmc, pgynther; +Cc: Al Cooper

Use the kernel "KEYS" subsystem to get a password for a card based on
the card's CID. This code was based on a patch set submitted by
Anderson Briglia in 2006.

Signed-off-by: Al Cooper <alcooperx@gmail.com>
---
 drivers/mmc/core/Kconfig |  8 ++++
 drivers/mmc/core/core.c  | 97 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/mmc/core/core.h  | 10 ++++-
 3 files changed, 114 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig
index 9ebee72..1d073cd 100644
--- a/drivers/mmc/core/Kconfig
+++ b/drivers/mmc/core/Kconfig
@@ -11,3 +11,11 @@ config MMC_CLKGATE
 	  support handling this in order for it to be of any use.
 
 	  If unsure, say N.
+
+config MMC_LOCK
+	bool "MMC/SD password based card lock/unlock"
+	select KEYS
+	help
+	  This will add the ability to lock/unlock SD and MMC cards.
+
+	  If unsure, say N.
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 92e7671..f7d7ad9 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -29,6 +29,7 @@
 #include <linux/random.h>
 #include <linux/slab.h>
 #include <linux/of.h>
+#include <linux/key-type.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
@@ -2707,6 +2708,96 @@ void mmc_init_context_info(struct mmc_host *host)
 	init_waitqueue_head(&host->context_info.wait);
 }
 
+#ifdef CONFIG_MMC_LOCK
+
+static int mmc_key_instantiate(struct key *key,
+			       struct key_preparsed_payload *prep)
+{
+	char *payload;
+
+	if (prep->datalen <= 0 || prep->datalen > MMC_PASSWORD_MAX ||
+	    !prep->data) {
+		pr_warn("Invalid data\n");
+		return  -EINVAL;
+	}
+
+	payload = kmalloc(prep->datalen, GFP_KERNEL);
+	if (!payload)
+		return -ENOMEM;
+	memcpy(payload, prep->data, prep->datalen);
+	key->payload.data = payload;
+	key->datalen = prep->datalen;
+	return 0;
+}
+
+/*
+ * dispose of the data dangling from the corpse of a mmc key
+ */
+static void mmc_key_destroy(struct key *key)
+{
+	kfree(key->payload.data);
+}
+
+struct key_type key_type_mmc = {
+	.name		= "mmc",
+	.instantiate	= mmc_key_instantiate,
+	.destroy	= mmc_key_destroy,
+};
+
+int mmc_get_password(struct mmc_card *card, struct mmc_password *password)
+{
+	struct key *mmc_key;
+	char key_desc[(sizeof(card->raw_cid) * 2) + 1];
+
+	/* Use the CID to uniquely identify the card */
+	snprintf(key_desc, sizeof(key_desc), "%08x%08x%08x%08x",
+		 card->raw_cid[0], card->raw_cid[1],
+		 card->raw_cid[2], card->raw_cid[3]);
+
+	mmc_key = request_key(&key_type_mmc, key_desc,
+			      "password");
+	if (IS_ERR(mmc_key)) {
+		dev_warn(&card->dev, "Error, request_key %ld\n",
+			 PTR_ERR(mmc_key));
+		return PTR_ERR(mmc_key);
+	}
+	dev_dbg(&card->dev, "Found matching key\n");
+	memcpy(&password->password, mmc_key->payload.data,
+	       mmc_key->datalen);
+	password->length = mmc_key->datalen;
+	key_put(mmc_key);
+
+	return 0;
+}
+
+static inline int mmc_register_key_type(void)
+{
+	return register_key_type(&key_type_mmc);
+}
+
+static inline void mmc_unregister_key_type(void)
+{
+	unregister_key_type(&key_type_mmc);
+}
+
+#else /* CONFIG_MMC_LOCK */
+
+int mmc_get_password(struct mmc_card *card, struct mmc_password *password)
+{
+	return -ENOKEY;
+}
+
+static inline int mmc_register_key_type(void)
+{
+	return 0;
+}
+
+static inline void mmc_unregister_key_type(void)
+{
+}
+
+#endif /* CONFIG_MMC_LOCK */
+
 static int __init mmc_init(void)
 {
 	int ret;
@@ -2727,8 +2818,13 @@ static int __init mmc_init(void)
 	if (ret)
 		goto unregister_host_class;
 
+	ret = mmc_register_key_type();
+	if (ret)
+		goto unregister_sdio_bus;
 	return 0;
 
+unregister_sdio_bus:
+	sdio_unregister_bus();
 unregister_host_class:
 	mmc_unregister_host_class();
 unregister_bus:
@@ -2741,6 +2837,7 @@ destroy_workqueue:
 
 static void __exit mmc_exit(void)
 {
+	mmc_unregister_key_type();
 	sdio_unregister_bus();
 	mmc_unregister_host_class();
 	mmc_unregister_bus();
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index cfba3c0..b91bc3e 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -89,5 +89,13 @@ void mmc_init_context_info(struct mmc_host *host);
 
 int mmc_execute_tuning(struct mmc_card *card);
 
-#endif
+/* Lock/Unlock functionality */
+#define MMC_PASSWORD_MAX 16
+struct mmc_password {
+	char password[MMC_PASSWORD_MAX];
+	int length;
+};
+int mmc_unlock_card(struct mmc_card *card);
+int mmc_get_password(struct mmc_card *card, struct mmc_password *password);
 
+#endif
-- 
1.9.0.138.g2de3478


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

* [PATCH V3 2/8] mmc: lock: Add low level LOCK_UNLOCK command
  2015-05-19 23:11 [PATCH V3 0/8] Add password protected lock/unlock support for SD/MMC Al Cooper
  2015-05-19 23:11 ` [PATCH V3 1/8] mmc: lock: Use the kernel "KEYS" subsystem to get a card's password Al Cooper
@ 2015-05-19 23:11 ` Al Cooper
  2015-05-19 23:11 ` [PATCH V3 3/8] mmc: lock: Add function to unlock a password locked card Al Cooper
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Al Cooper @ 2015-05-19 23:11 UTC (permalink / raw)
  To: ulf.hansson, linux-mmc, pgynther; +Cc: Al Cooper

Add support for the LOCK_UNLOCK command. This command can lock,
unlock, set password, clear password and force erase SD and
MMC cards.

Signed-off-by: Al Cooper <alcooperx@gmail.com>
---
 drivers/mmc/core/core.c    |   5 +-
 drivers/mmc/core/mmc_ops.c | 150 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/mmc/core/mmc_ops.h |  13 ++++
 include/linux/mmc/card.h   |   5 ++
 4 files changed, 169 insertions(+), 4 deletions(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index f7d7ad9..4b0d26e 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2716,11 +2716,8 @@ static int mmc_key_instantiate(struct key *key,
 	char *payload;
 
 	if (prep->datalen <= 0 || prep->datalen > MMC_PASSWORD_MAX ||
-	    !prep->data) {
-		pr_warn("Invalid data\n");
+	    !prep->data)
 		return  -EINVAL;
-	}
-
 	payload = kmalloc(prep->datalen, GFP_KERNEL);
 	if (!payload)
 		return -ENOMEM;
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 0ea042d..c15c285 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -13,6 +13,8 @@
 #include <linux/export.h>
 #include <linux/types.h>
 #include <linux/scatterlist.h>
+#include <linux/key.h>
+#include <linux/err.h>
 
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
@@ -783,3 +785,151 @@ int mmc_can_ext_csd(struct mmc_card *card)
 {
 	return (card && card->csd.mmca_vsn > CSD_SPEC_VER_3);
 }
+
+#ifdef CONFIG_MMC_LOCK
+/**
+ *	mmc_lock_unlock - send LOCK_UNLOCK command to a specific card.
+ *	@card: card to which the LOCK_UNLOCK command should be sent
+ *	@key: key containing the MMC password
+ *	@mode: LOCK_UNLOCK mode
+ *
+ */
+int mmc_lock_unlock(struct mmc_card *card, struct mmc_password *password,
+		    int mode)
+{
+	struct mmc_request mrq;
+	struct mmc_command cmd_sbl;
+	struct mmc_command cmd;
+	struct mmc_data data;
+	struct scatterlist sg;
+	unsigned long erase_timeout;
+	int err, data_size;
+	u8 *data_buf = NULL;
+
+	if (mmc_card_mmc(card)) {
+		/* Lock commands only work on the data partition, select it */
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				EXT_CSD_PART_CONFIG,
+				card->ext_csd.part_config &
+				~EXT_CSD_PART_CONFIG_ACC_MASK,
+				card->ext_csd.part_time);
+
+		if (err != 0)
+			pr_warn("%s: Data partition select failed.\n",
+				mmc_hostname(card->host));
+
+		/*
+		 * The MMC spec does not allow rounding up the data to 512
+		 * bytes like SD spec
+		 */
+		if (mode & MMC_LOCK_MODE_ERASE)
+			data_size = 4;
+		else
+			data_size = 2 + password->length;
+	} else {
+		/* Round up the size of the data block to 512 bytes for SD */
+		data_size = 512;
+	}
+	data_buf = kzalloc(data_size, GFP_KERNEL);
+	if (!data_buf)
+		return -ENOMEM;
+	data_buf[0] |= mode;
+	if (!(mode & MMC_LOCK_MODE_ERASE)) {
+		data_buf[1] = password->length;
+		memcpy(data_buf + 2, password->password, password->length);
+	}
+
+	memset(&cmd_sbl, 0, sizeof(struct mmc_command));
+	cmd_sbl.opcode = MMC_SET_BLOCKLEN;
+	cmd_sbl.arg = data_size;
+	cmd_sbl.flags = MMC_RSP_R1 | MMC_CMD_AC;
+	err = mmc_wait_for_cmd(card->host, &cmd_sbl, MMC_CMD_RETRIES);
+	if (err)
+		goto out;
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+	cmd.opcode = MMC_LOCK_UNLOCK;
+	cmd.arg = 0;
+	cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+	memset(&data, 0, sizeof(struct mmc_data));
+	mmc_set_data_timeout(&data, card);
+	data.blksz = data_size;
+	data.blocks = 1;
+	data.flags = MMC_DATA_WRITE;
+	data.sg = &sg;
+	data.sg_len = 1;
+
+	memset(&mrq, 0, sizeof(struct mmc_request));
+	mrq.cmd = &cmd;
+	mrq.data = &data;
+
+	sg_init_one(&sg, data_buf, data_size);
+	mmc_wait_for_req(card->host, &mrq);
+	if (cmd.error) {
+		err = cmd.error;
+		goto out;
+	}
+	if (data.error) {
+		err = data.error;
+		goto out;
+	}
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+	cmd.opcode = MMC_SEND_STATUS;
+	cmd.arg = card->rca << 16;
+	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+	/* set timeout for forced erase operation to 3 min. (see MMC spec) */
+	erase_timeout = jiffies + 180 * HZ;
+	do {
+		/*
+		 * we cannot use "retries" here because the
+		 * R1_LOCK_UNLOCK_FAILED bit is cleared by subsequent reads to
+		 * the status register, hiding the error condition
+		 */
+		err = mmc_wait_for_cmd(card->host, &cmd, 0);
+		if (err)
+			break;
+		/* the other modes don't need timeout checking */
+		if (!(mode & MMC_LOCK_MODE_ERASE))
+			continue;
+		if (time_after(jiffies, erase_timeout) &&
+		    !(cmd.resp[0] & R1_READY_FOR_DATA)) {
+			dev_err(&card->dev, "forced erase timed out\n");
+			err = -ETIMEDOUT;
+			break;
+		}
+	} while (!(cmd.resp[0] & R1_READY_FOR_DATA));
+	if (cmd.resp[0] & R1_LOCK_UNLOCK_FAILED) {
+		dev_dbg(&card->dev, "LOCK_UNLOCK operation failed\n");
+		err = -EIO;
+	}
+	if (cmd.resp[0] & R1_CARD_IS_LOCKED)
+		mmc_card_set_locked(card);
+	else
+		mmc_card_clear_locked(card);
+
+out:
+	/* Restore Block Length to the default */
+	cmd_sbl.arg = 512;
+	err = mmc_wait_for_cmd(card->host, &cmd_sbl, MMC_CMD_RETRIES);
+	if (err)
+		pr_warn("%s: Error restoring Block Length.\n",
+			mmc_hostname(card->host));
+	if (mmc_card_mmc(card)) {
+
+		/* Restore the selected partition */
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				EXT_CSD_PART_CONFIG,
+				card->ext_csd.part_config,
+				card->ext_csd.part_time);
+
+		if (err != 0)
+			pr_warn("%s: Data partition select failed.\n",
+				mmc_hostname(card->host));
+	}
+	kfree(data_buf);
+	return err;
+}
+#endif /* CONFIG_MMC_LOCK */
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index 6f4b00e..92c9790 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -12,6 +12,15 @@
 #ifndef _MMC_MMC_OPS_H
 #define _MMC_MMC_OPS_H
 
+/*
+ * MMC_LOCK_UNLOCK modes
+ */
+#define MMC_LOCK_MODE_ERASE	(1<<3)
+#define MMC_LOCK_MODE_LOCK	(1<<2)
+#define MMC_LOCK_MODE_UNLOCK	(0<<2)
+#define MMC_LOCK_MODE_CLR_PWD	(1<<1)
+#define MMC_LOCK_MODE_SET_PWD	(1<<0)
+
 int mmc_select_card(struct mmc_card *card);
 int mmc_deselect_cards(struct mmc_host *host);
 int mmc_set_dsr(struct mmc_host *host);
@@ -27,6 +36,10 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc);
 int mmc_bus_test(struct mmc_card *card, u8 bus_width);
 int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status);
 int mmc_can_ext_csd(struct mmc_card *card);
+#ifdef CONFIG_MMC_LOCK
+int mmc_lock_unlock(struct mmc_card *card, struct mmc_password *password,
+		    int mode);
+#endif
 
 #endif
 
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 19f0175..0c510b4 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -262,6 +262,7 @@ struct mmc_card {
 #define MMC_CARD_REMOVED	(1<<4)		/* card has been removed */
 #define MMC_STATE_DOING_BKOPS	(1<<5)		/* card is doing BKOPS */
 #define MMC_STATE_SUSPENDED	(1<<6)		/* card is suspended */
+#define MMC_STATE_LOCKED	(1<<7)		/* card is currently locked */
 	unsigned int		quirks; 	/* card quirks */
 #define MMC_QUIRK_LENIENT_FN0	(1<<0)		/* allow SDIO FN0 writes outside of the VS CCCR range */
 #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)	/* use func->cur_blksize */
@@ -427,6 +428,8 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 #define mmc_card_removed(c)	((c) && ((c)->state & MMC_CARD_REMOVED))
 #define mmc_card_doing_bkops(c)	((c)->state & MMC_STATE_DOING_BKOPS)
 #define mmc_card_suspended(c)	((c)->state & MMC_STATE_SUSPENDED)
+#define mmc_card_locked(c)	((c)->state & MMC_STATE_LOCKED)
+#define mmc_card_lockable(c)	((c)->csd.cmdclass & CCC_LOCK_CARD)
 
 #define mmc_card_set_present(c)	((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
@@ -437,6 +440,8 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 #define mmc_card_clr_doing_bkops(c)	((c)->state &= ~MMC_STATE_DOING_BKOPS)
 #define mmc_card_set_suspended(c) ((c)->state |= MMC_STATE_SUSPENDED)
 #define mmc_card_clr_suspended(c) ((c)->state &= ~MMC_STATE_SUSPENDED)
+#define mmc_card_set_locked(c)	((c)->state |= MMC_STATE_LOCKED)
+#define mmc_card_clear_locked(c) ((c)->state &= ~MMC_STATE_LOCKED)
 
 /*
  * Quirk add/remove for MMC products.
-- 
1.9.0.138.g2de3478


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

* [PATCH V3 3/8] mmc: lock: Add function to unlock a password locked card
  2015-05-19 23:11 [PATCH V3 0/8] Add password protected lock/unlock support for SD/MMC Al Cooper
  2015-05-19 23:11 ` [PATCH V3 1/8] mmc: lock: Use the kernel "KEYS" subsystem to get a card's password Al Cooper
  2015-05-19 23:11 ` [PATCH V3 2/8] mmc: lock: Add low level LOCK_UNLOCK command Al Cooper
@ 2015-05-19 23:11 ` Al Cooper
  2015-05-19 23:11 ` [PATCH V3 4/8] mmc: lock: Add card lock/unlock maintenance commands Al Cooper
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Al Cooper @ 2015-05-19 23:11 UTC (permalink / raw)
  To: ulf.hansson, linux-mmc, pgynther; +Cc: Al Cooper

This function will try to get a password for the card and use the
password to unlock it. It will leave the card state flag set
appropriately.

Signed-off-by: Al Cooper <alcooperx@gmail.com>
---
 drivers/mmc/core/core.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 4b0d26e..61f1f78 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2777,6 +2777,27 @@ static inline void mmc_unregister_key_type(void)
 	unregister_key_type(&key_type_mmc);
 }
 
+int mmc_unlock_card(struct mmc_card *card)
+{
+	int stat;
+	struct mmc_password password;
+
+	mmc_card_set_locked(card);
+	stat = mmc_get_password(card, &password);
+	if (stat) {
+		pr_warn("%s: Cannot find matching key\n",
+			mmc_hostname(card->host));
+		return stat;
+	}
+	stat = mmc_lock_unlock(card, &password, MMC_LOCK_MODE_UNLOCK);
+	if (stat)
+		pr_warn("%s: Password failed to unlock card\n",
+			mmc_hostname(card->host));
+	else
+		mmc_card_clear_locked(card);
+	return stat;
+}
+
 #else /* CONFIG_MMC_LOCK */
 
 int mmc_get_password(struct mmc_card *card, struct mmc_password *password)
@@ -2793,6 +2814,11 @@ static inline void mmc_unregister_key_type(void)
 {
 }
 
+int mmc_unlock_card(struct mmc_card *card)
+{
+	return -ENOKEY;
+}
+
 #endif /* CONFIG_MMC_LOCK */
 
 static int __init mmc_init(void)
-- 
1.9.0.138.g2de3478


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

* [PATCH V3 4/8] mmc: lock: Add card lock/unlock maintenance commands
  2015-05-19 23:11 [PATCH V3 0/8] Add password protected lock/unlock support for SD/MMC Al Cooper
                   ` (2 preceding siblings ...)
  2015-05-19 23:11 ` [PATCH V3 3/8] mmc: lock: Add function to unlock a password locked card Al Cooper
@ 2015-05-19 23:11 ` Al Cooper
  2015-05-19 23:11 ` [PATCH V3 5/8] mmc: lock: Change SD init functionality to handle locked SD cards Al Cooper
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Al Cooper @ 2015-05-19 23:11 UTC (permalink / raw)
  To: ulf.hansson, linux-mmc, pgynther; +Cc: Al Cooper

Create a sysfs interface that allows a user to manage an inserted
cards lock state. The sysfs attribute "lock" will be added to the
device's sysfs directory. The following commands are supported:
"setpw"   - Set the cards password
"clearpw" - Clear the cards password
"lock"    - Lock the card
"unlock"  - Unlock the card
"erase"   - Force erase the card, clear the password and unlock it
Commands that require a password will request the password through
the kernels KEYS subsystem.

Signed-off-by: Al Cooper <alcooperx@gmail.com>
---
 drivers/mmc/core/mmc.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 81 insertions(+)

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index f36c76f..8e94eb8 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -697,6 +697,84 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
 	return err;
 }
 
+#ifdef CONFIG_MMC_LOCK
+
+ssize_t mmc_lock_show(struct device *dev, struct device_attribute *att,
+			  char *buf)
+{
+	struct mmc_card *card = mmc_dev_to_card(dev);
+
+	if (!mmc_card_lockable(card))
+		return sprintf(buf, "unsupported\n");
+	else
+		return sprintf(buf, "%slocked\n", mmc_card_locked(card) ?
+			       "" : "un");
+}
+
+
+static struct lock_cmd {
+	const char *name;
+	int io_cmd;
+	int locked_required;
+	int need_pw;
+} lock_cmds[] = {
+	{ "erase", MMC_LOCK_MODE_ERASE,  true,  false },
+	{ "clrpw", MMC_LOCK_MODE_CLR_PWD, false, true },
+	{ "setpw", MMC_LOCK_MODE_SET_PWD, false, true },
+	{ "lock", MMC_LOCK_MODE_LOCK, false,  true },
+	{ "unlock", MMC_LOCK_MODE_UNLOCK, true,  true },
+};
+
+/*
+ * implement MMC password functions: force erase, set password,
+ * clear password, lock and unlock.
+ */
+ssize_t mmc_lock_store(struct device *dev, struct device_attribute *att,
+			   const char *data, size_t len)
+{
+	struct mmc_card *card = mmc_dev_to_card(dev);
+	int res = -EINVAL;
+	int x;
+	struct mmc_password password;
+
+	mmc_claim_host(card->host);
+	if (!mmc_card_lockable(card))
+		goto out;
+	for (x = 0; x < ARRAY_SIZE(lock_cmds); x++) {
+		if (sysfs_streq(data, lock_cmds[x].name))
+			break;
+	}
+	if (x >= ARRAY_SIZE(lock_cmds))
+		goto out;
+
+	if ((lock_cmds[x].locked_required && !mmc_card_locked(card)) ||
+	    (!lock_cmds[x].locked_required && mmc_card_locked(card))) {
+		dev_warn(dev, "%s requires %slocked card\n",
+			 lock_cmds[x].name,
+			 lock_cmds[x].locked_required ? "" : "un");
+		goto out;
+	}
+	if (lock_cmds[x].need_pw) {
+		res = mmc_get_password(card, &password);
+		if (res)
+			goto out;
+	}
+	res = mmc_lock_unlock(card, &password, lock_cmds[x].io_cmd);
+out:
+	mmc_release_host(card->host);
+	if (res == 0)
+		return len;
+	else
+		return res;
+}
+
+static DEVICE_ATTR(lock, S_IWUSR | S_IRUGO,
+		   mmc_lock_show, mmc_lock_store);
+
+
+#endif /* CONFIG_MMC_LOCK */
+
+
 MMC_DEV_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
 	card->raw_cid[2], card->raw_cid[3]);
 MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
@@ -751,6 +829,9 @@ static struct attribute *mmc_std_attrs[] = {
 	&dev_attr_enhanced_area_size.attr,
 	&dev_attr_raw_rpmb_size_mult.attr,
 	&dev_attr_rel_sectors.attr,
+#ifdef CONFIG_MMC_LOCK
+	&dev_attr_lock.attr,
+#endif /* CONFIG_MMC_LOCK */
 	NULL,
 };
 ATTRIBUTE_GROUPS(mmc_std);
-- 
1.9.0.138.g2de3478


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

* [PATCH V3 5/8] mmc: lock: Change SD init functionality to handle locked SD cards
  2015-05-19 23:11 [PATCH V3 0/8] Add password protected lock/unlock support for SD/MMC Al Cooper
                   ` (3 preceding siblings ...)
  2015-05-19 23:11 ` [PATCH V3 4/8] mmc: lock: Add card lock/unlock maintenance commands Al Cooper
@ 2015-05-19 23:11 ` Al Cooper
  2015-05-19 23:11 ` [PATCH V3 6/8] mmc: lock: Prevent partition table read for locked cards Al Cooper
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Al Cooper @ 2015-05-19 23:11 UTC (permalink / raw)
  To: ulf.hansson, linux-mmc, pgynther; +Cc: Al Cooper

- Change mmc_sd_init_card() to check for a locked card and, if found,
try to get a password using the kernel KEYS subsystem, unlock the card
and continue. The unlock can fail due to a bad password, no password
or during boot when the rootfs that holds the password is not yet
available. To handle this, mmc_sd_init_card() will send just the early
init commands before trying to unlock and, on unlock failure, skip the
later init commands (which would fail on a locked card). mmc_sd_init_card()
will also handle the retry case, trigger via sysfs, where it will skip
the already issued early init commands, try again to unlock the card and
if successful issue the previously skipped later init commands.
These changes allow a card that failed unlock to still come up to the
point that the block device and sysfs for the device is created. This
allows the sysfs to be used to issue LOCK maintenance commands or to
trigger a retry, presumably after the password has be made available
by user space.

- Add sysfs attribute "unlock_retry" that will try again to unlock
and fully init the card.

- Add sysfs attribute "lock" to enable sysfs LOCK maintenance
commands

Signed-off-by: Al Cooper <alcooperx@gmail.com>
---
 drivers/mmc/core/core.h  |   4 ++
 drivers/mmc/core/sd.c    | 161 +++++++++++++++++++++++++++++++++--------------
 include/linux/mmc/card.h |   1 +
 3 files changed, 118 insertions(+), 48 deletions(-)

diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index b91bc3e..6b9c972 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -97,5 +97,9 @@ struct mmc_password {
 };
 int mmc_unlock_card(struct mmc_card *card);
 int mmc_get_password(struct mmc_card *card, struct mmc_password *password);
+ssize_t mmc_lock_show(struct device *dev, struct device_attribute *att,
+		char *buf);
+ssize_t mmc_lock_store(struct device *dev, struct device_attribute *att,
+		const char *data, size_t len);
 
 #endif
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 31a9ef2..fd40946 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -27,6 +27,9 @@
 #include "sd.h"
 #include "sd_ops.h"
 
+static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
+			    struct mmc_card *oldcard);
+
 static const unsigned int tran_exp[] = {
 	10000,		100000,		1000000,	10000000,
 	0,		0,		0,		0
@@ -670,6 +673,40 @@ out:
 	return err;
 }
 
+#ifdef CONFIG_MMC_LOCK
+static ssize_t mmc_sd_unlock_retry_store(struct device *dev,
+					 struct device_attribute *att,
+					 const char *data, size_t len)
+{
+	int err;
+	struct mmc_card *card = mmc_dev_to_card(dev);
+	struct mmc_host *host = card->host;
+
+	BUG_ON(!card);
+	BUG_ON(!host);
+
+	mmc_claim_host(host);
+	if (!mmc_card_locked(card)) {
+		mmc_release_host(host);
+		return len;
+	}
+	err = mmc_sd_init_card(host, card->ocr, card);
+	mmc_release_host(host);
+	if (err)
+		return len;
+	device_release_driver(dev);
+	err = device_attach(dev);
+	if (err < 0)
+		dev_warn(dev, "device_attach() failed, error: %d\n", err);
+	return len;
+}
+
+static DEVICE_ATTR(lock, S_IWUSR | S_IRUGO,
+		   mmc_lock_show, mmc_lock_store);
+static DEVICE_ATTR(unlock_retry, S_IWUSR,
+		   NULL, mmc_sd_unlock_retry_store);
+#endif /* CONFIG_MMC_LOCK */
+
 MMC_DEV_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
 	card->raw_cid[2], card->raw_cid[3]);
 MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
@@ -699,6 +736,10 @@ static struct attribute *sd_std_attrs[] = {
 	&dev_attr_name.attr,
 	&dev_attr_oemid.attr,
 	&dev_attr_serial.attr,
+#ifdef CONFIG_MMC_LOCK
+	&dev_attr_lock.attr,
+	&dev_attr_unlock_retry.attr,
+#endif /* CONFIG_MMC_LOCK */
 	NULL,
 };
 ATTRIBUTE_GROUPS(sd_std);
@@ -901,69 +942,92 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
 	int err;
 	u32 cid[4];
 	u32 rocr = 0;
+	u32 status;
 
 	BUG_ON(!host);
 	WARN_ON(!host->claimed);
 
-	err = mmc_sd_get_cid(host, ocr, cid, &rocr);
-	if (err)
-		return err;
-
-	if (oldcard) {
-		if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0)
-			return -ENOENT;
-
+	/* Retry init of locked card */
+	if (oldcard && mmc_card_locked(oldcard)) {
 		card = oldcard;
+		oldcard = NULL;
+		rocr = card->raw_ocr;
 	} else {
+		err = mmc_sd_get_cid(host, ocr, cid, &rocr);
+		if (err)
+			return err;
+
+		if (oldcard) {
+			if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0)
+				return -ENOENT;
+
+			card = oldcard;
+		} else {
+			/*
+			 * Allocate card structure.
+			 */
+			card = mmc_alloc_card(host, &sd_type);
+			if (IS_ERR(card))
+				return PTR_ERR(card);
+
+			card->ocr = ocr;
+			card->type = MMC_TYPE_SD;
+			memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
+		}
+
 		/*
-		 * Allocate card structure.
+		 * Call the optional HC's init_card function to handle quirks.
 		 */
-		card = mmc_alloc_card(host, &sd_type);
-		if (IS_ERR(card))
-			return PTR_ERR(card);
+		if (host->ops->init_card)
+			host->ops->init_card(host, card);
 
-		card->ocr = ocr;
-		card->type = MMC_TYPE_SD;
-		memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
-	}
+		/*
+		 * For native busses:  get card RCA and quit open drain mode.
+		 */
+		if (!mmc_host_is_spi(host)) {
+			err = mmc_send_relative_addr(host, &card->rca);
+			if (err)
+				goto free_card;
+		}
 
-	/*
-	 * Call the optional HC's init_card function to handle quirks.
-	 */
-	if (host->ops->init_card)
-		host->ops->init_card(host, card);
+		if (!oldcard) {
+			err = mmc_sd_get_csd(host, card);
+			if (err)
+				goto free_card;
 
-	/*
-	 * For native busses:  get card RCA and quit open drain mode.
-	 */
-	if (!mmc_host_is_spi(host)) {
-		err = mmc_send_relative_addr(host, &card->rca);
-		if (err)
-			goto free_card;
-	}
+			mmc_decode_cid(card);
+		}
 
-	if (!oldcard) {
-		err = mmc_sd_get_csd(host, card);
-		if (err)
-			goto free_card;
+		/*
+		 * handling only for cards supporting DSR and hosts requesting
+		 * DSR configuration
+		 */
+		if (card->csd.dsr_imp && host->dsr_req)
+			mmc_set_dsr(host);
 
-		mmc_decode_cid(card);
+		/*
+		 * Select card, as all following commands rely on that.
+		 */
+		if (!mmc_host_is_spi(host)) {
+			err = mmc_select_card(card);
+			if (err)
+				goto free_card;
+		}
 	}
 
-	/*
-	 * handling only for cards supporting DSR and hosts requesting
-	 * DSR configuration
-	 */
-	if (card->csd.dsr_imp && host->dsr_req)
-		mmc_set_dsr(host);
-
-	/*
-	 * Select card, as all following commands rely on that.
-	 */
-	if (!mmc_host_is_spi(host)) {
-		err = mmc_select_card(card);
-		if (err)
-			goto free_card;
+	/* If card is locked, skip the rest of the init */
+	err = mmc_send_status(card, &status);
+	if (err)
+		goto free_card;
+	if (status & R1_CARD_IS_LOCKED) {
+		pr_info("%s: card is locked.\n", mmc_hostname(card->host));
+		err = mmc_unlock_card(card);
+		if (err != 0) {
+			pr_warn("%s: Card unlock failed.\n",
+				mmc_hostname(card->host));
+			card->raw_ocr = rocr;
+			goto locked_return;
+		}
 	}
 
 	err = mmc_sd_setup_card(host, card, oldcard != NULL);
@@ -1003,6 +1067,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
 		}
 	}
 
+locked_return:
 	host->card = card;
 	return 0;
 
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 0c510b4..38d5572 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -288,6 +288,7 @@ struct mmc_card {
 	u32			raw_cid[4];	/* raw card CID */
 	u32			raw_csd[4];	/* raw card CSD */
 	u32			raw_scr[2];	/* raw card SCR */
+	u32			raw_ocr;	/* raw card OCR */
 	struct mmc_cid		cid;		/* card identification */
 	struct mmc_csd		csd;		/* card specific */
 	struct mmc_ext_csd	ext_csd;	/* mmc v4 extended card specific */
-- 
1.9.0.138.g2de3478


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

* [PATCH V3 6/8] mmc: lock: Prevent partition table read for locked cards.
  2015-05-19 23:11 [PATCH V3 0/8] Add password protected lock/unlock support for SD/MMC Al Cooper
                   ` (4 preceding siblings ...)
  2015-05-19 23:11 ` [PATCH V3 5/8] mmc: lock: Change SD init functionality to handle locked SD cards Al Cooper
@ 2015-05-19 23:11 ` Al Cooper
  2015-05-19 23:11 ` [PATCH V3 7/8] mmc: lock: Change MMC init to handle " Al Cooper
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Al Cooper @ 2015-05-19 23:11 UTC (permalink / raw)
  To: ulf.hansson, linux-mmc, pgynther; +Cc: Al Cooper

Change the MMC block layer to avoid reading the partition table
when the card is locked because read commands will fail.

Signed-off-by: Al Cooper <alcooperx@gmail.com>
---
 drivers/mmc/card/block.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 60f7141..5650748 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -2147,6 +2147,13 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
 		md->disk->flags |= GENHD_FL_NO_PART_SCAN;
 
 	/*
+	 * If the card is locked, reads will fail so prevent partition
+	 * table scan
+	 */
+	if (mmc_card_locked(card))
+		md->disk->flags |= GENHD_FL_NO_PART_SCAN;
+
+	/*
 	 * As discussed on lkml, GENHD_FL_REMOVABLE should:
 	 *
 	 * - be set for removable media with permanent block devices
-- 
1.9.0.138.g2de3478


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

* [PATCH V3 7/8] mmc: lock: Change MMC init to handle locked cards.
  2015-05-19 23:11 [PATCH V3 0/8] Add password protected lock/unlock support for SD/MMC Al Cooper
                   ` (5 preceding siblings ...)
  2015-05-19 23:11 ` [PATCH V3 6/8] mmc: lock: Prevent partition table read for locked cards Al Cooper
@ 2015-05-19 23:11 ` Al Cooper
  2015-05-19 23:11 ` [PATCH V3 8/8] According to SD Physical Layer Specifications: Locked cards respond to (and execute) all commands in the "basic" command class (class 0), ACMD41, CMD16 and "lock card" command class. Thus, the host is allowed to reset, initialize, select, query for status, etc., but not to access data on the card Al Cooper
  2016-07-07  1:15 ` [PATCH V3 0/8] Add password protected lock/unlock support for SD/MMC Yoshihiro Shimoda
  8 siblings, 0 replies; 12+ messages in thread
From: Al Cooper @ 2015-05-19 23:11 UTC (permalink / raw)
  To: ulf.hansson, linux-mmc, pgynther; +Cc: Al Cooper

- Change mmc_init_card() to check for a locked card and, if found,
try to get a password using the kernel KEYS subsystem, unlock the card
and continue. Unlike SD cards, MMC cards support all initialization
commands when locked so the init sequence can be completed on a
locked card and the card can be used without further init after being
unlocked. If the unlock fails, the card state will be marked as "locked"
which will prevent the block layer from reading the partition table.

- Add sysfs attribute "unlock_retry" that will try again to unlock
the card. If the unlock succeeds, the cards "locked" state will be cleared
and the block layer restarted which will now read the partition table.

Signed-off-by: Al Cooper <alcooperx@gmail.com>
---
 drivers/mmc/core/mmc.c | 46 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 44 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 8e94eb8..2c953c5 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -768,10 +768,37 @@ out:
 		return res;
 }
 
-static DEVICE_ATTR(lock, S_IWUSR | S_IRUGO,
-		   mmc_lock_show, mmc_lock_store);
+static ssize_t mmc_unlock_retry_store(struct device *dev,
+				      struct device_attribute *att,
+				      const char *data, size_t len)
+{
+	struct mmc_card *card = mmc_dev_to_card(dev);
+	struct mmc_host *host = card->host;
+	int err;
 
+	BUG_ON(!card);
+	BUG_ON(!host);
 
+	mmc_claim_host(host);
+	if (!mmc_card_locked(card)) {
+		mmc_release_host(host);
+		return len;
+	}
+	err = mmc_unlock_card(card);
+	mmc_release_host(host);
+	if (err < 0)
+		return err;
+	device_release_driver(dev);
+	err = device_attach(dev);
+	if (err < 0)
+		return err;
+	return len;
+}
+
+static DEVICE_ATTR(lock, S_IWUSR | S_IRUGO,
+		   mmc_lock_show, mmc_lock_store);
+static DEVICE_ATTR(unlock_retry, S_IWUSR,
+		   NULL, mmc_unlock_retry_store);
 #endif /* CONFIG_MMC_LOCK */
 
 
@@ -831,6 +858,7 @@ static struct attribute *mmc_std_attrs[] = {
 	&dev_attr_rel_sectors.attr,
 #ifdef CONFIG_MMC_LOCK
 	&dev_attr_lock.attr,
+	&dev_attr_unlock_retry.attr,
 #endif /* CONFIG_MMC_LOCK */
 	NULL,
 };
@@ -1279,6 +1307,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	int err;
 	u32 cid[4];
 	u32 rocr;
+	u32 status;
 
 	BUG_ON(!host);
 	WARN_ON(!host->claimed);
@@ -1568,6 +1597,19 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		}
 	}
 
+	/* If card is locked, try to unlock it */
+	err = mmc_send_status(card, &status);
+	if (err)
+		goto free_card;
+	if (status & R1_CARD_IS_LOCKED) {
+		pr_info("%s: card is locked.\n", mmc_hostname(card->host));
+		err = mmc_unlock_card(card);
+		if (err != 0) {
+			pr_warn("%s: Card unlock failed.\n",
+				mmc_hostname(card->host));
+		}
+	}
+
 	if (!oldcard)
 		host->card = card;
 
-- 
1.9.0.138.g2de3478


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

* [PATCH V3 8/8] According to SD Physical Layer Specifications: Locked cards respond to (and execute) all commands in the "basic" command class (class 0), ACMD41, CMD16 and "lock card" command class. Thus, the host is allowed to reset, initialize, select, query for status, etc., but not to access data on the card.
  2015-05-19 23:11 [PATCH V3 0/8] Add password protected lock/unlock support for SD/MMC Al Cooper
                   ` (6 preceding siblings ...)
  2015-05-19 23:11 ` [PATCH V3 7/8] mmc: lock: Change MMC init to handle " Al Cooper
@ 2015-05-19 23:11 ` Al Cooper
  2016-07-07  1:15 ` [PATCH V3 0/8] Add password protected lock/unlock support for SD/MMC Yoshihiro Shimoda
  8 siblings, 0 replies; 12+ messages in thread
From: Al Cooper @ 2015-05-19 23:11 UTC (permalink / raw)
  To: ulf.hansson, linux-mmc, pgynther; +Cc: Abbas Raza, Al Cooper, Chris Ball

From: Abbas Raza <Abbas_Raza@mentor.com>

But when a locked card is inserted into system having no key added for
this card, following errors are observed until the card is removed

[   36.955193] mmc0: card is locked.
[   36.959746] mmc (null): Error, request_key -2
[   36.964622] mmc0: Cannot find matching key
[   36.968765] mmc0: Card unlock failed.
[   36.972717] mmc0: new SDHC card at address 0002
[   36.977747] mmcblk0: mmc0:0002 00000 7.41 GiB
[   36.989596] mmcblk0: timed out sending r/w cmd command, card status 0x2400900
[   36.999630] mmcblk0: timed out sending r/w cmd command, card status 0x2400900
[   37.009604] mmcblk0: timed out sending r/w cmd command, card status 0x2400900
[   37.019574] mmcblk0: timed out sending r/w cmd command, card status 0x2400900
[   37.029548] mmcblk0: timed out sending r/w cmd command, card status 0x2400900
[   37.039514] mmcblk0: timed out sending r/w cmd command, card status 0x2400900
[   37.046729] end_request: I/O error, dev mmcblk0, sector 15556480
[   37.052813] Buffer I/O error on device mmcblk0, logical block 1944560
[   37.062139] mmcblk0: timed out sending r/w cmd command, card status 0x2400900
[   37.072106] mmcblk0: timed out sending r/w cmd command, card status 0x2400900
[   37.082072] mmcblk0: timed out sending r/w cmd command, card status 0x2400900
.............
[   46.249273] mmcblk0: timed out sending r/w cmd command, card status 0x2400900
[   46.259247] mmcblk0: timed out sending r/w cmd command, card status 0x2400900
[   46.269215] mmcblk0: timed out sending r/w cmd command, card status 0x2400900
[   46.279183] mmcblk0: timed out sending r/w cmd command, card status 0x2400900
[   46.289151] mmcblk0: timed out sending r/w cmd command, card status 0x2400900

As a workaround, skip all the regular block io operations if the card is locked.
One can unlock the card after system boot by following below steps
1) Add key for this card.
2) Unlock the card using sysfs attribute 'unlock_retry' for this card.

Cc: Al Cooper <alcooperx@gmail.com>
Cc: Chris Ball <cjb@laptop.org>
Signed-off-by: Abbas Raza <Abbas_Raza@mentor.com>
---
 drivers/mmc/card/block.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 5650748..79c8861 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -2026,6 +2026,13 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 		/* claim host only for the first request */
 		mmc_get_card(card);
 
+	if (mmc_card_locked(card)) {
+		if (req)
+			blk_end_request_all(req, 0);
+		ret = 0;
+		goto out;
+	}
+
 	ret = mmc_blk_part_switch(card, md);
 	if (ret) {
 		if (req) {
-- 
1.9.0.138.g2de3478


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

* RE: [PATCH V3 0/8] Add password protected lock/unlock support for SD/MMC
  2015-05-19 23:11 [PATCH V3 0/8] Add password protected lock/unlock support for SD/MMC Al Cooper
                   ` (7 preceding siblings ...)
  2015-05-19 23:11 ` [PATCH V3 8/8] According to SD Physical Layer Specifications: Locked cards respond to (and execute) all commands in the "basic" command class (class 0), ACMD41, CMD16 and "lock card" command class. Thus, the host is allowed to reset, initialize, select, query for status, etc., but not to access data on the card Al Cooper
@ 2016-07-07  1:15 ` Yoshihiro Shimoda
  2016-07-12 13:34   ` Alan Cooper
  8 siblings, 1 reply; 12+ messages in thread
From: Yoshihiro Shimoda @ 2016-07-07  1:15 UTC (permalink / raw)
  To: Al Cooper; +Cc: ulf.hansson, linux-mmc, pgynther

Hi,

> From: Al Cooper
> Sent: Wednesday, May 20, 2015 8:11 AM
> To: ulf.hansson@linaro.org; linux-mmc@vger.kernel.org; pgynther@google.com
> Cc: Al Cooper <alcooperx@gmail.com>
> Subject: [PATCH V3 0/8] Add password protected lock/unlock support for SD/MMC

This patch set is quite old, but do you have any update for upstreaming of this patch set?
Our team would like to use this function on our platform.
So, if possible, we would like to apply this function on upstream.

Best regards,
Yoshihiro Shimoda

> This set of patches adds support for password protected locking
> and unlocking of MMC and SD devices. It uses the LOCK/UNLOCK command
> (CMD42) available in both the MMC and SD command sets.
> 
> Some of this code was based on a patch set submitted in 2006 by
> Anderson Briglia "Add MMC Password Protection (lock/unlock)". This
> patch set never made it into mainline.
> 
> By default, a card with no password assigned is always in "unlocked"
> state. After password assignment, in the next power cycle the card
> switches to a "locked" state where only the "basic" and "lock card"
> command classes are accepted by the card. Only after unlocking it with
> the correct password can the card be used for normal operations like
> block I/O.
> 
> Password management and caching is done through the "Kernel Key
> Retention Service" mechanism and the sysfs filesystem. Two new sysfs
> attributes were added. The "lock" attribute is used to lock, unlock,
> assign a password, clear a password and force erase a card. The
> "unlock_retry" attribute is used to retry an unlock that failed
> during boot because the rootfs was not yet available with the password.
> 
> The user space software needed to test this new feature
> is available on GitHub at:
> https://github.com/alcooper/mmc-password-utils
> See the README for a detailed description of the user space layer
> and how to use this feature.
> 
> Changed for V3:
>   - Ported the V2 patch set submitted Aug. 2013 to the latest mainline
>     (v4.1-rc4).
>   - Created a GitHub project for the user space layer.
>   - Change the lock command (CMD42) to round up the data buffer
>     size to 512 for SD but leave exact size for eMMC based on the
>     SD and eMMC specs.
> 
> 
> Changed for V2:
> The V2 changes were not functional and were just general cleanup.
>   - Use stub functions to reduce the number of CONFIG ifdefs.
>   - Add static to a few functions that were local.
>   - Use pr_warn instead of pr_warning.
>   - Improve a few variable names and messages.
> 
> 
> Abbas Raza (1):
>   According to SD Physical Layer Specifications: Locked cards respond to
>     (and execute) all commands in the "basic" command class (class 0),
>     ACMD41, CMD16 and "lock card" command class. Thus, the host is
>     allowed to reset, initialize, select, query for status, etc., but
>     not to access data on the card.
> 
> Al Cooper (7):
>   mmc: lock: Use the kernel "KEYS" subsystem to get a card's password
>   mmc: lock: Add low level LOCK_UNLOCK command
>   mmc: lock: Add function to unlock a password locked card
>   mmc: lock: Add card lock/unlock maintenance commands
>   mmc: lock: Change SD init functionality to handle locked SD cards
>   mmc: lock: Prevent partition table read for locked cards.
>   mmc: lock: Change MMC init to handle locked cards.
> 
>  drivers/mmc/card/block.c   |  14 ++++
>  drivers/mmc/core/Kconfig   |   8 +++
>  drivers/mmc/core/core.c    | 120 +++++++++++++++++++++++++++++++++
>  drivers/mmc/core/core.h    |  14 +++-
>  drivers/mmc/core/mmc.c     | 123 ++++++++++++++++++++++++++++++++++
>  drivers/mmc/core/mmc_ops.c | 150 +++++++++++++++++++++++++++++++++++++++++
>  drivers/mmc/core/mmc_ops.h |  13 ++++
>  drivers/mmc/core/sd.c      | 161 +++++++++++++++++++++++++++++++--------------
>  include/linux/mmc/card.h   |   6 ++
>  9 files changed, 560 insertions(+), 49 deletions(-)
> 
> --
> 1.9.0.138.g2de3478
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH V3 0/8] Add password protected lock/unlock support for SD/MMC
  2016-07-07  1:15 ` [PATCH V3 0/8] Add password protected lock/unlock support for SD/MMC Yoshihiro Shimoda
@ 2016-07-12 13:34   ` Alan Cooper
  0 siblings, 0 replies; 12+ messages in thread
From: Alan Cooper @ 2016-07-12 13:34 UTC (permalink / raw)
  To: Yoshihiro Shimoda; +Cc: ulf.hansson, linux-mmc, pgynther

This is always on my todo list but it never bubbles to the top.
In a few weeks I will probably be in a position to take another pass
at getting this in.

Al

On Wed, Jul 6, 2016 at 9:15 PM, Yoshihiro Shimoda
<yoshihiro.shimoda.uh@renesas.com> wrote:
> Hi,
>
>> From: Al Cooper
>> Sent: Wednesday, May 20, 2015 8:11 AM
>> To: ulf.hansson@linaro.org; linux-mmc@vger.kernel.org; pgynther@google.com
>> Cc: Al Cooper <alcooperx@gmail.com>
>> Subject: [PATCH V3 0/8] Add password protected lock/unlock support for SD/MMC
>
> This patch set is quite old, but do you have any update for upstreaming of this patch set?
> Our team would like to use this function on our platform.
> So, if possible, we would like to apply this function on upstream.
>
> Best regards,
> Yoshihiro Shimoda
>
>> This set of patches adds support for password protected locking
>> and unlocking of MMC and SD devices. It uses the LOCK/UNLOCK command
>> (CMD42) available in both the MMC and SD command sets.
>>
>> Some of this code was based on a patch set submitted in 2006 by
>> Anderson Briglia "Add MMC Password Protection (lock/unlock)". This
>> patch set never made it into mainline.
>>
>> By default, a card with no password assigned is always in "unlocked"
>> state. After password assignment, in the next power cycle the card
>> switches to a "locked" state where only the "basic" and "lock card"
>> command classes are accepted by the card. Only after unlocking it with
>> the correct password can the card be used for normal operations like
>> block I/O.
>>
>> Password management and caching is done through the "Kernel Key
>> Retention Service" mechanism and the sysfs filesystem. Two new sysfs
>> attributes were added. The "lock" attribute is used to lock, unlock,
>> assign a password, clear a password and force erase a card. The
>> "unlock_retry" attribute is used to retry an unlock that failed
>> during boot because the rootfs was not yet available with the password.
>>
>> The user space software needed to test this new feature
>> is available on GitHub at:
>> https://github.com/alcooper/mmc-password-utils
>> See the README for a detailed description of the user space layer
>> and how to use this feature.
>>
>> Changed for V3:
>>   - Ported the V2 patch set submitted Aug. 2013 to the latest mainline
>>     (v4.1-rc4).
>>   - Created a GitHub project for the user space layer.
>>   - Change the lock command (CMD42) to round up the data buffer
>>     size to 512 for SD but leave exact size for eMMC based on the
>>     SD and eMMC specs.
>>
>>
>> Changed for V2:
>> The V2 changes were not functional and were just general cleanup.
>>   - Use stub functions to reduce the number of CONFIG ifdefs.
>>   - Add static to a few functions that were local.
>>   - Use pr_warn instead of pr_warning.
>>   - Improve a few variable names and messages.
>>
>>
>> Abbas Raza (1):
>>   According to SD Physical Layer Specifications: Locked cards respond to
>>     (and execute) all commands in the "basic" command class (class 0),
>>     ACMD41, CMD16 and "lock card" command class. Thus, the host is
>>     allowed to reset, initialize, select, query for status, etc., but
>>     not to access data on the card.
>>
>> Al Cooper (7):
>>   mmc: lock: Use the kernel "KEYS" subsystem to get a card's password
>>   mmc: lock: Add low level LOCK_UNLOCK command
>>   mmc: lock: Add function to unlock a password locked card
>>   mmc: lock: Add card lock/unlock maintenance commands
>>   mmc: lock: Change SD init functionality to handle locked SD cards
>>   mmc: lock: Prevent partition table read for locked cards.
>>   mmc: lock: Change MMC init to handle locked cards.
>>
>>  drivers/mmc/card/block.c   |  14 ++++
>>  drivers/mmc/core/Kconfig   |   8 +++
>>  drivers/mmc/core/core.c    | 120 +++++++++++++++++++++++++++++++++
>>  drivers/mmc/core/core.h    |  14 +++-
>>  drivers/mmc/core/mmc.c     | 123 ++++++++++++++++++++++++++++++++++
>>  drivers/mmc/core/mmc_ops.c | 150 +++++++++++++++++++++++++++++++++++++++++
>>  drivers/mmc/core/mmc_ops.h |  13 ++++
>>  drivers/mmc/core/sd.c      | 161 +++++++++++++++++++++++++++++++--------------
>>  include/linux/mmc/card.h   |   6 ++
>>  9 files changed, 560 insertions(+), 49 deletions(-)
>>
>> --
>> 1.9.0.138.g2de3478
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH V3 1/8] mmc: lock: Use the kernel "KEYS" subsystem to get a card's password
  2015-06-05 17:42 [PATCH V3 0/8 RESEND] " Al Cooper
@ 2015-06-05 17:42 ` Al Cooper
  0 siblings, 0 replies; 12+ messages in thread
From: Al Cooper @ 2015-06-05 17:42 UTC (permalink / raw)
  To: ulf.hansson, linux-mmc, pgynther; +Cc: Al Cooper

Use the kernel "KEYS" subsystem to get a password for a card based on
the card's CID. This code was based on a patch set submitted by
Anderson Briglia in 2006.

Signed-off-by: Al Cooper <alcooperx@gmail.com>
---
 drivers/mmc/core/Kconfig |  8 ++++
 drivers/mmc/core/core.c  | 97 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/mmc/core/core.h  | 10 ++++-
 3 files changed, 114 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig
index 9ebee72..1d073cd 100644
--- a/drivers/mmc/core/Kconfig
+++ b/drivers/mmc/core/Kconfig
@@ -11,3 +11,11 @@ config MMC_CLKGATE
 	  support handling this in order for it to be of any use.
 
 	  If unsure, say N.
+
+config MMC_LOCK
+	bool "MMC/SD password based card lock/unlock"
+	select KEYS
+	help
+	  This will add the ability to lock/unlock SD and MMC cards.
+
+	  If unsure, say N.
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 92e7671..f7d7ad9 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -29,6 +29,7 @@
 #include <linux/random.h>
 #include <linux/slab.h>
 #include <linux/of.h>
+#include <linux/key-type.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
@@ -2707,6 +2708,96 @@ void mmc_init_context_info(struct mmc_host *host)
 	init_waitqueue_head(&host->context_info.wait);
 }
 
+#ifdef CONFIG_MMC_LOCK
+
+static int mmc_key_instantiate(struct key *key,
+			       struct key_preparsed_payload *prep)
+{
+	char *payload;
+
+	if (prep->datalen <= 0 || prep->datalen > MMC_PASSWORD_MAX ||
+	    !prep->data) {
+		pr_warn("Invalid data\n");
+		return  -EINVAL;
+	}
+
+	payload = kmalloc(prep->datalen, GFP_KERNEL);
+	if (!payload)
+		return -ENOMEM;
+	memcpy(payload, prep->data, prep->datalen);
+	key->payload.data = payload;
+	key->datalen = prep->datalen;
+	return 0;
+}
+
+/*
+ * dispose of the data dangling from the corpse of a mmc key
+ */
+static void mmc_key_destroy(struct key *key)
+{
+	kfree(key->payload.data);
+}
+
+struct key_type key_type_mmc = {
+	.name		= "mmc",
+	.instantiate	= mmc_key_instantiate,
+	.destroy	= mmc_key_destroy,
+};
+
+int mmc_get_password(struct mmc_card *card, struct mmc_password *password)
+{
+	struct key *mmc_key;
+	char key_desc[(sizeof(card->raw_cid) * 2) + 1];
+
+	/* Use the CID to uniquely identify the card */
+	snprintf(key_desc, sizeof(key_desc), "%08x%08x%08x%08x",
+		 card->raw_cid[0], card->raw_cid[1],
+		 card->raw_cid[2], card->raw_cid[3]);
+
+	mmc_key = request_key(&key_type_mmc, key_desc,
+			      "password");
+	if (IS_ERR(mmc_key)) {
+		dev_warn(&card->dev, "Error, request_key %ld\n",
+			 PTR_ERR(mmc_key));
+		return PTR_ERR(mmc_key);
+	}
+	dev_dbg(&card->dev, "Found matching key\n");
+	memcpy(&password->password, mmc_key->payload.data,
+	       mmc_key->datalen);
+	password->length = mmc_key->datalen;
+	key_put(mmc_key);
+
+	return 0;
+}
+
+static inline int mmc_register_key_type(void)
+{
+	return register_key_type(&key_type_mmc);
+}
+
+static inline void mmc_unregister_key_type(void)
+{
+	unregister_key_type(&key_type_mmc);
+}
+
+#else /* CONFIG_MMC_LOCK */
+
+int mmc_get_password(struct mmc_card *card, struct mmc_password *password)
+{
+	return -ENOKEY;
+}
+
+static inline int mmc_register_key_type(void)
+{
+	return 0;
+}
+
+static inline void mmc_unregister_key_type(void)
+{
+}
+
+#endif /* CONFIG_MMC_LOCK */
+
 static int __init mmc_init(void)
 {
 	int ret;
@@ -2727,8 +2818,13 @@ static int __init mmc_init(void)
 	if (ret)
 		goto unregister_host_class;
 
+	ret = mmc_register_key_type();
+	if (ret)
+		goto unregister_sdio_bus;
 	return 0;
 
+unregister_sdio_bus:
+	sdio_unregister_bus();
 unregister_host_class:
 	mmc_unregister_host_class();
 unregister_bus:
@@ -2741,6 +2837,7 @@ destroy_workqueue:
 
 static void __exit mmc_exit(void)
 {
+	mmc_unregister_key_type();
 	sdio_unregister_bus();
 	mmc_unregister_host_class();
 	mmc_unregister_bus();
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index cfba3c0..b91bc3e 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -89,5 +89,13 @@ void mmc_init_context_info(struct mmc_host *host);
 
 int mmc_execute_tuning(struct mmc_card *card);
 
-#endif
+/* Lock/Unlock functionality */
+#define MMC_PASSWORD_MAX 16
+struct mmc_password {
+	char password[MMC_PASSWORD_MAX];
+	int length;
+};
+int mmc_unlock_card(struct mmc_card *card);
+int mmc_get_password(struct mmc_card *card, struct mmc_password *password);
 
+#endif
-- 
1.9.0.138.g2de3478


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

end of thread, other threads:[~2016-07-12 13:34 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-05-19 23:11 [PATCH V3 0/8] Add password protected lock/unlock support for SD/MMC Al Cooper
2015-05-19 23:11 ` [PATCH V3 1/8] mmc: lock: Use the kernel "KEYS" subsystem to get a card's password Al Cooper
2015-05-19 23:11 ` [PATCH V3 2/8] mmc: lock: Add low level LOCK_UNLOCK command Al Cooper
2015-05-19 23:11 ` [PATCH V3 3/8] mmc: lock: Add function to unlock a password locked card Al Cooper
2015-05-19 23:11 ` [PATCH V3 4/8] mmc: lock: Add card lock/unlock maintenance commands Al Cooper
2015-05-19 23:11 ` [PATCH V3 5/8] mmc: lock: Change SD init functionality to handle locked SD cards Al Cooper
2015-05-19 23:11 ` [PATCH V3 6/8] mmc: lock: Prevent partition table read for locked cards Al Cooper
2015-05-19 23:11 ` [PATCH V3 7/8] mmc: lock: Change MMC init to handle " Al Cooper
2015-05-19 23:11 ` [PATCH V3 8/8] According to SD Physical Layer Specifications: Locked cards respond to (and execute) all commands in the "basic" command class (class 0), ACMD41, CMD16 and "lock card" command class. Thus, the host is allowed to reset, initialize, select, query for status, etc., but not to access data on the card Al Cooper
2016-07-07  1:15 ` [PATCH V3 0/8] Add password protected lock/unlock support for SD/MMC Yoshihiro Shimoda
2016-07-12 13:34   ` Alan Cooper
2015-06-05 17:42 [PATCH V3 0/8 RESEND] " Al Cooper
2015-06-05 17:42 ` [PATCH V3 1/8] mmc: lock: Use the kernel "KEYS" subsystem to get a card's password Al Cooper

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.