From patchwork Thu Aug 6 11:08:05 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Doucha X-Patchwork-Id: 1341615 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.linux.it (client-ip=2001:1418:10:5::2; helo=picard.linux.it; envelope-from=ltp-bounces+incoming=patchwork.ozlabs.org@lists.linux.it; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.cz Received: from picard.linux.it (picard.linux.it [IPv6:2001:1418:10:5::2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BMm1y20Z7z9sTM for ; Thu, 6 Aug 2020 21:08:20 +1000 (AEST) Received: from picard.linux.it (localhost [IPv6:::1]) by picard.linux.it (Postfix) with ESMTP id 6763B3C320A for ; Thu, 6 Aug 2020 13:08:10 +0200 (CEST) X-Original-To: ltp@lists.linux.it Delivered-To: ltp@picard.linux.it Received: from in-6.smtp.seeweb.it (in-6.smtp.seeweb.it [217.194.8.6]) by picard.linux.it (Postfix) with ESMTP id 6A9573C13DC for ; Thu, 6 Aug 2020 13:08:08 +0200 (CEST) Received: from mx2.suse.de (mx2.suse.de [195.135.220.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by in-6.smtp.seeweb.it (Postfix) with ESMTPS id 1D4AC14070B7 for ; Thu, 6 Aug 2020 13:08:07 +0200 (CEST) Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id 9CF1AABE9 for ; Thu, 6 Aug 2020 11:08:24 +0000 (UTC) From: Martin Doucha To: ltp@lists.linux.it Date: Thu, 6 Aug 2020 13:08:05 +0200 Message-Id: <20200806110806.28793-1-mdoucha@suse.cz> X-Mailer: git-send-email 2.27.0 MIME-Version: 1.0 X-Virus-Scanned: clamav-milter 0.99.2 at in-6.smtp.seeweb.it X-Virus-Status: Clean X-Spam-Status: No, score=0.0 required=7.0 tests=SPF_HELO_NONE,SPF_PASS autolearn=disabled version=3.4.0 X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on in-6.smtp.seeweb.it Subject: [LTP] [PATCH 1/2] Add some 32-bit instruction macros to BPF LAPI X-BeenThere: ltp@lists.linux.it X-Mailman-Version: 2.1.29 Precedence: list List-Id: Linux Test Project List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ltp-bounces+incoming=patchwork.ozlabs.org@lists.linux.it Sender: "ltp" Signed-off-by: Martin Doucha --- include/lapi/bpf.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/include/lapi/bpf.h b/include/lapi/bpf.h index 22b13b47b..f27a92146 100644 --- a/include/lapi/bpf.h +++ b/include/lapi/bpf.h @@ -449,6 +449,14 @@ enum bpf_func_id { .off = 0, \ .imm = 0 }) +#define BPF_ALU32_REG(OP, DST, SRC) \ + ((struct bpf_insn) { \ + .code = BPF_ALU | BPF_OP(OP) | BPF_X, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = 0, \ + .imm = 0 }) + #define BPF_ALU64_IMM(OP, DST, IMM) \ ((struct bpf_insn) { \ .code = BPF_ALU64 | BPF_OP(OP) | BPF_K, \ @@ -457,6 +465,14 @@ enum bpf_func_id { .off = 0, \ .imm = IMM }) +#define BPF_ALU32_IMM(OP, DST, IMM) \ + ((struct bpf_insn) { \ + .code = BPF_ALU | BPF_OP(OP) | BPF_K, \ + .dst_reg = DST, \ + .src_reg = 0, \ + .off = 0, \ + .imm = IMM }) + #define BPF_MOV64_REG(DST, SRC) \ ((struct bpf_insn) { \ .code = BPF_ALU64 | BPF_MOV | BPF_X, \ @@ -465,6 +481,14 @@ enum bpf_func_id { .off = 0, \ .imm = 0 }) +#define BPF_MOV32_REG(DST, SRC) \ + ((struct bpf_insn) { \ + .code = BPF_ALU | BPF_MOV | BPF_X, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = 0, \ + .imm = 0 }) + #define BPF_LD_IMM64(DST, IMM) \ BPF_LD_IMM64_RAW(DST, 0, IMM) From patchwork Thu Aug 6 11:08:06 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Doucha X-Patchwork-Id: 1341616 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.linux.it (client-ip=2001:1418:10:5::2; helo=picard.linux.it; envelope-from=ltp-bounces+incoming=patchwork.ozlabs.org@lists.linux.it; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.cz Received: from picard.linux.it (picard.linux.it [IPv6:2001:1418:10:5::2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BMm1y3Ympz9sTR for ; Thu, 6 Aug 2020 21:08:22 +1000 (AEST) Received: from picard.linux.it (localhost [IPv6:::1]) by picard.linux.it (Postfix) with ESMTP id 8277F3C3231 for ; Thu, 6 Aug 2020 13:08:19 +0200 (CEST) X-Original-To: ltp@lists.linux.it Delivered-To: ltp@picard.linux.it Received: from in-3.smtp.seeweb.it (in-3.smtp.seeweb.it [217.194.8.3]) by picard.linux.it (Postfix) with ESMTP id 74B123C14A2 for ; Thu, 6 Aug 2020 13:08:08 +0200 (CEST) Received: from mx2.suse.de (mx2.suse.de [195.135.220.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by in-3.smtp.seeweb.it (Postfix) with ESMTPS id 0B4041A008B9 for ; Thu, 6 Aug 2020 13:08:07 +0200 (CEST) Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id B983AACB0 for ; Thu, 6 Aug 2020 11:08:24 +0000 (UTC) From: Martin Doucha To: ltp@lists.linux.it Date: Thu, 6 Aug 2020 13:08:06 +0200 Message-Id: <20200806110806.28793-2-mdoucha@suse.cz> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200806110806.28793-1-mdoucha@suse.cz> References: <20200806110806.28793-1-mdoucha@suse.cz> MIME-Version: 1.0 X-Virus-Scanned: clamav-milter 0.99.2 at in-3.smtp.seeweb.it X-Virus-Status: Clean X-Spam-Status: No, score=0.0 required=7.0 tests=SPF_HELO_NONE,SPF_PASS autolearn=disabled version=3.4.0 X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on in-3.smtp.seeweb.it Subject: [LTP] [PATCH 2/2] Add test for CVE 2018-18445 X-BeenThere: ltp@lists.linux.it X-Mailman-Version: 2.1.29 Precedence: list List-Id: Linux Test Project List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ltp-bounces+incoming=patchwork.ozlabs.org@lists.linux.it Sender: "ltp" Fixes #413 Signed-off-by: Martin Doucha --- I'm not entirely sure whether my assumption that the BPF program must always fail verification is correct. It does fail verification on patched systems. But I'd like an opinion from one of our BPF experts. runtest/cve | 1 + runtest/syscalls | 1 + testcases/kernel/syscalls/bpf/.gitignore | 1 + testcases/kernel/syscalls/bpf/bpf_prog04.c | 145 +++++++++++++++++++++ 4 files changed, 148 insertions(+) create mode 100644 testcases/kernel/syscalls/bpf/bpf_prog04.c diff --git a/runtest/cve b/runtest/cve index fdb455af1..953319735 100644 --- a/runtest/cve +++ b/runtest/cve @@ -51,6 +51,7 @@ cve-2018-9568 connect02 cve-2018-1000001 realpath01 cve-2018-1000199 ptrace08 cve-2018-1000204 ioctl_sg01 +cve-2018-18445 bpf_prog04 cve-2018-18559 bind06 cve-2018-19854 crypto_user01 cve-2020-11494 pty04 diff --git a/runtest/syscalls b/runtest/syscalls index b4c5b1ebe..106010e8d 100644 --- a/runtest/syscalls +++ b/runtest/syscalls @@ -40,6 +40,7 @@ bpf_map01 bpf_map01 bpf_prog01 bpf_prog01 bpf_prog02 bpf_prog02 bpf_prog03 bpf_prog03 +bpf_prog04 bpf_prog04 brk01 brk01 diff --git a/testcases/kernel/syscalls/bpf/.gitignore b/testcases/kernel/syscalls/bpf/.gitignore index 3c33a844b..74742c0cd 100644 --- a/testcases/kernel/syscalls/bpf/.gitignore +++ b/testcases/kernel/syscalls/bpf/.gitignore @@ -2,3 +2,4 @@ bpf_map01 bpf_prog01 bpf_prog02 bpf_prog03 +bpf_prog04 diff --git a/testcases/kernel/syscalls/bpf/bpf_prog04.c b/testcases/kernel/syscalls/bpf/bpf_prog04.c new file mode 100644 index 000000000..36e13034c --- /dev/null +++ b/testcases/kernel/syscalls/bpf/bpf_prog04.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018 Jann Horn + * Copyright (c) 2020 SUSE LLC + */ + +/* + * CVE 2018-18445 + * + * Check that eBPF verifier correctly handles 32-bit arithmetic, in particular + * the right bit shift instruction. It is an error if the BPF program passes + * verification regardless of whether it then causes any actual damage. Kernel + * bug fixed in: + * + * commit b799207e1e1816b09e7a5920fbb2d5fcf6edd681 + * Author: Jann Horn + * Date: Fri Oct 5 18:17:59 2018 +0200 + * + * bpf: 32-bit RSH verification must truncate input before the ALU op + */ + +#include +#include + +#include "config.h" +#include "tst_test.h" +#include "tst_taint.h" +#include "tst_capability.h" +#include "lapi/socket.h" +#include "lapi/bpf.h" +#include "bpf_common.h" + +#define BUFSIZE 8192 +#define CHECK_BPF_RET(x) ((x) >= 0 || ((x) == -1 && errno != EACCES)) + +static const char MSG[] = "Ahoj!"; +static char *msg; + +static char *log; +static union bpf_attr *attr; + +static int load_prog(int fd) +{ + int ret; + struct bpf_insn insn[] = { + BPF_MOV64_IMM(BPF_REG_8, 2), + BPF_ALU64_IMM(BPF_LSH, BPF_REG_8, 31), + BPF_ALU32_IMM(BPF_RSH, BPF_REG_8, 31), + BPF_ALU32_IMM(BPF_SUB, BPF_REG_8, 2), + + // store r8 into map + BPF_LD_MAP_FD(BPF_REG_1, fd), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4), + BPF_ST_MEM(BPF_W, BPF_REG_2, 0, 0), + BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), + BPF_EXIT_INSN(), + BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_8), + BPF_STX_MEM(BPF_DW, BPF_REG_0, BPF_REG_8, 0), + + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN() + }; + + bpf_init_prog_attr(attr, insn, sizeof(insn), log, BUFSIZE); + ret = TST_RETRY_FUNC(bpf(BPF_PROG_LOAD, attr, sizeof(*attr)), + CHECK_BPF_RET); + + if (ret >= 0) { + tst_res(TINFO, "Verification log:"); + fputs(log, stderr); + return ret; + } + + if (ret < -1) + tst_brk(TBROK, "Invalid bpf() return value %d", ret); + + if (!*log) + tst_brk(TBROK | TERRNO, "Failed to load BPF program"); + + tst_res(TPASS | TERRNO, "BPF program failed verification"); + return ret; +} + +static void setup(void) +{ + tst_taint_init(TST_TAINT_W | TST_TAINT_D); + + rlimit_bump_memlock(); + memcpy(msg, MSG, sizeof(MSG)); +} + +static void run(void) +{ + int map_fd, prog_fd; + int sk[2]; + + memset(attr, 0, sizeof(*attr)); + attr->map_type = BPF_MAP_TYPE_ARRAY; + attr->key_size = 4; + attr->value_size = 8; + attr->max_entries = 1; + + map_fd = bpf_map_create(attr); + prog_fd = load_prog(map_fd); + + if (prog_fd >= 0) { + tst_res(TFAIL, "Malicious eBPF code passed verification. " + "Now let's try crashing the kernel."); + SAFE_SOCKETPAIR(AF_UNIX, SOCK_DGRAM, 0, sk); + SAFE_SETSOCKOPT(sk[1], SOL_SOCKET, SO_ATTACH_BPF, &prog_fd, + sizeof(prog_fd)); + + SAFE_WRITE(1, sk[0], msg, sizeof(MSG)); + SAFE_CLOSE(sk[0]); + SAFE_CLOSE(sk[1]); + } + + if (prog_fd >= 0) + SAFE_CLOSE(prog_fd); + + SAFE_CLOSE(map_fd); +} + +static struct tst_test test = { + .setup = setup, + .test_all = run, + .min_kver = "3.18", + .caps = (struct tst_cap []) { + TST_CAP(TST_CAP_DROP, CAP_SYS_ADMIN), + {} + }, + .bufs = (struct tst_buffers []) { + {&log, .size = BUFSIZE}, + {&attr, .size = sizeof(*attr)}, + {&msg, .size = sizeof(MSG)}, + {} + }, + .tags = (const struct tst_tag[]) { + {"linux-git", "b799207e1e18"}, + {"CVE", "2018-18445"}, + {} + } +};