Skip to content

Commit

Permalink
Fix: integer overflow in main thread stack base detection
Browse files Browse the repository at this point in the history
Using `getrlimit` led to invalid STACK SIZE limits in some cases
which in turn led to an integer overflow while detecting the stack
base of the main stack.

This patch replaces `getrlimit` with proper, but non portable, calls
to pthread functions that return the stack of a given thread.

fixes crystal-lang#7368
fixes crystal-lang#7369
  • Loading branch information
ysbaddaden committed Feb 4, 2019
1 parent 0ef090a commit 0da2b62
Show file tree
Hide file tree
Showing 14 changed files with 82 additions and 24 deletions.
18 changes: 1 addition & 17 deletions src/fiber.cr
Original file line number Diff line number Diff line change
Expand Up @@ -87,28 +87,12 @@ class Fiber
end

# :nodoc:
def initialize
def initialize(@stack : Void*)
@proc = Proc(Void).new { }
@stack_top = _fiber_get_stack_top
@stack_bottom = GC.stack_bottom
@name = "main"

# Determine location of the top of the stack.
# The technique here works only for the main stack on a POSIX platform.
# TODO: implement for Windows with GetCurrentThreadStackLimits
# TODO: implement for pthreads using
# linux-glibc/musl: pthread_getattr_np
# macosx: pthread_get_stackaddr_np, pthread_get_stacksize_np
# freebsd: pthread_attr_get_np
# openbsd: pthread_stackseg_np
@stack = Pointer(Void).null
{% unless flag?(:win32) %}
if LibC.getrlimit(LibC::RLIMIT_STACK, out rlim) == 0
stack_size = rlim.rlim_cur
@stack = Pointer(Void).new(@stack_bottom.address - stack_size)
end
{% end %}

@@fibers.push(self)
end

Expand Down
3 changes: 3 additions & 0 deletions src/lib_c/aarch64-linux-gnu/c/pthread.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ require "./sys/types"
lib LibC
PTHREAD_MUTEX_ERRORCHECK = 2

fun pthread_attr_destroy(attr : PthreadAttrT*) : Int
fun pthread_attr_getstack(addr : PthreadAttrT*, stackaddr : Void**, stacksize : SizeT*) : Int
fun pthread_condattr_destroy(attr : PthreadCondattrT*) : Int
fun pthread_condattr_init(attr : PthreadCondattrT*) : Int
fun pthread_condattr_setclock(attr : PthreadCondattrT*, type : ClockidT) : Int
Expand All @@ -14,6 +16,7 @@ lib LibC
fun pthread_cond_wait(cond : PthreadCondT*, mutex : PthreadMutexT*) : Int
fun pthread_create(newthread : PthreadT*, attr : PthreadAttrT*, start_routine : Void* -> Void*, arg : Void*) : Int
fun pthread_detach(th : PthreadT) : Int
fun pthread_getattr_np(thread : PthreadT, attr : PthreadAttrT*) : Int
fun pthread_equal(thread1 : PthreadT, thread2 : PthreadT) : Int
fun pthread_join(th : PthreadT, thread_return : Void**) : Int
fun pthread_mutexattr_destroy(attr : PthreadMutexattrT*) : Int
Expand Down
3 changes: 3 additions & 0 deletions src/lib_c/aarch64-linux-musl/c/pthread.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ require "./sys/types"
lib LibC
PTHREAD_MUTEX_ERRORCHECK = 2

fun pthread_attr_destroy(x0 : PthreadAttrT*) : Int
fun pthread_attr_getstack(x0 : PthreadAttrT*, x1 : Void**, x2 : SizeT*) : Int
fun pthread_condattr_destroy(x0 : PthreadCondattrT*) : Int
fun pthread_condattr_init(x0 : PthreadCondattrT*) : Int
fun pthread_condattr_setclock(x0 : PthreadCondattrT*, x1 : ClockidT) : Int
Expand All @@ -14,6 +16,7 @@ lib LibC
fun pthread_cond_wait(x0 : PthreadCondT*, x1 : PthreadMutexT*) : Int
fun pthread_create(x0 : PthreadT*, x1 : PthreadAttrT*, x2 : Void* -> Void*, x3 : Void*) : Int
fun pthread_detach(x0 : PthreadT) : Int
fun pthread_getattr_np(x0 : PthreadT, x1 : PthreadAttrT*) : Int
fun pthread_join(x0 : PthreadT, x1 : Void**) : Int
fun pthread_mutexattr_destroy(x0 : PthreadMutexattrT*) : Int
fun pthread_mutexattr_init(x0 : PthreadMutexattrT*) : Int
Expand Down
3 changes: 3 additions & 0 deletions src/lib_c/arm-linux-gnueabihf/c/pthread.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ require "./sys/types"
lib LibC
PTHREAD_MUTEX_ERRORCHECK = 2

fun pthread_attr_destroy(attr : PthreadAttrT*) : Int
fun pthread_attr_getstack(addr : PthreadAttrT*, stackaddr : Void**, stacksize : SizeT*) : Int
fun pthread_condattr_destroy(attr : PthreadCondattrT*) : Int
fun pthread_condattr_init(attr : PthreadCondattrT*) : Int
fun pthread_condattr_setclock(attr : PthreadCondattrT*, type : ClockidT) : Int
Expand All @@ -14,6 +16,7 @@ lib LibC
fun pthread_cond_wait(cond : PthreadCondT*, mutex : PthreadMutexT*) : Int
fun pthread_create(newthread : PthreadT*, attr : PthreadAttrT*, start_routine : Void* -> Void*, arg : Void*) : Int
fun pthread_detach(th : PthreadT) : Int
fun pthread_getattr_np(thread : PthreadT, attr : PthreadAttrT*) : Int
fun pthread_equal(thread1 : PthreadT, thread2 : PthreadT) : Int
fun pthread_join(th : PthreadT, thread_return : Void**) : Int
fun pthread_mutexattr_destroy(attr : PthreadMutexattrT*) : Int
Expand Down
3 changes: 3 additions & 0 deletions src/lib_c/i386-linux-gnu/c/pthread.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ require "./sys/types"
lib LibC
PTHREAD_MUTEX_ERRORCHECK = 2

fun pthread_attr_destroy(attr : PthreadAttrT*) : Int
fun pthread_attr_getstack(addr : PthreadAttrT*, stackaddr : Void**, stacksize : SizeT*) : Int
fun pthread_condattr_destroy(attr : PthreadCondattrT*) : Int
fun pthread_condattr_init(attr : PthreadCondattrT*) : Int
fun pthread_condattr_setclock(attr : PthreadCondattrT*, type : ClockidT) : Int
Expand All @@ -14,6 +16,7 @@ lib LibC
fun pthread_cond_wait(cond : PthreadCondT*, mutex : PthreadMutexT*) : Int
fun pthread_create(newthread : PthreadT*, attr : PthreadAttrT*, start_routine : Void* -> Void*, arg : Void*) : Int
fun pthread_detach(th : PthreadT) : Int
fun pthread_getattr_np(thread : PthreadT, attr : PthreadAttrT*) : Int
fun pthread_join(th : PthreadT, thread_return : Void**) : Int
fun pthread_mutexattr_destroy(attr : PthreadMutexattrT*) : Int
fun pthread_mutexattr_init(attr : PthreadMutexattrT*) : Int
Expand Down
3 changes: 3 additions & 0 deletions src/lib_c/i386-linux-musl/c/pthread.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ require "./sys/types"
lib LibC
PTHREAD_MUTEX_ERRORCHECK = 2

fun pthread_attr_destroy(x0 : PthreadAttrT*) : Int
fun pthread_attr_getstack(x0 : PthreadAttrT*, x1 : Void**, x2 : SizeT*) : Int
fun pthread_condattr_destroy(x0 : PthreadCondattrT*) : Int
fun pthread_condattr_init(x0 : PthreadCondattrT*) : Int
fun pthread_condattr_setclock(x0 : PthreadCondattrT*, x1 : ClockidT) : Int
Expand All @@ -14,6 +16,7 @@ lib LibC
fun pthread_cond_wait(x0 : PthreadCondT*, x1 : PthreadMutexT*) : Int
fun pthread_create(x0 : PthreadT*, x1 : PthreadAttrT*, x2 : Void* -> Void*, x3 : Void*) : Int
fun pthread_detach(x0 : PthreadT) : Int
fun pthread_getattr_np(x0 : PthreadT, x1 : PthreadAttrT*) : Int
fun pthread_join(x0 : PthreadT, x1 : Void**) : Int
fun pthread_mutexattr_destroy(x0 : PthreadMutexattrT*) : Int
fun pthread_mutexattr_init(x0 : PthreadMutexattrT*) : Int
Expand Down
2 changes: 2 additions & 0 deletions src/lib_c/x86_64-darwin/c/pthread.cr
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ lib LibC
fun pthread_cond_wait(x0 : PthreadCondT*, x1 : PthreadMutexT*) : Int
fun pthread_create(x0 : PthreadT*, x1 : PthreadAttrT*, x2 : Void* -> Void*, x3 : Void*) : Int
fun pthread_detach(x0 : PthreadT) : Int
fun pthread_get_stackaddr_np(x0 : PthreadT) : Void*
fun pthread_get_stacksize_np(x0 : PthreadT) : SizeT
fun pthread_join(x0 : PthreadT, x1 : Void**) : Int
fun pthread_mutexattr_destroy(x0 : PthreadMutexattrT*) : Int
fun pthread_mutexattr_init(x0 : PthreadMutexattrT*) : Int
Expand Down
4 changes: 4 additions & 0 deletions src/lib_c/x86_64-freebsd/c/pthread.cr
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ require "./sys/types"
lib LibC
PTHREAD_MUTEX_ERRORCHECK = 1

fun pthread_attr_destroy(x0 : PthreadAttrT*) : Int
fun pthread_attr_get_np(x0 : PthreadT, x1 : PthreadAttrT*) : Int
fun pthread_attr_getstack(x0 : PthreadAttrT*, x1 : Void**, x2 : SizeT*) : Int
fun pthread_attr_init(x0 : PthreadAttrT*) : Int
fun pthread_condattr_destroy(x0 : PthreadCondattrT*) : Int
fun pthread_condattr_init(x0 : PthreadCondattrT*) : Int
fun pthread_condattr_setclock(x0 : PthreadCondattrT*, x1 : ClockidT) : Int
Expand Down
3 changes: 3 additions & 0 deletions src/lib_c/x86_64-linux-gnu/c/pthread.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ require "./sys/types"
lib LibC
PTHREAD_MUTEX_ERRORCHECK = 2

fun pthread_attr_destroy(attr : PthreadAttrT*) : Int
fun pthread_attr_getstack(addr : PthreadAttrT*, stackaddr : Void**, stacksize : SizeT*) : Int
fun pthread_condattr_destroy(attr : PthreadCondattrT*) : Int
fun pthread_condattr_init(attr : PthreadCondattrT*) : Int
fun pthread_condattr_setclock(attr : PthreadCondattrT*, type : ClockidT) : Int
Expand All @@ -14,6 +16,7 @@ lib LibC
fun pthread_cond_wait(cond : PthreadCondT*, mutex : PthreadMutexT*) : Int
fun pthread_create(newthread : PthreadT*, attr : PthreadAttrT*, start_routine : Void* -> Void*, arg : Void*) : Int
fun pthread_detach(th : PthreadT) : Int
fun pthread_getattr_np(thread : PthreadT, attr : PthreadAttrT*) : Int
fun pthread_join(th : PthreadT, thread_return : Void**) : Int
fun pthread_mutexattr_destroy(attr : PthreadMutexattrT*) : Int
fun pthread_mutexattr_init(attr : PthreadMutexattrT*) : Int
Expand Down
3 changes: 3 additions & 0 deletions src/lib_c/x86_64-linux-musl/c/pthread.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ require "./sys/types"
lib LibC
PTHREAD_MUTEX_ERRORCHECK = 2

fun pthread_attr_destroy(x0 : PthreadAttrT*) : Int
fun pthread_attr_getstack(x0 : PthreadAttrT*, x1 : Void**, x2 : SizeT*) : Int
fun pthread_condattr_destroy(x0 : PthreadCondattrT*) : Int
fun pthread_condattr_init(x0 : PthreadCondattrT*) : Int
fun pthread_condattr_setclock(x0 : PthreadCondattrT*, x1 : ClockidT) : Int
Expand All @@ -14,6 +16,7 @@ lib LibC
fun pthread_cond_wait(x0 : PthreadCondT*, x1 : PthreadMutexT*) : Int
fun pthread_create(x0 : PthreadT*, x1 : PthreadAttrT*, x2 : Void* -> Void*, x3 : Void*) : Int
fun pthread_detach(x0 : PthreadT) : Int
fun pthread_getattr_np(x0 : PthreadT, x1 : PthreadAttrT*) : Int
fun pthread_join(x0 : PthreadT, x1 : Void**) : Int
fun pthread_mutexattr_destroy(x0 : PthreadMutexattrT*) : Int
fun pthread_mutexattr_init(x0 : PthreadMutexattrT*) : Int
Expand Down
2 changes: 2 additions & 0 deletions src/lib_c/x86_64-openbsd/c/pthread.cr
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ lib LibC
fun pthread_join(x0 : PthreadT, x1 : Void**) : Int
alias PthreadKeyDestructor = (Void*) ->
fun pthread_key_create(PthreadKeyT*, PthreadKeyDestructor) : Int
fun pthread_main_np : Int
fun pthread_mutexattr_destroy(x0 : PthreadMutexattrT*) : Int
fun pthread_mutexattr_init(x0 : PthreadMutexattrT*) : Int
fun pthread_mutexattr_settype(x0 : PthreadMutexattrT*, x1 : Int) : Int
Expand All @@ -30,4 +31,5 @@ lib LibC
fun pthread_mutex_unlock(x0 : PthreadMutexT*) : Int
fun pthread_self : PthreadT
fun pthread_setspecific(PthreadKeyT, Void*) : Int
fun pthread_stackseg_np(PthreadT, StackT*) : Int
end
6 changes: 6 additions & 0 deletions src/lib_c/x86_64-openbsd/c/signal.cr
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ lib LibC
SIG_DFL = SighandlerT.new(Pointer(Void).new(0_u64), Pointer(Void).null)
SIG_IGN = SighandlerT.new(Pointer(Void).new(1_u64), Pointer(Void).null)

struct StackT
ss_sp : Void*
ss_size : SizeT
ss_flags : Int
end

fun kill(x0 : PidT, x1 : Int) : Int
fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int
fun signal(x0 : Int, x1 : Int -> Void) : Int -> Void
Expand Down
11 changes: 6 additions & 5 deletions src/lib_c/x86_64-openbsd/c/unistd.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ require "./sys/types"
require "./stdint"

lib LibC
F_OK = 0
R_OK = 0x04
W_OK = 0x02
X_OK = 0x01
SC_CLK_TCK = 3
F_OK = 0
R_OK = 0x04
W_OK = 0x02
X_OK = 0x01
SC_CLK_TCK = 3
SC_PAGESIZE = 28

fun chroot(dirname : Char*) : Int
fun access(x0 : Char*, x1 : Int) : Int
Expand Down
42 changes: 40 additions & 2 deletions src/thread.cr
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class Thread
def initialize
@func = ->{}
@th = LibC.pthread_self
@main_fiber = Fiber.new
@main_fiber = Fiber.new(stack_address)

@@threads.push(self)
end
Expand Down Expand Up @@ -124,7 +124,7 @@ class Thread

protected def start
Thread.current = self
@main_fiber = fiber = Fiber.new
@main_fiber = fiber = Fiber.new(stack_address)

begin
@func.call
Expand All @@ -135,4 +135,42 @@ class Thread
Fiber.inactive(fiber)
end
end

private def stack_address : Void*
address = Pointer(Void).null

{% if flag?(:darwin) %}
address = LibC.pthread_get_stackaddr_np(@th) - pthread_get_stacksize_np(@th)

{% elsif flag?(:freebsd) %}
ret = LibC.pthread_attr_init(out attr)
raise Errno.new("pthread_attr_init", ret) unless ret == 0

if LibC.pthread_attr_get_np(@th, pointerof(attr)) == 0
LibC.pthread_attr_getstack(pointerof(attr), pointerof(address), out _)
end
ret = LibC.pthread_attr_destroy(pointerof(attr))
raise Errno.new("pthread_attr_destroy", ret) unless ret == 0

{% elsif flag?(:linux) %}
if LibC.pthread_getattr_np(@th, out attr) == 0
LibC.pthread_attr_getstack(pointerof(attr), pointerof(address), out _)
end
ret = LibC.pthread_attr_destroy(pointerof(attr))
raise Errno.new("pthread_attr_destroy", ret) unless ret == 0

{% elsif flag?(:openbsd) %}
ret = LibC.pthread_stackseg_np(@th, out stack)
raise Errno.new("pthread_stackseg_np", ret) unless ret == 0

address =
if LibC.pthread_main_np == 1
stack.ss_sp - stack.ss_size + sysconf(LibC::SC_PAGESIZE)
else
stack.ss_sp - stack.ss_size
end
{% end %}

address
end
end

0 comments on commit 0da2b62

Please sign in to comment.