Received: by 2002:a05:6a10:6d10:0:0:0:0 with SMTP id gq16csp2433690pxb; Sun, 24 Apr 2022 14:50:26 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyzZWzyvYRN15wHuP+xORmpKbeqP+F4Qnoa4mhnOB177GMhjoACY9gHq3ZTgycW4L7RedAh X-Received: by 2002:aa7:c793:0:b0:408:4a69:90b4 with SMTP id n19-20020aa7c793000000b004084a6990b4mr15906367eds.58.1650837025833; Sun, 24 Apr 2022 14:50:25 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1650837025; cv=none; d=google.com; s=arc-20160816; b=KbOgucDwhS5F6vFOSMJeOTTwsJbomoUD3wD/0kvft0GM0AM5ymx1tWyu1v2kQNPLBc 0ca6y3GfW05cyWugBPBmaNvC6pofQ86KHxoclLZlNB8cheSvOsM4neKfKeneCyM/dLYl x/+MQiP3FBwkhOoSEqW3j3XjwnimyCVlf0R/UC8QEd3aYmhQodUq7xAmEkhxQN9BUOfW FHxuaeHmj0ef+IqPAbEayOOZJC6Oy+5X09IHWo+lhEHu+NYVZmtgUQj7iXlHU3MIe4vn QW1VlGD9TIkBLu3PAlAyVGGJ7gci7aDxAd+qYPicoDTEqCnVKt3dyQKVshaUd0MUzTqz Xglg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:mime-version:user-agent:message-id:subject:cc:to :from:date:dkim-signature; bh=DHCWz0NT7/oap0KtY1nMcbeGh8Z12KZ0bXl9rYv24JM=; b=s4Z7H13Hnqf4JURzPKJaDQuHBKQ0TQ3RUvV9QkYs60hbm9wjADX2c9YACWLrQ8OAnp fiCgN7m8d8+/AGALAk9yTr1AWsRzhQq2u0B5EP0JBW9o6k+2ngoqGuHAFVjBI8em4i0c DPUnhd4SakkpbOfH7LhCiAeTSUkPalzkxpHKpwuIiAf/m3N8ckXPN28DrRkcuRyOil2A QvrTrem08aIkNt8jMN3sPTL6R8GTSKsKyZwSUBRVUpTdqmX7zdp+YF71Q82AQuwxhzmN 9bCWiyxMhYS5iRpfA61jWf8IcwWpIA40GDjECGyMosW70qL2spKMf6T8j7cEBoortXLC 1uBQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=bKtKUVZX; spf=pass (google.com: domain of linux-crypto-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-crypto-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id e2-20020a17090618e200b006df76385ca1si11472769ejf.321.2022.04.24.14.49.45; Sun, 24 Apr 2022 14:50:25 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-crypto-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=bKtKUVZX; spf=pass (google.com: domain of linux-crypto-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-crypto-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236843AbiDXU53 (ORCPT + 99 others); Sun, 24 Apr 2022 16:57:29 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56424 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230200AbiDXU52 (ORCPT ); Sun, 24 Apr 2022 16:57:28 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 5486E54FAF for ; Sun, 24 Apr 2022 13:54:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1650833665; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type; bh=DHCWz0NT7/oap0KtY1nMcbeGh8Z12KZ0bXl9rYv24JM=; b=bKtKUVZXjOKX3YZj4QgYFVyONgghs1H/VOoYjMvOHmu6+jmD1N268XLZqz0CM/LKVBtNih QgObuyVtN2EEtPfYxOES0eeizEYqAlYLi3Q7AYKkPifb/kGON7F+Kz0VzmJvHAIyEbLq29 ppS/drW+lLg6x470xGu02Yu6KxsQneY= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-604-QKTgqLN-OMGNQNcJFbt0Wg-1; Sun, 24 Apr 2022 16:54:20 -0400 X-MC-Unique: QKTgqLN-OMGNQNcJFbt0Wg-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.rdu2.redhat.com [10.11.54.1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id B6892101AA45; Sun, 24 Apr 2022 20:54:19 +0000 (UTC) Received: from file01.intranet.prod.int.rdu2.redhat.com (file01.intranet.prod.int.rdu2.redhat.com [10.11.5.7]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 6311A4087D9C; Sun, 24 Apr 2022 20:54:19 +0000 (UTC) Received: from file01.intranet.prod.int.rdu2.redhat.com (localhost [127.0.0.1]) by file01.intranet.prod.int.rdu2.redhat.com (8.14.4/8.14.4) with ESMTP id 23OKsJ9h019671; Sun, 24 Apr 2022 16:54:19 -0400 Received: from localhost (mpatocka@localhost) by file01.intranet.prod.int.rdu2.redhat.com (8.14.4/8.14.4/Submit) with ESMTP id 23OKsIPc019666; Sun, 24 Apr 2022 16:54:18 -0400 X-Authentication-Warning: file01.intranet.prod.int.rdu2.redhat.com: mpatocka owned process doing -bs Date: Sun, 24 Apr 2022 16:54:18 -0400 (EDT) From: Mikulas Patocka X-X-Sender: mpatocka@file01.intranet.prod.int.rdu2.redhat.com To: Linus Torvalds , Andy Shevchenko cc: dm-devel@redhat.com, linux-kernel@vger.kernel.org, linux-crypto@vger.kernel.org, Herbert Xu , "David S. Miller" , Mike Snitzer , Mimi Zohar , Milan Broz Subject: [PATCH] hex2bin: make the function hex_to_bin constant-time Message-ID: User-Agent: Alpine 2.02 (LRH 1266 2009-07-14) MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII X-Scanned-By: MIMEDefang 2.84 on 10.11.54.1 X-Spam-Status: No, score=-3.4 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_LOW, SPF_HELO_NONE,SPF_NONE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org 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 Cc: stable@vger.kernel.org --- lib/hexdump.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 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-24 18:51:20.000000000 +0200 @@ -22,15 +22,30 @@ 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" --- we have -1 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) { - if ((ch >= '0') && (ch <= '9')) - return ch - '0'; - ch = tolower(ch); - if ((ch >= 'a') && (ch <= 'f')) - return ch - 'a' + 10; - return -1; + return -1 + + ((ch - '0' + 1) & (((ch - '9' - 1) & ('0' - 1 - ch)) >> 8)) + + (((ch & 0xdf) - 'A' + 11) & ((((ch & 0xdf) - 'F' - 1) & ('A' - 1 - (ch & 0xdf))) >> 8)); } EXPORT_SYMBOL(hex_to_bin);