From 52e50e20fae2b0a1853bd0657fc52dbf632416c3 Mon Sep 17 00:00:00 2001 From: Razvan Deaconescu Date: Sat, 24 Apr 2021 13:48:34 +0300 Subject: [PATCH 1/3] Add TLS (thread-local storage) tests Add tls/ folder. __thread.c highlights the use of implicit TLS, i.e. via the `__thread` storage class keyword. tsd.c uses explicit TLS, i.e. via `pthread_setspecific()` / `pthread_getspecific` function calls. --- tls/.gitignore | 4 ++++ tls/Makefile | 25 ++++++++++++++++++++ tls/__thread.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++ tls/tsd.c | 57 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 149 insertions(+) create mode 100644 tls/.gitignore create mode 100644 tls/Makefile create mode 100644 tls/__thread.c create mode 100644 tls/tsd.c diff --git a/tls/.gitignore b/tls/.gitignore new file mode 100644 index 0000000..6cc73e7 --- /dev/null +++ b/tls/.gitignore @@ -0,0 +1,4 @@ +/__thread +/__thread-static +/tsd +/tsd-static diff --git a/tls/Makefile b/tls/Makefile new file mode 100644 index 0000000..537215c --- /dev/null +++ b/tls/Makefile @@ -0,0 +1,25 @@ +CFLAGS = -Wall +LDLIBS = -lpthread + +.PHONY: all clean + +all: __thread __thread-static tsd tsd-static + +__thread-static: __thread.o + $(CC) $(LDLFAGS) -static -o $@ $^ $(LDLIBS) + +__thread: __thread.o + +__thread.o: __thread.c + +tsd-static: tsd.o + $(CC) $(LDLFAGS) -static -o $@ $^ $(LDLIBS) + +tsd: tsd.o + +tsd.o: tsd.c + +clean: + -rm -f __thread.o __thread __thread-static + -rm -f tsd.o tsd tsd-static + -rm -f *~ diff --git a/tls/__thread.c b/tls/__thread.c new file mode 100644 index 0000000..6958154 --- /dev/null +++ b/tls/__thread.c @@ -0,0 +1,63 @@ +#include +#include +#include +#include +#include +#include + +static __thread size_t me; +static __thread size_t you; +static __thread size_t them = 543; + +static void *tf(void *arg) +{ + unsigned long id = (unsigned long) arg; + static __thread size_t us = 13; + + me = 200 + id; + us += id*id; + printf("me in thread (%p): %zu\n", &me, me); + printf("you in thread (%p): %zu\n", &you, you); + printf("you in thread (%p): %zu\n", &them, them); + printf("us in thread (%p): %zu\n", &us, us); + printf("errno in thread (%p): %d\n", &errno, errno); + + return NULL; +} + +int main(void) +{ + pthread_t new; + int err; + + me = 100; + you = 999; + them = 3; + printf("me before create (%p): %zu\n", &me, me); + printf("you before create (%p): %zu\n", &you, you); + printf("them before create (%p): %zu\n", &them, them); + printf("errno before create (%p): %d\n", &errno, errno); + + err = pthread_create(&new, NULL, tf, (void *) 1); + if (err < 0) { + perror("pthread_create"); + exit(EXIT_FAILURE); + } + err = pthread_create(&new, NULL, tf, (void *) 2); + if (err < 0) { + perror("pthread_create"); + exit(EXIT_FAILURE); + } + + printf("me after create before join (%p): %zu\n", &me, me); + printf("you after create before join (%p): %zu\n", &you, you); + printf("them after create before join (%p): %zu\n", &them, them); + printf("errno after create before join (%p): %d\n", &errno, errno); + pthread_join(new, NULL); + printf("me after join (%p): %zu\n", &me, me); + printf("you after join (%p): %zu\n", &you, you); + printf("them after join (%p): %zu\n", &them, them); + printf("errno after join (%p): %d\n", &errno, errno); + + return 0; +} diff --git a/tls/tsd.c b/tls/tsd.c new file mode 100644 index 0000000..5fe9a49 --- /dev/null +++ b/tls/tsd.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include + +static pthread_key_t me_key; +static pthread_key_t you_key; +static pthread_key_t them_key; + +static void *tf(void *arg) +{ + pthread_setspecific(me_key, (const void *) 200); + printf("me_key in thread (%p): %u, me value in thread: %zu\n", &me_key, me_key, (size_t) pthread_getspecific(me_key)); + printf("you_key in thread (%p): %u, you value in thread: %zu\n", &you_key, you_key, (size_t) pthread_getspecific(you_key)); + printf("them_key in thread (%p): %u, them value in thread: %zu\n", &them_key, them_key, (size_t) pthread_getspecific(them_key)); + + return NULL; +} + +int main(void) +{ + pthread_t new; + int err; + + pthread_key_create(&me_key, NULL); + pthread_key_create(&you_key, NULL); + pthread_key_create(&them_key, NULL); + + pthread_setspecific(me_key, (const void *) 100); + pthread_setspecific(you_key, (const void *) 999); + pthread_setspecific(them_key, (const void *) 3); + printf("me_key before create (%p): %u, me value before create: %zu\n", &me_key, me_key, (size_t) pthread_getspecific(me_key)); + printf("you_key before create (%p): %u, me value before create: %zu\n", &you_key, you_key, (size_t) pthread_getspecific(you_key)); + printf("them_key before create (%p): %u, me value before create: %zu\n", &them_key, them_key, (size_t) pthread_getspecific(them_key)); + + err = pthread_create(&new, NULL, tf, NULL); + if (err < 0) { + perror("pthread_create"); + exit(EXIT_FAILURE); + } + + printf("me_key after create before join (%p): %u, me value after create before join: %zu\n", &me_key, me_key, (size_t) pthread_getspecific(me_key)); + printf("you_key after create before join (%p): %u, you value after create before join: %zu\n", &you_key, you_key, (size_t) pthread_getspecific(you_key)); + printf("them_key after create before join (%p): %u, them value beafter create before join: %zu\n", &them_key, them_key, (size_t) pthread_getspecific(them_key)); + pthread_join(new, NULL); + printf("me_key after join (%p): %u, me value after join: %zu\n", &me_key, me_key, (size_t) pthread_getspecific(me_key)); + printf("you_key after join (%p): %u, you value after join: %zu\n", &you_key, you_key, (size_t) pthread_getspecific(you_key)); + printf("them_key after join (%p): %u, them value after join: %zu\n", &them_key, them_key, (size_t) pthread_getspecific(them_key)); + + /* This is really not required, but we call it for API completeness. */ + pthread_key_delete(me_key); + pthread_key_delete(you_key); + pthread_key_delete(them_key); + + return 0; +} From d14c35b50e5068ab4af18d0bb564280fafe2736f Mon Sep 17 00:00:00 2001 From: Razvan Deaconescu Date: Sat, 24 Apr 2021 13:50:37 +0300 Subject: [PATCH 2/3] tls: Add draft README --- tls/README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tls/README.md diff --git a/tls/README.md b/tls/README.md new file mode 100644 index 0000000..243ddb0 --- /dev/null +++ b/tls/README.md @@ -0,0 +1,11 @@ +# Thread-Local Storage + +This is a tutorial / presentation on thread-local storage (TLS). +TLS is a per-thread memory area used to store thread-specific data. +Global data that are required to be specific per thread are usually stored as part of the TLS. + +https://docs.oracle.com/cd/E19120-01/open.solaris/819-0690/chapter8-1/index.html + +https://chao-tic.github.io/blog/2018/12/25/tls + +https://wiki.osdev.org/Thread_Local_Storage From ab270310d17ad3cfbee9e653504ddb31286bfd3b Mon Sep 17 00:00:00 2001 From: Razvan Deaconescu Date: Sat, 24 Apr 2021 22:22:08 +0300 Subject: [PATCH 3/3] tls: Add sample program to modify TLS (and stack guard) using local (on stack) variable --- tls/Makefile | 8 +++++- tls/indirect_modify | Bin 0 -> 8704 bytes tls/indirect_modify.c | 58 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100755 tls/indirect_modify create mode 100644 tls/indirect_modify.c diff --git a/tls/Makefile b/tls/Makefile index 537215c..ab69ae6 100644 --- a/tls/Makefile +++ b/tls/Makefile @@ -3,7 +3,7 @@ LDLIBS = -lpthread .PHONY: all clean -all: __thread __thread-static tsd tsd-static +all: __thread __thread-static tsd tsd-static indirect_modify __thread-static: __thread.o $(CC) $(LDLFAGS) -static -o $@ $^ $(LDLIBS) @@ -19,7 +19,13 @@ tsd: tsd.o tsd.o: tsd.c +indirect_modify: indirect_modify.o + +indirect_modify.o: indirect_modify.c + $(CC) $(CFLAGS) -fstack-protector-strong -c -o $@ $< + clean: -rm -f __thread.o __thread __thread-static -rm -f tsd.o tsd tsd-static + -rm -f indirect_modify.o indirect_modify -rm -f *~ diff --git a/tls/indirect_modify b/tls/indirect_modify new file mode 100755 index 0000000000000000000000000000000000000000..f6458c325c0de951ac0b8dcd3dc008e7412c585a GIT binary patch literal 8704 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 literal 0 HcmV?d00001 diff --git a/tls/indirect_modify.c b/tls/indirect_modify.c new file mode 100644 index 0000000..18bfcf0 --- /dev/null +++ b/tls/indirect_modify.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include + +/* + * Offset is determined by running the program and computing + * (&age - &placeholder) / sizeof(unsigned int). + */ +#define OFFSET_FROM_LOCAL_TO_TLS 522 + +/* + * &age is at fs:0xfffffffffffffffc, i.e. tcb-0x4 + * stack guard is at fs:0x28, i.e. tcb+x028 + * offset is (0x28-(-0x04))/4 = 11 + */ +#define OFFSET_FROM_TLS_TO_STACK_GUARD 11 + +static __thread unsigned int age; + +static void *tf(void *arg) +{ + unsigned int placeholder; + unsigned int *ptr; + unsigned long *stack_guard_ptr; + + ptr = &placeholder; + printf("placeholder address: %p\n", &placeholder); + + age = 22; + printf("age (address: %p): %u\n", &age, age); + + * (ptr + OFFSET_FROM_LOCAL_TO_TLS) = 99; + printf("age (address: %p): %u\n", &age, age); + + /* Print then overwrite stack guard with some gibberish. */ + stack_guard_ptr = (unsigned long *) (ptr + OFFSET_FROM_LOCAL_TO_TLS + OFFSET_FROM_TLS_TO_STACK_GUARD); + printf("stack guard / canary (address: %p): 0x%016lx\n", stack_guard_ptr, *stack_guard_ptr); + * (stack_guard_ptr) = 0xaabbccddeeff0011; + + return NULL; +} + +int main(void) +{ + pthread_t new; + int err; + + err = pthread_create(&new, NULL, tf, (void *) 1); + if (err < 0) { + perror("pthread_create"); + exit(EXIT_FAILURE); + } + pthread_join(new, NULL); + + return 0; +}