このマクロは安全ですか、それともallocaがNULLを返さないようにする必要がありますか?
#define DO_COPY(x) strcpy(alloca(strlen((x)) + 1), x)
このマクロは安全ですか、それともallocaがNULLを返さないようにする必要がありますか?
#define DO_COPY(x) strcpy(alloca(strlen((x)) + 1), x)
文字列がユーザー制御の場合、allocaは安全ではないと思います。allocaが多くのコンパイラーで実装される方法では、スタックポインターから減算する(またはスタックがそのように成長する場合は加算する)量について、いかなる種類の健全性チェックも行いません。スタックの周りに大きな赤いゾーンがある場合でも、alloca():ed文字列をスタックの外側を指すようにするのは比較的簡単です。
特にスレッド環境では、スレッドスタックは非常に小さく、互いに接近している可能性があります。
Linuxマシンでは、これをテストできます。これを使用して他のスレッドスタックで落書きを開始するには、10MBの文字列が必要になります。MacOSでは512kBで十分なようです。
これは、最終的にどれだけ近づくことができるかを確認するための簡単なハックです(OpenBSDのようなランダム化アロケータまたはアロケータの安全性を真剣に受け止めている他のシステムを使用してスタック割り当てが行われる場合、これは実際にはあまりわかりません)。
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <stdint.h>
void *
x(void *v)
{
int x;
return &x;
}
int
main(int argc, char **argv)
{
pthread_t ta, tb;
char *va, *vb;
pthread_create(&ta, NULL, x, NULL);
pthread_create(&tb, NULL, x, NULL);
pthread_join(ta, (void **)&va);
pthread_join(tb, (void **)&vb);
printf("diff: %d\n", abs((intptr_t)vb-(intptr_t)va));
return 0;
}
そして、これがstrcpy(alloca(strlen(s)+ 1)、s)がコンパイルされるものです:
movq %rbx, %rdi
call _strlen
addq $31, %rax
andq $-16, %rax
subq %rax, %rsp
movq %rsp, %rdi
movq %rbx, %rsi
call _strcpy
スタックポインタからstrlen(%rax)からの戻り値を減算する前に、クイックアライメント以外に健全性チェックがないことに注意してください。