mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Lorenz Kofler <lorenz@sigma-star.at>
To: Mikulas Patocka <mpatocka@redhat.com>
Cc: Mike Snitzer <snitzer@kernel.org>,
	Benjamin Marzinski <bmarzins@redhat.com>,
	Alasdair Kergon <agk@redhat.com>,
	dm-devel@lists.linux.dev, linux-kernel@vger.kernel.org,
	upstream+dm@sigma-star.at
Subject: Re: [RFC PATCH 1/1] dm-integrity: support keys in the kernel keyring
Date: Fri, 2 Oct 2026 11:12:27 +0200	[thread overview]
Message-ID: <b0f8f47a-beb0-426e-bdee-5d0d80ade8ad@sigma-star.at> (raw)
In-Reply-To: <6e7bd72b-6f1a-211d-16a8-a35a530af408@redhat.com>

Hi Mikulas,

thank you for the review!

Some notes below.

On 9/30/26 5:00 PM, Mikulas Patocka wrote:
> Hi
> 
> Generally, the approach in this patch is OK.
> 
> Here I have some comments for the patch:
> 
> Mikulas
> 
> 
> 
> The patch should increase target version - from "{1, 15, 0}" to "{1, 16,
> 0}".
> 
> 
> On Mon, 28 Sep 2026, Lorenz Kofler wrote:
> 
>> The keys of internal_hash, journal_crypt and journal_mac can only be
>> given as hex strings in the table. Keys that never leave the kernel,
>> such as trusted keys, cannot be used.
>>
>> In addition to hex strings, accept keys from the kernel keyring in the
>> same format as dm-crypt: ":<key_size>:<key_type>:<key_description>".
>> The lookup is the same as in dm-crypt.
>>
>> Like DM_CRYPT, DM_INTEGRITY must not be built in when the encrypted or
>> trusted key types are modules.
>>
>> Signed-off-by: Lorenz Kofler <lorenz@sigma-star.at>
>> ---
>>   .../device-mapper/dm-integrity.rst            |  25 +++
>>   drivers/md/Kconfig                            |   2 +
>>   drivers/md/dm-integrity.c                     | 164 ++++++++++++++++++
>>   3 files changed, 191 insertions(+)
>>
>> diff --git a/Documentation/admin-guide/device-mapper/dm-integrity.rst b/Documentation/admin-guide/device-mapper/dm-integrity.rst
>> index 9c21301423c9..2b7f82912962 100644
>> --- a/Documentation/admin-guide/device-mapper/dm-integrity.rst
>> +++ b/Documentation/admin-guide/device-mapper/dm-integrity.rst
>> @@ -146,6 +146,8 @@ internal_hash:algorithm(:key)	(the key is optional)
>>   	from an upper layer target, such as dm-crypt. The upper layer
>>   	target should check the validity of the integrity tags.
>>   
>> +	The format of the key is described below the list of arguments.
>> +
>>   recalculate
>>   	Recalculate the integrity tags automatically. It is only valid
>>   	when using internal hash.
>> @@ -162,6 +164,8 @@ journal_crypt:algorithm(:key)	(the key is optional)
>>   	the size of files that were written. To protect against this
>>   	situation, you can encrypt the journal.
>>   
>> +	The format of the key is described below the list of arguments.
>> +
>>   journal_mac:algorithm(:key)	(the key is optional)
>>   	Protect sector numbers in the journal from accidental or malicious
>>   	modification. To protect against accidental modification, use a
>> @@ -173,6 +177,8 @@ journal_mac:algorithm(:key)	(the key is optional)
>>   	the journal. Thus, modified sector number would be detected at
>>   	this stage.
>>   
>> +	The format of the key is described below the list of arguments.
>> +
>>   block_size:number (default 512)
>>   	The size of a data block in bytes. The larger the block size the
>>   	less overhead there is for per-block integrity metadata.
>> @@ -225,6 +231,25 @@ legacy_recalculate
>>   	set recalc_sector to zero, and the kernel would not detect the
>>   	modification.
>>   
>> +The key of internal_hash, journal_crypt and journal_mac is encoded either as
>> +a hexadecimal number or it can be passed as <key_string> prefixed with single
>> +colon character (':') for keys residing in kernel keyring service.
> 
> The documentation omits the fact that you need double colon "::" - one
> colon to end the argument name and one colon as the key prefix.
> 
>> +
>> +<key_string>
>> +	The kernel keyring key is identified by string in following format:
>> +	<key_size>:<key_type>:<key_description>.
>> +
>> +<key_size>
>> +	The key size in bytes. The kernel key payload size must match
>> +	the value passed in <key_size>.
>> +
>> +<key_type>
>> +	Either 'logon', 'user', 'encrypted' or 'trusted' kernel key type.
>> +
>> +<key_description>
>> +	The kernel keyring key description integrity target should look for
>> +	when loading key of <key_type>.
>> +
>>   The journal mode (D/J), buffer_sectors, journal_watermark, commit_time and
>>   allow_discards can be changed when reloading the target (load an inactive
>>   table and swap the tables with suspend and resume). The other arguments
>> diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
>> index df27c7d066d2..e93bf0c3119d 100644
>> --- a/drivers/md/Kconfig
>> +++ b/drivers/md/Kconfig
>> @@ -653,6 +653,8 @@ config DM_LOG_WRITES
>>   config DM_INTEGRITY
>>   	tristate "Integrity target support"
>>   	depends on BLK_DEV_DM
>> +	depends on (ENCRYPTED_KEYS || ENCRYPTED_KEYS=n)
>> +	depends on (TRUSTED_KEYS || TRUSTED_KEYS=n)
>>   	select BLK_DEV_INTEGRITY
>>   	select DM_BUFIO
>>   	select CRYPTO
>> diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c
>> index 92970e12267a..6995c870cbf5 100644
>> --- a/drivers/md/dm-integrity.c
>> +++ b/drivers/md/dm-integrity.c
>> @@ -25,6 +25,11 @@
>>   #include <crypto/utils.h>
>>   #include <linux/async_tx.h>
>>   #include <linux/dm-bufio.h>
>> +#include <linux/ctype.h>
>> +#include <linux/key.h>
>> +#include <keys/user-type.h>
>> +#include <keys/encrypted-type.h>
>> +#include <keys/trusted-type.h>
>>   
>>   #include "dm-audit.h"
>>   
>> @@ -4415,6 +4420,152 @@ static void free_alg(struct alg_spec *a)
>>   	memset(a, 0, sizeof(*a));
>>   }
>>   
>> +#ifdef CONFIG_KEYS
>> +
>> +static bool contains_whitespace(const char *str)
>> +{
>> +	while (*str)
>> +		if (isspace(*str++))
>> +			return true;
>> +	return false;
>> +}
>> +
>> +static int set_key_user(struct alg_spec *a, struct key *key)
>> +{
>> +	const struct user_key_payload *ukp;
>> +
>> +	ukp = user_key_payload_locked(key);
>> +	if (!ukp)
>> +		return -EKEYREVOKED;
>> +
>> +	if (a->key_size != ukp->datalen)
>> +		return -EINVAL;
>> +
>> +	memcpy(a->key, ukp->data, a->key_size);
>> +
>> +	return 0;
>> +}
>> +
>> +static int set_key_encrypted(struct alg_spec *a, struct key *key)
>> +{
>> +	const struct encrypted_key_payload *ekp;
>> +
>> +	ekp = key->payload.data[0];
>> +	if (!ekp)
>> +		return -EKEYREVOKED;
>> +
>> +	if (a->key_size != ekp->decrypted_datalen)
>> +		return -EINVAL;
>> +
>> +	memcpy(a->key, ekp->decrypted_data, a->key_size);
>> +
>> +	return 0;
>> +}
>> +
>> +static int set_key_trusted(struct alg_spec *a, struct key *key)
>> +{
>> +	const struct trusted_key_payload *tkp;
>> +
>> +	tkp = key->payload.data[0];
>> +	if (!tkp)
>> +		return -EKEYREVOKED;
>> +
>> +	if (a->key_size != tkp->key_len)
>> +		return -EINVAL;
>> +
>> +	memcpy(a->key, tkp->key, a->key_size);
>> +
>> +	return 0;
>> +}
> 
> These four functions are copied from dm-crypt.c and dm-inlinecrypt.c.
> Copying code is generally malpattern, they should be unified and moved to
> an include file (that would be included in all three targets) or to the
> key management code (that would be called from all three targets).
> 

Yes that is the issue I described in the cover letters. But I don't
actually know which way is the preferred one. Afaik there are now
three options:

1. static inline helpers in a drivers/md header, so dm-crypt and
    dm-integrity each compile their own copy
2. a small library module, similar to dm-bufio, so there is one copy
    that follows the value (y/m) of dm-crypt and dm-integrity
3. integration into key management code

Please tell me which option you prefer.

>> +/*
>> + * Load the key from the kernel keyring. a->key_string has the format
>> + * ":<key_size>:<key_type>:<key_description>".
>> + */
>> +static int get_alg_key_from_keyring(struct alg_spec *a)
>> +{
>> +	int (*set_key)(struct alg_spec *a, struct key *key);
>> +	const char *key_type_desc, *key_desc;
>> +	struct key_type *type;
>> +	unsigned int key_size;
>> +	struct key *key;
>> +	char dummy;
>> +	int r;
>> +
>> +	/*
>> +	 * Reject key_string with whitespace. dm core currently lacks code for
>> +	 * proper whitespace escaping in arguments on DM_TABLE_STATUS path.
>> +	 */
>> +	if (contains_whitespace(a->key_string))
>> +		return -EINVAL;
>> +
>> +	if (sscanf(a->key_string, ":%u%c", &key_size, &dummy) != 2 || dummy != ':')
>> +		return -EINVAL;
>> +	if (!key_size || key_size > KMALLOC_MAX_SIZE)
>> +		return -EINVAL;
> 
> KMALLOC_MAX_SIZE allocations are unreliable, they may fail randomly
> anytime.
> 
> You should use "PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER" as the limit (I
> assume that this is enough for the key) - this is the reliability
> threshold for kmalloc.
> 
> If you really need larger allocation, you should use vmalloc or kvmalloc.
> 
>> +	/* skip ":<key_size>:", the sscanf() above guarantees the second ':' */
>> +	key_type_desc = strchr(a->key_string + 1, ':') + 1;
>> +
>> +	/* look for next ':' separating key_type from key_description */
>> +	key_desc = strchr(key_type_desc, ':');
>> +	if (!key_desc || key_desc == key_type_desc || !strlen(key_desc + 1))
>> +		return -EINVAL;
>> +
>> +	if (!strncmp(key_type_desc, "logon:", key_desc - key_type_desc + 1)) {
>> +		type = &key_type_logon;
>> +		set_key = set_key_user;
>> +	} else if (!strncmp(key_type_desc, "user:", key_desc - key_type_desc + 1)) {
>> +		type = &key_type_user;
>> +		set_key = set_key_user;
>> +	} else if (IS_ENABLED(CONFIG_ENCRYPTED_KEYS) &&
>> +		   !strncmp(key_type_desc, "encrypted:", key_desc - key_type_desc + 1)) {
>> +		type = &key_type_encrypted;
>> +		set_key = set_key_encrypted;
>> +	} else if (IS_ENABLED(CONFIG_TRUSTED_KEYS) &&
>> +		   !strncmp(key_type_desc, "trusted:", key_desc - key_type_desc + 1)) {
>> +		type = &key_type_trusted;
>> +		set_key = set_key_trusted;
>> +	} else {
>> +		return -EINVAL;
>> +	}
>> +
>> +	a->key = kmalloc(key_size, GFP_KERNEL);
>> +	if (!a->key)
>> +		return -ENOMEM;
>> +	a->key_size = key_size;
>> +
>> +	key = request_key(type, key_desc + 1, NULL);
>> +	if (IS_ERR(key)) {
>> +		r = PTR_ERR(key);
>> +		goto free_key;
>> +	}
>> +
>> +	down_read(&key->sem);
>> +	r = set_key(a, key);
>> +	up_read(&key->sem);
>> +	key_put(key);
>> +	if (r < 0)
>> +		goto free_key;
>> +
>> +	return 0;
>> +
>> +free_key:
>> +	kfree_sensitive(a->key);
>> +	a->key = NULL;
>> +	a->key_size = 0;
>> +	return r;
>> +}
>> +
>> +#else
>> +
>> +static int get_alg_key_from_keyring(struct alg_spec *a)
>> +{
>> +	return -EINVAL;
>> +}
>> +
>> +#endif /* CONFIG_KEYS */
>> +
>>   static int get_alg_and_key(const char *arg, struct alg_spec *a, char **error, char *error_inval)
>>   {
>>   	char *k;
>> @@ -4429,6 +4580,19 @@ static int get_alg_and_key(const char *arg, struct alg_spec *a, char **error, ch
>>   	if (k) {
>>   		*k = 0;
>>   		a->key_string = k + 1;
>> +
>> +		if (a->key_string[0] == ':') {
>> +			int r = get_alg_key_from_keyring(a);
>> +
>> +			if (r == -ENOMEM)
>> +				goto nomem;
>> +			if (r == -EINVAL)
>> +				goto inval;
>> +			if (r)
>> +				*error = "Cannot get key from the kernel keyring";
>> +			return r;
>> +		}
>> +
>>   		if (strlen(a->key_string) & 1)
>>   			goto inval;
>>   
>> -- 
>> 2.55.0
>>
> 

-- 
sigma star gmbh | Eduard-Bodem-Gasse 6, 6020 Innsbruck, Austria
UID/VAT Nr: ATU 66964118 | FN: 374287y


  reply	other threads:[~2026-10-02  9:12 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-28  6:27 [RFC PATCH 0/1] " Lorenz Kofler
2026-09-28  6:27 ` [RFC PATCH 1/1] " Lorenz Kofler
2026-09-30 15:00   ` Mikulas Patocka
2026-10-02  9:12     ` Lorenz Kofler [this message]
2026-10-02 11:48       ` Mikulas Patocka
2026-10-02 20:14         ` Eric Biggers
2026-10-02 21:09           ` Mikulas Patocka
2026-10-04  7:44           ` Milan Broz
2026-10-04 17:29             ` Eric Biggers
2026-10-05  6:20               ` Milan Broz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=b0f8f47a-beb0-426e-bdee-5d0d80ade8ad@sigma-star.at \
    --to=lorenz@sigma-star.at \
    --cc=agk@redhat.com \
    --cc=bmarzins@redhat.com \
    --cc=dm-devel@lists.linux.dev \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mpatocka@redhat.com \
    --cc=snitzer@kernel.org \
    --cc=upstream+dm@sigma-star.at \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®