Received: by 10.223.176.46 with SMTP id f43csp2746033wra; Thu, 25 Jan 2018 14:38:37 -0800 (PST) X-Google-Smtp-Source: AH8x225dqs6bW/whU/9n5Yp/U8BvbNcoo6jM9Ev6VDLC/vI+XaFEs4iH/W4Flw1G3CT+hY8T3WHS X-Received: by 2002:a17:902:9a8b:: with SMTP id w11-v6mr6643884plp.118.1516919917287; Thu, 25 Jan 2018 14:38:37 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1516919917; cv=none; d=google.com; s=arc-20160816; b=MVMmKaoRwb7biXMcWG4DUgMJsAoUz2qR7NJMBijccuWLlkB3tljbVOrK/cSqnW70ag Z23ap4w8YZJ51qblUYCrrLrrRuIXZvsqCmt57p/YYbi4u180qFdt2NrMXdNjbpzmpDcN LXYu7+P1aBUxx1Zda1XQCGPiAb5M8dWpAt5R7HnQ0yK8ShPD/3Afd++qbq0S4XKjEjVu FkuexdcIrI3K4eq6pfZIeiDB3JGsf+OFWhj1RGHFUiyI/Qf4wUlFd9l+cONblaw+KiAh SpIcRgmo3er4Dhq5pr6yyk2FJDaNEmgC19chfHN0IeTMrpFAGY9zAOHlcjoGDJ6yoSMo UgfQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:cc:to:subject:message-id:date:from :references:in-reply-to:mime-version:dkim-signature :arc-authentication-results; bh=x7BcXZ8ttpRgYaDlqAi4Rjhsq7hoNcB4K/mtlXH6VCQ=; b=drvQTTTSRvTZp/2kfcCG7tCf23+uHOrNMuGRc3lEl5S9w/yA45DKyEqDnlx5FAftBL EUiUoTUfsMHVy6rJThHYPNuDZ8fidh3VgJUYVNGdaiJlVpy4pCG/3USeoJ/OiWcmss+K 0PA8NosGvhjE2XV7EYXqHfVXg+RvsJH5xLaNf0igBQZtmaoDVTO72rIrHcy+h11RRhCL VDPKQ7ZHj/cNVJHasxdzp0e5543SADl8cUt/SIjGvGE8SAELXVi/OkL77wcMpGkmgPn1 t3nG5E56ZQzfYpIe0GcTA8YSyo0War3c5m+IfNnkeaIgALmxbrIR+Vt7iVDUQuTNfv6f GaDA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@intel-com.20150623.gappssmtp.com header.s=20150623 header.b=wTnXPhIq; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id l1si855331pgr.763.2018.01.25.14.38.20; Thu, 25 Jan 2018 14:38:37 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@intel-com.20150623.gappssmtp.com header.s=20150623 header.b=wTnXPhIq; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751429AbeAYWh4 (ORCPT + 99 others); Thu, 25 Jan 2018 17:37:56 -0500 Received: from mail-ot0-f169.google.com ([74.125.82.169]:45776 "EHLO mail-ot0-f169.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751204AbeAYWhy (ORCPT ); Thu, 25 Jan 2018 17:37:54 -0500 Received: by mail-ot0-f169.google.com with SMTP id r4so8457436oti.12 for ; Thu, 25 Jan 2018 14:37:54 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=intel-com.20150623.gappssmtp.com; s=20150623; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc; bh=x7BcXZ8ttpRgYaDlqAi4Rjhsq7hoNcB4K/mtlXH6VCQ=; b=wTnXPhIq1TX5G6uhvQ8yJDsqTkgVIBKxdBf2bhPVpF3RqYQV60dj+38bXpO+Qz5R42 v1+qyQ4nVTuw/f2PVF2Pi68506EiZkbNIgVYzHBS3rOtGJz0DffOTFuOK1NNp119X8w6 kGjm3x6VWgfZYJxi+MLySVhVuccemu/MhPG2ZhYRJW7sI9fj6rpY0lDFJyriC9axQnlv HJK8vJaBfySFnlI+t6nGmJD7xz9XZMEajQQustb4j5u3x55faONcM+0zdmcRZOFT9lII DEU0ZML0gdGcA8vP1DZucQXPBfHD0wYVBez8GWah4n6s8szkCtn7n+taWV/VUdlI/MwA QOFw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=x7BcXZ8ttpRgYaDlqAi4Rjhsq7hoNcB4K/mtlXH6VCQ=; b=RsZqXYu0+eb1Pf93tKOxdFDVSVo2HIrSUQx86WOtPYvihNf2ZmyzGWyhOyHpIbLy0d zHuLmsTAXRbG3YAQeFRkikI9c+z/r7DEMYhIRtkngxL5eHo9w7DQ5EZsd+b02biL9imS ifWLLenSXf2cm9908t0W5tUulEwhEtvXhSrhOVQ1xJ2jHfkL24qa6Lf/Ux/vZWJaPnvi DthqFX5sTHt6WtakoXV+vBa5NkUhSJZGjTD9EY6F2teOq1YKI8UqHAwH9IXJKwtXsC7K eSRs0GTliup3jJW11Rwm4oJd5lGnNB2mJW4Fedl4YBg0fR+QwZa6JQ36a5MQq/FE5GGZ mOXw== X-Gm-Message-State: AKwxyte2rT/reXnIMo5fLA8uCaY2vk1bMee8sZm5CF1cr+OVgLkFGkap eUChLe2mqwlCp96TNYkkQO+lvdjqS4TB+JVB+EJ3iQ== X-Received: by 10.157.0.102 with SMTP id 93mr12475800ota.175.1516919873976; Thu, 25 Jan 2018 14:37:53 -0800 (PST) MIME-Version: 1.0 Received: by 10.157.62.72 with HTTP; Thu, 25 Jan 2018 14:37:53 -0800 (PST) In-Reply-To: References: <151632009605.21271.11304291057104672116.stgit@dwillia2-desk3.amr.corp.intel.com> <151632010687.21271.12004432287640499992.stgit@dwillia2-desk3.amr.corp.intel.com> From: Dan Williams Date: Thu, 25 Jan 2018 14:37:53 -0800 Message-ID: Subject: Re: [PATCH v4 02/10] asm/nospec, array_ptr: sanitize speculative array de-references To: Cyril Novikov Cc: Linux Kernel Mailing List , linux-arch , Kernel Hardening , Catalin Marinas , X86 ML , Will Deacon , Russell King , Ingo Molnar , Greg KH , "H. Peter Anvin" , Thomas Gleixner , Linus Torvalds , Andrew Morton , Alan Cox , Adam Sampson Content-Type: text/plain; charset="UTF-8" Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Wed, Jan 24, 2018 at 11:09 PM, Cyril Novikov wrote: > On 1/18/2018 4:01 PM, Dan Williams wrote: >> >> 'array_ptr' is proposed as a generic mechanism to mitigate against >> Spectre-variant-1 attacks, i.e. an attack that bypasses boundary checks >> via speculative execution). The 'array_ptr' implementation is expected >> to be safe for current generation cpus across multiple architectures >> (ARM, x86). > > > I'm an outside reviewer, not subscribed to the list, so forgive me if I do > something not according to protocol. I have the following comments on this > change: > > After discarding the speculation barrier variant, is array_ptr() needed at > all? You could have a simpler sanitizing macro, say > > #define array_sanitize_idx(idx, sz) ((idx) & array_ptr_mask((idx), (sz))) > > (adjusted to not evaluate idx twice). And use it as follows: > > if (idx < array_size) { > idx = array_sanitize_idx(idx, array_size); > do_something(array[idx]); > } > > If I understand the speculation stuff correctly, unlike array_ptr(), this > "leaks" array[0] rather than nothing (*NULL) when executed speculatively. > However, it's still much better than leaking an arbitrary location in > memory. The attacker can likely get array[0] "leaked" by passing 0 as idx > anyway. True, we could simplify it to just sanitize the index with the expectation that speculating with index 0 is safe. Although we'd want to document it just case there is some odd code paths where the valid portion of the array is offset from 0. I like this approach better because it handles cases where the bounds check is far away from the array de-reference. I.e. instead of having array_ptr() and array_idx() for different cases, just sanitize the index. > >> +/* >> + * If idx is negative or if idx > size then bit 63 is set in the mask, >> + * and the value of ~(-1L) is zero. When the mask is zero, bounds check >> + * failed, array_ptr will return NULL. >> + */ >> +#ifndef array_ptr_mask >> +static inline unsigned long array_ptr_mask(unsigned long idx, unsigned >> long sz) >> +{ >> + return ~(long)(idx | (sz - 1 - idx)) >> (BITS_PER_LONG - 1); >> +} >> +#endif > > > Why does this have to resort to the undefined behavior of shifting a > negative number to the right? You can do without it: > > return ((idx | (sz - 1 - idx)) >> (BITS_PER_LONG - 1)) - 1; > > Of course, you could argue that subtracting 1 from 0 to get all ones is also > an undefined behavior, but it's still much better than the shift, isn't it? The goal is to prevent the compiler from emitting conditional instructions. For example, the simplest form of this sanitize operation from Adam: return 0 - ((long) (idx < sz)); ...produces the desired "cmp, sbb" sequence on x86, but leads to a "csel" instruction being emitted for arm64. Stepping back and realizing that all this churn is around the un-optimized form of the comparison vs the inline asm that an arch can provide, and we're effectively handling the carry bit in software, we can have a WARN_ON_ONCE(idx < 0 || sz < 0) to catch places where the expectations of the macro are violated. Archs can remove the overhead of that extra branch with an instruction sequence to handle the carry bit in hardware, otherwise we get runtime coverage of places where array_idx() gets used incorrectly. > >> +#define array_ptr(base, idx, sz) \ >> +({ \ >> + union { typeof(*(base)) *_ptr; unsigned long _bit; } __u; \ >> + typeof(*(base)) *_arr = (base); \ >> + unsigned long _i = (idx); \ >> + unsigned long _mask = array_ptr_mask(_i, (sz)); \ >> + \ >> + __u._ptr = _arr + (_i & _mask); \ >> + __u._bit &= _mask; \ >> + __u._ptr; \ >> +}) > > > Call me paranoid, but I think this may actually create an exploitable bug on > 32-bit systems due to casting the index to an unsigned long, if the index as > it comes from userland is a 64-bit value. You have *replaced* the "if (idx < > array_size)" check with checking if array_ptr() returns NULL. Well, it > doesn't return NULL if the low 32 bits of the index are in-bounds, but the > high 32 bits are not zero. Apart from the return value pointing to the wrong > place, the subsequent code may then assume that the 64-bit idx is actually > valid and trip on it badly. Yes, I'll add some BUILD_BUG_ON safety for cases where sizeof(idx) > sizeof(long). Thanks for taking a look.