1/* 2 * Copyright (c) 2015 Author: Oleg Nesterov <oleg@redhat.com> 3 * Modify: Li Wang <liwang@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@redhat.com> 31 * Date: Tue Sep 2 19:57:17 2014 +0200 32 * 33 * commit 66463db4fc5605d51c7bb81d009d5bf30a783a2c 34 * Author: Oleg Nesterov <oleg@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 53char *TCID = "signal06"; 54int TST_TOTAL = 5; 55 56#if __x86_64__ 57 58#define LOOPS 30000 59#define VALUE 123.456 60 61volatile double D; 62volatile int FLAGE; 63 64char altstack[4096 * 10] __attribute__((aligned(4096))); 65 66void 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 int unused; 76 asm volatile ("syscall" : "=a"(unused) : "a"(__NR_tkill), "D"(pid), "S"(SIGHUP) : "rcx", "r11"); 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 92void sigh(int sig LTP_ATTRIBUTE_UNUSED) 93{ 94} 95 96void *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 116int 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 169int main(void) 170{ 171 tst_brkm(TCONF, NULL, "Only test on x86_64."); 172} 173#endif 174