Re: clamav RWX

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

A comment on this bug reminded me that we haven't found any solution
for the JIT-under-SELinux issue (except double mapping):
https://bugzilla.redhat.com/show_bug.cgi?id=573191#c29

As discussed last time, the RW <-> RX change would be needed only during
a brief period (DB reload).
Using a shared mapping would trade RWX requirements on memory for
RWX requirements on a file which is not better.

I have some new ideas though.

1. new protection, lets call it execmem_trustedonly

Some observations first:
 - there is 1 thread in clamd that reloads the database
 - if that thread is compromised it is game over anyway (someone can
load a malformed signature that causes clamd to quit, load empty DB,
etc.)
 - hence that thread is somewhat "trusted" already
 - if you find a way to exploit that thread, then execmem protection
   won't help, you can do almost anything with ClamAV already, all you
   need is write access to memory
 - the official databases are digitally signed, and ClamAV by default
   won't load bytecode from unsigned databases (it will for normal
   signatures of course)

It'd be good if clamd could, on startup, tell the OS that it has a
*single* thread that needs RW <-> RX transitions. The OS could check
that the SELinux policy allows that, lets call it execmem_trustedonly.

Not sure what the proper mechanism would be to do this, maybe
some prctl() call, or some mechanism similar to dropping root
privileges:
 - if SELinux policy allows execmem_trustedonly the main thread starts
   with this capability (doing RW <-> RX transitions)
 - it can atomically transfer this capability to other threads
   (permanently losing it, with no transfer back possible)
 - it can completely turn off the capability if it doesn't need it

The DB reload thread happens to be clamd's main thread, so it would
have this capability. As discussed this thread is the most trusted in
clamd, if you found a way to make it execute arbitrary code then
execmem protections will get you no additional protection anyway.

If one of the scanner threads is exploited, then execmem protections
would trigger and stop it. The DB reload thread would be able to
use the JIT, and all would be good.

2. Investigate if LLVM can do relocations to a different map. In fact
it already does relocations, but it assumes the code will run in the
same place as original. Also there might be some absolute addresses
emitted.
If yes then the 2 maps approach would work (codegen to one, exec
another).

3. Once I codegened to the writable map, I don't need it anymore and
will probably free it. Wouldn't it be great if the OS could relocate
the executable mapping to the same place the writable mapping was?
We know for sure there is enough space there.
mremap() seems to be able to do this, and seems to automatically unmap
whatever was in place of the target address so it seems to be atomic
too.
Would this work for SELinux?

It would go like this:
create map pairs at addresses X(RW) and Y (RX) linked by a file as
described in the no execmem docs.
codegen to map at address X as usual.
When done, use mremap() to move the executable mapping from address Y
to X, atomically unmapping the existing RW mapping at address X.

I'm open to other ideas too of course.

Best regards,
--Edwin

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@xxxxxxxxxxxxx with
the words "unsubscribe selinux" without quotes as the message.


[Index of Archives]     [Selinux Refpolicy]     [Linux SGX]     [Fedora Users]     [Fedora Desktop]     [Yosemite Photos]     [Yosemite Camping]     [Yosemite Campsites]     [KDE Users]     [Gnome Users]

  Powered by Linux