1 /* 2 * Copyright (c) 2015 Author: Oleg Nesterov <oleg (at) redhat.com> 3 * Modify: Li Wang <liwang (at) redhat.com> 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of version 2 of the GNU General Public License as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it would be useful, but 10 * WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 * 13 * you should have received a copy of the GNU General Public License along 14 * with this program; if not, write the Free Software Foundation, Inc., 15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 */ 17 18 /* 19 * Description: 20 * 21 * save_xstate_sig()->drop_init_fpu() doesn't look right. setup_rt_frame() 22 * can fail after that, in this case the next setup_rt_frame() triggered 23 * by SIGSEGV won't save fpu simply because the old state was lost. This 24 * obviously mean that fpu won't be restored after sys_rt_sigreturn() from 25 * SIGSEGV handler. 26 * 27 * These commits fix the issue on v3.17-rc3-3 stable kernel: 28 * 29 * commit df24fb859a4e200d9324e2974229fbb7adf00aef 30 * Author: Oleg Nesterov <oleg (at) redhat.com> 31 * Date: Tue Sep 2 19:57:17 2014 +0200 32 * 33 * commit 66463db4fc5605d51c7bb81d009d5bf30a783a2c 34 * Author: Oleg Nesterov <oleg (at) redhat.com> 35 * Date: Tue Sep 2 19:57:13 2014 +0200 36 * 37 * Reproduce: 38 * Test-case (needs -O2). 39 */ 40 41 #include <stdio.h> 42 #include <signal.h> 43 #include <unistd.h> 44 #include <sys/syscall.h> 45 #include <sys/mman.h> 46 #include <pthread.h> 47 #include <assert.h> 48 #include <errno.h> 49 50 #include "test.h" 51 #include "lapi/syscalls.h" 52 53 char *TCID = "signal06"; 54 int TST_TOTAL = 5; 55 56 #if __x86_64__ 57 58 #define LOOPS 30000 59 #define VALUE 123.456 60 61 volatile double D; 62 volatile int FLAGE; 63 64 char altstack[4096 * 10] __attribute__((aligned(4096))); 65 66 void test(void) 67 { 68 int loop = 0; 69 int pid = getpid(); 70 71 D = VALUE; 72 while (D == VALUE && loop < LOOPS) { 73 /* sys_tkill(pid, SIGHUP); asm to avoid save/reload 74 * fp regs around c call */ 75 asm ("" : : "a"(__NR_tkill), "D"(pid), "S"(SIGHUP)); 76 asm ("syscall" : : : "ax"); 77 78 loop++; 79 } 80 81 FLAGE = 1; 82 tst_resm(TINFO, "loop = %d", loop); 83 84 if (loop == LOOPS) { 85 tst_resm(TPASS, "%s call succeeded", TCID); 86 } else { 87 tst_resm(TFAIL, "Bug Reproduced!"); 88 tst_exit(); 89 } 90 } 91 92 void sigh(int sig LTP_ATTRIBUTE_UNUSED) 93 { 94 } 95 96 void *tfunc(void *arg LTP_ATTRIBUTE_UNUSED) 97 { 98 int i; 99 100 for (i = -1; ; i *= -1) { 101 if (i == -1) { 102 TEST(mprotect(altstack, sizeof(altstack), PROT_READ)); 103 if (TEST_RETURN == -1) 104 tst_brkm(TBROK | TTERRNO, NULL, "mprotect failed"); 105 } 106 107 TEST(mprotect(altstack, sizeof(altstack), PROT_READ | PROT_WRITE)); 108 if (TEST_RETURN == -1) 109 tst_brkm(TBROK | TTERRNO, NULL, "mprotect failed"); 110 111 if (FLAGE == 1) 112 return NULL; 113 } 114 } 115 116 int main(int ac, char **av) 117 { 118 int i, lc; 119 pthread_t pt; 120 121 tst_parse_opts(ac, av, NULL, NULL); 122 123 stack_t st = { 124 .ss_sp = altstack, 125 .ss_size = sizeof(altstack), 126 .ss_flags = SS_ONSTACK, 127 }; 128 129 struct sigaction sa = { 130 .sa_handler = sigh, 131 }; 132 133 TEST(sigaction(SIGSEGV, &sa, NULL)); 134 if (TEST_RETURN == -1) 135 tst_brkm(TBROK | TTERRNO, NULL, 136 "SIGSEGV signal setup failed"); 137 sigaltstack(&st, NULL); 138 sa.sa_flags = SA_ONSTACK; 139 140 TEST(sigaction(SIGHUP, &sa, NULL)); 141 if (TEST_RETURN == -1) 142 tst_brkm(TBROK | TTERRNO, NULL, 143 "SIGHUP signal setup failed"); 144 145 for (lc = 0; TEST_LOOPING(lc); lc++) { 146 tst_count = 0; 147 148 for (i = 0; i < TST_TOTAL; i++) { 149 FLAGE = 0; 150 151 TEST(pthread_create(&pt, NULL, tfunc, NULL)); 152 if (TEST_RETURN) 153 tst_brkm(TBROK | TRERRNO, NULL, 154 "pthread_create failed"); 155 156 test(); 157 158 TEST(pthread_join(pt, NULL)); 159 if (TEST_RETURN) 160 tst_brkm(TBROK | TRERRNO, NULL, 161 "pthread_join failed"); 162 } 163 } 164 165 tst_exit(); 166 } 167 168 #else 169 int main(void) 170 { 171 tst_brkm(TCONF, NULL, "Only test on x86_64."); 172 } 173 #endif 174