cebix / macemu

Basilisk II and SheepShaver Macintosh emulators
1.37k stars 285 forks source link

BII real addressing "map Low Memory area 0x0000-0x2000" configure check fails erroneously #231

Open rakslice opened 3 years ago

rakslice commented 3 years ago

As @rickyzhang82 points out at https://github.com/cebix/macemu/wiki/Basilisk-II-Core-Emulation-Analysis#mapping-in-real-addressing, when building Basilisk II on x86 with gcc, with --enable-addressing=real, the configure check for

checking whether we can map Low Memory area 0x0000-0x2000... no

is failing even when the mapping succeeds because gcc's optimization for null pointer checks treats the assignment to the actual zero address in the test case as undefined behaviour and replaces the rest of the function with the explicit undefined opcode ud2.

    #include "../CrossPlatform/vm_alloc.cpp"
    int main(void) { /* returns 0 if we could map the lowmem globals */
      volatile char * lm = 0;
      if (vm_init() < 0) exit(1);
      if (vm_acquire_fixed(0, 0x2000) < 0) exit(1);
      lm[0] = 'z';
      if (vm_release((char *)lm, 0x2000) < 0) exit(1);
      vm_exit(); exit(0);
    }

Disassembly: ... snip ...

.text:00000000004006C0                 call    _Z16vm_acquire_fixedPvmi ; vm_acquire_fixed(void *,ulong,int)
.text:00000000004006C5                 test    eax, eax
.text:00000000004006C7                 js      short loc_4006D3
.text:00000000004006C9                 mov     byte ptr ds:0, 0
.text:00000000004006D1                 ud2

@rickyzhang82 points out that an -O0 build of this creates a working version.

rakslice commented 3 years ago

I was able to reproduce this in Debian 10 i686 with its "gcc (Debian 8.3.0-6) 8.3.0".

I assume that assigning the value in the test case is being done to cause the page to actually become backed by a memory page rather than merely allocated.

In fact there are a number of other ways to make the check pass:

This issue seems to only affect the check. There is presumably no code in BII that evaluates to an assignment to a null pointer at compile time, and thus no need for the optimization options BII is actually built with to change.

rakslice commented 3 years ago

I can't imagine a reason why assigning to address 0 specifically would be needed for a valid test, but that may be a lack of imagination on my part 😃

rakslice commented 3 years ago

For posterity I guess I should say: On Linux and similar, this check is effectively a check at compile time of a kernel tunable behaviour that isn't needed at compile time and is needed at run time. That is... not the best.

rakslice commented 3 years ago

Oddly enough SheepShaver's configure.ac also has this check even though it doesn't actually do anything with the result there?

rickyzhang82 commented 3 years ago

The optimization is not limited to x86 but x86_64 as well.

As you said, the check in configure is compile time check on accessing NULL pointer. But do BII or SS have this explicitly reference/deference on NULL pointer in production code? I highly doubt it

We may just vm_acquire_fixed or vm_acquire with starting address on 0x0 and see if we can access the returned address, instead of explicitly access NULL pointer.

After all what's the purpose of the check?

SegHaxx commented 3 years ago

Real addressing is only interesting to people running on real m68k hardware. And that stuff is pretty obsolete now.

I've confirmed BII JIT works great with direct addressing mode on linux x86_64 with my mmap patch #227

I dare say just rip real addressing mode out completely. It's broken and obsolete. :)

rakslice commented 3 years ago

@SegHaxx You know we're talking about emulators that only run operating systems abandoned 20 years ago with network stacks and no memory protection, right? Just checking.

SegHaxx commented 3 years ago

What, are you saying Mac OS is insecure so we should bypass ASLR and hand it an attack surface directly into the host kernel? :) https://security.stackexchange.com/questions/178382/how-detrimental-is-a-null-pointer-dereference-vulnerability-today

also for windows: https://pwnrip.com/exploiting-cve-2019-1132-another-null-pointer-dereference-in-windows-kernel/

rakslice commented 3 years ago

Look, I just meant: the fact that we're here giving a whit about classic Mac OS is evidence that not distributing something anymore, removing it from the latest versions, and it actually being riskier to use are three things that won't make people who are here for the lower overhead old thing actually stop using it. That's not a clear cut reason to not remove it -- people will do what they will. I'm on board with it not being the default. I appreciate it's a good precaution to avoid the kernel tunable setting it needs. It still works as an available build-time option in the actual codebase and the associated kernel tunable still exists and isn't even deprecated. Removing it to save on maintenance effort is a choice for people actually working on code changes based on this fork, and that ain't really me chief, I was here to ask a question, and I looked at this issue because somebody asked.

It's funny you mention Windows, since the Windows versions don't have this, and didn't originally -- the reason being that the API did not historically have a way to map the zero page https://macintoshgarden.org/forum/basilisk-ii-old-windows-builds-lauri-pesonen#comment-73879