Received: by 2002:a05:6a10:22f:0:0:0:0 with SMTP id 15csp786107pxk; Wed, 23 Sep 2020 16:37:53 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzhdMJ0s7fjKjTq7zsNlXFT8U8tMzZx9JeIkVTh2atUedAulh80aO15ppqx7qryHJSmr2mY X-Received: by 2002:a50:e807:: with SMTP id e7mr1867797edn.84.1600904273196; Wed, 23 Sep 2020 16:37:53 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1600904273; cv=none; d=google.com; s=arc-20160816; b=xbwq4G1h0BwEGRlSM9r6Vt5FHAMZ3eQRyu/qgl+yPw2/dTmmyFYDw7rcpuikMG828g S8ejGi2Tt0B9XRs+mKfZCUmX9Za8xJP9zoRkHFnvUTxY0t4i+dZ+o8MMTySuENoT2Ok6 dMmyN7BK1wg/BsO3Yo4Aqh8XWbEj51eW6bEwcnqscwkiXs/bl8Sh/JfWpucjnYN02+0H q7PBD68mqr+BLRZorhY0hzSeOrBG1aBdMmOIO52MKe/nbSnGNE+5rUZuExVk2ralhr9I Iq80cr/PMItbtM5TIrlC77X/21N4nyRoZ5tSLknYR9c/cFp+QVqst//ismEfyFhkAyHc ogBA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=Sc3ebczz8rmNH2w8JraN/35ap0kTxnvAQhEv63luYfE=; b=oec+GXBQ4CicuEogF7xmzxPye3fFKyH9tK25yYJbmonFnXmtYgHZDUpBIQzDYKjjcr h7sC3OEb3FwNu53OgEWzyJ+THl91LvzJBs9Z6NZ4PxJIbJtI4M1jGYCx0HRkRvUbKq0R XsZzluxtum4TvTGNVOye9C9RjAWSDAi8ZnFVTMTs9Va9MA5dCT91tGZk9bZkLeSmlfC1 c6bDdj8JKP9ESgBOAX70mvpK+o15mouy8UuhuljsD0VR7GOAO1Uw3P5ZDjPwugMTgVb0 W+fdyMmJQAbVmgt6pQTumrO0HWhIMA5HIw2vmBJKPDLk4zvsXhS8MiK5PNV9/c/tmnuk 0z1g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b="CK/yLRWK"; 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; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id r9si845787eju.84.2020.09.23.16.37.29; Wed, 23 Sep 2020 16:37:53 -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=@chromium.org header.s=google header.b="CK/yLRWK"; 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; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726788AbgIWXfq (ORCPT + 99 others); Wed, 23 Sep 2020 19:35:46 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60296 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726691AbgIWX32 (ORCPT ); Wed, 23 Sep 2020 19:29:28 -0400 Received: from mail-pj1-x1044.google.com (mail-pj1-x1044.google.com [IPv6:2607:f8b0:4864:20::1044]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3936EC0613D1 for ; Wed, 23 Sep 2020 16:29:28 -0700 (PDT) Received: by mail-pj1-x1044.google.com with SMTP id mn7so534547pjb.5 for ; Wed, 23 Sep 2020 16:29:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=Sc3ebczz8rmNH2w8JraN/35ap0kTxnvAQhEv63luYfE=; b=CK/yLRWK/GnklstIhHZjn/0pYYnnQjH99MYWDkAXuYI9+NOqvUU0ANa6rBD+NsWFEz c7QexSPQWD74DI1zL2hhf0A48GuOV9gJ6xUM59jCUCjfUWNr9xxPmzGVjGXG9Ux5vdnC z4nOhOyvGdEr88w/pVmbgsicGvkUkxDZlRCWA= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Sc3ebczz8rmNH2w8JraN/35ap0kTxnvAQhEv63luYfE=; b=NBathpYPkLyerMcF5/2nK4G0exDGd+7dl++yETkSROcFW10VKVx6XZiaK054fnDrUP zodC9Ix0pOHuPq6EBLBeXp2R6/UJlt+2eRHa09/6o0iwOO5cZvDASsRxY4/EPtB+8Yb0 JlVRhqhgwgRhd9qJAFitvr/rPWsNSg280xkYd16k0AZvpB5Qgn82n/4zWygAQWyU2nab 7Vfrl3s0CafxA6xbxGSyCh3aHn27JMcSdrf/+kbEstGbYG7BEzcw4kVDkose1Hrp7okT fGXRAk53ba5QXOH5FqTJt9UCJ/pWHM/vE98kx/eDiSTdFM4uuksK4k9R5i6i4KVOjFY2 XT4w== X-Gm-Message-State: AOAM5302+Rb0/IE5wisikkCmC8MTBfSfL1bTAWmXduIBkKsJVGgTIvYJ KBdCl4PZ2djJgjKm6MyHp+ukBQ== X-Received: by 2002:a17:90a:db05:: with SMTP id g5mr1549879pjv.22.1600903767757; Wed, 23 Sep 2020 16:29:27 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id w185sm724485pfc.36.2020.09.23.16.29.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 23 Sep 2020 16:29:26 -0700 (PDT) From: Kees Cook To: YiFei Zhu Cc: Kees Cook , Jann Horn , Christian Brauner , Tycho Andersen , Andy Lutomirski , Will Drewry , Andrea Arcangeli , Giuseppe Scrivano , Tobin Feldman-Fitzthum , Dimitrios Skarlatos , Valentin Rothberg , Hubertus Franke , Jack Chen , Josep Torrellas , Tianyin Xu , bpf@vger.kernel.org, containers@lists.linux-foundation.org, linux-api@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 4/6] seccomp: Emulate basic filters for constant action results Date: Wed, 23 Sep 2020 16:29:21 -0700 Message-Id: <20200923232923.3142503-5-keescook@chromium.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200923232923.3142503-1-keescook@chromium.org> References: <20200923232923.3142503-1-keescook@chromium.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This emulates absolutely the most basic seccomp filters to figure out if they will always give the same results for a given arch/nr combo. Nearly all seccomp filters are built from the following ops: BPF_LD | BPF_W | BPF_ABS BPF_JMP | BPF_JEQ | BPF_K BPF_JMP | BPF_JGE | BPF_K BPF_JMP | BPF_JGT | BPF_K BPF_JMP | BPF_JSET | BPF_K BPF_JMP | BPF_JA BPF_RET | BPF_K These are now emulated to check for accesses beyond seccomp_data::arch or unknown instructions. Not yet implemented are: BPF_ALU | BPF_AND (generated by libseccomp and Chrome) Suggested-by: Jann Horn Link: https://lore.kernel.org/lkml/CAG48ez1p=dR_2ikKq=xVxkoGg0fYpTBpkhJSv1w-6BG=76PAvw@mail.gmail.com/ Signed-off-by: Kees Cook --- kernel/seccomp.c | 82 ++++++++++++++++++++++++++++++++++++++++++++--- net/core/filter.c | 3 +- 2 files changed, 79 insertions(+), 6 deletions(-) diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 111a238bc532..9921f6f39d12 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -610,7 +610,12 @@ static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog) { struct seccomp_filter *sfilter; int ret; - const bool save_orig = IS_ENABLED(CONFIG_CHECKPOINT_RESTORE); + const bool save_orig = +#if defined(CONFIG_CHECKPOINT_RESTORE) || defined(SECCOMP_ARCH) + true; +#else + false; +#endif if (fprog->len == 0 || fprog->len > BPF_MAXINSNS) return ERR_PTR(-EINVAL); @@ -690,11 +695,78 @@ static inline bool sd_touched(pte_t *ptep) * This approach could also be used to test for access to sd->arch too, * if we wanted to warn about compat-unsafe filters. */ -static inline bool seccomp_filter_action_is_constant(struct bpf_prog *prog, - struct seccomp_data *sd, - u32 *action) +static bool seccomp_filter_action_is_constant(struct bpf_prog *prog, + struct seccomp_data *sd, + u32 *action) { - /* No evaluation implementation yet. */ + struct sock_fprog_kern *fprog = prog->orig_prog; + unsigned int insns; + unsigned int reg_value = 0; + unsigned int pc; + bool op_res; + + if (WARN_ON_ONCE(!fprog)) + return false; + + insns = bpf_classic_proglen(fprog); + for (pc = 0; pc < insns; pc++) { + struct sock_filter *insn = &fprog->filter[pc]; + u16 code = insn->code; + u32 k = insn->k; + + switch (code) { + case BPF_LD | BPF_W | BPF_ABS: + switch (k) { + case offsetof(struct seccomp_data, nr): + reg_value = sd->nr; + break; + case offsetof(struct seccomp_data, arch): + reg_value = sd->arch; + break; + default: + /* can't optimize (non-constant value load) */ + return false; + } + break; + case BPF_RET | BPF_K: + *action = insn->k; + /* success: reached return with constant values only */ + return true; + case BPF_JMP | BPF_JA: + pc += insn->k; + break; + case BPF_JMP | BPF_JEQ | BPF_K: + case BPF_JMP | BPF_JGE | BPF_K: + case BPF_JMP | BPF_JGT | BPF_K: + case BPF_JMP | BPF_JSET | BPF_K: + switch (BPF_OP(code)) { + case BPF_JEQ: + op_res = reg_value == k; + break; + case BPF_JGE: + op_res = reg_value >= k; + break; + case BPF_JGT: + op_res = reg_value > k; + break; + case BPF_JSET: + op_res = !!(reg_value & k); + break; + default: + /* can't optimize (unknown jump) */ + return false; + } + + pc += op_res ? insn->jt : insn->jf; + break; + default: + /* can't optimize (unknown insn) */ + return false; + } + } + + /* ran off the end of the filter?! */ + WARN_ON(1); return false; } diff --git a/net/core/filter.c b/net/core/filter.c index b2df52086445..cb1bdb0bfe87 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -1145,7 +1145,7 @@ static int bpf_prog_store_orig_filter(struct bpf_prog *fp, return 0; } -static void bpf_release_orig_filter(struct bpf_prog *fp) +void bpf_release_orig_filter(struct bpf_prog *fp) { struct sock_fprog_kern *fprog = fp->orig_prog; @@ -1154,6 +1154,7 @@ static void bpf_release_orig_filter(struct bpf_prog *fp) kfree(fprog); } } +EXPORT_SYMBOL_GPL(bpf_release_orig_filter); static void __bpf_prog_release(struct bpf_prog *prog) { -- 2.25.1