Received: by 2002:a05:6a10:9848:0:0:0:0 with SMTP id x8csp38927pxf; Wed, 24 Mar 2021 20:15:08 -0700 (PDT) X-Google-Smtp-Source: ABdhPJx5PQznfyZ/6QzFNblE+lFeiDE/Xgr9Ycx3qi08htqPA7efkDhWAwo56KF0QQpJzKSrKx39 X-Received: by 2002:aa7:cb82:: with SMTP id r2mr6734664edt.209.1616642107951; Wed, 24 Mar 2021 20:15:07 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1616642107; cv=none; d=google.com; s=arc-20160816; b=ZvpUQYC+0AtVdS/TY6WkTG4AmbOnouXFWJbIhAQHVG9C0ocHoxqlK5TcmX8XNJvTiq gsl7Tya/fnIxDvEwTmbOBmYsQyHDvNGurERQznitQJCBlqPOkvqBraqJW+BwwiyXmQF9 xo07u+RlGgWyFnodEgvyFqX9Bxzh86Zf2MfHPFM9FjwRGFOzS4WRPloK0TiI35U6WHbh S1olxDIYz30qv/0m6VjigzIcAyAy/T5obZ6sAQ+9Dzy3ANSiERFX4v3BH5fRzXrqqxks K2H3DbGgTpHjmesjU4HC1Uqr0+i4ylvZzyCkcwJUsdJIlON6bgOUPSQrpQbdZ9szaewp 8B5w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:content-language :in-reply-to:mime-version:user-agent:date:message-id:from:references :cc:to:subject:dkim-signature; bh=fckQzWuJnvD6S/jFF8HUa1PwKAcbSDOKJ4gWr/ndvyk=; b=NNNoMZxx2rWEuydO6tNoSbjhuauGadjrZP/xn7cdiEovd0ySgR0+/FjpFwvFut+kdw imiWpWBs0pFpp9GP8wvdtyVRM54nAq6sSHgBBfaJn+nHtnVe6AkFs3F5wqY5vTMZy+sE 6PYpUAzYoVGIV5+vUn6KtDhSaw4KOJksOEDSdBbU7i3w8jn5je452DK+DZPvAaqMsitl JjJHMlf4e+FVhk0+wf3L3imLmYbp39dnnTggnUQRdTDKOwFd+uY1e+46+h/P628CYgZg bgJwF+n28+NpgYcBzinLrAbgYI7HN3wtxk5rHg3StUyEonQLInbHfNAWN4nVoRbx3fQ4 Xaig== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@rasmusvillemoes.dk header.s=google header.b=OlKQtU1q; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id o13si3159246eje.367.2021.03.24.20.14.45; Wed, 24 Mar 2021 20:15:07 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@rasmusvillemoes.dk header.s=google header.b=OlKQtU1q; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236664AbhCXPbg (ORCPT + 99 others); Wed, 24 Mar 2021 11:31:36 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35264 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236684AbhCXPbW (ORCPT ); Wed, 24 Mar 2021 11:31:22 -0400 Received: from mail-ej1-x632.google.com (mail-ej1-x632.google.com [IPv6:2a00:1450:4864:20::632]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A3946C0613E2 for ; Wed, 24 Mar 2021 08:31:20 -0700 (PDT) Received: by mail-ej1-x632.google.com with SMTP id hq27so33576698ejc.9 for ; Wed, 24 Mar 2021 08:31:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rasmusvillemoes.dk; s=google; h=subject:to:cc:references:from:message-id:date:user-agent :mime-version:in-reply-to:content-language:content-transfer-encoding; bh=fckQzWuJnvD6S/jFF8HUa1PwKAcbSDOKJ4gWr/ndvyk=; b=OlKQtU1q2ZxhFAsb1Cs2Js3zE+ZJzDOEI4+bnRMrr1+uVB7P/Iu6eKckjnXg8zK56l Irrft7thQGCzqA32QFBdXE4+uBuO6iQgfPeDjc1NS4TUbZsPKk2pdNdVY5R9tx4z25Dg ozY6uLy7niX57VhmCVl+dE8zMrZFu7sQlODj4= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:cc:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-language :content-transfer-encoding; bh=fckQzWuJnvD6S/jFF8HUa1PwKAcbSDOKJ4gWr/ndvyk=; b=BrTHFr1nTsWGYS7ercs47NyYaMXoC1VsprzEJrUqEw7W33hUxqJbXZhNQq4Iz4nMLz 6SC02wH+VeGV4QOJTClQf/K8Pu8mHlDd2+2UWhWhSzCsgZD0xAVjnb+RQZ5EIX4wtMmF pe0czh1kycb871xyrNE2FJE21pUc81O58WhYJ+EkL3yKvoi2iT7iIQybNmaNUgrjKXAx hPMlWNEfQtt6bhGf7FkYgfI4qDt6BkkYijIaJnKXiRjknSD8El9+UFo2khE7nnIi/SGi VJDMwbCrS6FVqjAZ69r1nG9WbahAwTgu/v5IxB/Uzh8sto0N2oWcQ91QPMoac8sKcHeY 7SKw== X-Gm-Message-State: AOAM532th3OnCvliTRe8CbdZa/F2iWQ57PRlxR+ysi62DZAhTljoKVHU EsVh8o2lQ0oEChCwAzFGOIeZrEqv6mRHQod+ X-Received: by 2002:a17:906:358c:: with SMTP id o12mr4397574ejb.156.1616599878962; Wed, 24 Mar 2021 08:31:18 -0700 (PDT) Received: from [192.168.1.149] ([80.208.71.248]) by smtp.gmail.com with ESMTPSA id b12sm1262238eds.94.2021.03.24.08.31.17 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Wed, 24 Mar 2021 08:31:18 -0700 (PDT) Subject: Re: [PATCH v3 02/17] cfi: add __cficanonical To: Sami Tolvanen , Kees Cook Cc: Nathan Chancellor , Nick Desaulniers , Masahiro Yamada , Will Deacon , Jessica Yu , Arnd Bergmann , Tejun Heo , "Paul E. McKenney" , Christoph Hellwig , Peter Zijlstra , bpf@vger.kernel.org, linux-hardening@vger.kernel.org, linux-arch@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kbuild@vger.kernel.org, linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org References: <20210323203946.2159693-1-samitolvanen@google.com> <20210323203946.2159693-3-samitolvanen@google.com> From: Rasmus Villemoes Message-ID: <92afcbea-1415-2df1-5e78-4e9a7a4d364b@rasmusvillemoes.dk> Date: Wed, 24 Mar 2021 16:31:17 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.7.1 MIME-Version: 1.0 In-Reply-To: <20210323203946.2159693-3-samitolvanen@google.com> Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 7bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 23/03/2021 21.39, Sami Tolvanen wrote: > With CONFIG_CFI_CLANG, the compiler replaces a function address taken > in C code with the address of a local jump table entry, which passes > runtime indirect call checks. However, the compiler won't replace > addresses taken in assembly code, which will result in a CFI failure > if we later jump to such an address in instrumented C code. The code > generated for the non-canonical jump table looks this: > > : /* In C, &noncanonical points here */ > jmp noncanonical > ... > : /* function body */ > ... > > This change adds the __cficanonical attribute, which tells the > compiler to use a canonical jump table for the function instead. This > means the compiler will rename the actual function to .cfi > and points the original symbol to the jump table entry instead: > > : /* jump table entry */ > jmp canonical.cfi > ... > : /* function body */ > ... > > As a result, the address taken in assembly, or other non-instrumented > code always points to the jump table and therefore, can be used for > indirect calls in instrumented code without tripping CFI checks. Random ramblings, I'm trying to understand how this CFI stuff works. First, patch 1 and 2 explain the pros and cons of canonical vs non-canonical jump tables, in either case, there's problems with stuff implemented in assembly. But I don't understand why those pros and cons then end up with using the non-canonical jump tables by default. IIUC, with canonical jump tables, function pointer equality would keep working for functions implemented in C, because &func would always refer to the same stub "function" that lives in the same object file as func.cfi, whereas with the non-canonical version, each TU (or maybe DSO) that takes the address of func ends up with its own func.cfi_jt. There are of course lots of direct calls of assembly functions, but I don't think we take the address of such functions very often. So why can't we instead equip the declarations of those with a __cfi_noncanonical attribute? And now, more directed at the clang folks on cc: As to how CFI works, I've tried to make sense of the clang docs. So at place where some int (*)(long, int) function pointer is called, the compiler computes (roughly) md5sum("int (*)(long, int)") and uses the first 8 bytes as a cookie representing that type. It then goes to some global table of jump table ranges indexed by that cookie and checks that the address it is about to call is within that range. All jump table entries for one type of function are consecutive in memory (with complications arising from cross-DSO calls). What I don't understand about all this is why that indirection through some hidden global table and magic jump table (whether canonical or not) is even needed in the simple common case of ordinary C functions. Why can't the compiler just emit the cookie corresponding to a given function's prototype immediately prior to the function? Then the inline check would just be "if (*(u64*)((void*)func - 8) == cookie)" and function pointer comparison would just work because there's no magic involved when doing &func. Cross-DSO calls of C function have no extra cost to look up a __cfi_check function in the target DSO. An indirect call doesn't touch at least two extra cache lines (the range table and the jump table entry). It seems to rely on LTO anyway, so it's not even that the compiler would have to emit that cookie for every single function, it knows at link time which functions have their address taken. Calling functions implemented in assembly through a function pointer will have the same problem as with the "canonical" jump table approach, but with a suitable attribute on those surely the compiler could emit a func.cfi_hoop .quad 0x1122334455667788 // cookie : jmp func and perhaps no such attribute would even be needed (with LTO, the compiler should be able to see "hey, I don't know that function, it's probably implemented in assembly, so lemme emit that trampoline with a cookie in front and redirect address-of to that"). Rasmus