1 /*
2  * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  *
23  */
24 
25 #include "precompiled.hpp"
26 #include "logging/log.hpp"
27 #include "runtime/os.inline.hpp"
28 #include "runtime/stackOverflow.hpp"
29 #include "runtime/thread.hpp"
30 #include "utilities/align.hpp"
31 #include "utilities/globalDefinitions.hpp"
32 
33 size_t StackOverflow::_stack_red_zone_size = 0;
34 size_t StackOverflow::_stack_yellow_zone_size = 0;
35 size_t StackOverflow::_stack_reserved_zone_size = 0;
36 size_t StackOverflow::_stack_shadow_zone_size = 0;
37 
initialize_stack_zone_sizes()38 void StackOverflow::initialize_stack_zone_sizes() {
39   // Stack zone sizes must be page aligned.
40   size_t page_size = os::vm_page_size();
41 
42   // We need to adapt the configured number of stack protection pages given
43   // in 4K pages to the actual os page size. We must do this before setting
44   // up minimal stack sizes etc. in os::init_2().
45   size_t alignment = 4*K;
46 
47   assert(_stack_red_zone_size == 0, "This should be called only once.");
48   _stack_red_zone_size = align_up(StackRedPages * alignment, page_size);
49 
50   assert(_stack_yellow_zone_size == 0, "This should be called only once.");
51   _stack_yellow_zone_size = align_up(StackYellowPages * alignment, page_size);
52 
53   assert(_stack_reserved_zone_size == 0, "This should be called only once.");
54   _stack_reserved_zone_size = align_up(StackReservedPages * alignment, page_size);
55 
56   // The shadow area is not allocated or protected, so
57   // it needs not be page aligned.
58   // But the stack bang currently assumes that it is a
59   // multiple of page size. This guarantees that the bang
60   // loop touches all pages in the shadow zone.
61   // This can be guaranteed differently, as well.  E.g., if
62   // the page size is a multiple of 4K, banging in 4K steps
63   // suffices to touch all pages. (Some pages are banged
64   // several times, though.)
65   assert(_stack_shadow_zone_size == 0, "This should be called only once.");
66   _stack_shadow_zone_size = align_up(StackShadowPages * alignment, page_size);
67 }
68 
stack_guards_enabled() const69 bool StackOverflow::stack_guards_enabled() const {
70 #ifdef ASSERT
71   if (os::uses_stack_guard_pages() &&
72       !(DisablePrimordialThreadGuardPages && os::is_primordial_thread())) {
73     assert(_stack_guard_state != stack_guard_unused, "guard pages must be in use");
74   }
75 #endif
76   return _stack_guard_state == stack_guard_enabled;
77 }
78 
create_stack_guard_pages()79 void StackOverflow::create_stack_guard_pages() {
80   if (!os::uses_stack_guard_pages() ||
81       _stack_guard_state != stack_guard_unused ||
82       (DisablePrimordialThreadGuardPages && os::is_primordial_thread())) {
83       log_info(os, thread)("Stack guard page creation for thread "
84                            UINTX_FORMAT " disabled", os::current_thread_id());
85     return;
86   }
87   address low_addr = stack_end();
88   size_t len = stack_guard_zone_size();
89 
90   assert(is_aligned(low_addr, os::vm_page_size()), "Stack base should be the start of a page");
91   assert(is_aligned(len, os::vm_page_size()), "Stack size should be a multiple of page size");
92 
93   int must_commit = os::must_commit_stack_guard_pages();
94   // warning("Guarding at " PTR_FORMAT " for len " SIZE_FORMAT "\n", low_addr, len);
95 
96   if (must_commit && !os::create_stack_guard_pages((char *) low_addr, len)) {
97     log_warning(os, thread)("Attempt to allocate stack guard pages failed.");
98     return;
99   }
100 
101   if (os::guard_memory((char *) low_addr, len)) {
102     _stack_guard_state = stack_guard_enabled;
103   } else {
104     log_warning(os, thread)("Attempt to protect stack guard pages failed ("
105       PTR_FORMAT "-" PTR_FORMAT ").", p2i(low_addr), p2i(low_addr + len));
106     vm_exit_out_of_memory(len, OOM_MPROTECT_ERROR, "memory to guard stack pages");
107   }
108 
109   log_debug(os, thread)("Thread " UINTX_FORMAT " stack guard pages activated: "
110     PTR_FORMAT "-" PTR_FORMAT ".",
111     os::current_thread_id(), p2i(low_addr), p2i(low_addr + len));
112 }
113 
remove_stack_guard_pages()114 void StackOverflow::remove_stack_guard_pages() {
115   if (_stack_guard_state == stack_guard_unused) return;
116   address low_addr = stack_end();
117   size_t len = stack_guard_zone_size();
118 
119   if (os::must_commit_stack_guard_pages()) {
120     if (os::remove_stack_guard_pages((char *) low_addr, len)) {
121       _stack_guard_state = stack_guard_unused;
122     } else {
123       log_warning(os, thread)("Attempt to deallocate stack guard pages failed ("
124         PTR_FORMAT "-" PTR_FORMAT ").", p2i(low_addr), p2i(low_addr + len));
125       return;
126     }
127   } else {
128     if (_stack_guard_state == stack_guard_unused) return;
129     if (os::unguard_memory((char *) low_addr, len)) {
130       _stack_guard_state = stack_guard_unused;
131     } else {
132       log_warning(os, thread)("Attempt to unprotect stack guard pages failed ("
133         PTR_FORMAT "-" PTR_FORMAT ").", p2i(low_addr), p2i(low_addr + len));
134       return;
135     }
136   }
137 
138   log_debug(os, thread)("Thread " UINTX_FORMAT " stack guard pages removed: "
139     PTR_FORMAT "-" PTR_FORMAT ".",
140     os::current_thread_id(), p2i(low_addr), p2i(low_addr + len));
141 }
142 
enable_stack_reserved_zone(bool check_if_disabled)143 void StackOverflow::enable_stack_reserved_zone(bool check_if_disabled) {
144   if (check_if_disabled && _stack_guard_state == stack_guard_reserved_disabled) {
145     return;
146   }
147   assert(_stack_guard_state == stack_guard_reserved_disabled, "inconsistent state");
148 
149   // The base notation is from the stack's point of view, growing downward.
150   // We need to adjust it to work correctly with guard_memory()
151   address base = stack_reserved_zone_base() - stack_reserved_zone_size();
152 
153   guarantee(base < stack_base(),"Error calculating stack reserved zone");
154   guarantee(base < os::current_stack_pointer(),"Error calculating stack reserved zone");
155 
156   if (os::guard_memory((char *) base, stack_reserved_zone_size())) {
157     _stack_guard_state = stack_guard_enabled;
158   } else {
159     warning("Attempt to guard stack reserved zone failed.");
160   }
161 }
162 
disable_stack_reserved_zone()163 void StackOverflow::disable_stack_reserved_zone() {
164   assert(_stack_guard_state == stack_guard_enabled, "inconsistent state");
165 
166   // Simply return if called for a thread that does not use guard pages.
167   if (_stack_guard_state != stack_guard_enabled) return;
168 
169   // The base notation is from the stack's point of view, growing downward.
170   // We need to adjust it to work correctly with guard_memory()
171   address base = stack_reserved_zone_base() - stack_reserved_zone_size();
172 
173   if (os::unguard_memory((char *)base, stack_reserved_zone_size())) {
174     _stack_guard_state = stack_guard_reserved_disabled;
175   } else {
176     warning("Attempt to unguard stack reserved zone failed.");
177   }
178 }
179 
enable_stack_yellow_reserved_zone()180 void StackOverflow::enable_stack_yellow_reserved_zone() {
181   assert(_stack_guard_state != stack_guard_unused, "must be using guard pages.");
182   assert(_stack_guard_state != stack_guard_enabled, "already enabled");
183 
184   // The base notation is from the stacks point of view, growing downward.
185   // We need to adjust it to work correctly with guard_memory()
186   address base = stack_red_zone_base();
187 
188   guarantee(base < stack_base(), "Error calculating stack yellow zone");
189   guarantee(base < os::current_stack_pointer(), "Error calculating stack yellow zone");
190 
191   if (os::guard_memory((char *) base, stack_yellow_reserved_zone_size())) {
192     _stack_guard_state = stack_guard_enabled;
193   } else {
194     warning("Attempt to guard stack yellow zone failed.");
195   }
196 }
197 
disable_stack_yellow_reserved_zone()198 void StackOverflow::disable_stack_yellow_reserved_zone() {
199   assert(_stack_guard_state != stack_guard_unused, "must be using guard pages.");
200   assert(_stack_guard_state != stack_guard_yellow_reserved_disabled, "already disabled");
201 
202   // Simply return if called for a thread that does not use guard pages.
203   if (_stack_guard_state == stack_guard_unused) return;
204 
205   // The base notation is from the stacks point of view, growing downward.
206   // We need to adjust it to work correctly with guard_memory()
207   address base = stack_red_zone_base();
208 
209   if (os::unguard_memory((char *)base, stack_yellow_reserved_zone_size())) {
210     _stack_guard_state = stack_guard_yellow_reserved_disabled;
211   } else {
212     warning("Attempt to unguard stack yellow zone failed.");
213   }
214 }
215 
enable_stack_red_zone()216 void StackOverflow::enable_stack_red_zone() {
217   // The base notation is from the stacks point of view, growing downward.
218   // We need to adjust it to work correctly with guard_memory()
219   assert(_stack_guard_state != stack_guard_unused, "must be using guard pages.");
220   address base = stack_red_zone_base() - stack_red_zone_size();
221 
222   guarantee(base < stack_base(), "Error calculating stack red zone");
223   guarantee(base < os::current_stack_pointer(), "Error calculating stack red zone");
224 
225   if (!os::guard_memory((char *) base, stack_red_zone_size())) {
226     warning("Attempt to guard stack red zone failed.");
227   }
228 }
229 
disable_stack_red_zone()230 void StackOverflow::disable_stack_red_zone() {
231   // The base notation is from the stacks point of view, growing downward.
232   // We need to adjust it to work correctly with guard_memory()
233   assert(_stack_guard_state != stack_guard_unused, "must be using guard pages.");
234   address base = stack_red_zone_base() - stack_red_zone_size();
235   if (!os::unguard_memory((char *)base, stack_red_zone_size())) {
236     warning("Attempt to unguard stack red zone failed.");
237   }
238 }
239 
reguard_stack(address cur_sp)240 bool StackOverflow::reguard_stack(address cur_sp) {
241   if (_stack_guard_state != stack_guard_yellow_reserved_disabled
242       && _stack_guard_state != stack_guard_reserved_disabled) {
243     return true; // Stack already guarded or guard pages not needed.
244   }
245 
246   // Java code never executes within the yellow zone: the latter is only
247   // there to provoke an exception during stack banging.  If java code
248   // is executing there, either StackShadowPages should be larger, or
249   // some exception code in c1, c2 or the interpreter isn't unwinding
250   // when it should.
251   guarantee(cur_sp > stack_reserved_zone_base(),
252             "not enough space to reguard - increase StackShadowPages");
253   if (_stack_guard_state == stack_guard_yellow_reserved_disabled) {
254     enable_stack_yellow_reserved_zone();
255     if (reserved_stack_activation() != stack_base()) {
256       set_reserved_stack_activation(stack_base());
257     }
258   } else if (_stack_guard_state == stack_guard_reserved_disabled) {
259     set_reserved_stack_activation(stack_base());
260     enable_stack_reserved_zone();
261   }
262   return true;
263 }
264 
reguard_stack(void)265 bool StackOverflow::reguard_stack(void) {
266   return reguard_stack(os::current_stack_pointer());
267 }
268 
reguard_stack_if_needed()269 bool StackOverflow::reguard_stack_if_needed() {
270   return !stack_guards_enabled() ? reguard_stack() : true;
271 }
272