1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) 2019 SUSE LLC <mdoucha@suse.cz> 4f08c3bdfSopenharmony_ci */ 5f08c3bdfSopenharmony_ci 6f08c3bdfSopenharmony_ci/* 7f08c3bdfSopenharmony_ci * CVE-2020-14386 8f08c3bdfSopenharmony_ci * 9f08c3bdfSopenharmony_ci * Check for vulnerability in tpacket_rcv() which allows an unprivileged user 10f08c3bdfSopenharmony_ci * to write arbitrary data to a memory area outside the allocated packet 11f08c3bdfSopenharmony_ci * buffer. Kernel crash fixed in: 12f08c3bdfSopenharmony_ci * 13f08c3bdfSopenharmony_ci * commit acf69c946233259ab4d64f8869d4037a198c7f06 14f08c3bdfSopenharmony_ci * Author: Or Cohen <orcohen@paloaltonetworks.com> 15f08c3bdfSopenharmony_ci * Date: Thu Sep 3 21:05:28 2020 -0700 16f08c3bdfSopenharmony_ci * 17f08c3bdfSopenharmony_ci * net/packet: fix overflow in tpacket_rcv 18f08c3bdfSopenharmony_ci */ 19f08c3bdfSopenharmony_ci 20f08c3bdfSopenharmony_ci#include <stdio.h> 21f08c3bdfSopenharmony_ci#include <limits.h> 22f08c3bdfSopenharmony_ci#include <sys/types.h> 23f08c3bdfSopenharmony_ci#include <sys/socket.h> 24f08c3bdfSopenharmony_ci#include <sys/ioctl.h> 25f08c3bdfSopenharmony_ci#include <net/if.h> 26f08c3bdfSopenharmony_ci#include <net/ethernet.h> 27f08c3bdfSopenharmony_ci 28f08c3bdfSopenharmony_ci#include "tst_test.h" 29f08c3bdfSopenharmony_ci#include "tst_net.h" 30f08c3bdfSopenharmony_ci#include "lapi/if_packet.h" 31f08c3bdfSopenharmony_ci 32f08c3bdfSopenharmony_ci#define BUFSIZE 1024 33f08c3bdfSopenharmony_ci 34f08c3bdfSopenharmony_cistatic int dst_sock = -1, sock = -1; 35f08c3bdfSopenharmony_cistatic unsigned char buf[BUFSIZE]; 36f08c3bdfSopenharmony_cistatic struct sockaddr_ll bind_addr, addr; 37f08c3bdfSopenharmony_ci 38f08c3bdfSopenharmony_cistatic void setup(void) 39f08c3bdfSopenharmony_ci{ 40f08c3bdfSopenharmony_ci struct ifreq ifr; 41f08c3bdfSopenharmony_ci 42f08c3bdfSopenharmony_ci tst_setup_netns(); 43f08c3bdfSopenharmony_ci 44f08c3bdfSopenharmony_ci sock = SAFE_SOCKET(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); 45f08c3bdfSopenharmony_ci strcpy(ifr.ifr_name, "lo"); 46f08c3bdfSopenharmony_ci ifr.ifr_flags = IFF_UP; 47f08c3bdfSopenharmony_ci SAFE_IOCTL(sock, SIOCSIFFLAGS, &ifr); 48f08c3bdfSopenharmony_ci SAFE_IOCTL(sock, SIOCGIFINDEX, &ifr); 49f08c3bdfSopenharmony_ci SAFE_CLOSE(sock); 50f08c3bdfSopenharmony_ci 51f08c3bdfSopenharmony_ci memset(buf, 0x42, BUFSIZE); 52f08c3bdfSopenharmony_ci 53f08c3bdfSopenharmony_ci bind_addr.sll_family = AF_PACKET; 54f08c3bdfSopenharmony_ci bind_addr.sll_protocol = htons(ETH_P_ALL); 55f08c3bdfSopenharmony_ci bind_addr.sll_ifindex = ifr.ifr_ifindex; 56f08c3bdfSopenharmony_ci 57f08c3bdfSopenharmony_ci addr.sll_family = AF_PACKET; 58f08c3bdfSopenharmony_ci addr.sll_ifindex = ifr.ifr_ifindex; 59f08c3bdfSopenharmony_ci addr.sll_halen = ETH_ALEN; 60f08c3bdfSopenharmony_ci} 61f08c3bdfSopenharmony_ci 62f08c3bdfSopenharmony_ci/* Test for commit bcc5364bdcfe (cap PACKET_RESERVE to INT_MAX) */ 63f08c3bdfSopenharmony_cistatic int check_tiny_frame(void) 64f08c3bdfSopenharmony_ci{ 65f08c3bdfSopenharmony_ci unsigned int val = (UINT_MAX - TPACKET2_HDRLEN) + 1; 66f08c3bdfSopenharmony_ci struct tpacket_req tpreq; 67f08c3bdfSopenharmony_ci 68f08c3bdfSopenharmony_ci tpreq.tp_block_size = SAFE_SYSCONF(_SC_PAGESIZE); 69f08c3bdfSopenharmony_ci tpreq.tp_frame_size = TPACKET_ALIGNMENT; 70f08c3bdfSopenharmony_ci tpreq.tp_block_nr = 1; 71f08c3bdfSopenharmony_ci tpreq.tp_frame_nr = (tpreq.tp_block_size * tpreq.tp_block_nr) / 72f08c3bdfSopenharmony_ci tpreq.tp_frame_size; 73f08c3bdfSopenharmony_ci 74f08c3bdfSopenharmony_ci dst_sock = SAFE_SOCKET(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); 75f08c3bdfSopenharmony_ci SAFE_SETSOCKOPT_INT(dst_sock, SOL_PACKET, PACKET_VERSION, TPACKET_V2); 76f08c3bdfSopenharmony_ci TEST(setsockopt(dst_sock, SOL_PACKET, PACKET_RESERVE, &val, 77f08c3bdfSopenharmony_ci sizeof(val))); 78f08c3bdfSopenharmony_ci 79f08c3bdfSopenharmony_ci if (TST_RET == -1 && TST_ERR == EINVAL) { 80f08c3bdfSopenharmony_ci SAFE_CLOSE(dst_sock); 81f08c3bdfSopenharmony_ci tst_res(TPASS | TTERRNO, 82f08c3bdfSopenharmony_ci "setsockopt(PACKET_RESERVE) value is capped"); 83f08c3bdfSopenharmony_ci return 0; 84f08c3bdfSopenharmony_ci } 85f08c3bdfSopenharmony_ci 86f08c3bdfSopenharmony_ci if (TST_RET == -1) { 87f08c3bdfSopenharmony_ci tst_brk(TBROK | TTERRNO, 88f08c3bdfSopenharmony_ci "setsockopt(PACKET_RESERVE): unexpected error"); 89f08c3bdfSopenharmony_ci } 90f08c3bdfSopenharmony_ci 91f08c3bdfSopenharmony_ci if (TST_RET) { 92f08c3bdfSopenharmony_ci tst_brk(TBROK | TTERRNO, 93f08c3bdfSopenharmony_ci "Invalid setsockopt(PACKET_RESERVE) return value"); 94f08c3bdfSopenharmony_ci } 95f08c3bdfSopenharmony_ci 96f08c3bdfSopenharmony_ci tst_res(TINFO, "setsockopt(PACKET_RESERVE) accepted too large value"); 97f08c3bdfSopenharmony_ci tst_res(TINFO, "Checking whether this will cause integer overflow..."); 98f08c3bdfSopenharmony_ci TEST(setsockopt(dst_sock, SOL_PACKET, PACKET_RX_RING, &tpreq, 99f08c3bdfSopenharmony_ci sizeof(tpreq))); 100f08c3bdfSopenharmony_ci SAFE_CLOSE(dst_sock); 101f08c3bdfSopenharmony_ci 102f08c3bdfSopenharmony_ci if (!TST_RET) { 103f08c3bdfSopenharmony_ci tst_res(TFAIL, "setsockopt(PACKET_RX_RING) accepted frame " 104f08c3bdfSopenharmony_ci "size smaller than packet header"); 105f08c3bdfSopenharmony_ci return 0; 106f08c3bdfSopenharmony_ci } 107f08c3bdfSopenharmony_ci 108f08c3bdfSopenharmony_ci if (TST_RET != -1) { 109f08c3bdfSopenharmony_ci tst_brk(TBROK | TTERRNO, 110f08c3bdfSopenharmony_ci "Invalid setsockopt(PACKET_RX_RING) return value"); 111f08c3bdfSopenharmony_ci } 112f08c3bdfSopenharmony_ci 113f08c3bdfSopenharmony_ci if (TST_ERR != EINVAL) { 114f08c3bdfSopenharmony_ci tst_brk(TBROK | TTERRNO, 115f08c3bdfSopenharmony_ci "setsockopt(PACKET_RX_RING): unexpeced error"); 116f08c3bdfSopenharmony_ci } 117f08c3bdfSopenharmony_ci 118f08c3bdfSopenharmony_ci tst_res(TPASS | TTERRNO, "setsockopt(PACKET_RX_RING) frame size check " 119f08c3bdfSopenharmony_ci "rejects values smaller than packet header"); 120f08c3bdfSopenharmony_ci /* This test case should not cause kernel taint, skip taint check */ 121f08c3bdfSopenharmony_ci return 0; 122f08c3bdfSopenharmony_ci} 123f08c3bdfSopenharmony_ci 124f08c3bdfSopenharmony_ci/* Test for commit acf69c946233 (drop packet if netoff overflows) */ 125f08c3bdfSopenharmony_cistatic int check_vnet_hdr(void) 126f08c3bdfSopenharmony_ci{ 127f08c3bdfSopenharmony_ci struct tpacket_req tpreq; 128f08c3bdfSopenharmony_ci size_t blocksize = 0x800000, pagesize = SAFE_SYSCONF(_SC_PAGESIZE); 129f08c3bdfSopenharmony_ci 130f08c3bdfSopenharmony_ci /* Make sure blocksize is big enough and pagesize aligned */ 131f08c3bdfSopenharmony_ci if (blocksize % pagesize) 132f08c3bdfSopenharmony_ci blocksize += pagesize - (blocksize % pagesize); 133f08c3bdfSopenharmony_ci 134f08c3bdfSopenharmony_ci tpreq.tp_block_size = blocksize; 135f08c3bdfSopenharmony_ci tpreq.tp_frame_size = 0x11000; 136f08c3bdfSopenharmony_ci tpreq.tp_block_nr = 1; 137f08c3bdfSopenharmony_ci tpreq.tp_frame_nr = (tpreq.tp_block_size * tpreq.tp_block_nr) / 138f08c3bdfSopenharmony_ci tpreq.tp_frame_size; 139f08c3bdfSopenharmony_ci 140f08c3bdfSopenharmony_ci dst_sock = SAFE_SOCKET(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); 141f08c3bdfSopenharmony_ci SAFE_SETSOCKOPT_INT(dst_sock, SOL_PACKET, PACKET_VERSION, TPACKET_V2); 142f08c3bdfSopenharmony_ci SAFE_SETSOCKOPT_INT(dst_sock, SOL_PACKET, PACKET_VNET_HDR, 1); 143f08c3bdfSopenharmony_ci SAFE_SETSOCKOPT_INT(dst_sock, SOL_PACKET, PACKET_RESERVE, 0xffff - 75); 144f08c3bdfSopenharmony_ci TEST(setsockopt(dst_sock, SOL_PACKET, PACKET_RX_RING, &tpreq, 145f08c3bdfSopenharmony_ci sizeof(tpreq))); 146f08c3bdfSopenharmony_ci 147f08c3bdfSopenharmony_ci if (TST_RET == -1 && TST_ERR == EINVAL) { 148f08c3bdfSopenharmony_ci SAFE_CLOSE(dst_sock); 149f08c3bdfSopenharmony_ci tst_res(TCONF, "PACKET_VNET_HDR and PACKET_RX_RING not " 150f08c3bdfSopenharmony_ci "supported together"); 151f08c3bdfSopenharmony_ci return 0; 152f08c3bdfSopenharmony_ci } 153f08c3bdfSopenharmony_ci 154f08c3bdfSopenharmony_ci if (TST_RET == -1) { 155f08c3bdfSopenharmony_ci tst_brk(TBROK | TTERRNO, 156f08c3bdfSopenharmony_ci "setsockopt(PACKET_RX_RING): unexpected error"); 157f08c3bdfSopenharmony_ci } 158f08c3bdfSopenharmony_ci 159f08c3bdfSopenharmony_ci if (TST_RET) { 160f08c3bdfSopenharmony_ci tst_brk(TBROK | TTERRNO, 161f08c3bdfSopenharmony_ci "Invalid setsockopt(PACKET_RX_RING) return value"); 162f08c3bdfSopenharmony_ci } 163f08c3bdfSopenharmony_ci 164f08c3bdfSopenharmony_ci SAFE_BIND(dst_sock, (struct sockaddr *)&bind_addr, sizeof(addr)); 165f08c3bdfSopenharmony_ci 166f08c3bdfSopenharmony_ci sock = SAFE_SOCKET(AF_PACKET, SOCK_RAW, IPPROTO_RAW); 167f08c3bdfSopenharmony_ci SAFE_SENDTO(1, sock, buf, BUFSIZE, 0, (struct sockaddr *)&addr, 168f08c3bdfSopenharmony_ci sizeof(addr)); 169f08c3bdfSopenharmony_ci 170f08c3bdfSopenharmony_ci SAFE_CLOSE(sock); 171f08c3bdfSopenharmony_ci SAFE_CLOSE(dst_sock); 172f08c3bdfSopenharmony_ci return 1; /* Continue to taint check */ 173f08c3bdfSopenharmony_ci} 174f08c3bdfSopenharmony_ci 175f08c3bdfSopenharmony_cistatic int (*testcase_list[])(void) = {check_tiny_frame, check_vnet_hdr}; 176f08c3bdfSopenharmony_ci 177f08c3bdfSopenharmony_cistatic void run(unsigned int n) 178f08c3bdfSopenharmony_ci{ 179f08c3bdfSopenharmony_ci if (!testcase_list[n]()) 180f08c3bdfSopenharmony_ci return; 181f08c3bdfSopenharmony_ci 182f08c3bdfSopenharmony_ci if (tst_taint_check()) { 183f08c3bdfSopenharmony_ci tst_res(TFAIL, "Kernel is vulnerable"); 184f08c3bdfSopenharmony_ci return; 185f08c3bdfSopenharmony_ci } 186f08c3bdfSopenharmony_ci 187f08c3bdfSopenharmony_ci tst_res(TPASS, "Nothing bad happened, probably"); 188f08c3bdfSopenharmony_ci} 189f08c3bdfSopenharmony_ci 190f08c3bdfSopenharmony_cistatic void cleanup(void) 191f08c3bdfSopenharmony_ci{ 192f08c3bdfSopenharmony_ci if (sock != -1) 193f08c3bdfSopenharmony_ci SAFE_CLOSE(sock); 194f08c3bdfSopenharmony_ci 195f08c3bdfSopenharmony_ci if (dst_sock != -1) 196f08c3bdfSopenharmony_ci SAFE_CLOSE(dst_sock); 197f08c3bdfSopenharmony_ci} 198f08c3bdfSopenharmony_ci 199f08c3bdfSopenharmony_cistatic struct tst_test test = { 200f08c3bdfSopenharmony_ci .test = run, 201f08c3bdfSopenharmony_ci .tcnt = ARRAY_SIZE(testcase_list), 202f08c3bdfSopenharmony_ci .setup = setup, 203f08c3bdfSopenharmony_ci .cleanup = cleanup, 204f08c3bdfSopenharmony_ci .taint_check = TST_TAINT_W | TST_TAINT_D, 205f08c3bdfSopenharmony_ci .needs_kconfigs = (const char *[]) { 206f08c3bdfSopenharmony_ci "CONFIG_USER_NS=y", 207f08c3bdfSopenharmony_ci "CONFIG_NET_NS=y", 208f08c3bdfSopenharmony_ci NULL 209f08c3bdfSopenharmony_ci }, 210f08c3bdfSopenharmony_ci .save_restore = (const struct tst_path_val[]) { 211f08c3bdfSopenharmony_ci {"/proc/sys/user/max_user_namespaces", "1024", TST_SR_SKIP}, 212f08c3bdfSopenharmony_ci {} 213f08c3bdfSopenharmony_ci }, 214f08c3bdfSopenharmony_ci .tags = (const struct tst_tag[]) { 215f08c3bdfSopenharmony_ci {"linux-git", "bcc5364bdcfe"}, 216f08c3bdfSopenharmony_ci {"linux-git", "acf69c946233"}, 217f08c3bdfSopenharmony_ci {"CVE", "2020-14386"}, 218f08c3bdfSopenharmony_ci {} 219f08c3bdfSopenharmony_ci } 220f08c3bdfSopenharmony_ci}; 221