1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) 2019 SUSE LLC 4f08c3bdfSopenharmony_ci * Author: Christian Amann <camann@suse.com> 5f08c3bdfSopenharmony_ci */ 6f08c3bdfSopenharmony_ci/*\ 7f08c3bdfSopenharmony_ci * [Description] 8f08c3bdfSopenharmony_ci * 9f08c3bdfSopenharmony_ci * Test for CVE-2017-8890 10f08c3bdfSopenharmony_ci * 11f08c3bdfSopenharmony_ci * In Kernels up to 4.10.15 missing commit 657831ff the multicast 12f08c3bdfSopenharmony_ci * group information of a socket gets copied over to a newly created 13f08c3bdfSopenharmony_ci * socket when using the accept() syscall. This will cause a double free 14f08c3bdfSopenharmony_ci * when closing the original and the cloned socket. 15f08c3bdfSopenharmony_ci * 16f08c3bdfSopenharmony_ci * WARNING: 17f08c3bdfSopenharmony_ci * There is a high chance that this test will cause an unstable system 18f08c3bdfSopenharmony_ci * if it does not succeed! 19f08c3bdfSopenharmony_ci * 20f08c3bdfSopenharmony_ci * For more information about this CVE see: 21f08c3bdfSopenharmony_ci * https://www.suse.com/security/cve/CVE-2017-8890/ 22f08c3bdfSopenharmony_ci */ 23f08c3bdfSopenharmony_ci 24f08c3bdfSopenharmony_ci#include <errno.h> 25f08c3bdfSopenharmony_ci#include <sys/socket.h> 26f08c3bdfSopenharmony_ci#include "tst_test.h" 27f08c3bdfSopenharmony_ci#include "tst_safe_net.h" 28f08c3bdfSopenharmony_ci#include "tst_safe_pthread.h" 29f08c3bdfSopenharmony_ci 30f08c3bdfSopenharmony_ci#define MULTICASTIP "224.0.0.0" 31f08c3bdfSopenharmony_ci#define LOCALHOSTIP "127.0.0.1" 32f08c3bdfSopenharmony_ci 33f08c3bdfSopenharmony_cistatic int server_sockfd; 34f08c3bdfSopenharmony_cistatic int clone_server_sockfd; 35f08c3bdfSopenharmony_cistatic int client_sockfd; 36f08c3bdfSopenharmony_cistatic int server_port; 37f08c3bdfSopenharmony_cistatic socklen_t addr_len; 38f08c3bdfSopenharmony_ci 39f08c3bdfSopenharmony_cistatic struct sockaddr_in *server_addr; 40f08c3bdfSopenharmony_cistatic struct sockaddr_in *client_addr; 41f08c3bdfSopenharmony_cistatic struct group_req *mc_group; 42f08c3bdfSopenharmony_ci 43f08c3bdfSopenharmony_cistatic void *server_thread(void *arg) 44f08c3bdfSopenharmony_ci{ 45f08c3bdfSopenharmony_ci int op, op_len, mc_group_len; 46f08c3bdfSopenharmony_ci 47f08c3bdfSopenharmony_ci op = 1; 48f08c3bdfSopenharmony_ci op_len = sizeof(op); 49f08c3bdfSopenharmony_ci mc_group_len = sizeof(*mc_group); 50f08c3bdfSopenharmony_ci 51f08c3bdfSopenharmony_ci server_sockfd = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0); 52f08c3bdfSopenharmony_ci 53f08c3bdfSopenharmony_ci SAFE_SETSOCKOPT(server_sockfd, SOL_SOCKET, SO_REUSEADDR, &op, op_len); 54f08c3bdfSopenharmony_ci SAFE_SETSOCKOPT(server_sockfd, SOL_IP, MCAST_JOIN_GROUP, 55f08c3bdfSopenharmony_ci mc_group, mc_group_len); 56f08c3bdfSopenharmony_ci 57f08c3bdfSopenharmony_ci SAFE_BIND(server_sockfd, (struct sockaddr *)server_addr, addr_len); 58f08c3bdfSopenharmony_ci SAFE_LISTEN(server_sockfd, 1); 59f08c3bdfSopenharmony_ci 60f08c3bdfSopenharmony_ci TST_CHECKPOINT_WAKE(0); 61f08c3bdfSopenharmony_ci 62f08c3bdfSopenharmony_ci TEST(accept(server_sockfd, (struct sockaddr *)client_addr, &addr_len)); 63f08c3bdfSopenharmony_ci if (TST_RET == -1) 64f08c3bdfSopenharmony_ci tst_brk(TBROK | TTERRNO, "Could not accept connection"); 65f08c3bdfSopenharmony_ci 66f08c3bdfSopenharmony_ci clone_server_sockfd = TST_RET; 67f08c3bdfSopenharmony_ci 68f08c3bdfSopenharmony_ci TEST(setsockopt(clone_server_sockfd, SOL_IP, MCAST_LEAVE_GROUP, 69f08c3bdfSopenharmony_ci mc_group, mc_group_len)); 70f08c3bdfSopenharmony_ci SAFE_CLOSE(clone_server_sockfd); 71f08c3bdfSopenharmony_ci 72f08c3bdfSopenharmony_ci if (TST_RET != -1) 73f08c3bdfSopenharmony_ci tst_res(TFAIL, "Multicast group was copied!"); 74f08c3bdfSopenharmony_ci else if (TST_ERR == EADDRNOTAVAIL) 75f08c3bdfSopenharmony_ci tst_res(TPASS | TTERRNO, "Multicast group was not copied"); 76f08c3bdfSopenharmony_ci else 77f08c3bdfSopenharmony_ci tst_brk(TBROK | TTERRNO, "setsockopt() failed unexpectedly"); 78f08c3bdfSopenharmony_ci 79f08c3bdfSopenharmony_ci SAFE_CLOSE(server_sockfd); 80f08c3bdfSopenharmony_ci return arg; 81f08c3bdfSopenharmony_ci} 82f08c3bdfSopenharmony_ci 83f08c3bdfSopenharmony_cistatic void *client_thread(void *arg) 84f08c3bdfSopenharmony_ci{ 85f08c3bdfSopenharmony_ci client_sockfd = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0); 86f08c3bdfSopenharmony_ci SAFE_BIND(client_sockfd, (struct sockaddr *)client_addr, addr_len); 87f08c3bdfSopenharmony_ci 88f08c3bdfSopenharmony_ci SAFE_CONNECT(client_sockfd, (struct sockaddr *)server_addr, addr_len); 89f08c3bdfSopenharmony_ci 90f08c3bdfSopenharmony_ci SAFE_CLOSE(client_sockfd); 91f08c3bdfSopenharmony_ci return arg; 92f08c3bdfSopenharmony_ci} 93f08c3bdfSopenharmony_ci 94f08c3bdfSopenharmony_cistatic void run(void) 95f08c3bdfSopenharmony_ci{ 96f08c3bdfSopenharmony_ci pthread_t server_thr, client_thr; 97f08c3bdfSopenharmony_ci 98f08c3bdfSopenharmony_ci server_addr->sin_port = server_port; 99f08c3bdfSopenharmony_ci client_addr->sin_port = htons(0); 100f08c3bdfSopenharmony_ci 101f08c3bdfSopenharmony_ci SAFE_PTHREAD_CREATE(&server_thr, NULL, server_thread, NULL); 102f08c3bdfSopenharmony_ci TST_CHECKPOINT_WAIT(0); 103f08c3bdfSopenharmony_ci SAFE_PTHREAD_CREATE(&client_thr, NULL, client_thread, NULL); 104f08c3bdfSopenharmony_ci 105f08c3bdfSopenharmony_ci SAFE_PTHREAD_JOIN(server_thr, NULL); 106f08c3bdfSopenharmony_ci SAFE_PTHREAD_JOIN(client_thr, NULL); 107f08c3bdfSopenharmony_ci} 108f08c3bdfSopenharmony_ci 109f08c3bdfSopenharmony_cistatic void setup(void) 110f08c3bdfSopenharmony_ci{ 111f08c3bdfSopenharmony_ci struct sockaddr_in *mc_group_addr; 112f08c3bdfSopenharmony_ci 113f08c3bdfSopenharmony_ci server_addr = tst_alloc(sizeof(*server_addr)); 114f08c3bdfSopenharmony_ci client_addr = tst_alloc(sizeof(*client_addr)); 115f08c3bdfSopenharmony_ci mc_group = tst_alloc(sizeof(*mc_group)); 116f08c3bdfSopenharmony_ci 117f08c3bdfSopenharmony_ci mc_group->gr_interface = 0; 118f08c3bdfSopenharmony_ci mc_group_addr = (struct sockaddr_in *) &mc_group->gr_group; 119f08c3bdfSopenharmony_ci mc_group_addr->sin_family = AF_INET; 120f08c3bdfSopenharmony_ci inet_aton(MULTICASTIP, &mc_group_addr->sin_addr); 121f08c3bdfSopenharmony_ci 122f08c3bdfSopenharmony_ci server_addr->sin_family = AF_INET; 123f08c3bdfSopenharmony_ci inet_aton(LOCALHOSTIP, &server_addr->sin_addr); 124f08c3bdfSopenharmony_ci 125f08c3bdfSopenharmony_ci client_addr->sin_family = AF_INET; 126f08c3bdfSopenharmony_ci client_addr->sin_addr.s_addr = htons(INADDR_ANY); 127f08c3bdfSopenharmony_ci 128f08c3bdfSopenharmony_ci addr_len = sizeof(struct sockaddr_in); 129f08c3bdfSopenharmony_ci 130f08c3bdfSopenharmony_ci server_port = TST_GET_UNUSED_PORT(AF_INET, SOCK_STREAM); 131f08c3bdfSopenharmony_ci tst_res(TINFO, "Starting listener on port: %d", ntohs(server_port)); 132f08c3bdfSopenharmony_ci} 133f08c3bdfSopenharmony_ci 134f08c3bdfSopenharmony_cistatic void cleanup(void) 135f08c3bdfSopenharmony_ci{ 136f08c3bdfSopenharmony_ci if (clone_server_sockfd > 0) 137f08c3bdfSopenharmony_ci SAFE_CLOSE(clone_server_sockfd); 138f08c3bdfSopenharmony_ci if (client_sockfd > 0) 139f08c3bdfSopenharmony_ci SAFE_CLOSE(client_sockfd); 140f08c3bdfSopenharmony_ci if (server_sockfd > 0) 141f08c3bdfSopenharmony_ci SAFE_CLOSE(server_sockfd); 142f08c3bdfSopenharmony_ci} 143f08c3bdfSopenharmony_ci 144f08c3bdfSopenharmony_cistatic struct tst_test test = { 145f08c3bdfSopenharmony_ci .test_all = run, 146f08c3bdfSopenharmony_ci .setup = setup, 147f08c3bdfSopenharmony_ci .cleanup = cleanup, 148f08c3bdfSopenharmony_ci .needs_checkpoints = 1, 149f08c3bdfSopenharmony_ci .tags = (const struct tst_tag[]) { 150f08c3bdfSopenharmony_ci {"CVE", "2017-8890"}, 151f08c3bdfSopenharmony_ci {"linux-git", "657831ff"}, 152f08c3bdfSopenharmony_ci {}, 153f08c3bdfSopenharmony_ci } 154f08c3bdfSopenharmony_ci}; 155