Age | Commit message (Collapse) | Author |
|
Don't just pass argv[0] to the new UE, pass the full program path.
|
|
With this, you can now kinda sorta run the shell in UserspaceEmulator!
|
|
|
|
|
|
When compiling with "-Os", GCC produces the following pattern for
atomic decrement (which is used by our RefCounted template):
or eax, -1
lock xadd [destination], eax
Since or-ing with -1 will always produce the same output (-1), we can
mark the result of these operations as initialized. This stops us from
complaining about false positives when running the shell in UE. :^)
|
|
Errors here are (rc < 0), not (rc < 1).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The emulator will now register signal handlers for all possible signals
and act as a translation layer between the kernel and the emulated
process.
To get an accurate simulation of signal handling, we duplicate the same
trampoline mechanism used by the kernel's signal delivery system, and
also use the "sigreturn" syscall to return from a signal handler.
Signal masking is not fully implemented yet, but this is pretty cool!
|
|
File/line is way more interesting than offsets, so let's only do the
offsets if we don't have file/line information.
|
|
|
|
We don't have to be clever at all to figure out which MmapRegions are
malloc blocks, we can just mark the containing region as such when
the emulated process performs a malloc! :^)
|
|
|
|
Ultimately we'll want to make it a bit easier to add more reporting.
This at least makes it easier to redirect the logging.
|
|
Some of the remaining instructions have different behavior for
register and non-register ops. Since we already have the
two-level flags tables, model this by setting all handlers in
the two-level table to the register op handler, while the
first-level flags table stores the action for the non-reg handler.
|
|
Some of these don't just use the REG bits of the mod/rm byte
as slashes, but also the R/M bits to have up to 9 different
instructions per opcode/slash combination (1 opcode requires
that MOD is != 11, the other 8 have MODE == 11).
This is done by making the slashes table two levels deep for
these cases.
Some of this is cosmetic (e.g "FST st0" has no effect already,
but its bit pattern gets disassembled as "FNOP"), but for
most uses it isn't.
FSTENV and FSTCW have an extraordinary 0x9b prefix. This is
not yet handled in this patch.
|
|
This is enough to run /bin/ls :^)
|
|
Now that emulated processes have their real name (with a "(UE)" prefix)
we can actually let them know their name.
|
|
This is very commonly used by terminal programs, and easy to support.
|
|
This makes it much easier to see who's who when running multiple
emulators at the same time. :^)
|
|
This virtual syscall works by exec'ing the UserspaceEmulator itself,
with the emulated program's provided arguments as the arguments to the
new UserspaceEmulator instance.
This means that we "follow" exec'ed programs and emulate them as well.
In the future we might want to make this an opt-in (or opt-out, idk)
behavior, but for now it's what we do.
This is really quite cool, I think! :^)
|
|
|
|
Note that running a setuid program (e.g /bin/ping) in UE does not
actually run uid=0. You'll have to run UE itself as uid=0 if you want
to test programs that do setuid/setgid.
|
|
It's now possible to run LookupServer in UE (by setting up SystemServer
to run the service inside UE.) No bugs found, but very cool! :^)
|
|
|
|
This prevents some false positives since the initial stack is expected
to be zero-initialized.
|
|
"xor reg,reg" or "sub reg,reg" both zero out the register, which means
we know for sure the result is 0. So mark the value as initialized,
and make sure we don't taint the CPU flags.
This removes some false positives from the uninitialized memory use
detection mechanism.
Fixes #2850.
|
|
|
|
Thanks to Rick van Schijndel for pointing this out. :^)
|
|
|
|
|
|
Instead of using SoftCPU::eip() which points at the *next* instruction
most of the time, stash away a "base EIP" so we can use it when making
backtraces. This makes the correct line number show up! :^)
|
|
|
|
This was super easy thanks to the awesome LibDebug work by @itamar8910!
|
|
Now that LibC caches this for us, we can stop worrying.
|
|
This made it impossible to add more thread-local things to LibC. :^)
|
|
We now track whether the flags register is tainted by the use of one or
more uninitialized values in a computation.
For now, the state is binary; the flags are either tainted or not.
We could be more precise about this and only taint the specific flags
that get updated by each instruction, but I think this will already get
us 99% of the results we want. :^)
|
|
This makes the CPU dump output interleave correctly with instructions.
|
|
Since we zero out all the register values, let's also mark them all
as fully initialized.
|
|
A lot of software relies on the fact that mmap and shbuf memory is
zeroed out by the kernel, so we should consider it initialized from the
shadow bit perspective as well.
|
|
|
|
This patch introduces the concept of shadow bits. For every byte of
memory there is a corresponding shadow byte that contains metadata
about that memory.
Initially, the only metadata is whether the byte has been initialized
or not. That's represented by the least significant shadow bit.
Shadow bits travel together with regular values throughout the entire
CPU and MMU emulation. There are two main helper classes to facilitate
this: ValueWithShadow and ValueAndShadowReference.
ValueWithShadow<T> is basically a struct { T value; T shadow; } whereas
ValueAndShadowReference<T> is struct { T& value; T& shadow; }.
The latter is used as a wrapper around general-purpose registers, since
they can't use the plain ValueWithShadow memory as we need to be able
to address individual 8-bit and 16-bit subregisters (EAX, AX, AL, AH.)
Whenever a computation is made using uninitialized inputs, the result
is tainted and becomes uninitialized as well. This allows us to track
this state as it propagates throughout memory and registers.
This patch doesn't yet keep track of tainted flags, that will be an
important upcoming improvement to this.
I'm sure I've messed up some things here and there, but it seems to
basically work, so we have a place to start! :^)
|
|
|
|
These were not doing mashing together the signed double-size results
correctly and lost bits in the signed/unsigned casting process.
|
|
These were not recording the higher part of the result correctly.
Since the flags are much less complicated than the inline assembly
here, just implement IMUL in C++ instead.
|
|
These are the unsigned variants. Signed variants sold separately.
|