1/* 2 * Copyright (C) 2011-2017 Red Hat, Inc. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 12 * the GNU General Public License for more details. 13 * 14 * KSM - NULL pointer dereference in ksm_do_scan() (CVE-2011-2183) 15 * 16 * This is a testcase from upstream commit: 17 * 2b472611a32a72f4a118c069c2d62a1a3f087afd. 18 * 19 * an exiting task can race against ksmd::scan_get_next_rmap_item 20 * (http://lkml.org/lkml/2011/6/1/742) easily triggering a NULL pointer 21 * dereference in ksmd. 22 * ksm_scan.mm_slot == &ksm_mm_head with only one registered mm 23 * 24 * CPU 1 (__ksm_exit) CPU 2 (scan_get_next_rmap_item) 25 * list_empty() is false 26 * lock slot == &ksm_mm_head 27 * list_del(slot->mm_list) 28 * (list now empty) 29 * unlock 30 * lock 31 * slot = list_entry(slot->mm_list.next) 32 * (list is empty, so slot is still ksm_mm_head) 33 * unlock 34 * slot->mm == NULL ... Oops 35 * 36 * Close this race by revalidating that the new slot is not simply the list 37 * head again. 38 * 39 * Test Prerequisites: 40 * 41 * *) ksm and ksmtuned daemons need to be disabled. Otherwise, it could 42 * distrub the testing as they also change some ksm tunables depends 43 * on current workloads. 44 */ 45 46#include <sys/wait.h> 47#include <signal.h> 48#include <stdlib.h> 49#include <errno.h> 50#include "tst_test.h" 51#include "mem.h" 52 53#ifdef HAVE_MADV_MERGEABLE 54 55static int ksm_run_orig; 56static void sighandler(int sig); 57 58static void test_ksm(void) 59{ 60 int status; 61 long ps; 62 pid_t pid; 63 void *ptr; 64 struct sigaction sa; 65 66 memset (&sa, '\0', sizeof(sa)); 67 sa.sa_handler = sighandler; 68 sa.sa_flags = 0; 69 TEST(sigaction(SIGSEGV, &sa, NULL)); 70 if (TEST_RETURN == -1) 71 tst_brk(TBROK | TRERRNO, 72 "SIGSEGV signal setup failed"); 73 74 ps = sysconf(_SC_PAGESIZE); 75 76 pid = SAFE_FORK(); 77 if (pid == 0) { 78 ptr = SAFE_MEMALIGN(ps, ps); 79 if (madvise(ptr, ps, MADV_MERGEABLE) < 0) 80 tst_brk(TBROK | TERRNO, "madvise"); 81 *(char *)NULL = 0; /* SIGSEGV occurs as expected. */ 82 } 83 SAFE_WAITPID(pid, &status, WUNTRACED | WCONTINUED); 84 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) 85 tst_brk(TBROK, "invalid signal received: %d", status); 86 87 tst_res(TPASS, "still alive."); 88} 89 90static void sighandler(int sig) 91{ 92 _exit((sig == SIGSEGV) ? 0 : sig); 93} 94 95static void setup(void) 96{ 97 if (access(PATH_KSM, F_OK) == -1) 98 tst_brk(TCONF, "KSM configuration is not enabled"); 99 100 /* save original /sys/kernel/mm/ksm/run value */ 101 SAFE_FILE_SCANF(PATH_KSM "run", "%d", &ksm_run_orig); 102 103 /* echo 1 > /sys/kernel/mm/ksm/run */ 104 SAFE_FILE_PRINTF(PATH_KSM "run", "1"); 105} 106 107static void cleanup(void) 108{ 109 /* restore /sys/kernel/mm/ksm/run value */ 110 FILE_PRINTF(PATH_KSM "run", "%d", ksm_run_orig); 111} 112 113static struct tst_test test = { 114 .needs_root = 1, 115 .forks_child = 1, 116 .setup = setup, 117 .cleanup = cleanup, 118 .test_all = test_ksm, 119 .min_kver = "2.6.32", 120}; 121 122#else 123 TST_TEST_TCONF("no MADV_MERGEABLE found."); 124#endif 125