~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/powerpc/mm/stack_expansion_ldst.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*
  3  * Test that loads/stores expand the stack segment, or trigger a SEGV, in
  4  * various conditions.
  5  *
  6  * Based on test code by Tom Lane.
  7  */
  8 
  9 #undef NDEBUG
 10 #include <assert.h>
 11 
 12 #include <err.h>
 13 #include <errno.h>
 14 #include <stdio.h>
 15 #include <signal.h>
 16 #include <stdlib.h>
 17 #include <string.h>
 18 #include <sys/resource.h>
 19 #include <sys/time.h>
 20 #include <sys/types.h>
 21 #include <sys/wait.h>
 22 #include <unistd.h>
 23 
 24 #define _KB (1024)
 25 #define _MB (1024 * 1024)
 26 
 27 volatile char *stack_top_ptr;
 28 volatile unsigned long stack_top_sp;
 29 volatile char c;
 30 
 31 enum access_type {
 32         LOAD,
 33         STORE,
 34 };
 35 
 36 /*
 37  * Consume stack until the stack pointer is below @target_sp, then do an access
 38  * (load or store) at offset @delta from either the base of the stack or the
 39  * current stack pointer.
 40  */
 41 __attribute__ ((noinline))
 42 int consume_stack(unsigned long target_sp, unsigned long stack_high, int delta, enum access_type type)
 43 {
 44         unsigned long target;
 45         char stack_cur;
 46 
 47         if ((unsigned long)&stack_cur > target_sp)
 48                 return consume_stack(target_sp, stack_high, delta, type);
 49         else {
 50                 // We don't really need this, but without it GCC might not
 51                 // generate a recursive call above.
 52                 stack_top_ptr = &stack_cur;
 53 
 54 #ifdef __powerpc__
 55                 asm volatile ("mr %[sp], %%r1" : [sp] "=r" (stack_top_sp));
 56 #else
 57                 asm volatile ("mov %%rsp, %[sp]" : [sp] "=r" (stack_top_sp));
 58 #endif
 59                 target = stack_high - delta + 1;
 60                 volatile char *p = (char *)target;
 61 
 62                 if (type == STORE)
 63                         *p = c;
 64                 else
 65                         c = *p;
 66 
 67                 // Do something to prevent the stack frame being popped prior to
 68                 // our access above.
 69                 getpid();
 70         }
 71 
 72         return 0;
 73 }
 74 
 75 static int search_proc_maps(char *needle, unsigned long *low, unsigned long *high)
 76 {
 77         unsigned long start, end;
 78         static char buf[4096];
 79         char name[128];
 80         FILE *f;
 81         int rc;
 82 
 83         f = fopen("/proc/self/maps", "r");
 84         if (!f) {
 85                 perror("fopen");
 86                 return -1;
 87         }
 88 
 89         while (fgets(buf, sizeof(buf), f)) {
 90                 rc = sscanf(buf, "%lx-%lx %*c%*c%*c%*c %*x %*d:%*d %*d %127s\n",
 91                             &start, &end, name);
 92                 if (rc == 2)
 93                         continue;
 94 
 95                 if (rc != 3) {
 96                         printf("sscanf errored\n");
 97                         rc = -1;
 98                         break;
 99                 }
100 
101                 if (strstr(name, needle)) {
102                         *low = start;
103                         *high = end - 1;
104                         rc = 0;
105                         break;
106                 }
107         }
108 
109         fclose(f);
110 
111         return rc;
112 }
113 
114 int child(unsigned int stack_used, int delta, enum access_type type)
115 {
116         unsigned long low, stack_high;
117 
118         assert(search_proc_maps("[stack]", &low, &stack_high) == 0);
119 
120         assert(consume_stack(stack_high - stack_used, stack_high, delta, type) == 0);
121 
122         printf("Access OK: %s delta %-7d used size 0x%06x stack high 0x%lx top_ptr %p top sp 0x%lx actual used 0x%lx\n",
123                type == LOAD ? "load" : "store", delta, stack_used, stack_high,
124                stack_top_ptr, stack_top_sp, stack_high - stack_top_sp + 1);
125 
126         return 0;
127 }
128 
129 static int test_one(unsigned int stack_used, int delta, enum access_type type)
130 {
131         pid_t pid;
132         int rc;
133 
134         pid = fork();
135         if (pid == 0)
136                 exit(child(stack_used, delta, type));
137 
138         assert(waitpid(pid, &rc, 0) != -1);
139 
140         if (WIFEXITED(rc) && WEXITSTATUS(rc) == 0)
141                 return 0;
142 
143         // We don't expect a non-zero exit that's not a signal
144         assert(!WIFEXITED(rc));
145 
146         printf("Faulted:   %s delta %-7d used size 0x%06x signal %d\n",
147                type == LOAD ? "load" : "store", delta, stack_used,
148                WTERMSIG(rc));
149 
150         return 1;
151 }
152 
153 // This is fairly arbitrary but is well below any of the targets below,
154 // so that the delta between the stack pointer and the target is large.
155 #define DEFAULT_SIZE    (32 * _KB)
156 
157 static void test_one_type(enum access_type type, unsigned long page_size, unsigned long rlim_cur)
158 {
159         unsigned long delta;
160 
161         // We should be able to access anywhere within the rlimit
162         for (delta = page_size; delta <= rlim_cur; delta += page_size)
163                 assert(test_one(DEFAULT_SIZE, delta, type) == 0);
164 
165         assert(test_one(DEFAULT_SIZE, rlim_cur, type) == 0);
166 
167         // But if we go past the rlimit it should fail
168         assert(test_one(DEFAULT_SIZE, rlim_cur + 1, type) != 0);
169 }
170 
171 static int test(void)
172 {
173         unsigned long page_size;
174         struct rlimit rlimit;
175 
176         page_size = getpagesize();
177         getrlimit(RLIMIT_STACK, &rlimit);
178         printf("Stack rlimit is 0x%lx\n", rlimit.rlim_cur);
179 
180         printf("Testing loads ...\n");
181         test_one_type(LOAD, page_size, rlimit.rlim_cur);
182         printf("Testing stores ...\n");
183         test_one_type(STORE, page_size, rlimit.rlim_cur);
184 
185         printf("All OK\n");
186 
187         return 0;
188 }
189 
190 #ifdef __powerpc__
191 #include "utils.h"
192 
193 int main(void)
194 {
195         return test_harness(test, "stack_expansion_ldst");
196 }
197 #else
198 int main(void)
199 {
200         return test();
201 }
202 #endif
203 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php