linux的线程私有数据以及编译器stack_protector选项
fs和gs提供per-task数据
这两个寄存器被用来访问一些线程私有数据, 其中fs
被用户态程序使用, gs
被内核态使用。应该知道, 在使用pthread时, 可以通过pthread_self()
拿到当前线程的线程id, 其实就是从fs
里面拿数据。至于为什么能这么做, 可以参考这篇文章, 详细介绍了linux
实现per-task数据的原理。作为应用, 我们只需通过glibc间接的访问errbo
和pthread_self()
即可。例如看glibc的代码:
1 |
|
看不懂没关系, 这个属于系统内核细节, 只需要知道内核私有数据通过fs
寄存器访问就行了, 至于我们怎么拿这些私有数据, 那是glibc该考虑的事情, 作为用户态程序, 只管调别人写好的函数就完了。另外, errno
也属于线程私有数据, 知道了上面的这些事情, 很容易理解为啥errno
是线程独享的了。
栈溢出攻击保护机制
介绍另一个奇妙的东西: stack canary
, 这是一个安全策略。这个安全选项专门用于预防栈溢出攻击, 每个线程(在内核中对应一个task_struct
)都有它自己的一个stack canary
, 它相当于一个随机数。在函数入口需要向函数栈push
一个canary
, 函数出口需要将函数栈中的canary
和原始值做对比。这个stack canary
其实就是存储在fs
中的, 它也是线程私有数据!当我们开启gcc的fstack-protector
时, 编译器就自己打桩, 做相关检查。我们可以通过fs:40
拿到这个随机数。