* [patch 0/5] Add MMC password protection (lock/unlock) support V2
@ 2005-12-28 18:40 Anderson Lizardo
2005-12-28 18:40 ` [patch 1/5] " Anderson Lizardo
` (4 more replies)
0 siblings, 5 replies; 8+ messages in thread
From: Anderson Lizardo @ 2005-12-28 18:40 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel
Cc: Russell King - ARM Linux, David Brownell, Tony Lindgren,
Anderson Briglia, Anderson Lizardo, Carlos Eduardo Aguiar
Hi,
These series of patches add support for MultiMediaCard (MMC) password
protection, as described in the MMC Specification v4.1. This feature is
supported by all compliant MMC cards, and used by some devices such as Symbian
OS cell phones to optionally protect MMC cards with a password.
By default, a MMC 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 the
card can be normally used for operations like block I/O.
Password management and caching is done through the "Kernel Key Retention
Service" mechanism and the sysfs filesystem. The Key Retention Service is used
for (1) unlocking the card, (2) assigning a password to an unlocked card and
(3) change a card's password. To remove the password and check locked/unlocked
status, a new sysfs attribute was added to the MMC driver.
A sample text-mode reference UI written in shell script (using the keyctl
command from the keyutils package), can be found at:
http://www.indt.org.br/10le/mmc_pwd/mmc_reference_ui-20051215.tar.gz
New in this version:
- Removed unnecessary #include directive
- Fixed comment formatting issues.
- Added code to force the block driver to re-probe() the card after unlocking
it.
TODO:
- Password caching: when inserting a locked card, the driver should try to
unlock it with the currently stored password (if any), and if it fails,
revoke the key containing it and fallback to the normal "no password present"
situation.
- Currently, some host drivers assume the block length will always be a power
of 2. This is not true for the MMC_LOCK_UNLOCK command, which is a block
command that accepts arbitratry block lengths. We have made the necessary
changes to the omap.c driver (present on the linux-omap tree), but the same
needs to be done for other hosts' drivers.
Known Issue:
- Some cards have an incorrect behaviour (hardware bug?) regarding password
acceptance: if an affected card has password <pwd>, it accepts <pwd><xxx> as
the correct password too, where <xxx> is any sequence of characters, of any
length. In other words, on these cards only the first <password length> bytes
need to match the correct password.
Comments, suggestions are welcome.
--
Anderson Briglia,
Anderson Lizardo,
Carlos Eduardo Aguiar
Embedded Linux Lab - 10LE
Nokia Institute of Technology - INdT
Manaus - Brazil
^ permalink raw reply [flat|nested] 8+ messages in thread
* [patch 1/5] Add MMC password protection (lock/unlock) support V2
2005-12-28 18:40 [patch 0/5] Add MMC password protection (lock/unlock) support V2 Anderson Lizardo
@ 2005-12-28 18:40 ` Anderson Lizardo
2005-12-28 18:40 ` [patch 2/5] " Anderson Lizardo
` (3 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Anderson Lizardo @ 2005-12-28 18:40 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel
Cc: Russell King - ARM Linux, David Brownell, Tony Lindgren,
Anderson Briglia, Anderson Lizardo, Carlos Eduardo Aguiar
[-- Attachment #1: mmc_ignore_locked.diff --]
[-- Type: text/plain, Size: 4090 bytes --]
When a card is locked, only commands from the "basic" and "lock card" classes
are accepted. To be able to use the other commands, the card must be unlocked
first.
This patch prevents the block driver from trying to run privileged class
commands on locked MMC cards, which will fail anyway.
Signed-off-by: Anderson Briglia <anderson.briglia@indt.org.br>
Signed-off-by: Anderson Lizardo <anderson.lizardo@indt.org.br>
Signed-off-by: Carlos Eduardo Aguiar <carlos.aguiar@indt.org.br>
Signed-off-by: David Brownell <david-b@pacbell.net>
Index: linux-2.6.15-rc4-omap1/drivers/mmc/mmc.c
===================================================================
--- linux-2.6.15-rc4-omap1.orig/drivers/mmc/mmc.c 2005-12-15 15:48:20.000000000 -0400
+++ linux-2.6.15-rc4-omap1/drivers/mmc/mmc.c 2005-12-28 14:18:18.000000000 -0400
@@ -986,10 +986,15 @@ static void mmc_check_cards(struct mmc_h
cmd.flags = MMC_RSP_R1;
err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
- if (err == MMC_ERR_NONE)
+ if (err != MMC_ERR_NONE) {
+ mmc_card_set_dead(card);
continue;
+ }
- mmc_card_set_dead(card);
+ if (cmd.resp[0] & R1_CARD_IS_LOCKED)
+ mmc_card_set_locked(card);
+ else
+ card->state &= ~MMC_STATE_LOCKED;
}
}
Index: linux-2.6.15-rc4-omap1/drivers/mmc/mmc_sysfs.c
===================================================================
--- linux-2.6.15-rc4-omap1.orig/drivers/mmc/mmc_sysfs.c 2005-12-15 15:48:20.000000000 -0400
+++ linux-2.6.15-rc4-omap1/drivers/mmc/mmc_sysfs.c 2005-12-28 14:20:04.000000000 -0400
@@ -16,6 +16,7 @@
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
+#include <linux/mmc/protocol.h>
#include "mmc.h"
@@ -72,10 +73,19 @@ static void mmc_release_card(struct devi
* This currently matches any MMC driver to any MMC card - drivers
* themselves make the decision whether to drive this card in their
* probe method. However, we force "bad" cards to fail.
+ *
+ * We also fail for all locked cards; drivers expect to be able to do
+ * block I/O still on probe(), which is not possible while the card is
+ * locked. Device probing must be triggered sometime later to make the
+ * card available to the block driver.
*/
static int mmc_bus_match(struct device *dev, struct device_driver *drv)
{
struct mmc_card *card = dev_to_mmc_card(dev);
+ if (mmc_card_lockable(card) && mmc_card_locked(card)) {
+ dev_dbg(&card->dev, "card is locked; binding is deferred\n");
+ return 0;
+ }
return !mmc_card_bad(card);
}
Index: linux-2.6.15-rc4-omap1/include/linux/mmc/card.h
===================================================================
--- linux-2.6.15-rc4-omap1.orig/include/linux/mmc/card.h 2005-12-15 15:48:20.000000000 -0400
+++ linux-2.6.15-rc4-omap1/include/linux/mmc/card.h 2005-12-28 14:18:18.000000000 -0400
@@ -56,6 +56,7 @@ struct mmc_card {
#define MMC_STATE_BAD (1<<2) /* unrecognised device */
#define MMC_STATE_SDCARD (1<<3) /* is an SD card */
#define MMC_STATE_READONLY (1<<4) /* card is read-only */
+#define MMC_STATE_LOCKED (1<<5) /* card is currently locked */
u32 raw_cid[4]; /* raw card CID */
u32 raw_csd[4]; /* raw card CSD */
u32 raw_scr[2]; /* raw card SCR */
@@ -69,12 +70,16 @@ struct mmc_card {
#define mmc_card_bad(c) ((c)->state & MMC_STATE_BAD)
#define mmc_card_sd(c) ((c)->state & MMC_STATE_SDCARD)
#define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY)
+#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_dead(c) ((c)->state |= MMC_STATE_DEAD)
#define mmc_card_set_bad(c) ((c)->state |= MMC_STATE_BAD)
#define mmc_card_set_sd(c) ((c)->state |= MMC_STATE_SDCARD)
#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
+#define mmc_card_set_locked(c) ((c)->state |= MMC_STATE_LOCKED)
#define mmc_card_name(c) ((c)->cid.prod_name)
#define mmc_card_id(c) ((c)->dev.bus_id)
--
Anderson Lizardo
Embedded Linux Lab - 10LE
Nokia Institute of Technology - INdT
Manaus - Brazil
^ permalink raw reply [flat|nested] 8+ messages in thread
* [patch 2/5] Add MMC password protection (lock/unlock) support V2
2005-12-28 18:40 [patch 0/5] Add MMC password protection (lock/unlock) support V2 Anderson Lizardo
2005-12-28 18:40 ` [patch 1/5] " Anderson Lizardo
@ 2005-12-28 18:40 ` Anderson Lizardo
2005-12-28 18:40 ` [patch 3/5] " Anderson Lizardo
` (2 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Anderson Lizardo @ 2005-12-28 18:40 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel
Cc: Russell King - ARM Linux, David Brownell, Tony Lindgren,
Anderson Briglia, Anderson Lizardo, Carlos Eduardo Aguiar
[-- Attachment #1: mmc_lock_unlock.diff --]
[-- Type: text/plain, Size: 6387 bytes --]
Implement card lock/unlock card operation, using the MMC_LOCK_UNLOCK command.
Signed-off-by: Anderson Briglia <anderson.briglia@indt.org.br>
Signed-off-by: Anderson Lizardo <anderson.lizardo@indt.org.br>
Signed-off-by: Carlos Eduardo Aguiar <carlos.aguiar@indt.org.br>
Index: linux-2.6.15-rc4-omap1/drivers/mmc/mmc.c
===================================================================
--- linux-2.6.15-rc4-omap1.orig/drivers/mmc/mmc.c 2005-12-28 14:18:18.000000000 -0400
+++ linux-2.6.15-rc4-omap1/drivers/mmc/mmc.c 2005-12-28 14:20:30.000000000 -0400
@@ -4,6 +4,8 @@
* Copyright (C) 2003-2004 Russell King, All Rights Reserved.
* SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
* SD support Copyright (C) 2005 Pierre Ossman, All Rights Reserved.
+ * MMC password protection (C) 2005 Instituto Nokia de Tecnologia (INdT),
+ * All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -20,6 +22,7 @@
#include <linux/err.h>
#include <asm/scatterlist.h>
#include <linux/scatterlist.h>
+#include <linux/key.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@@ -1088,6 +1091,159 @@ static void mmc_setup(struct mmc_host *h
mmc_read_scrs(host);
}
+static int pop(unsigned x)
+{
+ x = x - ((x >> 1) & 0x55555555);
+ x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
+ x = (x + (x >> 4)) & 0x0F0F0F0F;
+ x = x + (x >> 8);
+ x = x + (x >> 16);
+
+ return x & 0x0000003F;
+}
+
+static int ilog2(unsigned x)
+{
+ x = x | (x >> 1);
+ x = x | (x >> 2);
+ x = x | (x >> 4);
+ x = x | (x >> 8);
+ x = x | (x >> 16);
+
+ return pop(x) - 1;
+}
+
+/* Calculate the minimal blksz_bits to hold x bytes. The two math functions
+ * above are used to do the calculation.
+ *
+ * XXX There must be a simpler way to do this... */
+static inline int blksz_bits(unsigned x)
+{
+ return 1 + ilog2(x - 1);
+}
+
+/**
+ * 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 key *key, int mode)
+{
+ struct mmc_request mrq;
+ struct mmc_command cmd;
+ struct mmc_data data;
+ struct scatterlist sg;
+ struct mmc_key_payload *mpayload;
+ unsigned long erase_timeout;
+ int err, data_size;
+ u8 *data_buf;
+
+ mpayload = NULL;
+ data_size = 1;
+ if (mode != MMC_LOCK_MODE_ERASE) {
+ mpayload = rcu_dereference(key->payload.data);
+ data_size = 2 + mpayload->datalen;
+ }
+
+ data_buf = kmalloc(data_size, GFP_KERNEL);
+ if (!data_buf)
+ return -ENOMEM;
+ memset(data_buf, 0, data_size);
+
+ data_buf[0] = mode;
+ if (mode != MMC_LOCK_MODE_ERASE) {
+ data_buf[1] = mpayload->datalen;
+ memcpy(data_buf + 2, mpayload->data, mpayload->datalen);
+ }
+
+ err = mmc_card_claim_host(card);
+ if (err != MMC_ERR_NONE) {
+ mmc_card_set_dead(card);
+ goto out;
+ }
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = MMC_SET_BLOCKLEN;
+ cmd.arg = data_size;
+ cmd.flags = MMC_RSP_R1;
+ err = mmc_wait_for_cmd(card->host, &cmd, CMD_RETRIES);
+ if (err != MMC_ERR_NONE) {
+ mmc_card_set_dead(card);
+ goto error;
+ }
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = MMC_LOCK_UNLOCK;
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_R1B;
+
+ memset(&data, 0, sizeof(struct mmc_data));
+
+ data.timeout_ns = card->csd.tacc_ns * 10;
+ data.timeout_clks = card->csd.tacc_clks * 10;
+ data.blksz_bits = blksz_bits(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);
+ err = mmc_wait_for_req(card->host, &mrq);
+ if (err != MMC_ERR_NONE) {
+ mmc_card_set_dead(card);
+ goto error;
+ }
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = MMC_SEND_STATUS;
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_R1;
+
+ /* 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 != MMC_ERR_NONE)
+ break;
+ /* the other modes don't need timeout checking */
+ if (mode != MMC_LOCK_MODE_ERASE)
+ continue;
+ if (time_after(jiffies, erase_timeout)) {
+ dev_dbg(&card->dev, "forced erase timed out\n");
+ err = MMC_ERR_TIMEOUT;
+ 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 = MMC_ERR_FAILED;
+ }
+
+error:
+ mmc_check_cards(card->host);
+ mmc_deselect_cards(card->host);
+ mmc_card_release_host(card);
+out:
+ kfree(data_buf);
+
+ return err;
+}
+
+EXPORT_SYMBOL(mmc_lock_unlock);
+
/**
* mmc_detect_change - process change of state on a MMC socket
Index: linux-2.6.15-rc4-omap1/include/linux/mmc/card.h
===================================================================
--- linux-2.6.15-rc4-omap1.orig/include/linux/mmc/card.h 2005-12-28 14:18:18.000000000 -0400
+++ linux-2.6.15-rc4-omap1/include/linux/mmc/card.h 2005-12-28 14:33:31.000000000 -0400
@@ -109,4 +109,7 @@ static inline int mmc_card_claim_host(st
#define mmc_card_release_host(c) mmc_release_host((c)->host)
+struct key;
+extern int mmc_lock_unlock(struct mmc_card *card, struct key *key, int mode);
+
#endif
Index: linux-2.6.15-rc4-omap1/include/linux/mmc/protocol.h
===================================================================
--- linux-2.6.15-rc4-omap1.orig/include/linux/mmc/protocol.h 2005-12-28 14:18:18.000000000 -0400
+++ linux-2.6.15-rc4-omap1/include/linux/mmc/protocol.h 2005-12-28 14:20:30.000000000 -0400
@@ -243,5 +243,13 @@ struct _mmc_csd {
#define SD_BUS_WIDTH_1 0
#define SD_BUS_WIDTH_4 2
+/*
+ * MMC_LOCK_UNLOCK modes
+ */
+#define MMC_LOCK_MODE_ERASE (1<<3)
+#define MMC_LOCK_MODE_UNLOCK (0<<2)
+#define MMC_LOCK_MODE_CLR_PWD (1<<1)
+#define MMC_LOCK_MODE_SET_PWD (1<<0)
+
#endif /* MMC_MMC_PROTOCOL_H */
--
Anderson Lizardo
Embedded Linux Lab - 10LE
Nokia Institute of Technology - INdT
Manaus - Brazil
^ permalink raw reply [flat|nested] 8+ messages in thread
* [patch 3/5] Add MMC password protection (lock/unlock) support V2
2005-12-28 18:40 [patch 0/5] Add MMC password protection (lock/unlock) support V2 Anderson Lizardo
2005-12-28 18:40 ` [patch 1/5] " Anderson Lizardo
2005-12-28 18:40 ` [patch 2/5] " Anderson Lizardo
@ 2005-12-28 18:40 ` Anderson Lizardo
2005-12-29 9:07 ` Chris White
2005-12-28 18:40 ` [patch 4/5] " Anderson Lizardo
2005-12-28 18:40 ` [patch 5/5] " Anderson Lizardo
4 siblings, 1 reply; 8+ messages in thread
From: Anderson Lizardo @ 2005-12-28 18:40 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel
Cc: Russell King - ARM Linux, David Brownell, Tony Lindgren,
Anderson Briglia, Anderson Lizardo, Carlos Eduardo Aguiar
[-- Attachment #1: mmc_key_retention.diff --]
[-- Type: text/plain, Size: 7162 bytes --]
Implement key retention operations. mmc_key_instantiate() is used for unlocking
and password assignment (from no-password state). mmc_key_update() is used for
password change.
Signed-off-by: Anderson Briglia <anderson.briglia@indt.org.br>
Signed-off-by: Anderson Lizardo <anderson.lizardo@indt.org.br>
Signed-off-by: Carlos Eduardo Aguiar <carlos.aguiar@indt.org.br>
Index: linux-2.6.15-rc4-omap1/drivers/mmc/Kconfig
===================================================================
--- linux-2.6.15-rc4-omap1.orig/drivers/mmc/Kconfig 2005-12-27 17:19:47.000000000 -0400
+++ linux-2.6.15-rc4-omap1/drivers/mmc/Kconfig 2005-12-27 17:20:18.000000000 -0400
@@ -19,6 +19,19 @@ config MMC_DEBUG
This is an option for use by developers; most people should
say N here. This enables MMC core and driver debugging.
+config MMC_PASSWORDS
+ boolean "MMC card lock/unlock passwords (EXPERIMENTAL)"
+ depends on MMC && EXPERIMENTAL
+ select KEYS
+ help
+ Say Y here to enable the use of passwords to lock and unlock
+ MMC cards. This uses the access key retention support, using
+ request_key to look up the key associated with each card.
+
+ For example, if you have an MMC card that was locked using
+ Symbian OS on your cell phone, you won't be able to read it
+ on Linux without this support.
+
config MMC_BLOCK
tristate "MMC block device driver"
depends on MMC
Index: linux-2.6.15-rc4-omap1/drivers/mmc/mmc.h
===================================================================
--- linux-2.6.15-rc4-omap1.orig/drivers/mmc/mmc.h 2005-12-27 17:19:47.000000000 -0400
+++ linux-2.6.15-rc4-omap1/drivers/mmc/mmc.h 2005-12-27 17:20:18.000000000 -0400
@@ -18,4 +18,12 @@ struct mmc_host *mmc_alloc_host_sysfs(in
int mmc_add_host_sysfs(struct mmc_host *host);
void mmc_remove_host_sysfs(struct mmc_host *host);
void mmc_free_host_sysfs(struct mmc_host *host);
+
+/* core-internal data */
+extern struct key_type mmc_key_type;
+struct mmc_key_payload {
+ struct rcu_head rcu; /* RCU destructor */
+ unsigned short datalen; /* length of this data */
+ char data[0]; /* actual data */
+};
#endif
Index: linux-2.6.15-rc4-omap1/drivers/mmc/mmc_sysfs.c
===================================================================
--- linux-2.6.15-rc4-omap1.orig/drivers/mmc/mmc_sysfs.c 2005-12-27 17:19:47.000000000 -0400
+++ linux-2.6.15-rc4-omap1/drivers/mmc/mmc_sysfs.c 2005-12-27 17:21:35.000000000 -0400
@@ -2,6 +2,8 @@
* linux/drivers/mmc/mmc_sysfs.c
*
* Copyright (C) 2003 Russell King, All Rights Reserved.
+ * MMC password protection (C) 2005 Instituto Nokia de Tecnologia (INdT),
+ * All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -13,6 +15,7 @@
#include <linux/init.h>
#include <linux/device.h>
#include <linux/idr.h>
+#include <linux/key.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@@ -267,6 +270,150 @@ static struct class mmc_host_class = {
static DEFINE_IDR(mmc_host_idr);
static DEFINE_SPINLOCK(mmc_host_lock);
+#ifdef CONFIG_MMC_PASSWORDS
+
+#define MMC_KEYLEN_MAXBYTES 32
+
+static int mmc_match_lockable(struct device *dev, void *data)
+{
+ struct mmc_card *card = dev_to_mmc_card(dev);
+
+ return mmc_card_lockable(card);
+}
+
+int mmc_key_instantiate(struct key *key, const void *data, size_t datalen)
+{
+ struct mmc_key_payload *mpayload;
+ struct device *dev;
+ struct mmc_card *card;
+ int ret;
+
+ ret = -EINVAL;
+ if (datalen <= 0 || datalen > MMC_KEYLEN_MAXBYTES || !data)
+ goto error;
+
+ ret = key_payload_reserve(key, datalen);
+ if (ret < 0)
+ goto error;
+
+ ret = -ENOMEM;
+ mpayload = kmalloc(sizeof(*mpayload) + datalen, GFP_KERNEL);
+ if (!mpayload)
+ goto error;
+
+ /* attach the data */
+ mpayload->datalen = datalen;
+ memcpy(mpayload->data, data, datalen);
+ rcu_assign_pointer(key->payload.data, mpayload);
+
+ ret = -EINVAL;
+ dev = bus_find_device(&mmc_bus_type, NULL, NULL, mmc_match_lockable);
+ if (!dev)
+ goto error;
+ card = dev_to_mmc_card(dev);
+ if (mmc_card_locked(card)) {
+ ret = mmc_lock_unlock(card, key, MMC_LOCK_MODE_UNLOCK);
+ mmc_remove_card(card);
+ mmc_register_card(card);
+ } else
+ ret = mmc_lock_unlock(card, key, MMC_LOCK_MODE_SET_PWD);
+ if (ret)
+ ret = -EKEYREJECTED;
+
+error:
+ return ret;
+}
+
+/*
+ * dispose of the old data from an updated mmc key
+ */
+static void mmc_key_update_rcu_disposal(struct rcu_head *rcu)
+{
+ struct mmc_key_key_payload *mpayload;
+
+ mpayload = (struct mmc_key_key_payload *)container_of(rcu, struct mmc_key_payload, rcu);
+
+ kfree(mpayload);
+}
+
+/*
+ * update a mmc key
+ * - the key's semaphore is write-locked
+ */
+int mmc_key_update(struct key *key, const void *data, size_t datalen)
+{
+ struct mmc_key_payload *mpayload, *zap;
+ struct device *dev;
+ struct mmc_card *card;
+ int ret;
+
+ ret = -EINVAL;
+ if (datalen <= 0 || datalen > MMC_KEYLEN_MAXBYTES || !data)
+ goto error;
+
+ /* construct a replacement payload */
+ ret = -ENOMEM;
+ mpayload = kmalloc(sizeof(*mpayload) + datalen, GFP_KERNEL);
+ if (!mpayload)
+ goto error;
+
+ mpayload->datalen = datalen;
+ memcpy(mpayload->data, data, datalen);
+
+ /* check the quota and attach the new data */
+ zap = mpayload;
+
+ ret = key_payload_reserve(key, datalen);
+
+ if (ret == 0) {
+ /* attach the new data, displacing the old */
+ zap = key->payload.data;
+ rcu_assign_pointer(key->payload.data, mpayload);
+ key->expiry = 0;
+ }
+
+ ret = -EINVAL;
+ dev = bus_find_device(&mmc_bus_type, NULL, NULL, mmc_match_lockable);
+ if (!dev)
+ goto error;
+ card = dev_to_mmc_card(dev);
+ if (!mmc_card_locked(card))
+ ret = mmc_lock_unlock(card, key, MMC_LOCK_MODE_SET_PWD);
+ if (ret)
+ ret = -EKEYREJECTED;
+
+ call_rcu(&zap->rcu, mmc_key_update_rcu_disposal);
+
+error:
+ return ret;
+}
+
+int mmc_key_match(const struct key *key, const void *description)
+{
+ return strcmp(key->description, description) == 0;
+}
+
+/*
+ * dispose of the data dangling from the corpse of a mmc key
+ */
+void mmc_key_destroy(struct key *key)
+{
+ struct mmc_key_payload *mpayload = key->payload.data;
+
+ kfree(mpayload);
+}
+
+struct key_type mmc_key_type = {
+ .name = "mmc",
+ .def_datalen = MMC_KEYLEN_MAXBYTES,
+ .instantiate = mmc_key_instantiate,
+ .update = mmc_key_update,
+ .match = mmc_key_match,
+ .destroy = mmc_key_destroy,
+};
+
+#endif
+
/*
* Internal function. Allocate a new MMC host.
*/
@@ -337,6 +484,15 @@ static int __init mmc_init(void)
ret = class_register(&mmc_host_class);
if (ret)
bus_unregister(&mmc_bus_type);
+#ifdef CONFIG_MMC_PASSWORDS
+ else {
+ ret = register_key_type(&mmc_key_type);
+ if (ret) {
+ class_unregister(&mmc_host_class);
+ bus_unregister(&mmc_bus_type);
+ }
+ }
+#endif
}
return ret;
}
@@ -345,6 +501,9 @@ static void __exit mmc_exit(void)
{
class_unregister(&mmc_host_class);
bus_unregister(&mmc_bus_type);
+#ifdef CONFIG_MMC_PASSWORDS
+ unregister_key_type(&mmc_key_type);
+#endif
}
module_init(mmc_init);
--
Anderson Lizardo
Embedded Linux Lab - 10LE
Nokia Institute of Technology - INdT
Manaus - Brazil
^ permalink raw reply [flat|nested] 8+ messages in thread
* [patch 4/5] Add MMC password protection (lock/unlock) support V2
2005-12-28 18:40 [patch 0/5] Add MMC password protection (lock/unlock) support V2 Anderson Lizardo
` (2 preceding siblings ...)
2005-12-28 18:40 ` [patch 3/5] " Anderson Lizardo
@ 2005-12-28 18:40 ` Anderson Lizardo
2005-12-28 21:23 ` Arnd Bergmann
2005-12-28 18:40 ` [patch 5/5] " Anderson Lizardo
4 siblings, 1 reply; 8+ messages in thread
From: Anderson Lizardo @ 2005-12-28 18:40 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel
Cc: Russell King - ARM Linux, David Brownell, Tony Lindgren,
Anderson Briglia, Anderson Lizardo, Carlos Eduardo Aguiar
[-- Attachment #1: mmc_sysfs.diff --]
[-- Type: text/plain, Size: 3343 bytes --]
Implement MMC password reset and forced erase support. It uses the sysfs
mechanism to send commands to the MMC subsystem. Usage:
Forced erase:
echo erase > /sys/bus/mmc/devices/mmc0\:0001/lockable
Remove password:
echo remove > /sys/bus/mmc/devices/mmc0\:0001/lockable
Signed-off-by: Anderson Briglia <anderson.briglia@indt.org.br>
Signed-off-by: Anderson Lizardo <anderson.lizardo@indt.org.br>
Signed-off-by: Carlos Eduardo Aguiar <carlos.aguiar@indt.org.br>
Index: linux-2.6.15-rc4-omap1/drivers/mmc/mmc_sysfs.c
===================================================================
--- linux-2.6.15-rc4-omap1.orig/drivers/mmc/mmc_sysfs.c 2005-12-15 15:47:40.000000000 -0400
+++ linux-2.6.15-rc4-omap1/drivers/mmc/mmc_sysfs.c 2005-12-15 15:47:40.000000000 -0400
@@ -16,6 +16,7 @@
#include <linux/device.h>
#include <linux/idr.h>
#include <linux/key.h>
+#include <linux/err.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@@ -64,6 +65,58 @@ static struct device_attribute mmc_dev_a
static struct device_attribute mmc_dev_attr_scr = MMC_ATTR_RO(scr);
+#ifdef CONFIG_MMC_PASSWORDS
+
+static ssize_t
+mmc_lockable_show(struct device *dev, struct device_attribute *att, char *buf)
+{
+ struct mmc_card *card = dev_to_mmc_card(dev);
+
+ if (!mmc_card_lockable(card))
+ return sprintf(buf, "unlockable\n");
+ else
+ return sprintf(buf, "lockable, %slocked\n", mmc_card_locked(card) ?
+ "" : "un");
+}
+
+/*
+ * implement MMC password reset ("remove password") and forced erase ("forgot
+ * password").
+ */
+static ssize_t
+mmc_lockable_store(struct device *dev, struct device_attribute *att,
+ const char *data, size_t len)
+{
+ struct mmc_card *card = dev_to_mmc_card(dev);
+
+ if (!mmc_card_lockable(card))
+ return -EINVAL;
+
+ if (mmc_card_locked(card) && !strncmp(data, "erase", 5)) {
+ /* forced erase only works while card is locked */
+ mmc_lock_unlock(card, NULL, MMC_LOCK_MODE_ERASE);
+ return len;
+ } else if (!mmc_card_locked(card) && !strncmp(data, "remove", 6)) {
+ /* remove password only works while card is unlocked */
+ struct key *mmc_key = request_key(&mmc_key_type, "mmc:key", NULL);
+
+ if (!IS_ERR(mmc_key)) {
+ int err = mmc_lock_unlock(card, mmc_key, MMC_LOCK_MODE_CLR_PWD);
+ if (!err)
+ return len;
+ } else
+ dev_dbg(&card->dev, "request_key returned error %ld\n", PTR_ERR(mmc_key));
+ }
+
+ return -EINVAL;
+}
+
+static struct device_attribute mmc_dev_attr_lockable =
+ __ATTR(lockable, S_IWUSR | S_IRUGO,
+ mmc_lockable_show, mmc_lockable_store);
+
+#endif
+
static void mmc_release_card(struct device *dev)
{
@@ -235,6 +288,13 @@ int mmc_register_card(struct mmc_card *c
if (ret)
device_del(&card->dev);
}
+#ifdef CONFIG_MMC_PASSWORDS
+ if (mmc_card_lockable(card)) {
+ ret = device_create_file(&card->dev, &mmc_dev_attr_lockable);
+ if (ret)
+ device_del(&card->dev);
+ }
+#endif
}
return ret;
}
@@ -248,7 +308,10 @@ void mmc_remove_card(struct mmc_card *ca
if (mmc_card_present(card)) {
if (mmc_card_sd(card))
device_remove_file(&card->dev, &mmc_dev_attr_scr);
-
+#ifdef CONFIG_MMC_PASSWORDS
+ if (mmc_card_lockable(card))
+ device_remove_file(&card->dev, &mmc_dev_attr_lockable);
+#endif
device_del(&card->dev);
}
--
Anderson Lizardo
Embedded Linux Lab - 10LE
Nokia Institute of Technology - INdT
Manaus - Brazil
^ permalink raw reply [flat|nested] 8+ messages in thread
* [patch 5/5] Add MMC password protection (lock/unlock) support V2
2005-12-28 18:40 [patch 0/5] Add MMC password protection (lock/unlock) support V2 Anderson Lizardo
` (3 preceding siblings ...)
2005-12-28 18:40 ` [patch 4/5] " Anderson Lizardo
@ 2005-12-28 18:40 ` Anderson Lizardo
4 siblings, 0 replies; 8+ messages in thread
From: Anderson Lizardo @ 2005-12-28 18:40 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel
Cc: Russell King - ARM Linux, David Brownell, Tony Lindgren,
Anderson Briglia, Anderson Lizardo, Carlos Eduardo Aguiar
[-- Attachment #1: mmc_omap_blklen.diff --]
[-- Type: text/plain, Size: 1301 bytes --]
The MMC_LOCK_UNLOCK command requires the block length to be exactly the
password length + 2 bytes, but hardware-specific drivers force a "power of 2"
block size.
This patch sends the exact block size (password + 2 bytes) to the host. OMAP
specific.
Signed-off-by: Anderson Briglia <anderson.briglia@indt.org.br>
Signed-off-by: Anderson Lizardo <anderson.lizardo@indt.org.br>
Signed-off-by: Carlos Eduardo Aguiar <carlos.aguiar@indt.org.br>
Index: linux-2.6.15-rc4-omap1/drivers/mmc/omap.c
===================================================================
--- linux-2.6.15-rc4-omap1.orig/drivers/mmc/omap.c 2005-12-28 14:30:06.000000000 -0400
+++ linux-2.6.15-rc4-omap1/drivers/mmc/omap.c 2005-12-28 14:31:42.000000000 -0400
@@ -889,8 +889,12 @@ mmc_omap_prepare_data(struct mmc_omap_ho
return;
}
-
- block_size = 1 << data->blksz_bits;
+ /* password protection: we need to send the exact block size to the
+ * card (password + 2), not a power of two */
+ if (req->cmd->opcode == MMC_LOCK_UNLOCK)
+ block_size = data->sg[0].length;
+ else
+ block_size = 1 << data->blksz_bits;
OMAP_MMC_WRITE(host->base, NBLK, data->blocks - 1);
OMAP_MMC_WRITE(host->base, BLEN, block_size - 1);
--
Anderson Lizardo
Embedded Linux Lab - 10LE
Nokia Institute of Technology - INdT
Manaus - Brazil
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [patch 4/5] Add MMC password protection (lock/unlock) support V2
2005-12-28 18:40 ` [patch 4/5] " Anderson Lizardo
@ 2005-12-28 21:23 ` Arnd Bergmann
0 siblings, 0 replies; 8+ messages in thread
From: Arnd Bergmann @ 2005-12-28 21:23 UTC (permalink / raw)
To: Anderson Lizardo, linux-ide
Cc: linux-kernel, linux-arm-kernel, Russell King - ARM Linux,
David Brownell, Tony Lindgren, Anderson Briglia,
Carlos Eduardo Aguiar
On Wednesday 28 December 2005 18:40, Anderson Lizardo wrote:
>
> Implement MMC password reset and forced erase support. It uses the sysfs
> mechanism to send commands to the MMC subsystem. Usage:
>
> Forced erase:
>
> echo erase > /sys/bus/mmc/devices/mmc0\:0001/lockable
>
> Remove password:
>
> echo remove > /sys/bus/mmc/devices/mmc0\:0001/lockable
The MMC password support seems to be a subset of the operations
possible on modern ATA drives. IMHO, any interface you introduce
should be usable for both types of devices.
The only interface I could find for ATA is through HDIO_DRIVE_CMD.
This is currently used by hdparm, but it does not look like it
fits the MMC problem well.
Has anyone already done an ioctl or sysfs implementation of ATA
password user interfaces, or is perhaps the one proposed here
sufficient for ATA drives as well?
Arnd <><
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [patch 3/5] Add MMC password protection (lock/unlock) support V2
2005-12-28 18:40 ` [patch 3/5] " Anderson Lizardo
@ 2005-12-29 9:07 ` Chris White
0 siblings, 0 replies; 8+ messages in thread
From: Chris White @ 2005-12-29 9:07 UTC (permalink / raw)
To: Anderson Lizardo
Cc: linux-kernel, linux-arm-kernel, Russell King - ARM Linux,
David Brownell, Tony Lindgren, Anderson Briglia,
Carlos Eduardo Aguiar
[-- Attachment #1: Type: text/plain, Size: 3606 bytes --]
On Thursday 29 December 2005 03:40, Anderson Lizardo wrote:
Something that sort of caught my eye while looking at this (I generally don't
post here so I'm bitting the bullet and hoping I don't screw up), it seems
that this is an experimental driver, but doesn't contain any sort of uniquely
seperated verbose debug information. Let me try and narrow that down:
> +int mmc_key_instantiate(struct key *key, const void *data, size_t datalen)
> +{
> + struct mmc_key_payload *mpayload;
> + struct device *dev;
> + struct mmc_card *card;
> + int ret;
> +
> + ret = -EINVAL;
> + if (datalen <= 0 || datalen > MMC_KEYLEN_MAXBYTES || !data)
> + goto error;
Right here something about the data being passed to the function is invalid.
> + ret = key_payload_reserve(key, datalen);
> + if (ret < 0)
> + goto error;
> +
> + ret = -ENOMEM;
> + mpayload = kmalloc(sizeof(*mpayload) + datalen, GFP_KERNEL);
> + if (!mpayload)
> + goto error;
Unable to allocate mpayload structure, or something of the like.
> + /* attach the data */
> + mpayload->datalen = datalen;
> + memcpy(mpayload->data, data, datalen);
> + rcu_assign_pointer(key->payload.data, mpayload);
> +
> + ret = -EINVAL;
> + dev = bus_find_device(&mmc_bus_type, NULL, NULL, mmc_match_lockable);
> + if (!dev)
> + goto error;
Unable to locate device.
> + card = dev_to_mmc_card(dev);
> + if (mmc_card_locked(card)) {
> + ret = mmc_lock_unlock(card, key, MMC_LOCK_MODE_UNLOCK);
> + mmc_remove_card(card);
> + mmc_register_card(card);
> + } else
> + ret = mmc_lock_unlock(card, key, MMC_LOCK_MODE_SET_PWD);
> + if (ret)
> + ret = -EKEYREJECTED;
Key was rejected, though I suppose EKEYREJECTED pretty much states that.
[snip snip]
> +
> +/*
> + * update a mmc key
> + * - the key's semaphore is write-locked
> + */
> +int mmc_key_update(struct key *key, const void *data, size_t datalen)
> +{
> + struct mmc_key_payload *mpayload, *zap;
> + struct device *dev;
> + struct mmc_card *card;
> + int ret;
> +
> + ret = -EINVAL;
> + if (datalen <= 0 || datalen > MMC_KEYLEN_MAXBYTES || !data)
> + goto error;
See above about invalid data
> + /* construct a replacement payload */
> + ret = -ENOMEM;
> + mpayload = kmalloc(sizeof(*mpayload) + datalen, GFP_KERNEL);
> + if (!mpayload)
> + goto error;
This code almost seemed similiar to mmc_key_instantiate.. I almost wonder if
the code could be consolidated into a single function with some sort of
update conditional code. With that the debug information wouldn't be
duplicated. so snip
> +#ifdef CONFIG_MMC_PASSWORDS
> + else {
> + ret = register_key_type(&mmc_key_type);
> + if (ret) {
Something about the registration failing.
> + class_unregister(&mmc_host_class);
> + bus_unregister(&mmc_bus_type);
> + }
> + }
> +#endif
> }
> return ret;
> }
> @@ -345,6 +501,9 @@ static void __exit mmc_exit(void)
> {
> class_unregister(&mmc_host_class);
> bus_unregister(&mmc_bus_type);
> +#ifdef CONFIG_MMC_PASSWORDS
> + unregister_key_type(&mmc_key_type);
> +#endif
> }
>
> module_init(mmc_init);
That was mainly it. The verbose debug information is more of a "this would be
nice" sort of thing. Just from a user's perspective of debuggin experimental
drivers, this sort of thing is always nice. The code duplication in
mmc_key_instantiate/update still catches my eye though, there may be a
functional code flow to this that I'm not aware of, so again I bite the
bullet. Best hope that I don't make a fool of myself :).
Chris White
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2005-12-29 9:06 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-12-28 18:40 [patch 0/5] Add MMC password protection (lock/unlock) support V2 Anderson Lizardo
2005-12-28 18:40 ` [patch 1/5] " Anderson Lizardo
2005-12-28 18:40 ` [patch 2/5] " Anderson Lizardo
2005-12-28 18:40 ` [patch 3/5] " Anderson Lizardo
2005-12-29 9:07 ` Chris White
2005-12-28 18:40 ` [patch 4/5] " Anderson Lizardo
2005-12-28 21:23 ` Arnd Bergmann
2005-12-28 18:40 ` [patch 5/5] " Anderson Lizardo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Powered by JetHome