From: Al Cooper <acooper@xxxxxxxxxxxx> 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. refs #SWLINUX-2545 Signed-off-by: Al Cooper <acooper@xxxxxxxxxxxx> --- drivers/mmc/core/Kconfig | 8 +++++ drivers/mmc/core/core.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/mmc/core/core.h | 16 ++++++++- 3 files changed, 109 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig index 269d072..b0ba79d 100644 --- a/drivers/mmc/core/Kconfig +++ b/drivers/mmc/core/Kconfig @@ -26,3 +26,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 49a5bca..510927f 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -27,6 +27,7 @@ #include <linux/fault-inject.h> #include <linux/random.h> #include <linux/slab.h> +#include <linux/key-type.h> #include <linux/mmc/card.h> #include <linux/mmc/host.h> @@ -2705,6 +2706,78 @@ void mmc_init_context_info(struct mmc_host *host) init_waitqueue_head(&host->context_info.wait); } +#ifdef CONFIG_MMC_LOCK + +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(&mmc_key_type, 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 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; +} + +static int mmc_key_match(const struct key *key, const void *description) +{ + pr_debug("mmc_key_match: %s, %s\n", + key->description, (char *)description); + return strcmp(key->description, description) == 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 mmc_key_type = { + .name = "mmc", + .instantiate = mmc_key_instantiate, + .match = mmc_key_match, + .destroy = mmc_key_destroy, +}; +#endif /* CONFIG_MMC_LOCK */ + static int __init mmc_init(void) { int ret; @@ -2725,8 +2798,18 @@ static int __init mmc_init(void) if (ret) goto unregister_host_class; +#ifdef CONFIG_MMC_LOCK + ret = register_key_type(&mmc_key_type); + if (ret) + goto unregister_sdio_bus; +#endif /* CONFIG_MMC_LOCK */ + return 0; +#ifdef CONFIG_MMC_LOCK +unregister_sdio_bus: + sdio_unregister_bus(); +#endif /* CONFIG_MMC_LOCK */ unregister_host_class: mmc_unregister_host_class(); unregister_bus: @@ -2739,6 +2822,9 @@ destroy_workqueue: static void __exit mmc_exit(void) { +#ifdef CONFIG_MMC_LOCK + unregister_key_type(&mmc_key_type); +#endif /* CONFIG_MMC_LOCK */ 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 5345d15..dcf516d 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -81,5 +81,19 @@ void mmc_add_card_debugfs(struct mmc_card *card); void mmc_remove_card_debugfs(struct mmc_card *card); void mmc_init_context_info(struct mmc_host *host); -#endif +/* Lock/Unlock functionality */ +int mmc_unlock_card(struct mmc_card *card); + +#ifdef CONFIG_MMC_LOCK +#define MMC_PASSWORD_MAX 16 +struct mmc_password { + char password[MMC_PASSWORD_MAX]; + int length; +}; +extern struct key_type mmc_key_type; + +int mmc_get_password(struct mmc_card *card, struct mmc_password *password); +#endif /* CONFIG_MMC_LOCK */ + +#endif -- 1.8.1.3 -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html