
In-Memory-Only ELF Execution Without Tmpfs - wooby
https://magisterquis.github.io/2018/03/31/in-memory-only-elf-execution.html
======
dimkr1
There are other ways to do this that don't involve tmpfs or write() - see
[https://github.com/dimkr/papaw](https://github.com/dimkr/papaw) and
[https://github.com/dimkr/Mirai-Source-Code](https://github.com/dimkr/Mirai-
Source-Code)

~~~
adito
But the readme says:

 _The payload executable is extracted to a temporary file. When running as
root, this is done by mounting a tmpfs file system and lazily unmounting it
before the extraction._

~~~
dimkr1
When not running as root, it doesn't use a tmpfs. Also, papaw replaces
/proc/self/exe with an empty file. And it has some basic anti-debugging, like
locking of the payload to RAM so it cannot be recovered by reading it from a
swap partition.

------
derefr
Given that Linux now has both file descriptors, and process memory-page
ranges, pointing to anonymous allocated memory regions, are they
interchangeable?

What I mean is:

\- to go from a memfd to anonymous memory, you can call mmap(2) on the fd

\- to go from anonymous memory to a memfd, you...?

~~~
the8472
Semantically this should do the job: anonymous memory -> vmsplice(gift) ->
pipe -> splice(move) -> memfd. Then remap the pages from memfd to the original
address ranges so you're allowed to use them again. But I don't know whether
this is supported on memfds. And of course it's not atomic.

------
ldng
And when would you want to do that ? Really curious as I fail to see a usecase
where the same goal could not be achieve otherwise. But there must be some
otherwise the API would not have been introduced i guess.

~~~
twoodfin
Organizing and executing code via a storage scheme other than a file system?

Security issues aside, I can imagine maintaining compiled code for stored
procedures in database BLOBs.

Similarly, in an appropriate trust environment, I might want to ship work
units to remote machines in the form of raw ELF. Copying the bits to disk just
to execute them is unneeded overhead.

~~~
shawnz
But a tmpfs (the usual way to do this) isn't persisted to a disk

~~~
gnode
It can be; swap and suspend-to-disk / hibernation can cause tmpfs to be
written.

I wonder if there's a way to execute from mlock'd or madvised memory. I can
imagine this be particularly useful, if you wanted to prevent your injected
program (malware? valuable IP?) from being written to disk or appearing in a
core dump.

~~~
shawnz
True, but those caveats apply to OP's technique too. What I am saying is that
there is no specific behavior of a tmpfs which causes things in it to be
necessarily persisted to disk like the parent was suggesting. It works just
like any other anonymous memory does.

------
pwdisswordfish2
Oh yeah, I've once discovered this method myself. With execveat() one can even
avoid going through procfs.

It doesn't work worth shbang-based scripts, though; that just returns ENOENT.
Makes sense, I suppose.

~~~
ifoundthetao
Would you be willing to share how you did that (avoiding procfs too)?

~~~
pwdisswordfish2
Instead of

    
    
        snprintf(pathbuf, sizeof(pathbuf), "/proc/self/fd/%u", fd);
        execve(pathbuf, argv, envp);
    

you do

    
    
        execveat(fd, "", argv, envp, AT_EMPTY_PATH);
    

and that's it.

~~~
ifoundthetao
Thanks!!

------
joosters
A bit off-topic, but their perl code is buggy. fork() returns _undef_ on
error, not -1.

And you can use '$FH->autoflush(1)' instead of the eye-watering
'select((select($FH), $|=1)[0])'

~~~
jwilk
I was going to say that you need to use the IO::Handle module to be able to
use the autoflush method, but apparently this no longer necessary with modern
Perl.

From [https://metacpan.org/pod/perl5120delta#Other-potentially-
inc...](https://metacpan.org/pod/perl5120delta#Other-potentially-incompatible-
changes) :

> _Filehandles are now always blessed into IO::File._

> _The previous behaviour was to bless Filehandles into FileHandle (an empty
> proxy class) if it was loaded into memory and otherwise to bless them into
> IO::Handle._

~~~
jwilk
On a second thought, this is probably the right changelog entry:

[https://metacpan.org/pod/perl5140delta#Filehandle-method-
cal...](https://metacpan.org/pod/perl5140delta#Filehandle-method-calls-load-
IO::File-on-demand)

 _When a method call on a filehandle would die because the method cannot be
resolved and IO::File has not been loaded, Perl now loads IO::File via require
and attempts method resolution again_

