From 141e582ead507103a5f8860a3ec8c0f237d2690a Mon Sep 17 00:00:00 2001 From: Dan Good Date: Mon, 8 Feb 2016 20:57:23 +0000 Subject: [PATCH] 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: Dan Good --- ccan/altstack/altstack.c | 22 +++++++++++++++++++--- ccan/altstack/altstack.h | 14 ++++++++++++++ ccan/altstack/test/run.c | 23 +++++++++++++++-------- 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/ccan/altstack/altstack.c b/ccan/altstack/altstack.c index 6faf38f5..67f457bc 100644 --- a/ccan/altstack/altstack.c +++ b/ccan/altstack/altstack.c @@ -8,6 +8,7 @@ #include #include #include +#include #include static __thread char ebuf[ALTSTACK_ERR_MAXLEN]; @@ -37,6 +38,11 @@ static void segvjmp(int signum) } 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) { assert(i < 2); @@ -57,6 +63,7 @@ static __thread void *arg_, *out_; int altstack(rlim_t max, void *(*fn)(void *), void *arg, void **out) { + long pgsz = sysconf(_SC_PAGESIZE); int ret = -1, undo = 0; char *m; struct rlimit rl_save; @@ -69,11 +76,16 @@ int altstack(rlim_t max, void *(*fn)(void *), void *arg, void **out) fn_ = fn; arg_ = arg; out_ = 0; + max_ = max; ebuf[elen = 0] = '\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(setrlimit(RLIMIT_STACK, &(struct rlimit) { max, rl_save.rlim_max }), 1); + ok(setrlimit(RLIMIT_STACK, &(struct rlimit) { max_, rl_save.rlim_max }), 1); undo++; 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) ok(sigaction(SIGSEGV, &sa, &sa_save), 1); undo++; - asm volatile ("movq %%rsp, %%r10\nmov %0, %%rsp\npush %%r10" : : "g" (m + max) : "r10"); - rsp_save(0); + asm volatile ( + "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_); asm volatile ("pop %rsp"); ret = 0; diff --git a/ccan/altstack/altstack.h b/ccan/altstack/altstack.h index 5570e7b5..4445a2a3 100644 --- a/ccan/altstack/altstack.h +++ b/ccan/altstack/altstack.h @@ -103,6 +103,20 @@ char *altstack_geterr(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 * diff --git a/ccan/altstack/test/run.c b/ccan/altstack/test/run.c index adc1020e..de948872 100644 --- a/ccan/altstack/test/run.c +++ b/ccan/altstack/test/run.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -20,13 +21,13 @@ enum { }; int fail, call1, call2; char *m_; -rlim_t max_; +rlim_t msz_; #define e(x) (900+(x)) #define seterr(x) (errno = e(x)) #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 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 sigaltstack(...) (fail&sigaltstack_ ? (seterr(sigaltstack_), -1) : (setcall(sigaltstack_), sigaltstack(__VA_ARGS__))) #define sigaction(...) (fail&sigaction_ ? (seterr(sigaction_), -1) : (setcall(sigaction_), sigaction(__VA_ARGS__))) @@ -58,7 +59,9 @@ static void *wrap(void *i) 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 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) chkfail(munmap_, altstack(8*MiB, wrap, 0, 0) == 1, e(munmap_), getrlimit_|setrlimit_|mmap_|sigaltstack_|sigaction_, setrlimit_|sigaltstack_|sigaction_); - if (fail = 0, munmap(m_, max_) == -1) + if (fail = 0, munmap(m_, msz_) == -1) err(1, "munmap"); chkok( altstack(1*MiB, wrap, (void *) 1000000, 0) == -1, EOVERFLOW, @@ -102,10 +105,12 @@ int main(void) chkfail(munmap_, altstack(1*MiB, wrap, (void *) 1000000, 0) == -1, EOVERFLOW, getrlimit_|setrlimit_|mmap_|sigaltstack_|sigaction_, setrlimit_|sigaltstack_|sigaction_); - if (fail = 0, munmap(m_, max_) == -1) + if (fail = 0, munmap(m_, msz_) == -1) 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; for(p = altstack_geterr(); *p; p++) @@ -128,7 +133,8 @@ int main(void) getrlimit_|setrlimit_|mmap_|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; chkok( altstack(8*MiB, wrap, (void *) 100000, 0) == 0, 0, @@ -138,7 +144,8 @@ int main(void) used = 1; altstack_rsp_save(); dn(0); - ok1(used == 32); + diag("used: %lu", used); + ok1(used == 32 || used == 40); return exit_status(); } -- 2.39.2