Re: [PATCH] crypto: xxhash - Implement xxhash support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On 27.05.19 г. 21:39 ч., Eric Biggers wrote:
> Hi Nikolay,
> 
> On Mon, May 27, 2019 at 05:28:10PM +0300, Nikolay Borisov wrote:
>> xxhash is currently implemented as a self-contained module in /lib.
>> This patch enables that module to be used as part of the generic kernel
>> crypto framework. It adds a simple wrapper to the 64bit version. I've
>> also added a couple of simplistic test vectors to ensure I haven't
>> screwed up anything doing the plumbing.
> 
> What is this planned to be used for?

Possibly as a replacement hash of crc32c in btrfs.

> 
> Please also run the crypto self-tests (i.e. boot a kernel with
> CONFIG_CRYPTO_MANAGER_DISABLE_TESTS unset) for all crypto API patches.
> When that's done this code immediately crashes, see output below.

Not for me, I tested the vectors I've added for correct results. I
wouldn't have sent the patch otherwise. Strange why I didn't observe
this crash, I wonder if it's due to an unaligned buffer or digest not
initialising the state.

> 
> More comments below.
> 
> 	[    0.305235] BUG: unable to handle page fault for address: ffff88817c1966fe
> 	[    0.306613] #PF: supervisor write access in kernel mode
> 	[    0.307653] #PF: error_code(0x0002) - not-present page
> 	[    0.308503] PGD 2a01067 P4D 2a01067 PUD 0 
> 	[    0.308503] Oops: 0002 [#1] SMP
> 	[    0.308503] CPU: 3 PID: 59 Comm: cryptomgr_test Not tainted 5.2.0-rc2-00001-g4fcf4df09e23d #3
> 	[    0.308503] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-20181126_142135-anatol 04/01/2014
> 	[    0.308503] RIP: 0010:__memcpy+0x12/0x20
> 	[    0.308503] Code: 8b 43 60 48 2b 43 50 88 43 4e 5b 5d c3 c3 90 90 90 90 90 90 90 90 90 90 0f 1f 44 00 00 48 89 f8 48 89 d1 48 c1 e9 4
> 	[    0.308503] RSP: 0018:ffffc900006b7ab0 EFLAGS: 00010202
> 	[    0.308503] RAX: ffff88817c1966fe RBX: ffff88807d1a67d8 RCX: 0000000000202024
> 	[    0.308503] RDX: 0000000000000002 RSI: ffff88807c996000 RDI: ffff88817c1966fe
> 	[    0.308503] RBP: ffffc900006b7ad8 R08: ffffffff81c81bf0 R09: 0000000000000000
> 	[    0.308503] R10: ffff88807c996000 R11: ffffffff81a33fb0 R12: 0000000000000007
> 	[    0.308503] R13: ffff88807c996000 R14: 0000000000000020 R15: ffffffff81a373c8
> 	[    0.308503] FS:  0000000000000000(0000) GS:ffff88807fd80000(0000) knlGS:0000000000000000
> 	[    0.308503] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> 	[    0.308503] CR2: ffff88817c1966fe CR3: 0000000001c0f000 CR4: 00000000003406e0
> 	[    0.308503] Call Trace:
> 	[    0.308503]  ? xxh64_update+0x51/0x1e0
> 	[    0.308503]  xxhash64_finup+0x18/0x30
> 	[    0.308503]  xxhash64_digest+0x9/0x10
> 	[    0.308503]  crypto_shash_digest+0x24/0x40
> 	[    0.308503]  shash_ahash_digest+0x9a/0xf0
> 	[    0.308503]  ? shash_ahash_digest+0xf0/0xf0
> 	[    0.308503]  shash_async_digest+0x19/0x20
> 	[    0.308503]  crypto_ahash_op+0x24/0x60
> 	[    0.308503]  crypto_ahash_digest+0x16/0x20
> 	[    0.308503]  do_ahash_op.constprop.12+0x10/0x40
> 	[    0.308503]  test_hash_vec_cfg+0x205/0x610
> 	[    0.308503]  ? _raw_spin_unlock+0x11/0x30
> 	[    0.308503]  ? sprintf+0x56/0x70
> 	[    0.308503]  __alg_test_hash.isra.8+0x115/0x1d0
> 	[    0.308503]  alg_test_hash+0x7b/0x100
> 	[    0.308503]  alg_test+0xb6/0x375
> 	[    0.308503]  ? __kthread_parkme+0x5c/0x90
> 	[    0.308503]  ? lockdep_hardirqs_on+0xf6/0x190
> 	[    0.308503]  ? _raw_spin_unlock_irqrestore+0x44/0x50
> 	[    0.308503]  ? trace_hardirqs_on+0x22/0xf0
> 	[    0.308503]  ? __kthread_parkme+0x2a/0x90
> 	[    0.308503]  cryptomgr_test+0x26/0x40
> 	[    0.308503]  kthread+0x124/0x140
> 	[    0.308503]  ? cryptomgr_probe+0xd0/0xd0
> 	[    0.308503]  ? __kthread_create_on_node+0x1c0/0x1c0
> 	[    0.308503]  ret_from_fork+0x24/0x30
> 	[    0.308503] CR2: ffff88817c1966fe
> 	[    0.308503] ---[ end trace 3ee93ad10b0b79d0 ]---
> 
>> diff --git a/crypto/xxhash_generic.c b/crypto/xxhash_generic.c
>> new file mode 100644
>> index 000000000000..aedaabe55d45
>> --- /dev/null
>> +++ b/crypto/xxhash_generic.c
>> @@ -0,0 +1,112 @@
>> +#include <crypto/internal/hash.h>
>> +#include <linux/init.h>
>> +#include <linux/module.h>
>> +#include <linux/xxhash.h>
>> +
>> +#define XXHASH_BLOCK_SIZE	1
> 
> This should be set to 32 bytes (the "stripe size" of xxhash64), to match the
> size of the chunks in which the algorithm processes data.  I.e., if you pass 31
> bytes to xxhash64 it just buffers them, without doing any real work yet.
> 
> A "block size" of 1 is only appropriate for algorithms like CRC whose simplest
> mathematical description operates directly on bytes.
> 
>> +#define XXHASH64_DIGEST_SIZE	8
>> +
>> +struct xxhash64_crypto_ctx {
>> +	u64 seed;
>> +};
> 
> To make it clearer what kind of "context" this is, please name this
> "xxhash64_tfm_ctx", not "xxhash64_crypto_ctx".
> 
> Similarly, name the variables "tctx" instead of "cctx".

ACK

> 
>> +
>> +struct xxhash64_desc_ctx {
>> +	struct xxh64_state xxhstate;
>> +	u64 seed;
>> +};
>> +
>> +static int xxhash64_init(struct shash_desc *desc)
>> +{
>> +	struct xxhash64_crypto_ctx *cctx = crypto_shash_ctx(desc->tfm);
>> +	struct xxhash64_desc_ctx *dctx = shash_desc_ctx(desc);
>> +
>> +	dctx->seed = cctx->seed;
>> +	xxh64_reset(&dctx->xxhstate, dctx->seed);
>> +
>> +	return 0;
>> +}
> 
> What's the point of storing 'seed' in the desc_ctx, given that it's already
> represented in the initialized 'xxhstate'?

Good point will remove seed in next iteration.

> 
>> +
>> +static int xxhash64_setkey(struct crypto_shash *tfm, const u8 *key,
>> +			 unsigned int keylen)
>> +{
>> +	struct xxhash64_crypto_ctx *ctx = crypto_shash_ctx(tfm);
>> +
>> +	if (keylen != sizeof(ctx->seed)) {
>> +		crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
>> +		return -EINVAL;
>> +	}
>> +	ctx->seed = *(u64 *)key;
>> +	return 0;
>> +}
> 
> The crypto API takes the "key" as a byte array which might be unaligned.  Also,
> the sequence of "key" bytes is conventionally interpreted the same way on all
> architectures, e.g. it's not endian-dependent.  So, I suggest:
> 
> 	ctx->seed = get_unaligned_le64(key);

Can it actually be unaligned though, looking at
crypto_shash_setkey->shash_setkey_unaligned it seems that the generic
layer aligns the buffer and passes the aligned one to ->setkey.
> 
> Note that without this fix, your test vectors are wrong on big endian CPUs.
> 
>> +
>> +static int xxhash64_update(struct shash_desc *desc, const u8 *data,
>> +			 unsigned int length)
>> +{
>> +	struct xxhash64_desc_ctx *ctx = shash_desc_ctx(desc);
>> +
>> +	xxh64_update(&ctx->xxhstate, data, length);
>> +
>> +	return 0;
>> +}
>> +
>> +static int xxhash64_final(struct shash_desc *desc, u8 *out)
>> +{
>> +	struct xxhash64_desc_ctx *ctx = shash_desc_ctx(desc);
>> +
>> +	*(u64 *)out = xxh64_digest(&ctx->xxhstate);
>> +
>> +	return 0;
>> +}
> 
> Similarly, the 'out' array might be misaligned.  And conventionally the same
> bytes are output on all architectures.  So I suggest:
> 
> 	put_unaligned_u64(xxh64_digest(&ctx->xxhstate), out);

Fair enough, will fix it in next version.

> 
>> +
>> +static int xxhash64_finup(struct shash_desc *desc, const u8 *data,
>> +			unsigned int len, u8 *out)
>> +{
>> +	xxhash64_update(desc, data, len);
>> +	xxhash64_final(desc, out);
>> +
>> +	return 0;
>> +}
>> +
>> +static int xxhash64_digest(struct shash_desc *desc, const u8 *data,
>> +			 unsigned int length, u8 *out)
>> +{
>> +	return xxhash64_finup(desc, data, length, out);
>> +}
>> +
> 
> It seems that xxhash64_digest() is forgetting to initialize the hash state.
> 
>> +static struct shash_alg alg = {
>> +	.digestsize		=	XXHASH64_DIGEST_SIZE,
>> +	.setkey			= xxhash64_setkey,
> 
> Please use consistent indentation.

This was copy/pasted from crc32c struct but yeah, I admit it looks ugly,
will fix.

> 
>> +	.init		=	xxhash64_init,
>> +	.update		=	xxhash64_update,
>> +	.final		=	xxhash64_final,
>> +	.finup		=	xxhash64_finup,
>> +	.digest		=	xxhash64_digest,
>> +	.descsize		=	sizeof(struct xxhash64_desc_ctx),
>> +	.base			=	{
>> +		.cra_name		=	"xxhash64",
>> +		.cra_driver_name	=	"xxhash64-generic",
>> +		.cra_priority		=	100,
>> +		.cra_flags		=	CRYPTO_ALG_OPTIONAL_KEY,
>> +		.cra_blocksize		=	XXHASH_BLOCK_SIZE,
>> +		.cra_ctxsize		=	sizeof(struct xxhash64_crypto_ctx),
>> +		.cra_module		=	THIS_MODULE,
>> +	}
>> +};
>> +
>> +static int __init xxhash_mod_init(void)
>> +{
>> +	return crypto_register_shash(&alg);
>> +}
>> +
>> +static void __exit xxhash_mod_fini(void)
>> +{
>> +	crypto_unregister_shash(&alg);
>> +}
>> +
>> +module_init(xxhash_mod_init);
>> +module_exit(xxhash_mod_fini);
>> +
>> +MODULE_AUTHOR("Nikolay Borisov <nborisov@xxxxxxxx>");
>> +MODULE_DESCRIPTION("xxhash  calculations wrapper for lib/xxhash.c");
>> +MODULE_LICENSE("GPL");
>> +MODULE_ALIAS_CRYPTO("xxhash-generic");
> 
> The purpose of MODULE_ALIAS_CRYPTO() is to allow the module to be dynamically
> loaded when someone requests the algorithm by name.  So, putting a string here
> which doesn't match the algorithm name is wrong.  It should be:
> 
> 	MODULE_ALIAS_CRYPTO("xxhash64");
> 	MODULE_ALIAS_CRYPTO("xxhash64-generic");
> 
> - Eric
> 



[Index of Archives]     [Kernel]     [Gnu Classpath]     [Gnu Crypto]     [DM Crypt]     [Netfilter]     [Bugtraq]

  Powered by Linux