1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) 2020 SUSE LLC <mdoucha@suse.cz> 4f08c3bdfSopenharmony_ci */ 5f08c3bdfSopenharmony_ci 6f08c3bdfSopenharmony_ci/* 7f08c3bdfSopenharmony_ci * CVE-2017-1000111 8f08c3bdfSopenharmony_ci * 9f08c3bdfSopenharmony_ci * Check for race condition between packet_set_ring() and tp_reserve. 10f08c3bdfSopenharmony_ci * The race allows you to set tp_reserve bigger than ring buffer size. 11f08c3bdfSopenharmony_ci * While this will cause truncation of all incoming packets to 0 bytes, 12f08c3bdfSopenharmony_ci * sanity checks in tpacket_rcv() prevent any exploitable buffer overflows. 13f08c3bdfSopenharmony_ci * Race fixed in: 14f08c3bdfSopenharmony_ci * 15f08c3bdfSopenharmony_ci * commit c27927e372f0785f3303e8fad94b85945e2c97b7 (HEAD) 16f08c3bdfSopenharmony_ci * Author: Willem de Bruijn <willemb@google.com> 17f08c3bdfSopenharmony_ci * Date: Thu Aug 10 12:41:58 2017 -0400 18f08c3bdfSopenharmony_ci * 19f08c3bdfSopenharmony_ci * packet: fix tp_reserve race in packet_set_ring 20f08c3bdfSopenharmony_ci */ 21f08c3bdfSopenharmony_ci 22f08c3bdfSopenharmony_ci#include <unistd.h> 23f08c3bdfSopenharmony_ci#include <sys/types.h> 24f08c3bdfSopenharmony_ci#include <sys/socket.h> 25f08c3bdfSopenharmony_ci 26f08c3bdfSopenharmony_ci#include "tst_test.h" 27f08c3bdfSopenharmony_ci#include "tst_fuzzy_sync.h" 28f08c3bdfSopenharmony_ci#include "lapi/if_packet.h" 29f08c3bdfSopenharmony_ci#include "lapi/if_ether.h" 30f08c3bdfSopenharmony_ci 31f08c3bdfSopenharmony_cistatic int sock = -1; 32f08c3bdfSopenharmony_cistatic unsigned int pagesize; 33f08c3bdfSopenharmony_cistatic struct tst_fzsync_pair fzsync_pair; 34f08c3bdfSopenharmony_ci 35f08c3bdfSopenharmony_cistatic void setup(void) 36f08c3bdfSopenharmony_ci{ 37f08c3bdfSopenharmony_ci pagesize = SAFE_SYSCONF(_SC_PAGESIZE); 38f08c3bdfSopenharmony_ci tst_setup_netns(); 39f08c3bdfSopenharmony_ci 40f08c3bdfSopenharmony_ci /* 41f08c3bdfSopenharmony_ci * Reproducing the bug on unpatched system takes <15 loops. The test 42f08c3bdfSopenharmony_ci * is slow and the bug is mostly harmless so don't waste too much 43f08c3bdfSopenharmony_ci * time. 44f08c3bdfSopenharmony_ci */ 45f08c3bdfSopenharmony_ci fzsync_pair.exec_loops = 500; 46f08c3bdfSopenharmony_ci tst_fzsync_pair_init(&fzsync_pair); 47f08c3bdfSopenharmony_ci} 48f08c3bdfSopenharmony_ci 49f08c3bdfSopenharmony_cistatic void *thread_run(void *arg) 50f08c3bdfSopenharmony_ci{ 51f08c3bdfSopenharmony_ci unsigned int val = 1 << 30; 52f08c3bdfSopenharmony_ci 53f08c3bdfSopenharmony_ci while (tst_fzsync_run_b(&fzsync_pair)) { 54f08c3bdfSopenharmony_ci tst_fzsync_start_race_b(&fzsync_pair); 55f08c3bdfSopenharmony_ci setsockopt(sock, SOL_PACKET, PACKET_RESERVE, &val, sizeof(val)); 56f08c3bdfSopenharmony_ci tst_fzsync_end_race_b(&fzsync_pair); 57f08c3bdfSopenharmony_ci } 58f08c3bdfSopenharmony_ci 59f08c3bdfSopenharmony_ci return arg; 60f08c3bdfSopenharmony_ci} 61f08c3bdfSopenharmony_ci 62f08c3bdfSopenharmony_cistatic void run(void) 63f08c3bdfSopenharmony_ci{ 64f08c3bdfSopenharmony_ci unsigned int val, version = TPACKET_V3; 65f08c3bdfSopenharmony_ci socklen_t vsize = sizeof(val); 66f08c3bdfSopenharmony_ci struct tpacket_req3 req = { 67f08c3bdfSopenharmony_ci .tp_block_size = pagesize, 68f08c3bdfSopenharmony_ci .tp_block_nr = 1, 69f08c3bdfSopenharmony_ci .tp_frame_size = pagesize, 70f08c3bdfSopenharmony_ci .tp_frame_nr = 1, 71f08c3bdfSopenharmony_ci .tp_retire_blk_tov = 100 72f08c3bdfSopenharmony_ci }; 73f08c3bdfSopenharmony_ci 74f08c3bdfSopenharmony_ci tst_fzsync_pair_reset(&fzsync_pair, thread_run); 75f08c3bdfSopenharmony_ci 76f08c3bdfSopenharmony_ci while (tst_fzsync_run_a(&fzsync_pair)) { 77f08c3bdfSopenharmony_ci sock = SAFE_SOCKET(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); 78f08c3bdfSopenharmony_ci TEST(setsockopt(sock, SOL_PACKET, PACKET_VERSION, &version, 79f08c3bdfSopenharmony_ci sizeof(version))); 80f08c3bdfSopenharmony_ci 81f08c3bdfSopenharmony_ci if (TST_RET == -1 && TST_ERR == EINVAL) 82f08c3bdfSopenharmony_ci tst_brk(TCONF | TTERRNO, "TPACKET_V3 not supported"); 83f08c3bdfSopenharmony_ci 84f08c3bdfSopenharmony_ci if (TST_RET) { 85f08c3bdfSopenharmony_ci tst_brk(TBROK | TTERRNO, 86f08c3bdfSopenharmony_ci "setsockopt(PACKET_VERSION, TPACKET_V3"); 87f08c3bdfSopenharmony_ci } 88f08c3bdfSopenharmony_ci 89f08c3bdfSopenharmony_ci tst_fzsync_start_race_a(&fzsync_pair); 90f08c3bdfSopenharmony_ci TEST(setsockopt(sock, SOL_PACKET, PACKET_RX_RING, &req, 91f08c3bdfSopenharmony_ci sizeof(req))); 92f08c3bdfSopenharmony_ci tst_fzsync_end_race_a(&fzsync_pair); 93f08c3bdfSopenharmony_ci 94f08c3bdfSopenharmony_ci SAFE_GETSOCKOPT(sock, SOL_PACKET, PACKET_RESERVE, &val, &vsize); 95f08c3bdfSopenharmony_ci SAFE_CLOSE(sock); 96f08c3bdfSopenharmony_ci 97f08c3bdfSopenharmony_ci if (TST_RET == -1 && TST_ERR == EINVAL) { 98f08c3bdfSopenharmony_ci tst_fzsync_pair_add_bias(&fzsync_pair, 1); 99f08c3bdfSopenharmony_ci continue; 100f08c3bdfSopenharmony_ci } 101f08c3bdfSopenharmony_ci 102f08c3bdfSopenharmony_ci if (TST_RET) { 103f08c3bdfSopenharmony_ci tst_brk(TBROK | TTERRNO, 104f08c3bdfSopenharmony_ci "Invalid setsockopt() return value"); 105f08c3bdfSopenharmony_ci } 106f08c3bdfSopenharmony_ci 107f08c3bdfSopenharmony_ci if (val > req.tp_block_size) { 108f08c3bdfSopenharmony_ci tst_res(TFAIL, "PACKET_RESERVE checks bypassed"); 109f08c3bdfSopenharmony_ci return; 110f08c3bdfSopenharmony_ci } 111f08c3bdfSopenharmony_ci } 112f08c3bdfSopenharmony_ci 113f08c3bdfSopenharmony_ci tst_res(TPASS, "Cannot reproduce bug"); 114f08c3bdfSopenharmony_ci} 115f08c3bdfSopenharmony_ci 116f08c3bdfSopenharmony_cistatic void cleanup(void) 117f08c3bdfSopenharmony_ci{ 118f08c3bdfSopenharmony_ci tst_fzsync_pair_cleanup(&fzsync_pair); 119f08c3bdfSopenharmony_ci 120f08c3bdfSopenharmony_ci if (sock >= 0) 121f08c3bdfSopenharmony_ci SAFE_CLOSE(sock); 122f08c3bdfSopenharmony_ci} 123f08c3bdfSopenharmony_ci 124f08c3bdfSopenharmony_cistatic struct tst_test test = { 125f08c3bdfSopenharmony_ci .test_all = run, 126f08c3bdfSopenharmony_ci .setup = setup, 127f08c3bdfSopenharmony_ci .cleanup = cleanup, 128f08c3bdfSopenharmony_ci .max_runtime = 150, 129f08c3bdfSopenharmony_ci .needs_kconfigs = (const char *[]) { 130f08c3bdfSopenharmony_ci "CONFIG_USER_NS=y", 131f08c3bdfSopenharmony_ci "CONFIG_NET_NS=y", 132f08c3bdfSopenharmony_ci NULL 133f08c3bdfSopenharmony_ci }, 134f08c3bdfSopenharmony_ci .save_restore = (const struct tst_path_val[]) { 135f08c3bdfSopenharmony_ci {"/proc/sys/user/max_user_namespaces", "1024", TST_SR_SKIP}, 136f08c3bdfSopenharmony_ci {} 137f08c3bdfSopenharmony_ci }, 138f08c3bdfSopenharmony_ci .tags = (const struct tst_tag[]) { 139f08c3bdfSopenharmony_ci {"linux-git", "c27927e372f0"}, 140f08c3bdfSopenharmony_ci {"CVE", "2017-1000111"}, 141f08c3bdfSopenharmony_ci {} 142f08c3bdfSopenharmony_ci } 143f08c3bdfSopenharmony_ci}; 144