Commit 141e582e authored by Dan Good's avatar Dan Good

altstack: stack alignment and accounting tweaks

* add altstack_remn, returns amount of stack remaining
* increase mapping by 1 page to handle abutment case
* capture rsp earlier
* align stack to 16 bytes
Signed-off-by: default avatarDan Good <dan@dancancode.com>
parent 9a8344b2
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <signal.h> #include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include <sys/mman.h> #include <sys/mman.h>
static __thread char ebuf[ALTSTACK_ERR_MAXLEN]; static __thread char ebuf[ALTSTACK_ERR_MAXLEN];
...@@ -37,6 +38,11 @@ static void segvjmp(int signum) ...@@ -37,6 +38,11 @@ static void segvjmp(int signum)
} }
static __thread void *rsp_save_[2]; static __thread void *rsp_save_[2];
static __thread rlim_t max_;
rlim_t altstack_max(void) {
return max_;
}
static ptrdiff_t rsp_save(unsigned i) { static ptrdiff_t rsp_save(unsigned i) {
assert(i < 2); assert(i < 2);
...@@ -57,6 +63,7 @@ static __thread void *arg_, *out_; ...@@ -57,6 +63,7 @@ static __thread void *arg_, *out_;
int altstack(rlim_t max, void *(*fn)(void *), void *arg, void **out) int altstack(rlim_t max, void *(*fn)(void *), void *arg, void **out)
{ {
long pgsz = sysconf(_SC_PAGESIZE);
int ret = -1, undo = 0; int ret = -1, undo = 0;
char *m; char *m;
struct rlimit rl_save; struct rlimit rl_save;
...@@ -69,11 +76,16 @@ int altstack(rlim_t max, void *(*fn)(void *), void *arg, void **out) ...@@ -69,11 +76,16 @@ int altstack(rlim_t max, void *(*fn)(void *), void *arg, void **out)
fn_ = fn; fn_ = fn;
arg_ = arg; arg_ = arg;
out_ = 0; out_ = 0;
max_ = max;
ebuf[elen = 0] = '\0'; ebuf[elen = 0] = '\0';
if (out) *out = 0; if (out) *out = 0;
// if the first page below the mapping is in use, we get max-pgsz usable bytes
// add pgsz to max to guarantee at least max usable bytes
max += pgsz;
ok(getrlimit(RLIMIT_STACK, &rl_save), 1); ok(getrlimit(RLIMIT_STACK, &rl_save), 1);
ok(setrlimit(RLIMIT_STACK, &(struct rlimit) { max, rl_save.rlim_max }), 1); ok(setrlimit(RLIMIT_STACK, &(struct rlimit) { max_, rl_save.rlim_max }), 1);
undo++; undo++;
ok(m = mmap(0, max, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_GROWSDOWN|MAP_NORESERVE, -1, 0), 1); ok(m = mmap(0, max, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_GROWSDOWN|MAP_NORESERVE, -1, 0), 1);
...@@ -91,8 +103,12 @@ int altstack(rlim_t max, void *(*fn)(void *), void *arg, void **out) ...@@ -91,8 +103,12 @@ int altstack(rlim_t max, void *(*fn)(void *), void *arg, void **out)
ok(sigaction(SIGSEGV, &sa, &sa_save), 1); ok(sigaction(SIGSEGV, &sa, &sa_save), 1);
undo++; undo++;
asm volatile ("movq %%rsp, %%r10\nmov %0, %%rsp\npush %%r10" : : "g" (m + max) : "r10"); asm volatile (
rsp_save(0); "mov %%rsp, %%r10\n\t"
"mov %1, %%rsp\n\t"
"sub $8, %%rsp\n\t"
"push %%r10"
: "=r" (rsp_save_[0]) : "0" (m + max) : "r10");
out_ = fn_(arg_); out_ = fn_(arg_);
asm volatile ("pop %rsp"); asm volatile ("pop %rsp");
ret = 0; ret = 0;
......
...@@ -103,6 +103,20 @@ char *altstack_geterr(void); ...@@ -103,6 +103,20 @@ char *altstack_geterr(void);
*/ */
ptrdiff_t altstack_used(void); ptrdiff_t altstack_used(void);
/**
* altstack_max - return usable stack size
*
* Returns: max value from altstack() call
*/
rlim_t altstack_max(void);
/**
* altstack_remn - return amount of stack remaining
*
* Returns: altstack_max() minus altstack_used()
*/
#define altstack_remn() (altstack_max() - altstack_used())
/** /**
* altstack_rsp_save - set initial rsp value * altstack_rsp_save - set initial rsp value
* *
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include <setjmp.h> #include <setjmp.h>
#include <signal.h> #include <signal.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <ccan/tap/tap.h> #include <ccan/tap/tap.h>
#include <ccan/altstack/altstack.h> #include <ccan/altstack/altstack.h>
...@@ -20,13 +21,13 @@ enum { ...@@ -20,13 +21,13 @@ enum {
}; };
int fail, call1, call2; int fail, call1, call2;
char *m_; char *m_;
rlim_t max_; rlim_t msz_;
#define e(x) (900+(x)) #define e(x) (900+(x))
#define seterr(x) (errno = e(x)) #define seterr(x) (errno = e(x))
#define setcall(x) ((call1 |= !errno ? (x) : 0), (call2 |= errno || out_ ? (x) : 0)) #define setcall(x) ((call1 |= !errno ? (x) : 0), (call2 |= errno || out_ ? (x) : 0))
#define getrlimit(...) (fail&getrlimit_ ? (seterr(getrlimit_), -1) : (setcall(getrlimit_), getrlimit(__VA_ARGS__))) #define getrlimit(...) (fail&getrlimit_ ? (seterr(getrlimit_), -1) : (setcall(getrlimit_), getrlimit(__VA_ARGS__)))
#define mmap(...) (fail&mmap_ ? (seterr(mmap_), (void *)-1) : (setcall(mmap_), mmap(__VA_ARGS__))) #define mmap(...) (fail&mmap_ ? (seterr(mmap_), (void *)-1) : (setcall(mmap_), mmap(__VA_ARGS__)))
#define munmap(a, b) (fail&munmap_ ? (seterr(munmap_), -1) : (setcall(munmap_), munmap(m_=(a), max_=(b)))) #define munmap(a, b) (fail&munmap_ ? (seterr(munmap_), -1) : (setcall(munmap_), munmap(m_=(a), msz_=(b))))
#define setrlimit(...) (fail&setrlimit_ ? (seterr(setrlimit_), -1) : (setcall(setrlimit_), setrlimit(__VA_ARGS__))) #define setrlimit(...) (fail&setrlimit_ ? (seterr(setrlimit_), -1) : (setcall(setrlimit_), setrlimit(__VA_ARGS__)))
#define sigaltstack(...) (fail&sigaltstack_ ? (seterr(sigaltstack_), -1) : (setcall(sigaltstack_), sigaltstack(__VA_ARGS__))) #define sigaltstack(...) (fail&sigaltstack_ ? (seterr(sigaltstack_), -1) : (setcall(sigaltstack_), sigaltstack(__VA_ARGS__)))
#define sigaction(...) (fail&sigaction_ ? (seterr(sigaction_), -1) : (setcall(sigaction_), sigaction(__VA_ARGS__))) #define sigaction(...) (fail&sigaction_ ? (seterr(sigaction_), -1) : (setcall(sigaction_), sigaction(__VA_ARGS__)))
...@@ -58,7 +59,9 @@ static void *wrap(void *i) ...@@ -58,7 +59,9 @@ static void *wrap(void *i)
int main(void) int main(void)
{ {
plan_tests(16); long pgsz = sysconf(_SC_PAGESIZE);
plan_tests(17);
#define chkfail(x, y, z, c1, c2) (call1 = 0, call2 = 0, errno = 0, ok1((fail = x) && (y) && errno == (z) && call1 == (c1) && call2 == (c2))); #define chkfail(x, y, z, c1, c2) (call1 = 0, call2 = 0, errno = 0, ok1((fail = x) && (y) && errno == (z) && call1 == (c1) && call2 == (c2)));
#define chkok( y, z, c1, c2) (call1 = 0, call2 = 0, errno = 0, fail = 0, ok1((y) && errno == (z) && call1 == (c1) && call2 == (c2))); #define chkok( y, z, c1, c2) (call1 = 0, call2 = 0, errno = 0, fail = 0, ok1((y) && errno == (z) && call1 == (c1) && call2 == (c2)));
...@@ -86,7 +89,7 @@ int main(void) ...@@ -86,7 +89,7 @@ int main(void)
chkfail(munmap_, altstack(8*MiB, wrap, 0, 0) == 1, e(munmap_), chkfail(munmap_, altstack(8*MiB, wrap, 0, 0) == 1, e(munmap_),
getrlimit_|setrlimit_|mmap_|sigaltstack_|sigaction_, getrlimit_|setrlimit_|mmap_|sigaltstack_|sigaction_,
setrlimit_|sigaltstack_|sigaction_); setrlimit_|sigaltstack_|sigaction_);
if (fail = 0, munmap(m_, max_) == -1) if (fail = 0, munmap(m_, msz_) == -1)
err(1, "munmap"); err(1, "munmap");
chkok( altstack(1*MiB, wrap, (void *) 1000000, 0) == -1, EOVERFLOW, chkok( altstack(1*MiB, wrap, (void *) 1000000, 0) == -1, EOVERFLOW,
...@@ -102,10 +105,12 @@ int main(void) ...@@ -102,10 +105,12 @@ int main(void)
chkfail(munmap_, altstack(1*MiB, wrap, (void *) 1000000, 0) == -1, EOVERFLOW, chkfail(munmap_, altstack(1*MiB, wrap, (void *) 1000000, 0) == -1, EOVERFLOW,
getrlimit_|setrlimit_|mmap_|sigaltstack_|sigaction_, getrlimit_|setrlimit_|mmap_|sigaltstack_|sigaction_,
setrlimit_|sigaltstack_|sigaction_); setrlimit_|sigaltstack_|sigaction_);
if (fail = 0, munmap(m_, max_) == -1) if (fail = 0, munmap(m_, msz_) == -1)
err(1, "munmap"); err(1, "munmap");
ok1(used > 1*MiB-1*KiB && used < 1*MiB); ok1(altstack_max() == 1*MiB);
diag("used: %lu", used);
ok1(used >= 1*MiB - pgsz && used <= 1*MiB + pgsz);
char *p; char *p;
for(p = altstack_geterr(); *p; p++) for(p = altstack_geterr(); *p; p++)
...@@ -128,7 +133,8 @@ int main(void) ...@@ -128,7 +133,8 @@ int main(void)
getrlimit_|setrlimit_|mmap_|sigaltstack_|sigaction_, getrlimit_|setrlimit_|mmap_|sigaltstack_|sigaction_,
setrlimit_|munmap_|sigaltstack_|sigaction_); setrlimit_|munmap_|sigaltstack_|sigaction_);
ok1(used > 8*MiB-8*KiB && used < 8*MiB); diag("used: %lu", used);
ok1(used >= 8*MiB - pgsz && used <= 8*MiB + pgsz);
used = 0; used = 0;
chkok( altstack(8*MiB, wrap, (void *) 100000, 0) == 0, 0, chkok( altstack(8*MiB, wrap, (void *) 100000, 0) == 0, 0,
...@@ -138,7 +144,8 @@ int main(void) ...@@ -138,7 +144,8 @@ int main(void)
used = 1; used = 1;
altstack_rsp_save(); altstack_rsp_save();
dn(0); dn(0);
ok1(used == 32); diag("used: %lu", used);
ok1(used == 32 || used == 40);
return exit_status(); return exit_status();
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment