From: Stafford Horne <shorne@gmail.com>
To: Mikulas Patocka <mpatocka@redhat.com>
Cc: Andy Shevchenko <andy@kernel.org>,
Mike Snitzer <msnitzer@redhat.com>,
Herbert Xu <herbert@gondor.apana.org.au>,
Linux Kernel Mailing List <linux-kernel@vger.kernel.org>,
Mimi Zohar <zohar@linux.ibm.com>,
Milan Broz <gmazyland@gmail.com>,
device-mapper development <dm-devel@redhat.com>,
Linux Crypto Mailing List <linux-crypto@vger.kernel.org>,
Jason@zx2c4.com, Linus Torvalds <torvalds@linux-foundation.org>,
"David S. Miller" <davem@davemloft.net>
Subject: Re: [dm-devel] [PATCH v2] hex2bin: make the function hex_to_bin constant-time
Date: Wed, 4 May 2022 17:38:28 +0900 [thread overview]
Message-ID: <YnI7hE4cIfjsdKSF@antec> (raw)
In-Reply-To: <alpine.LRH.2.02.2204250723120.26714@file01.intranet.prod.int.rdu2.redhat.com>
On Mon, Apr 25, 2022 at 08:07:48AM -0400, Mikulas Patocka wrote:
> From: Mikulas Patocka <mpatocka@redhat.com>
>
> The function hex2bin is used to load cryptographic keys into device mapper
> targets dm-crypt and dm-integrity. It should take constant time
> independent on the processed data, so that concurrently running
> unprivileged code can't infer any information about the keys via
> microarchitectural convert channels.
>
> This patch changes the function hex_to_bin so that it contains no branches
> and no memory accesses.
>
> Note that this shouldn't cause performance degradation because the size of
> the new function is the same as the size of the old function (on x86-64) -
> and the new function causes no branch misprediction penalties.
>
> I compile-tested this function with gcc on aarch64 alpha arm hppa hppa64
> i386 ia64 m68k mips32 mips64 powerpc powerpc64 riscv sh4 s390x sparc32
> sparc64 x86_64 and with clang on aarch64 arm hexagon i386 mips32 mips64
> powerpc powerpc64 s390x sparc32 sparc64 x86_64 to verify that there are no
> branches in the generated code.
>
> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
> Cc: stable@vger.kernel.org
>
> ---
> include/linux/kernel.h | 2 +-
> lib/hexdump.c | 32 +++++++++++++++++++++++++-------
> 2 files changed, 26 insertions(+), 8 deletions(-)
>
> Index: linux-2.6/lib/hexdump.c
> ===================================================================
> --- linux-2.6.orig/lib/hexdump.c 2022-04-24 18:51:20.000000000 +0200
> +++ linux-2.6/lib/hexdump.c 2022-04-25 13:15:26.000000000 +0200
> @@ -22,15 +22,33 @@ EXPORT_SYMBOL(hex_asc_upper);
> *
> * hex_to_bin() converts one hex digit to its actual value or -1 in case of bad
> * input.
> + *
> + * This function is used to load cryptographic keys, so it is coded in such a
> + * way that there are no conditions or memory accesses that depend on data.
> + *
> + * Explanation of the logic:
> + * (ch - '9' - 1) is negative if ch <= '9'
> + * ('0' - 1 - ch) is negative if ch >= '0'
> + * we "and" these two values, so the result is negative if ch is in the range
> + * '0' ... '9'
> + * we are only interested in the sign, so we do a shift ">> 8"; note that right
> + * shift of a negative value is implementation-defined, so we cast the
> + * value to (unsigned) before the shift --- we have 0xffffff if ch is in
> + * the range '0' ... '9', 0 otherwise
> + * we "and" this value with (ch - '0' + 1) --- we have a value 1 ... 10 if ch is
> + * in the range '0' ... '9', 0 otherwise
> + * we add this value to -1 --- we have a value 0 ... 9 if ch is in the range '0'
> + * ... '9', -1 otherwise
> + * the next line is similar to the previous one, but we need to decode both
> + * uppercase and lowercase letters, so we use (ch & 0xdf), which converts
> + * lowercase to uppercase
> */
> -int hex_to_bin(char ch)
> +int hex_to_bin(unsigned char ch)
> {
> - if ((ch >= '0') && (ch <= '9'))
> - return ch - '0';
> - ch = tolower(ch);
> - if ((ch >= 'a') && (ch <= 'f'))
> - return ch - 'a' + 10;
> - return -1;
> + unsigned char cu = ch & 0xdf;
> + return -1 +
> + ((ch - '0' + 1) & (unsigned)((ch - '9' - 1) & ('0' - 1 - ch)) >> 8) +
> + ((cu - 'A' + 11) & (unsigned)((cu - 'F' - 1) & ('A' - 1 - cu)) >> 8);
> }
> EXPORT_SYMBOL(hex_to_bin);
Hello,
Just a heads up it seems this patch is causing some instability with crypto self
tests on OpenRISC when using a PREEMPT kernel (no SMP).
This was reported by Jason A. Donenfeld as it came up in wireguard testing.
I am trying to figure out if this is an OpenRISC PREEMPT issue or something
else.
The warning I am seeing is a bit random but looks something like the
following:
[ 0.164000] Freeing initrd memory: 1696K
[ 0.188000] xor: measuring software checksum speed
[ 0.196000] 8regs : 1343 MB/sec
[ 0.204000] 8regs_prefetch : 1347 MB/sec
[ 0.212000] 32regs : 1335 MB/sec
[ 0.220000] 32regs_prefetch : 1277 MB/sec
[ 0.220000] xor: using function: 8regs_prefetch (1347 MB/sec)
[ 0.252000] SARU running 25519 tests
[ 0.424000] curve25519 self-test 5: FAIL
[ 0.496000] curve25519 self-test 7: FAIL
[ 1.744000] curve25519 self-test 45: FAIL
[ 3.448000] ------------[ cut here ]------------
[ 3.448000] WARNING: CPU: 0 PID: 1 at lib/crypto/curve25519.c:19 curve25519_init+0x38/0x50
[ 3.448000] CPU: 0 PID: 1 Comm: swapper Not tainted 5.18.0-rc4+ #758
[ 3.448000] Call trace:
[ 3.448000] [<(ptrval)>] ? __warn+0xe0/0x114
[ 3.448000] [<(ptrval)>] ? curve25519_init+0x38/0x50
[ 3.448000] [<(ptrval)>] ? warn_slowpath_fmt+0x5c/0x94
[ 3.448000] [<(ptrval)>] ? curve25519_init+0x0/0x50
[ 3.452000] [<(ptrval)>] ? curve25519_init+0x38/0x50
[ 3.452000] [<(ptrval)>] ? do_one_initcall+0x98/0x328
[ 3.452000] [<(ptrval)>] ? proc_register+0x4c/0x284
[ 3.452000] [<(ptrval)>] ? ignore_unknown_bootoption+0x0/0x8
[ 3.452000] [<(ptrval)>] ? kernel_init_freeable+0x1fc/0x2a8
[ 3.452000] [<(ptrval)>] ? ignore_unknown_bootoption+0x0/0x8
[ 3.452000] [<(ptrval)>] ? kernel_init+0x0/0x164
[ 3.452000] [<(ptrval)>] ? kernel_init+0x28/0x164
[ 3.452000] [<(ptrval)>] ? schedule_tail+0x18/0xac
[ 3.452000] [<(ptrval)>] ? ret_from_fork+0x1c/0x9c
[ 3.452000] ---[ end trace 0000000000000000 ]---
[ 3.452000] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
[ 3.464000] printk: console [ttyS0] disabled
[ 3.464000] 90000000.serial: ttyS0 at MMIO 0x90000000 (irq = 2, base_baud = 1250000) is a 16550A
Example config: https://xn--4db.cc/cCRlQ1AE
The self-test iteration number that fails is always a bit different. I am
still in progress of investigating this and will not have a lot of time new the
next few days. If anything ring's a bell let me know.
-Stafford
--
dm-devel mailing list
dm-devel@redhat.com
https://listman.redhat.com/mailman/listinfo/dm-devel
WARNING: multiple messages have this Message-ID (diff)
From: Stafford Horne <shorne@gmail.com>
To: Mikulas Patocka <mpatocka@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>,
Andy Shevchenko <andy@kernel.org>,
device-mapper development <dm-devel@redhat.com>,
Linux Kernel Mailing List <linux-kernel@vger.kernel.org>,
Linux Crypto Mailing List <linux-crypto@vger.kernel.org>,
Herbert Xu <herbert@gondor.apana.org.au>,
"David S. Miller" <davem@davemloft.net>,
Mike Snitzer <msnitzer@redhat.com>,
Mimi Zohar <zohar@linux.ibm.com>,
Milan Broz <gmazyland@gmail.com>,
Jason@zx2c4.com
Subject: Re: [PATCH v2] hex2bin: make the function hex_to_bin constant-time
Date: Wed, 4 May 2022 17:38:28 +0900 [thread overview]
Message-ID: <YnI7hE4cIfjsdKSF@antec> (raw)
In-Reply-To: <alpine.LRH.2.02.2204250723120.26714@file01.intranet.prod.int.rdu2.redhat.com>
On Mon, Apr 25, 2022 at 08:07:48AM -0400, Mikulas Patocka wrote:
> From: Mikulas Patocka <mpatocka@redhat.com>
>
> The function hex2bin is used to load cryptographic keys into device mapper
> targets dm-crypt and dm-integrity. It should take constant time
> independent on the processed data, so that concurrently running
> unprivileged code can't infer any information about the keys via
> microarchitectural convert channels.
>
> This patch changes the function hex_to_bin so that it contains no branches
> and no memory accesses.
>
> Note that this shouldn't cause performance degradation because the size of
> the new function is the same as the size of the old function (on x86-64) -
> and the new function causes no branch misprediction penalties.
>
> I compile-tested this function with gcc on aarch64 alpha arm hppa hppa64
> i386 ia64 m68k mips32 mips64 powerpc powerpc64 riscv sh4 s390x sparc32
> sparc64 x86_64 and with clang on aarch64 arm hexagon i386 mips32 mips64
> powerpc powerpc64 s390x sparc32 sparc64 x86_64 to verify that there are no
> branches in the generated code.
>
> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
> Cc: stable@vger.kernel.org
>
> ---
> include/linux/kernel.h | 2 +-
> lib/hexdump.c | 32 +++++++++++++++++++++++++-------
> 2 files changed, 26 insertions(+), 8 deletions(-)
>
> Index: linux-2.6/lib/hexdump.c
> ===================================================================
> --- linux-2.6.orig/lib/hexdump.c 2022-04-24 18:51:20.000000000 +0200
> +++ linux-2.6/lib/hexdump.c 2022-04-25 13:15:26.000000000 +0200
> @@ -22,15 +22,33 @@ EXPORT_SYMBOL(hex_asc_upper);
> *
> * hex_to_bin() converts one hex digit to its actual value or -1 in case of bad
> * input.
> + *
> + * This function is used to load cryptographic keys, so it is coded in such a
> + * way that there are no conditions or memory accesses that depend on data.
> + *
> + * Explanation of the logic:
> + * (ch - '9' - 1) is negative if ch <= '9'
> + * ('0' - 1 - ch) is negative if ch >= '0'
> + * we "and" these two values, so the result is negative if ch is in the range
> + * '0' ... '9'
> + * we are only interested in the sign, so we do a shift ">> 8"; note that right
> + * shift of a negative value is implementation-defined, so we cast the
> + * value to (unsigned) before the shift --- we have 0xffffff if ch is in
> + * the range '0' ... '9', 0 otherwise
> + * we "and" this value with (ch - '0' + 1) --- we have a value 1 ... 10 if ch is
> + * in the range '0' ... '9', 0 otherwise
> + * we add this value to -1 --- we have a value 0 ... 9 if ch is in the range '0'
> + * ... '9', -1 otherwise
> + * the next line is similar to the previous one, but we need to decode both
> + * uppercase and lowercase letters, so we use (ch & 0xdf), which converts
> + * lowercase to uppercase
> */
> -int hex_to_bin(char ch)
> +int hex_to_bin(unsigned char ch)
> {
> - if ((ch >= '0') && (ch <= '9'))
> - return ch - '0';
> - ch = tolower(ch);
> - if ((ch >= 'a') && (ch <= 'f'))
> - return ch - 'a' + 10;
> - return -1;
> + unsigned char cu = ch & 0xdf;
> + return -1 +
> + ((ch - '0' + 1) & (unsigned)((ch - '9' - 1) & ('0' - 1 - ch)) >> 8) +
> + ((cu - 'A' + 11) & (unsigned)((cu - 'F' - 1) & ('A' - 1 - cu)) >> 8);
> }
> EXPORT_SYMBOL(hex_to_bin);
Hello,
Just a heads up it seems this patch is causing some instability with crypto self
tests on OpenRISC when using a PREEMPT kernel (no SMP).
This was reported by Jason A. Donenfeld as it came up in wireguard testing.
I am trying to figure out if this is an OpenRISC PREEMPT issue or something
else.
The warning I am seeing is a bit random but looks something like the
following:
[ 0.164000] Freeing initrd memory: 1696K
[ 0.188000] xor: measuring software checksum speed
[ 0.196000] 8regs : 1343 MB/sec
[ 0.204000] 8regs_prefetch : 1347 MB/sec
[ 0.212000] 32regs : 1335 MB/sec
[ 0.220000] 32regs_prefetch : 1277 MB/sec
[ 0.220000] xor: using function: 8regs_prefetch (1347 MB/sec)
[ 0.252000] SARU running 25519 tests
[ 0.424000] curve25519 self-test 5: FAIL
[ 0.496000] curve25519 self-test 7: FAIL
[ 1.744000] curve25519 self-test 45: FAIL
[ 3.448000] ------------[ cut here ]------------
[ 3.448000] WARNING: CPU: 0 PID: 1 at lib/crypto/curve25519.c:19 curve25519_init+0x38/0x50
[ 3.448000] CPU: 0 PID: 1 Comm: swapper Not tainted 5.18.0-rc4+ #758
[ 3.448000] Call trace:
[ 3.448000] [<(ptrval)>] ? __warn+0xe0/0x114
[ 3.448000] [<(ptrval)>] ? curve25519_init+0x38/0x50
[ 3.448000] [<(ptrval)>] ? warn_slowpath_fmt+0x5c/0x94
[ 3.448000] [<(ptrval)>] ? curve25519_init+0x0/0x50
[ 3.452000] [<(ptrval)>] ? curve25519_init+0x38/0x50
[ 3.452000] [<(ptrval)>] ? do_one_initcall+0x98/0x328
[ 3.452000] [<(ptrval)>] ? proc_register+0x4c/0x284
[ 3.452000] [<(ptrval)>] ? ignore_unknown_bootoption+0x0/0x8
[ 3.452000] [<(ptrval)>] ? kernel_init_freeable+0x1fc/0x2a8
[ 3.452000] [<(ptrval)>] ? ignore_unknown_bootoption+0x0/0x8
[ 3.452000] [<(ptrval)>] ? kernel_init+0x0/0x164
[ 3.452000] [<(ptrval)>] ? kernel_init+0x28/0x164
[ 3.452000] [<(ptrval)>] ? schedule_tail+0x18/0xac
[ 3.452000] [<(ptrval)>] ? ret_from_fork+0x1c/0x9c
[ 3.452000] ---[ end trace 0000000000000000 ]---
[ 3.452000] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
[ 3.464000] printk: console [ttyS0] disabled
[ 3.464000] 90000000.serial: ttyS0 at MMIO 0x90000000 (irq = 2, base_baud = 1250000) is a 16550A
Example config: https://xn--4db.cc/cCRlQ1AE
The self-test iteration number that fails is always a bit different. I am
still in progress of investigating this and will not have a lot of time new the
next few days. If anything ring's a bell let me know.
-Stafford
next prev parent reply other threads:[~2022-05-05 7:13 UTC|newest]
Thread overview: 66+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-04-24 20:54 [dm-devel] [PATCH] hex2bin: make the function hex_to_bin constant-time Mikulas Patocka
2022-04-24 20:54 ` Mikulas Patocka
2022-04-24 21:30 ` [dm-devel] " Joe Perches
2022-04-24 21:30 ` Joe Perches
2022-04-24 21:37 ` [dm-devel] " Linus Torvalds
2022-04-24 21:37 ` Linus Torvalds
2022-04-24 21:42 ` [dm-devel] " Linus Torvalds
2022-04-24 21:42 ` Linus Torvalds
2022-04-25 9:37 ` [dm-devel] " David Laight
2022-04-25 9:37 ` David Laight
2022-04-25 11:04 ` [dm-devel] " Mikulas Patocka
2022-04-25 11:04 ` Mikulas Patocka
2022-04-25 12:59 ` [dm-devel] " David Laight
2022-04-25 12:59 ` David Laight
2022-04-25 13:33 ` [dm-devel] " Mikulas Patocka
2022-04-25 13:33 ` Mikulas Patocka
2022-04-25 12:07 ` [dm-devel] [PATCH v2] " Mikulas Patocka
2022-04-25 12:07 ` Mikulas Patocka
2022-04-25 17:53 ` [dm-devel] " Linus Torvalds
2022-04-25 17:53 ` Linus Torvalds
2022-05-04 8:38 ` Stafford Horne [this message]
2022-05-04 8:38 ` Stafford Horne
2022-05-04 8:57 ` [dm-devel] " Mikulas Patocka
2022-05-04 8:57 ` Mikulas Patocka
2022-05-04 9:20 ` [dm-devel] " Andy Shevchenko
2022-05-04 9:20 ` Andy Shevchenko
2022-05-04 9:47 ` [dm-devel] " Milan Broz
2022-05-04 9:47 ` Milan Broz
2022-05-04 9:50 ` [dm-devel] " Jason A. Donenfeld
2022-05-04 9:50 ` Jason A. Donenfeld
2022-05-04 11:54 ` [dm-devel] " Mikulas Patocka
2022-05-04 11:54 ` Mikulas Patocka
2022-05-04 9:42 ` [dm-devel] " Jason A. Donenfeld
2022-05-04 9:42 ` Jason A. Donenfeld
2022-05-04 9:44 ` [dm-devel] " Jason A. Donenfeld
2022-05-04 9:44 ` Jason A. Donenfeld
2022-05-04 9:57 ` [dm-devel] " Jason A. Donenfeld
2022-05-04 9:57 ` Jason A. Donenfeld
2022-05-04 10:07 ` [dm-devel] " Andy Shevchenko
2022-05-04 10:07 ` Andy Shevchenko
2022-05-04 10:15 ` [dm-devel] " Jason A. Donenfeld
2022-05-04 10:15 ` Jason A. Donenfeld
2022-05-04 18:00 ` [dm-devel] " Linus Torvalds
2022-05-04 18:00 ` Linus Torvalds
2022-05-04 19:42 ` [dm-devel] " Jason A. Donenfeld
2022-05-04 19:42 ` Jason A. Donenfeld
2022-05-04 19:51 ` [dm-devel] " Linus Torvalds
2022-05-04 19:51 ` Linus Torvalds
2022-05-04 20:00 ` [dm-devel] " Linus Torvalds
2022-05-04 20:00 ` Linus Torvalds
2022-05-04 20:12 ` [dm-devel] " Stafford Horne
2022-05-04 20:12 ` Stafford Horne
2022-05-04 20:26 ` [dm-devel] " Linus Torvalds
2022-05-04 20:26 ` Linus Torvalds
2022-05-04 21:24 ` [dm-devel] " Linus Torvalds
2022-05-04 21:24 ` Linus Torvalds
2022-05-04 19:57 ` [dm-devel] " Stafford Horne
2022-05-04 19:57 ` Stafford Horne
2022-05-04 20:10 ` [dm-devel] " Linus Torvalds
2022-05-04 20:10 ` Linus Torvalds
2022-05-04 20:38 ` [dm-devel] " Stafford Horne
2022-05-04 20:38 ` Stafford Horne
2022-05-08 0:37 ` [dm-devel] " Stafford Horne
2022-05-08 0:37 ` Stafford Horne
2022-05-11 12:17 ` [dm-devel] " Stafford Horne
2022-05-11 12:17 ` Stafford Horne
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=YnI7hE4cIfjsdKSF@antec \
--to=shorne@gmail.com \
--cc=Jason@zx2c4.com \
--cc=andy@kernel.org \
--cc=davem@davemloft.net \
--cc=dm-devel@redhat.com \
--cc=gmazyland@gmail.com \
--cc=herbert@gondor.apana.org.au \
--cc=linux-crypto@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mpatocka@redhat.com \
--cc=msnitzer@redhat.com \
--cc=torvalds@linux-foundation.org \
--cc=zohar@linux.ibm.com \
/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 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.