Каков реальный адрес `%fs:0xffffffffffffffff8`?

Я хочу отслеживать goid программ go с помощью ebpf.

После прочтения некоторых сообщений и блогов я знаю, что %fs:0xfffffffffffffff8 указывает на структуру g функции go, а инструкция mov %fs:0xfffffffffffffff8,%rcx всегда появляется в начале функции go.

Возьмем main.main в качестве примера:

func main() {
 177341   458330:   64 48 8b 0c 25 f8 ff    mov    %fs:0xfffffffffffffff8,%rcx
 177342   458337:   ff ff
 177343   458339:   48 3b 61 10             cmp    0x10(%rcx),%rsp
 177344   45833d:   76 1a                   jbe    458359 <main.main+0x29>
 177345   45833f:   48 83 ec 08             sub    $0x8,%rsp
 177346   458343:   48 89 2c 24             mov    %rbp,(%rsp)
 177347   458347:   48 8d 2c 24             lea    (%rsp),%rbp
 177348     myFunc()
 177349   45834b:   e8 10 00 00 00          callq  458360 <main.myFunc>
 177350 }

Я также знаю, что информация о goid хранится в структуре g go. Значение регистра fs можно получить через аргумент ctx функции ebpf.

Но я не знаю настоящий адрес %fs:0xfffffffffffffff8, потому что я новичок в ассемблере. Может ли кто-нибудь дать мне несколько советов?

Если бы значение регистра fs было 0x88, каково значение %fs:0xfffffffffffffff8?


person jl0x61    schedule 19.03.2020    source источник


Ответы (1)


Это отрицательное число, так что это одно слово перед основанием FS. Вам нужен базовый адрес FS, который не является значением селектора в регистре сегмента FS, который вы можете увидеть с помощью отладчика.

Возможно, ваш процесс сделал системный вызов, чтобы попросить ОС установить его, или, возможно, использовал wrfsbase инструкции в какой-то момент на системах, которые его поддерживают.

Обратите внимание, что по крайней мере за пределами Go Linux обычно использует FS для локального хранилища потока.

(Я не уверен, каков стандартный способ найти базу FS; очевидно, что это зависит от ОС, чтобы сделать это в пользовательском пространстве, где rdmsr недоступен; базы FS и GS выставляются как MSR, поэтому ОС используют это вместо фактического изменения записи GDT или LDT. < href="https://www.felixcloutier.com/x86/rdfsbase:rdgsbase" rel="nofollow noreferrer">rdfsbase должен быть включен ядром, установившим бит в CR4 на процессорах, поддерживающих FSGSBASE. Расширение ISA, поэтому вы не можете рассчитывать на его работу.)

@MargaretBloom предполагает, что пользовательское пространство может вызвать ошибку недействительной страницы; большинство операционных систем сообщают об ошибочном виртуальном адресе обратно в пространство пользователя. В Linux, например, SIGSEGV имеет адрес. (Или SIGBUS, если он был неканоническим, IIRC, то есть не в младших или старших 47 битах виртуального адресного пространства, а в «дыре», где адрес не является расширением знака младших 48.)

Итак, вы хотите установить обработчики сигналов для этих сигналов и попробовать загрузить со смещения, которое (с базой 0) будет в середине пространства ядра или что-то в этом роде. Если по какой-то причине это не сработает, увеличьте виртуальный адрес на 1 ТБ или что-то в цикле. Обычно никакие MMIO не отображаются в виртуальное адресное пространство пользовательского пространства, поэтому простое чтение не вызывает побочных эффектов.

person Peter Cordes    schedule 19.03.2020
comment
Можно ли использовать индуцированный отказ страницы для нахождения базового адреса fs? То есть, если fs:x сбой с зарегистрированным виртуальным адресом y - person Margaret Bloom; 19.03.2020
comment
@MargaretBloom: Вы имеете в виду перехват SIGSEGV и SIGBUS (в случае неканонического IIRC), потому что ядро ​​таким образом сообщает виртуальный адрес обратно в пространство пользователя? Да, это может сработать! Я предполагаю, что вы захотите загрузиться с некоторого смещения в середине того, что обычно является пространством ядра. - person Peter Cordes; 19.03.2020