1

I'm using the pthread.h library in glibc-2.27 and when my process calls pthread_create() eighteen times or more (it's supposed to be a heavy multi-threaded application) the process is aborted with the error message:

*** stack smashing detected ***: <unknown> terminated
Aborted (core dumped)

I did some strace as part of my debugging ritual and I found the reason. Apparently all implicit calls for mmap() as part of the pthread_create() looks like this:

mmap(NULL, 8392704, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7f6de43fa000

One can notice the MAP_STACK flag which indicates:

Allocate the mapping at an address suitable for a process or thread stack. This flag is currently a no-op, but is used in the glibc threading implementation so that if some architectures require special treatment for stack allocations, support can later be transparently implemented for glibc.

(man mmap on my system - Ubuntu 18.04 LTS)

It is possible to configure the pthread_create call not to do this? or maybe use brk or something else to increase the data segment automatically?

Thanks for any help!

Z E Nir
  • 332
  • 1
  • 2
  • 15

2 Answers2

3

It is extremely unlikely that your issue has anything to do with this MAP_STACK flag.

You have a bug somewhere else in your application which causes stack corruption. Try running your application under valgrind, or building with -fsanitize=address. Either approach may pinpoint the exact location of the error, and you should be able to figure out what is wrong based on that.

Florian Weimer
  • 32,022
  • 3
  • 48
  • 92
  • Why not? it makes a lot of sense, the `mmap` allocates memory that can be stack, untill it actually hit it... (none the less I will try what you offered... thanks!) – Z E Nir Apr 06 '20 at 19:49
  • @ZENir: Because, as the documentation you quoted yourself says, *"This flag is currently a no-op"*, which means that it has no effect. The "stack smashing detected" generally means some code has overrun a stack-allocated variable. – caf Apr 07 '20 at 04:54
  • Oh, I thought the *"no op"* part meant this is the default behavior... – Z E Nir Apr 07 '20 at 08:15
  • Hey just wanted to update about the bug that caused the stack smash. I had an array of `pthread_t` and there was an out of bound vulnerability - means that the loop that allocated new threads allocated more threads than the array have indexes for, and in some point it overflowed - the loop allocated new thread with an index variable which is actually the stack cookie or something. – Z E Nir Apr 20 '20 at 09:06
2

It is possible to configure the pthread_create call not to do this?

pthread_create() needs to allocate space for the thread's stack, otherwise the thread cannot run -- not even with an empty thread function. That's what the mmap you're seeing is for. It is not possible to do without.

or maybe use brk or something else to increase the data segment automatically?

If you have the time and skill to write your own thread library, then do have a go and let us know what happens. Otherwise, no, the details of how pthread_create() reserves space for the new thread's stack is not configurable in any implementation I know.

And that does not matter anyway, because the mmap() call is not the problem. If a syscall has an unrecoverable failure then that's a failure of the kernel, and you get a kernel panic, not an application crash. GNU C's stack-smashing detection happens in userspace. The functions to which it applies therefore do not appear in your strace output, which traces only system calls.

It might be useful to you have a better understanding of stack smashing and GNU's defense against it. Dr. Dobb's ran a nice article on just that several years ago, and it is still well worth a read. The bottom line, though, is that stack smashing happens when a function implementation misbehaves by overwriting the part of its stack frame that contains its return address. Unless you've got some inline assembly going on, the smashing almost surely arises from one of your own functions overrunning the bounds of one of its local variables. It is detected when that function tries to return, by tooling in the function epilogue that serves that purpose.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • I rather quote the original [smashing the stack for fun and profit](http://www.phrack.org/issues/49/14.html#article) but thanks. anyway you did answer for my question about configuring `pthread_create`, and I'm not intending to write my own thread library o what happened to code reuse nowadays?! (just kidding). I will try to look for a buffer overflow in the rest of my code. – Z E Nir Apr 07 '20 at 08:36