From patchwork Wed Sep 16 15:23:45 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Doucha X-Patchwork-Id: 1365407 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=213.254.12.146; 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 [213.254.12.146]) (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 4Bs3lx4nDtz9sSW for ; Thu, 17 Sep 2020 01:23:55 +1000 (AEST) Received: from picard.linux.it (localhost [IPv6:::1]) by picard.linux.it (Postfix) with ESMTP id 78B923C4EA8 for ; Wed, 16 Sep 2020 17:23:49 +0200 (CEST) X-Original-To: ltp@lists.linux.it Delivered-To: ltp@picard.linux.it Received: from in-5.smtp.seeweb.it (in-5.smtp.seeweb.it [IPv6:2001:4b78:1:20::5]) by picard.linux.it (Postfix) with ESMTP id 0B0523C2AD6 for ; Wed, 16 Sep 2020 17:23:47 +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-5.smtp.seeweb.it (Postfix) with ESMTPS id 59052600A5A for ; Wed, 16 Sep 2020 17:23:47 +0200 (CEST) Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id B7A5AB004 for ; Wed, 16 Sep 2020 15:24:01 +0000 (UTC) From: Martin Doucha To: ltp@lists.linux.it Date: Wed, 16 Sep 2020 17:23:45 +0200 Message-Id: <20200916152345.10835-1-mdoucha@suse.cz> X-Mailer: git-send-email 2.28.0 MIME-Version: 1.0 X-Virus-Scanned: clamav-milter 0.102.4 at in-5.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.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on in-5.smtp.seeweb.it Subject: [LTP] [PATCH] Add test for CVE 2020-14386 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 #724 Signed-off-by: Martin Doucha --- I'd like to include this test int the upcoming release if possible. Tested on kernel v4.4, v4.12 and v5.3 both with and without fixes. runtest/cve | 1 + runtest/syscalls | 1 + testcases/kernel/syscalls/sendto/.gitignore | 1 + testcases/kernel/syscalls/sendto/sendto03.c | 224 ++++++++++++++++++++ 4 files changed, 227 insertions(+) create mode 100644 testcases/kernel/syscalls/sendto/sendto03.c diff --git a/runtest/cve b/runtest/cve index 07c69e8ff..0bb1983bc 100644 --- a/runtest/cve +++ b/runtest/cve @@ -58,4 +58,5 @@ cve-2018-18559 bind06 cve-2018-19854 crypto_user01 cve-2019-8912 af_alg07 cve-2020-11494 pty04 +cve-2020-14386 sendto03 cve-2020-14416 pty03 diff --git a/runtest/syscalls b/runtest/syscalls index ef1a1ba0b..91e6d55ca 100644 --- a/runtest/syscalls +++ b/runtest/syscalls @@ -1206,6 +1206,7 @@ sendmmsg01 sendmmsg01 sendto01 sendto01 sendto02 sendto02 +sendto03 sendto03 set_mempolicy01 set_mempolicy01 set_mempolicy02 set_mempolicy02 diff --git a/testcases/kernel/syscalls/sendto/.gitignore b/testcases/kernel/syscalls/sendto/.gitignore index 8d2bb6b5f..5fd24dfe6 100644 --- a/testcases/kernel/syscalls/sendto/.gitignore +++ b/testcases/kernel/syscalls/sendto/.gitignore @@ -1,2 +1,3 @@ /sendto01 /sendto02 +/sendto03 diff --git a/testcases/kernel/syscalls/sendto/sendto03.c b/testcases/kernel/syscalls/sendto/sendto03.c new file mode 100644 index 000000000..a6332ec52 --- /dev/null +++ b/testcases/kernel/syscalls/sendto/sendto03.c @@ -0,0 +1,224 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2019 SUSE LLC + */ + +/* + * CVE-2020-14386 + * + * Check for vulnerability in tpacket_rcv() which allows an unprivileged user + * to write arbitrary data to a memory area outside the allocated packet + * buffer. Kernel crash fixed in: + * + * commit acf69c946233259ab4d64f8869d4037a198c7f06 + * Author: Or Cohen + * Date: Thu Sep 3 21:05:28 2020 -0700 + * + * net/packet: fix overflow in tpacket_rcv + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tst_test.h" +#include "tst_net.h" + +#define BUFSIZE 1024 + +static int dst_sock = -1, sock = -1; +static unsigned char buf[BUFSIZE]; +static struct sockaddr_ll bind_addr, addr; + +static void setup(void) +{ + int real_uid = getuid(); + int real_gid = getgid(); + struct ifreq ifr; + + SAFE_UNSHARE(CLONE_NEWUSER); + SAFE_UNSHARE(CLONE_NEWNET); + SAFE_FILE_PRINTF("/proc/self/setgroups", "deny"); + SAFE_FILE_PRINTF("/proc/self/uid_map", "0 %d 1", real_uid); + SAFE_FILE_PRINTF("/proc/self/gid_map", "0 %d 1", real_gid); + + sock = SAFE_SOCKET(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + strcpy(ifr.ifr_name, "lo"); + ifr.ifr_flags = IFF_UP; + SAFE_IOCTL(sock, SIOCSIFFLAGS, &ifr); + SAFE_IOCTL(sock, SIOCGIFINDEX, &ifr); + SAFE_CLOSE(sock); + + memset(buf, 0x42, BUFSIZE); + + bind_addr.sll_family = AF_PACKET; + bind_addr.sll_protocol = htons(ETH_P_ALL); + bind_addr.sll_ifindex = ifr.ifr_ifindex; + + addr.sll_family = AF_PACKET; + addr.sll_ifindex = ifr.ifr_ifindex; + addr.sll_halen = ETH_ALEN; +} + +/* Test for commit bcc5364bdcfe (cap PACKET_RESERVE to INT_MAX) */ +static int check_tiny_frame(void) +{ + unsigned int val = (UINT_MAX - TPACKET2_HDRLEN) + 1; + struct tpacket_req tpreq; + + tpreq.tp_block_size = SAFE_SYSCONF(_SC_PAGESIZE); + tpreq.tp_frame_size = TPACKET_ALIGNMENT; + tpreq.tp_block_nr = 1; + tpreq.tp_frame_nr = (tpreq.tp_block_size * tpreq.tp_block_nr) / + tpreq.tp_frame_size; + + dst_sock = SAFE_SOCKET(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + SAFE_SETSOCKOPT_INT(dst_sock, SOL_PACKET, PACKET_VERSION, TPACKET_V2); + TEST(setsockopt(dst_sock, SOL_PACKET, PACKET_RESERVE, &val, + sizeof(val))); + + if (TST_RET == -1 && TST_ERR == EINVAL) { + SAFE_CLOSE(dst_sock); + tst_res(TPASS | TTERRNO, + "setsockopt(PACKET_RESERVE) value is capped"); + return 0; + } + + if (TST_RET == -1) { + tst_brk(TBROK | TTERRNO, + "setsockopt(PACKET_RESERVE): unexpected error"); + } + + if (TST_RET) { + tst_brk(TBROK | TTERRNO, + "Invalid setsockopt(PACKET_RESERVE) return value"); + } + + tst_res(TINFO, "setsockopt(PACKET_RESERVE) accepted too large value"); + tst_res(TINFO, "Checking whether this will cause integer overflow..."); + TEST(setsockopt(dst_sock, SOL_PACKET, PACKET_RX_RING, &tpreq, + sizeof(tpreq))); + SAFE_CLOSE(dst_sock); + + if (!TST_RET) { + tst_res(TFAIL, "setsockopt(PACKET_RX_RING) accepted frame " + "size smaller than packet header"); + return 0; + } + + if (TST_RET != -1) { + tst_brk(TBROK | TTERRNO, + "Invalid setsockopt(PACKET_RX_RING) return value"); + } + + if (TST_ERR != EINVAL) { + tst_brk(TBROK | TTERRNO, + "setsockopt(PACKET_RX_RING): unexpeced error"); + } + + tst_res(TPASS | TTERRNO, "setsockopt(PACKET_RX_RING) frame size check " + "rejects values smaller than packet header"); + /* This test case should not cause kernel taint, skip taint check */ + return 0; +} + +/* Test for commit acf69c946233 (drop packet if netoff overflows) */ +static int check_vnet_hdr(void) +{ + struct tpacket_req tpreq; + size_t blocksize = 0x800000, pagesize = SAFE_SYSCONF(_SC_PAGESIZE); + + /* Make sure blocksize is big enough and pagesize aligned */ + if (blocksize % pagesize) + blocksize += pagesize - (blocksize % pagesize); + + tpreq.tp_block_size = blocksize; + tpreq.tp_frame_size = 0x11000; + tpreq.tp_block_nr = 1; + tpreq.tp_frame_nr = (tpreq.tp_block_size * tpreq.tp_block_nr) / + tpreq.tp_frame_size; + + dst_sock = SAFE_SOCKET(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + SAFE_SETSOCKOPT_INT(dst_sock, SOL_PACKET, PACKET_VERSION, TPACKET_V2); + SAFE_SETSOCKOPT_INT(dst_sock, SOL_PACKET, PACKET_VNET_HDR, 1); + SAFE_SETSOCKOPT_INT(dst_sock, SOL_PACKET, PACKET_RESERVE, 0xffff - 75); + TEST(setsockopt(dst_sock, SOL_PACKET, PACKET_RX_RING, &tpreq, + sizeof(tpreq))); + + if (TST_RET == -1 && TST_ERR == EINVAL) { + SAFE_CLOSE(dst_sock); + tst_res(TCONF, "PACKET_VNET_HDR and PACKET_RX_RING not " + "supported together"); + return 0; + } + + if (TST_RET == -1) { + tst_brk(TBROK | TTERRNO, + "setsockopt(PACKET_RX_RING): unexpected error"); + } + + if (TST_RET) { + tst_brk(TBROK | TTERRNO, + "Invalid setsockopt(PACKET_RX_RING) return value"); + } + + SAFE_BIND(dst_sock, (struct sockaddr *)&bind_addr, sizeof(addr)); + + sock = SAFE_SOCKET(AF_PACKET, SOCK_RAW, IPPROTO_RAW); + SAFE_SENDTO(1, sock, buf, BUFSIZE, 0, (struct sockaddr *)&addr, + sizeof(addr)); + + SAFE_CLOSE(sock); + SAFE_CLOSE(dst_sock); + return 1; /* Continue to taint check */ +} + +static int (*testcase_list[])(void) = {check_tiny_frame, check_vnet_hdr}; + +static void run(unsigned int n) +{ + if (!testcase_list[n]()) + return; + + if (tst_taint_check()) { + tst_res(TFAIL, "Kernel is vulnerable"); + return; + } + + tst_res(TPASS, "Nothing bad happened, probably"); +} + +static void cleanup(void) +{ + if (sock != -1) + SAFE_CLOSE(sock); + + if (dst_sock != -1) + SAFE_CLOSE(dst_sock); +} + +static struct tst_test test = { + .test = run, + .tcnt = ARRAY_SIZE(testcase_list), + .setup = setup, + .cleanup = cleanup, + .taint_check = TST_TAINT_W | TST_TAINT_D, + .needs_kconfigs = (const char *[]) { + "CONFIG_USER_NS=y", + "CONFIG_NET_NS=y", + NULL + }, + .tags = (const struct tst_tag[]) { + {"linux-git", "bcc5364bdcfe"}, + {"linux-git", "acf69c946233"}, + {"CVE", "2020-14386"}, + {} + } +};