3

以下の 32 ビット プログラムはset_thread_area(2)、GDT でエントリを作成するために呼び出します。これは、TLS に使用するためのものです。FS通常、結果のセレクターはorに入れられGS、正常に使用されます。DSしかし、64ビットカーネルで実行されているorに入れられた場合ES、最終的に(おそらくコンテキストスイッチの後)、このセレクターはゼロになります。

しかし、代わりにmodify_ldt(2)結果の LDT エントリのセレクタを使用してこれらのセグメント レジスタに入れると、それらは値を保持しているように見えます!

また、どちらも GDT を参照する64 ビット コード セグメント ( 0x33) または 32ビット コード セグメント ( ) のセレクタなどをorに配置すると、それらはゼロに設定されません。0x23DSES

これがソースです(fasmでコンパイル)、奇妙な動作を示しています:

format ELF executable
segment readable executable

SYS_WRITE=4
STDERR=2
SYS_SET_THREAD_AREA=243
SYS_EXIT=1

entry $
start:
    mov eax, SYS_SET_THREAD_AREA
    mov ebx, user_desc_TLS1
    int 0x80
    mov ecx,[entry_number_TLS1]
    lea ecx,[ecx*8+3]
    mov ds,cx
; let's wait until DS spontaneously zeroes...
    xor eax,eax
checkDsZero:
    mov ax,ds
    test eax,eax
    jnz checkDsZero

    mov eax, SYS_WRITE
    mov ebx, STDERR
    mov ecx, dsZeroedMsg
    mov edx, dsZeroedMsgLen
    int 0x80

    xor ebx, ebx
    mov eax, SYS_EXIT
    int 0x80

segment readable writable
dsZeroedMsg:
    db "DS zeroed. Exiting",0xa
dsZeroedMsgLen=$-dsZeroedMsg

SEGMENT_32BIT=1
CONTENTS_DATA=0*2
CONTENTS_STACK=1*2
CONTENTS_CODE=2*2
READ_EXEC_ONLY=0x8
LIMIT_IN_PAGES=0x10
NOT_PRESENT=0x20
USABLE_BIT=0x40
LONG_MODE=0x80
user_desc_TLS1:
entry_number_TLS1:
    dd -1
base_addr_TLS1:
    dd start+0x345
limit_TLS1:
    dd 0x123
properties_TLS1:
    dd SEGMENT_32BIT+CONTENTS_DATA

これは、64 ビット プロセスがデフォルトでこれら 2 つのセグメント レジスタに NULL セレクタを持っているという事実に関係しているようです。

これは Linux 3.16.0 以前では発生しますが、4.2.0 以降では発生しません。

何が起きてる?ESTLS セレクターが含まれている場合にDSゼロアウトするのに、他のセレクターを使用しないのはなぜですか?

4

0 に答える 0