1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) 2018 Oracle and/or its affiliates. All Rights Reserved. 4f08c3bdfSopenharmony_ci * Copyright (c) Linux Test Project, 2019-2023 5f08c3bdfSopenharmony_ci */ 6f08c3bdfSopenharmony_ci 7f08c3bdfSopenharmony_ci/*\ 8f08c3bdfSopenharmony_ci * [Description] 9f08c3bdfSopenharmony_ci * 10f08c3bdfSopenharmony_ci * Regression test for the crash caused by over-sized SCTP chunk, 11f08c3bdfSopenharmony_ci * fixed by upstream commit 07f2c7ab6f8d ("sctp: verify size of a new 12f08c3bdfSopenharmony_ci * chunk in _sctp_make_chunk()"). 13f08c3bdfSopenharmony_ci */ 14f08c3bdfSopenharmony_ci 15f08c3bdfSopenharmony_ci#include <stdlib.h> 16f08c3bdfSopenharmony_ci#include <unistd.h> 17f08c3bdfSopenharmony_ci#include <sys/types.h> 18f08c3bdfSopenharmony_ci#include <sys/socket.h> 19f08c3bdfSopenharmony_ci#include <netinet/in.h> 20f08c3bdfSopenharmony_ci#include <netinet/ip.h> 21f08c3bdfSopenharmony_ci#include <netinet/ip6.h> 22f08c3bdfSopenharmony_ci#include <netdb.h> 23f08c3bdfSopenharmony_ci#include <sys/syscall.h> 24f08c3bdfSopenharmony_ci 25f08c3bdfSopenharmony_ci#include "tst_test.h" 26f08c3bdfSopenharmony_ci#include "tst_safe_stdio.h" 27f08c3bdfSopenharmony_ci#include "tst_checksum.h" 28f08c3bdfSopenharmony_ci#include "lapi/netinet_in.h" 29f08c3bdfSopenharmony_ci#include "lapi/socket.h" 30f08c3bdfSopenharmony_ci#include "lapi/sctp.h" 31f08c3bdfSopenharmony_ci 32f08c3bdfSopenharmony_cistatic int port; 33f08c3bdfSopenharmony_cistatic int sfd, cfd; 34f08c3bdfSopenharmony_cistatic struct sockaddr_in6 rmt, loc; 35f08c3bdfSopenharmony_ci 36f08c3bdfSopenharmony_cistatic uint8_t packet[IP_MAXPACKET]; 37f08c3bdfSopenharmony_cistatic int pkt_len; 38f08c3bdfSopenharmony_cistatic char *addr_param; 39f08c3bdfSopenharmony_cistatic int addr_num = 3273; 40f08c3bdfSopenharmony_ci 41f08c3bdfSopenharmony_cistatic void setup_server(void) 42f08c3bdfSopenharmony_ci{ 43f08c3bdfSopenharmony_ci const char hmac_algo_path[] = "/proc/sys/net/sctp/cookie_hmac_alg"; 44f08c3bdfSopenharmony_ci char hmac_algo[CHAR_MAX]; 45f08c3bdfSopenharmony_ci int hmac_algo_changed = 0; 46f08c3bdfSopenharmony_ci int fd; 47f08c3bdfSopenharmony_ci 48f08c3bdfSopenharmony_ci /* Disable md5 if fips is enabled. Set it to none */ 49f08c3bdfSopenharmony_ci if (tst_fips_enabled()) { 50f08c3bdfSopenharmony_ci /* Load sctp module */ 51f08c3bdfSopenharmony_ci if (access(hmac_algo_path, F_OK) < 0) { 52f08c3bdfSopenharmony_ci fd = SAFE_SOCKET(PF_INET, SOCK_STREAM, IPPROTO_SCTP); 53f08c3bdfSopenharmony_ci SAFE_CLOSE(fd); 54f08c3bdfSopenharmony_ci } 55f08c3bdfSopenharmony_ci 56f08c3bdfSopenharmony_ci if (!access(hmac_algo_path, F_OK)) { 57f08c3bdfSopenharmony_ci SAFE_FILE_SCANF(hmac_algo_path, "%s", hmac_algo); 58f08c3bdfSopenharmony_ci SAFE_FILE_PRINTF(hmac_algo_path, "%s", "none"); 59f08c3bdfSopenharmony_ci hmac_algo_changed = 1; 60f08c3bdfSopenharmony_ci } 61f08c3bdfSopenharmony_ci } 62f08c3bdfSopenharmony_ci 63f08c3bdfSopenharmony_ci loc.sin6_family = AF_INET6; 64f08c3bdfSopenharmony_ci loc.sin6_addr = in6addr_loopback; 65f08c3bdfSopenharmony_ci 66f08c3bdfSopenharmony_ci sfd = SAFE_SOCKET(AF_INET6, SOCK_STREAM, IPPROTO_SCTP); 67f08c3bdfSopenharmony_ci SAFE_BIND(sfd, (struct sockaddr *)&loc, sizeof(loc)); 68f08c3bdfSopenharmony_ci 69f08c3bdfSopenharmony_ci port = TST_GETSOCKPORT(sfd); 70f08c3bdfSopenharmony_ci tst_res(TINFO, "sctp server listen on %d", port); 71f08c3bdfSopenharmony_ci 72f08c3bdfSopenharmony_ci SAFE_LISTEN(sfd, 1); 73f08c3bdfSopenharmony_ci 74f08c3bdfSopenharmony_ci srand(port); 75f08c3bdfSopenharmony_ci 76f08c3bdfSopenharmony_ci if (hmac_algo_changed) 77f08c3bdfSopenharmony_ci SAFE_FILE_PRINTF(hmac_algo_path, "%s", hmac_algo); 78f08c3bdfSopenharmony_ci} 79f08c3bdfSopenharmony_ci 80f08c3bdfSopenharmony_cistatic void update_packet_field(size_t *off, void *buf, size_t buf_len) 81f08c3bdfSopenharmony_ci{ 82f08c3bdfSopenharmony_ci memcpy(packet + *off, buf, buf_len); 83f08c3bdfSopenharmony_ci *off += buf_len; 84f08c3bdfSopenharmony_ci} 85f08c3bdfSopenharmony_ci 86f08c3bdfSopenharmony_cistatic void setup_client(void) 87f08c3bdfSopenharmony_ci{ 88f08c3bdfSopenharmony_ci struct ip6_hdr ip6; 89f08c3bdfSopenharmony_ci const size_t ip6_hdr_len = sizeof(ip6); 90f08c3bdfSopenharmony_ci size_t cmn_hdr_off; 91f08c3bdfSopenharmony_ci size_t off; 92f08c3bdfSopenharmony_ci int i; 93f08c3bdfSopenharmony_ci 94f08c3bdfSopenharmony_ci memset(&ip6, 0, sizeof(ip6)); 95f08c3bdfSopenharmony_ci ip6.ip6_flow = htonl(6 << 28 | 2 << 20); 96f08c3bdfSopenharmony_ci ip6.ip6_hops = 64; 97f08c3bdfSopenharmony_ci ip6.ip6_nxt = IPPROTO_SCTP; 98f08c3bdfSopenharmony_ci ip6.ip6_src.s6_addr[15] = 1; 99f08c3bdfSopenharmony_ci ip6.ip6_dst.s6_addr[15] = 1; 100f08c3bdfSopenharmony_ci rmt.sin6_family = AF_INET6; 101f08c3bdfSopenharmony_ci rmt.sin6_addr = in6addr_loopback; 102f08c3bdfSopenharmony_ci 103f08c3bdfSopenharmony_ci /* SCTP common header */ 104f08c3bdfSopenharmony_ci off = ip6_hdr_len; 105f08c3bdfSopenharmony_ci 106f08c3bdfSopenharmony_ci uint16_t src_port = htons(port - 1); 107f08c3bdfSopenharmony_ci uint16_t dst_port = htons(port); 108f08c3bdfSopenharmony_ci uint32_t vtag = 0; 109f08c3bdfSopenharmony_ci uint32_t checksum = 0; 110f08c3bdfSopenharmony_ci 111f08c3bdfSopenharmony_ci update_packet_field(&off, &src_port, 2); 112f08c3bdfSopenharmony_ci update_packet_field(&off, &dst_port, 2); 113f08c3bdfSopenharmony_ci update_packet_field(&off, &vtag, 4); 114f08c3bdfSopenharmony_ci update_packet_field(&off, &checksum, 4); 115f08c3bdfSopenharmony_ci cmn_hdr_off = off; 116f08c3bdfSopenharmony_ci 117f08c3bdfSopenharmony_ci /* SCTP INIT chunk */ 118f08c3bdfSopenharmony_ci uint16_t chunk_len; 119f08c3bdfSopenharmony_ci 120f08c3bdfSopenharmony_ci packet[off++] = 1; 121f08c3bdfSopenharmony_ci packet[off++] = 0; 122f08c3bdfSopenharmony_ci off += 2; /* chunk length, will be set in the end */ 123f08c3bdfSopenharmony_ci 124f08c3bdfSopenharmony_ci uint32_t init_tag = rand(); 125f08c3bdfSopenharmony_ci uint32_t rwnd = htonl(106496); 126f08c3bdfSopenharmony_ci uint16_t outs = htons(10); 127f08c3bdfSopenharmony_ci uint16_t ins = htons(65535); 128f08c3bdfSopenharmony_ci uint32_t init_tsn = rand(); 129f08c3bdfSopenharmony_ci 130f08c3bdfSopenharmony_ci update_packet_field(&off, &init_tag, 4); 131f08c3bdfSopenharmony_ci update_packet_field(&off, &rwnd, 4); 132f08c3bdfSopenharmony_ci update_packet_field(&off, &outs, 2); 133f08c3bdfSopenharmony_ci update_packet_field(&off, &ins, 2); 134f08c3bdfSopenharmony_ci update_packet_field(&off, &init_tsn, 4); 135f08c3bdfSopenharmony_ci 136f08c3bdfSopenharmony_ci /* SCTP optional parameter for IPv6 addresses */ 137f08c3bdfSopenharmony_ci uint16_t param_type = htons(6); 138f08c3bdfSopenharmony_ci uint16_t param_len = htons(20); 139f08c3bdfSopenharmony_ci 140f08c3bdfSopenharmony_ci /* IPv6(40) + SCTP_COMMON(12) + SCTP_CHUNK(20) + SCTP_OPT(65460)) */ 141f08c3bdfSopenharmony_ci for (i = 0; i < addr_num; ++i) { 142f08c3bdfSopenharmony_ci update_packet_field(&off, ¶m_type, 2); 143f08c3bdfSopenharmony_ci update_packet_field(&off, ¶m_len, 2); 144f08c3bdfSopenharmony_ci packet[off + 15] = 1; 145f08c3bdfSopenharmony_ci off += 16; 146f08c3bdfSopenharmony_ci } 147f08c3bdfSopenharmony_ci pkt_len = off; 148f08c3bdfSopenharmony_ci 149f08c3bdfSopenharmony_ci tst_res(TINFO, "set chunk length %zu", pkt_len - cmn_hdr_off); 150f08c3bdfSopenharmony_ci chunk_len = htons(pkt_len - cmn_hdr_off); 151f08c3bdfSopenharmony_ci memcpy(packet + cmn_hdr_off + 2, &chunk_len, 2); 152f08c3bdfSopenharmony_ci 153f08c3bdfSopenharmony_ci /* set checksum for SCTP: common header + INIT chunk */ 154f08c3bdfSopenharmony_ci uint32_t csum = tst_crc32c(packet + ip6_hdr_len, pkt_len - ip6_hdr_len); 155f08c3bdfSopenharmony_ci 156f08c3bdfSopenharmony_ci memcpy(packet + ip6_hdr_len + 8, &csum, 4); 157f08c3bdfSopenharmony_ci 158f08c3bdfSopenharmony_ci ip6.ip6_plen = htons(pkt_len - ip6_hdr_len); 159f08c3bdfSopenharmony_ci memcpy(packet, &ip6, ip6_hdr_len); 160f08c3bdfSopenharmony_ci 161f08c3bdfSopenharmony_ci cfd = SAFE_SOCKET(AF_INET6, SOCK_RAW, IPPROTO_RAW); 162f08c3bdfSopenharmony_ci} 163f08c3bdfSopenharmony_ci 164f08c3bdfSopenharmony_cistatic const char mtu_path[] = "/sys/class/net/lo/mtu"; 165f08c3bdfSopenharmony_cistatic const unsigned int max_mtu = 65535; 166f08c3bdfSopenharmony_cistatic unsigned int mtu; 167f08c3bdfSopenharmony_ci 168f08c3bdfSopenharmony_cistatic void setup(void) 169f08c3bdfSopenharmony_ci{ 170f08c3bdfSopenharmony_ci if (tst_parse_int(addr_param, &addr_num, 1, INT_MAX)) 171f08c3bdfSopenharmony_ci tst_brk(TBROK, "wrong address number '%s'", addr_param); 172f08c3bdfSopenharmony_ci 173f08c3bdfSopenharmony_ci /* We don't fragment IPv6 packet here yet, check that MTU is 65535 */ 174f08c3bdfSopenharmony_ci SAFE_FILE_SCANF(mtu_path, "%d", &mtu); 175f08c3bdfSopenharmony_ci if (mtu < max_mtu) 176f08c3bdfSopenharmony_ci tst_brk(TCONF, "Test needs that 'lo' MTU has %d", max_mtu); 177f08c3bdfSopenharmony_ci 178f08c3bdfSopenharmony_ci setup_server(); 179f08c3bdfSopenharmony_ci setup_client(); 180f08c3bdfSopenharmony_ci} 181f08c3bdfSopenharmony_ci 182f08c3bdfSopenharmony_cistatic void run(void) 183f08c3bdfSopenharmony_ci{ 184f08c3bdfSopenharmony_ci int pid = SAFE_FORK(); 185f08c3bdfSopenharmony_ci 186f08c3bdfSopenharmony_ci if (!pid) { 187f08c3bdfSopenharmony_ci struct sockaddr_in6 addr6; 188f08c3bdfSopenharmony_ci socklen_t addr_size = sizeof(addr6); 189f08c3bdfSopenharmony_ci 190f08c3bdfSopenharmony_ci if (accept(sfd, (struct sockaddr *)&addr6, &addr_size) < 0) 191f08c3bdfSopenharmony_ci tst_brk(TBROK | TERRNO, "accept() failed"); 192f08c3bdfSopenharmony_ci exit(0); 193f08c3bdfSopenharmony_ci } 194f08c3bdfSopenharmony_ci 195f08c3bdfSopenharmony_ci SAFE_SENDTO(1, cfd, packet, pkt_len, 0, (struct sockaddr *)&rmt, 196f08c3bdfSopenharmony_ci sizeof(rmt)); 197f08c3bdfSopenharmony_ci 198f08c3bdfSopenharmony_ci SAFE_KILL(pid, SIGKILL); 199f08c3bdfSopenharmony_ci SAFE_WAITPID(pid, NULL, 0); 200f08c3bdfSopenharmony_ci 201f08c3bdfSopenharmony_ci tst_res(TPASS, "test doesn't cause crash"); 202f08c3bdfSopenharmony_ci} 203f08c3bdfSopenharmony_ci 204f08c3bdfSopenharmony_cistatic struct tst_test test = { 205f08c3bdfSopenharmony_ci .needs_root = 1, 206f08c3bdfSopenharmony_ci .setup = setup, 207f08c3bdfSopenharmony_ci .forks_child = 1, 208f08c3bdfSopenharmony_ci .test_all = run, 209f08c3bdfSopenharmony_ci .options = (struct tst_option[]) { 210f08c3bdfSopenharmony_ci {"a:", &addr_param, "Number of additional IP address params"}, 211f08c3bdfSopenharmony_ci {} 212f08c3bdfSopenharmony_ci }, 213f08c3bdfSopenharmony_ci .tags = (const struct tst_tag[]) { 214f08c3bdfSopenharmony_ci {"CVE", "2018-5803"}, 215f08c3bdfSopenharmony_ci {"linux-git", "07f2c7ab6f8d"}, 216f08c3bdfSopenharmony_ci {} 217f08c3bdfSopenharmony_ci } 218f08c3bdfSopenharmony_ci}; 219