Besides the obvious clobbering of ax, what other possible side effects will this assembly snippet have?

language: asm
mov ax, gs
mov gs, ax

Let's see, shall we? Given a function get_value that grabs the value at gs:0x0 and a function set_value that sets these values (trivial assembly helpers), plus a function gs_reset that contains the above code . . .

language: C
#include <stdio.h>
#include <stdint.h>
#include <asm/prctl.h>
#include <sys/prctl.h>
#include <asm/mman.h>
#include <sys/mman.h>

extern uint64_t get_value();
extern void set_value(uint64_t value);
extern void gs_reset();

int main() {
    uint64_t old;
    void *memory = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);

    arch_prctl(ARCH_GET_GS, &old);
    arch_prctl(ARCH_SET_GS, (uint64_t)memory);

    printf("Value: 0x%lx\n", get_value());
    printf("Value: 0x%lx\n", get_value());
    printf("Value: 0x%lx\n", get_value());

    arch_prctl(ARCH_SET_GS, old);
    return 0;

When run, we see:

$ ./a.out
Value: 0x0
Value: 0x42
zsh: segmentation fault (core dumped)  ./a.out

. . . wait, what?


Resetting the gs selector will also reset the value of the IA32_GS_BASE MSR back to zero, the default value. That is to say, setting gs back to itself will reset the base offset for the gs selector.

Note that arch_prctl works simply by setting this MSR, so the last get_value() call ends up simply accessing the memory at address zero.

- ethereal