Bug 573191 - SELinux is preventing /usr/sbin/clamd "execmem" access .
Summary: SELinux is preventing /usr/sbin/clamd "execmem" access .
Keywords:
Status: CLOSED WONTFIX
Alias: None
Product: Fedora
Classification: Fedora
Component: clamav
Version: 14
Hardware: x86_64
OS: Linux
low
medium
Target Milestone: ---
Assignee: Enrico Scholz
QA Contact: Fedora Extras Quality Assurance
URL:
Whiteboard: setroubleshoot_trace_hash:544b5a45bdc...
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2010-03-13 10:43 UTC by Frank Murphy
Modified: 2012-08-16 18:06 UTC (History)
15 users (show)

Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Clone Of:
Environment:
Last Closed: 2012-08-16 18:06:08 UTC
Type: ---
Embargoed:


Attachments (Terms of Use)
patch to allow turning off JIT (4.57 KB, patch)
2010-03-29 21:34 UTC, Török Edwin
no flags Details | Diff
Patch to allow turning off JIT (6.25 KB, patch)
2010-03-31 15:57 UTC, Török Edwin
no flags Details | Diff

Description Frank Murphy 2010-03-13 10:43:37 UTC
Summary:

SELinux is preventing /usr/sbin/clamd "execmem" access .

Detailed Description:

SELinux denied access requested by clamd. It is not expected that this access is
required by clamd and this access may signal an intrusion attempt. It is also
possible that the specific version or configuration of the application is
causing it to require additional access.

Allowing Access:

You can generate a local policy module to allow this access - see FAQ
(http://docs.fedoraproject.org/selinux-faq-fc5/#id2961385) Please file a bug
report.

Additional Information:

Source Context                system_u:system_r:clamd_t:s0
Target Context                system_u:system_r:clamd_t:s0
Target Objects                None [ process ]
Source                        clamd
Source Path                   /usr/sbin/clamd
Port                          <Unknown>
Host                          (removed)
Source RPM Packages           clamav-server-0.96-0.1400.rc1.fc14
Target RPM Packages           
Policy RPM                    selinux-policy-3.7.11-1.fc13
Selinux Enabled               True
Policy Type                   targeted
Enforcing Mode                Enforcing
Plugin Name                   catchall
Host Name                     (removed)
Platform                      Linux (removed)
                              2.6.34-0.10.rc1.git0.fc14.x86_64 #1 SMP Mon Mar 8
                              22:16:46 UTC 2010 x86_64 x86_64
Alert Count                   7
First Seen                    Fri 12 Mar 2010 22:35:50 GMT
Last Seen                     Sat 13 Mar 2010 09:32:52 GMT
Local ID                      85126c83-445f-4636-aaac-020b50a25de6
Line Numbers                  

Raw Audit Messages            

node=(removed) type=AVC msg=audit(1268472772.52:73): avc:  denied  { execmem } for  pid=1489 comm="clamd" scontext=system_u:system_r:clamd_t:s0 tcontext=system_u:system_r:clamd_t:s0 tclass=process

node=(removed) type=SYSCALL msg=audit(1268472772.52:73): arch=c000003e syscall=9 success=no exit=-13 a0=0 a1=10000 a2=7 a3=22 items=0 ppid=1 pid=1489 auid=4294967295 uid=489 gid=477 euid=489 suid=489 fsuid=489 egid=477 sgid=477 fsgid=477 tty=(none) ses=4294967295 comm="clamd" exe="/usr/sbin/clamd" subj=system_u:system_r:clamd_t:s0 key=(null)



Hash String generated from  catchall,clamd,clamd_t,clamd_t,process,execmem
audit2allow suggests:

#============= clamd_t ==============
allow clamd_t self:process execmem;

Comment 1 Daniel Walsh 2010-03-15 03:50:30 UTC
Clamd should not need this access.

Comment 2 Daniel Walsh 2010-03-15 03:51:02 UTC
http://people.redhat.com/~drepper/selinux-mem.html

Comment 3 Enrico Scholz 2010-03-15 08:40:24 UTC
clamav 0.96 in rawhide has a bytecode interpreter and uses a builtin llvm compiler.  The code causing this ACL is in the

---
/// AllocateRWX - Allocate a slab of memory with read/write/execute
/// permissions.  This is typically used for JIT applications where we want
/// to emit code to the memory then jump to it.  Getting this type of memory
/// is very OS specific.
///
llvm::sys::MemoryBlock
llvm::sys::Memory::AllocateRWX(...)
---

method. Access seems to be required hence.

@Frank: can you please set 'BytecodeSecurity Paranoid' in your configuration and check whether the ACL persists?  When it goes away, a SELinux boolean might be introduced.

Comment 4 Frank Murphy 2010-03-15 08:47:50 UTC
(In reply to comment #3)
> clamav 0.96 in rawhide has a bytecode interpreter and uses a builtin llvm
> compiler.  The code causing this ACL is in the
> 
> ---
> /// AllocateRWX - Allocate a slab of memory with read/write/execute
> /// permissions.  This is typically used for JIT applications where we want
> /// to emit code to the memory then jump to it.  Getting this type of memory
> /// is very OS specific.
> ///
> llvm::sys::MemoryBlock
> llvm::sys::Memory::AllocateRWX(...)
> ---
> 
> method. Access seems to be required hence.
> 
> @Frank: can you please set 'BytecodeSecurity Paranoid' in your configuration
> and check whether the ACL persists?  When it goes away, a SELinux boolean might
> be introduced.    


It might be a day or two.
Box offline needs new cooler.
Hope that's ok.

Comment 5 Frank Murphy 2010-03-16 09:45:20 UTC
(In reply to comment #3)
   
'BytecodeSecurity Paranoid' 
set rebooted got avc:


--snipped--

Additional Information:

Source Context                system_u:system_r:clamd_t:s0
Target Context                system_u:system_r:clamd_t:s0
Target Objects                None [ process ]
Source                        clamd
Source Path                   /usr/sbin/clamd
Port                          <Unknown>
Host                         xxxxxxx
Source RPM Packages           clamav-server-0.96-0.1400.rc1.fc14
Target RPM Packages           
Policy RPM                    selinux-policy-3.7.14-3.fc13
Selinux Enabled               True
Policy Type                   targeted
Enforcing Mode                Enforcing
Plugin Name                   catchall
Host Name                     (removed)
Platform                      xxxxxx
                              2.6.34-0.10.rc1.git0.fc14.x86_64 #1 SMP Mon Mar 8
                              22:16:46 UTC 2010 x86_64 x86_64
Alert Count                   1
First Seen                    Tue 16 Mar 2010 09:38:43 GMT
Last Seen                     Tue 16 Mar 2010 09:38:43 GMT
Local ID                      f28fdbcd-2a0c-4012-ad81-bdd8a2c4347f
Line Numbers                  

Raw Audit Messages            

node=(removed) type=AVC msg=audit(1268732323.28:6): avc:  denied  { execmem } for  pid=1550 comm="clamd" scontext=system_u:system_r:clamd_t:s0 tcontext=system_u:system_r:clamd_t:s0 tclass=process

node=(removed) type=SYSCALL msg=audit(1268732323.28:6): arch=c000003e syscall=9 success=yes exit=128 a0=0 a1=10000 a2=7 a3=22 items=0 ppid=1549 pid=1550 auid=4294967295 uid=490 gid=478 euid=490 suid=490 fsuid=490 egid=478 sgid=478 fsgid=478 tty=(none) ses=4294967295 comm="clamd" exe="/usr/sbin/clamd" subj=system_u:system_r:clamd_t:s0 key=(null)

Comment 6 Enrico Scholz 2010-03-16 10:37:20 UTC
It seems to be possible to disable bytecode JIT stuff by adding

| Bytecode 'no'

to freshclam.conf and removing bytecode.cvd.


Clamav developers claim that bytecode implementation is secure (see http://article.gmane.org/gmane.comp.security.virus.clamav.devel/3380) so that most people might want this feature and I probably should not disable it at compile time.

@Daniel: I suggest to add a SELinux boolean which enables 'execmem' for clamav.  I am not sure about the initial value but I tend to enable it by default.

Comment 7 Ulrich Drepper 2010-03-16 12:10:25 UTC
(In reply to comment #6)
> Clamav developers claim that bytecode implementation is secure (see
> http://article.gmane.org/gmane.comp.security.virus.clamav.devel/3380) so that
> most people might want this feature and I probably should not disable it at
> compile time.

They miss the point.  Possibly the code signing used will prevent injecting forged code sequences.  Completely irrelevant.

The real problem is that there is a memory region which can be written to and executed.  This will allow code injection.  Possibly not using the bytecode handling but, again, that's irrelevant.  We developed all these mechanisms mainly for normal programs where buffer overflows etc can be used to inject code.

A program like clamav which takes arbitrary data from the network is a prime target.

If the people developing the bytecode interpreter are not willing to rewrite it to be safer (double mapping, I described this several times and it's now used in firefox) then bytecode handling has to be disabled in Fedora and RHEL.

Comment 8 Enrico Scholz 2010-03-16 13:02:13 UTC
ok; I will disable the bytecode interpreter.

Nevertheless, I do not really understand how double buffering can increase security.  When attack code uses only relative addressing, you are in the same situation as before.

Comment 9 Ulrich Drepper 2010-03-16 13:23:55 UTC
(In reply to comment #8)
> Nevertheless, I do not really understand how double buffering can increase
> security.

Double buffering _plus_ address space randomization.  The relative position of the two buffers is not constant.  This is making an exploit significantly harder.

Comment 10 Török Edwin 2010-03-27 16:41:43 UTC
(In reply to comment #6)
> It seems to be possible to disable bytecode JIT stuff by adding
> 
> | Bytecode 'no'
> 
> to freshclam.conf and removing bytecode.cvd.

If you only want to disable the JIT, you should build with --disable-llvm.
The "interpreter" itself doesn't need execmem of course.
But see below, ClamAV should automatically fallback to non-JIT mode if SELinux is not allowing execmem.

(In reply to comment #7)
> (In reply to comment #6)
> > Clamav developers claim that bytecode implementation is secure (see
> > http://article.gmane.org/gmane.comp.security.virus.clamav.devel/3380) so that
> > most people might want this feature and I probably should not disable it at
> > compile time.
> 
> They miss the point.  Possibly the code signing used will prevent injecting
> forged code sequences.  Completely irrelevant.
> 
> The real problem is that there is a memory region which can be written to and
> executed.

The problem with 'execmem' is that on some older distros mmap returns a pointer
that is not MAP_FAILED when RWX mem is requested, which causes clamd to crash on startup. RHEL5 is one such system: https://wwws.clamav.net/bugzilla/show_bug.cgi?id=1901

I tested on a FC13-alpha liveCD, and it doesn't crash: it simply says
that it is not able to allocate RWX memory.

libclamav JIT: Allocation failed when allocating new memory in the JIT
Can't allocate RWX Memory: Permission denied
libclamav JIT: *** FATAL error encountered during bytecode generatio

However the process (clamd) is still running, and executing bytecodes, through the interpreter. 
Isn't this the case with the  clamav-server-0.96-0.1400.rc1.fc14 package?

To sum up:
 - distros where mmap() of RWX succeeds need execmem turned off, or ClamAV will crash on startup (or build with --disable-llvm, and take the performance hit)
 - distros where mmap() of RWX fails shouldn't even reach execmem, since ClamAV detects this on startup and fallbacks to the non-JIT code

>  This will allow code injection.  Possibly not using the bytecode
> handling but, again, that's irrelevant.  We developed all these mechanisms
> mainly for normal programs where buffer overflows etc can be used to inject
> code.
> 
> A program like clamav which takes arbitrary data from the network is a prime
> target.
> 
> If the people developing the bytecode interpreter are not willing to rewrite it
> to be safer

I've opened a bug about this in upstream LLVM: http://llvm.org/bugs/show_bug.cgi?id=6701 
Patches welcome.
I think at least relocations and absolute addresses need to be done against the executable buffer, and writes need to use the writable buffer. 

(In reply to comment #9)
> (In reply to comment #8)
> > Nevertheless, I do not really understand how double buffering can increase
> > security.
> 
> Double buffering _plus_ address space randomization.  The relative position of
> the two buffers is not constant.  This is making an exploit significantly
> harder.    

If there is an exploit that can defeat the address randomization on one buffer, why couldn't it defeat the address randomization on both? 
I don't think using two buffers adds any security, it only makes it harder to write JITs.

Comment 11 Török Edwin 2010-03-27 18:13:06 UTC
(In reply to comment #10)
> 
> (In reply to comment #9)
> > (In reply to comment #8)
> > > Nevertheless, I do not really understand how double buffering can increase
> > > security.
> > 
> > Double buffering _plus_ address space randomization.  The relative position of
> > the two buffers is not constant.  This is making an exploit significantly
> > harder.    
> 
> If there is an exploit that can defeat the address randomization on one buffer,
> why couldn't it defeat the address randomization on both? 

Actually it is even simpler than that: the exploit writes to the writable buffer,
and waits till the application eventually executes the executable page.
If you're lucky it'll execute your exploit (or crash if you overwrote middle of an instruction).
The exploit doesn't necessarily need to know the address where it is running, it can be written using only relative addresses (and delta coding).
Having 1 buffer, or 2 is the almost the same, you already have ASLR protection for the 1 buffer.

You can apply 'execmem' protection to pages mapped w/o PROT_EXEC, but if the app requests RWX, it should be granted RWX, and execmem shouldn't fail on those pages (you could still do execmem checks on other pages).

Comment 12 Enrico Scholz 2010-03-28 09:42:44 UTC
IMO, best solution would be:

* clamav: add an option to disable JIT at runtime (set by default)
* selinux: add a boolean to allow execmem for clamav (not set by default)

for now, the JIT compiler is disabled in rawhide's clamav.


Double buffering increases security when attacker writes to an address and places this address on the stack to jump into it.  Such a protection works only very limited for JIT compilers because jumping into the code is part of the normal program execution.

Comment 13 Török Edwin 2010-03-28 11:01:55 UTC
(In reply to comment #12)
> IMO, best solution would be:
> 
> * clamav: add an option to disable JIT at runtime (set by default)

Please try this patch (or just pull latest git master)
http://git.clamav.net/gitweb?p=clamav-devel.git;a=commitdiff_plain;h=c506c2c5554aa55f2f68767272fda7a2195dfce4;hp=041bc64aab1b477bacbf23594acada1503622c5b

Before attempting to initialize the JIT it tests whether it can mmap RWX memory, if it can't it'll fallback to interpreter mode.
So if you allow 'execmem' in the SELinux policy the JIT will be used, if you don't, the JIT will not be used.
I think no additional configuration is needed from ClamAV side.

Here is how it looks like:
# service clamd.myclamd start
Starting clamd.myclamd:
libclamav JIT: Can't allocate RWX Memory: Permission denied
libclamav JIT: SELinux is preventing 'execmem' access
libclamav JIT: falling back to interpreter mode
                                                           [  OK  ]

> * selinux: add a boolean to allow execmem for clamav (not set by default)

Yes, that would make sense. Perhaps document that in the README.

There is one problem though: whenever I tried to execute clamav it executed in the unconfined domain, both when executed directly, or via 'service clamd.myclamd start'.
Maybe it is something I've done wrong (I just overwrote the clamd binary and libclamav with the one I compiled on my Debian box with the patch applied,
then did a restorecon on the files),
but shouldn't SELinux transition to clamd's context when I execute it?

> 
> for now, the JIT compiler is disabled in rawhide's clamav.
> 
> 
> Double buffering increases security when attacker writes to an address and
> places this address on the stack to jump into it.  Such a protection works only
> very limited for JIT compilers because jumping into the code is part of the
> normal program execution.    

Agreed.

Comment 14 Daniel Walsh 2010-03-29 13:52:51 UTC
Is your init script labeled initrc_exec_t.


Adding the following to policy

## <desc>
## <p>
## Allow clamd to use JIT compiler
## </p>
## </desc>
gen_tunable(clamd_use_jit, false)


tunable_policy(`clamd_use_jit',`
	allow clamd_t self:process execmem;
') 

The problem with your suggested fix is it will cause SELinux to complain unless the user turns on the boolean.  I could modify the policy to look like.

tunable_policy(`clamd_use_jit',`
	allow clamd_t self:process execmem;
',`
        dontaudit clamd_t self:process execmem;
') 

And your log message would have to tell the user about the boolean.

Comment 15 Török Edwin 2010-03-29 14:04:01 UTC
(In reply to comment #14)
> Is your init script labeled initrc_exec_t.

Probably not, because I just copied it from /usr/share/doc/clamav-server-*/,
I'll try chcon-ing it.

> 
> 
> Adding the following to policy
> 
> ## <desc>
> ## <p>
> ## Allow clamd to use JIT compiler
> ## </p>
> ## </desc>
> gen_tunable(clamd_use_jit, false)
> 
> 
> tunable_policy(`clamd_use_jit',`
>  allow clamd_t self:process execmem;
> ') 
> 
> The problem with your suggested fix is it will cause SELinux to complain unless
> the user turns on the boolean.  I could modify the policy to look like.
> 
> tunable_policy(`clamd_use_jit',`
>  allow clamd_t self:process execmem;
> ',`
>         dontaudit clamd_t self:process execmem;
> ') 

Sounds good, one complaint (from libclamav) is enough.

> 
> And your log message would have to tell the user about the boolean.    

Sure, I can change the message.
How about something like this (is the setsebool command correct?)
"SELinux is preventing 'execmem' access. Run 'setsebool -P clamd_use_jit on' to allow access."

Comment 16 Daniel Walsh 2010-03-29 14:12:13 UTC
Fixed in selinux-policy-3.7.16-2.fc13.noarch

Comment 17 Enrico Scholz 2010-03-29 14:19:16 UTC
I think a runtime option to disable JIT would be a better solution than the 'dontaudit'.

Comment 18 Török Edwin 2010-03-29 14:34:04 UTC
(In reply to comment #17)
> I think a runtime option to disable JIT would be a better solution than the
> 'dontaudit'.    

I'll try to add something later today.
Would the installer ask the user at install time whether they want JIT enabled or not, and enable/disable the SELinux boolean (and clamd.conf setting) accordingly?
(it could also see if the user has SELinux enabled or not, and automatically set the clamd.conf).

Comment 19 Daniel Walsh 2010-03-29 15:30:26 UTC
The install should NEVER ask a user anything.  I think secure by default is what we are going for here.  So I would disable the JIT by default unless it gives you a Huge win for the vast majority of users.

Comment 20 Enrico Scholz 2010-03-29 15:41:27 UTC
> I'll try to add something later today.

Thanks


> Would the installer ask the user at install time whether they want JIT enabled
> or not, and enable/disable the SELinux boolean (and clamd.conf setting)
> accordingly?

no; package installation is done (resp. must be done) without user interaction so there is no way to ask the the user for such settings.


> (it could also see if the user has SELinux enabled or not, and automatically
> set the clamd.conf).

mmh... I see the existence of a (directly or indirectly) writable execmem region as a general security risk which affects also non-SELinux systems. SELinux detects it but I would not tie it to the state of SELinux.

Hence I am tending to disable it by default in the configuration file and add a comment about the SELinux boolean there.  User can decide then whether he enables the JIT compiler or not.

Comment 21 Török Edwin 2010-03-29 15:59:41 UTC
(In reply to comment #20)
> > I'll try to add something later today.
> 
> Thanks

I'll add it here as a patch, since it is too late to add a new config option after -rc2 and before final.

> 
> 
> > Would the installer ask the user at install time whether they want JIT enabled
> > or not, and enable/disable the SELinux boolean (and clamd.conf setting)
> > accordingly?
> 
> no; package installation is done (resp. must be done) without user interaction
> so there is no way to ask the the user for such settings.

So thats why I was not seeing any questions when installing something on Fedora.
As a Debian user, I am used to debconf questions ;)

> 
> 
> > (it could also see if the user has SELinux enabled or not, and automatically
> > set the clamd.conf).
> 
> mmh... I see the existence of a (directly or indirectly) writable execmem
> region as a general security risk which affects also non-SELinux systems.
> SELinux detects it but I would not tie it to the state of SELinux.
> 
> Hence I am tending to disable it by default in the configuration file and add a
> comment about the SELinux boolean there.  User can decide then whether he
> enables the JIT compiler or not.    

I won't argue about the defaults.

(In reply to comment #19)
> The install should NEVER ask a user anything.  I think secure by default is
> what we are going for here.
>  So I would disable the JIT by default unless it
> gives you a Huge win for the vast majority of users.    

I don't know have any recent performance benchmarks, hopefully I'll have something tomorrow.

Anyway the JIT is a performance optimization, ClamAV should work equally well (in terms of correctness) in interpreter (non-JIT) mode.
After all the interpreter is the only choice on OSes / CPUs that are not supported by the JIT [*], so it should be "fast enough" even if it is (much) slower than the JIT.

[*] It currently supports X86/X86-64, and PPC32/PPC64. In the future it may be possible to support ARM, and maybe Sparc too if someones tests/implements it.

Comment 22 Török Edwin 2010-03-29 16:01:57 UTC
(In reply to comment #16)
> Fixed in selinux-policy-3.7.16-2.fc13.noarch    

Thanks, will that policy you've shown work on RHEL5 too?
I intend to add it to our wiki's upgrade notes (wiki.clamav.net), and link to this bugreport.

Comment 23 Daniel Walsh 2010-03-29 16:41:35 UTC
No RHEl5 will not be updated for several months.


You can add a custom policy module using audit2allow though

grep clamd /var/log/audit/audit.log | audit2allow -M myclamd
semodule -i myclamd.pp

Comment 24 Török Edwin 2010-03-29 21:34:10 UTC
Created attachment 403367 [details]
patch to allow turning off JIT

This is a draft patch to allow turning off the JIT in clamd.conf.

TODO: add a commandline flag to clamscan, and update the manpage.

Comment 25 Török Edwin 2010-03-31 15:57:40 UTC
Created attachment 403775 [details]
Patch to allow turning off JIT

Here is a new patch that allows turning off the JIT.

Note that by turning off the JIT you are still running bytecodes via the interpreter.

Comment 26 Török Edwin 2010-03-31 16:07:46 UTC
(In reply to comment #21)
> 
> (In reply to comment #19)
> > The install should NEVER ask a user anything.  I think secure by default is
> > what we are going for here.
> >  So I would disable the JIT by default unless it
> > gives you a Huge win for the vast majority of users.    
> 
> I don't know have any recent performance benchmarks, hopefully I'll have
> something tomorrow.
> 
> Anyway the JIT is a performance optimization, ClamAV should work equally well
> (in terms of correctness) in interpreter (non-JIT) mode.

Here are some performance measurements on a small benchmark:
1050 PDF files, 80MB in total.

All measurements done with warm caches, 1 thread.
Baseline: 
empty database, no bytecode, no builtin PDF module: 2 seconds
full database, no bytecode, no builtin PDF module: 7.5 seconds
full database, builtin PDF module: 9.8 seconds

Bytecode:
empty database, and bytecode JIT, no builtin PDF: 3.2 seconds
empty database, and bytecode interpreter, no builtin PDF: 31.3 seconds

If we look at total execution time, the interpreter is 10x slower, if we look at the just the bytecode execution times we need to subtract the baseline, so:
bytecode JIT: 1.2
bytecode interpreter: 29.3

In that case the interpreter is 24x slower than the JIT.

I also tried LLVM's interpreter (yes it has one besides the JIT), and it was 33x slower than my interpreter in libclamav (no wonder, the LLVM one is generic,
the libclamav one is special-purpose).

If we look at the raw opcode processing speed of the interpreter, it doesn't look that bad though:
LibClamAV debug: intepreter bytecode run finished in 635975us, after
executing 69150579 opcodes.

We get ~100 million opcodes / second.

The bytecode used for this test is a quite complicated one, so this is mostly a worst case scenario, in practice bytecode execution won't trigger on each file, and not all bytecodes are as complicated as the one I tested.
Also there is some potential to optimize the bytecode opcodes produced by our compiler, we haven't done any interpreter-specific optimizations there (yet).

Comment 27 Török Edwin 2010-03-31 16:15:29 UTC
(In reply to comment #20)
> 
> mmh... I see the existence of a (directly or indirectly) writable execmem
> region as a general security risk which affects also non-SELinux systems.
> SELinux detects it but I would not tie it to the state of SELinux.
> 
> Hence I am tending to disable it by default in the configuration file and add a
> comment about the SELinux boolean there.  User can decide then whether he
> enables the JIT compiler or not.    

Actually I think there is a solution that doesn't involve 'execmem', or the 2 buffer workaround: the JIT could initially map the memory as RW, generate code, then use mprotect() to change it to RX.
This should work in eager JIT mode (ClamAV JITs all bytecode at DB load time), with some care for multi-threading. In fact LLVM already does this for ARM.

This is a rather invasive change, so it'll have to wait till 0.96.1, and care has to be taken in various modes the LLVM JIT can run (in non-eager mode there is a self-modifying stub, this trick won't work there; there is a mode where you can allocate global values together with code, won't work there either), but should be fairly safe in the default mode as long as it is ensured that the page we change from RX -> RW is not currently executing.
The RW -> RX change should be safe in all situations, since the code can't be executing yet.

This way there won't be a buffer that has both W and X permissions at the same time, it will have only W, and later X permissions. 
I hope SELinux won't deny the transition from RW -> RX, right?

Once these changes are made to the JIT, is it acceptable for Fedora to enable by default?

Comment 28 Bug Zapper 2010-07-30 11:03:40 UTC
This bug appears to have been reported against 'rawhide' during the Fedora 14 development cycle.
Changing version to '14'.

More information and reason for this action is here:
http://fedoraproject.org/wiki/BugZappers/HouseKeeping

Comment 29 James Ralston 2010-09-23 17:52:33 UTC
The release of ClamAV 0.96.3 prompted me to peruse this bug again.

Török, to answer your question: the way the execmem SELinux class is currently implemented, any attempt to allocate or transition an anonymous mapping to PROT_EXEC will trigger it. Here's the exact code, from security/selinux/hooks.c:

if ((prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
        /*
         * We are making executable an anonymous mapping or a
         * private file mapping that will also be writable.
         * This has an additional check.
         */
        rc = cred_has_perm(cred, cred, PROCESS__EXECMEM);
        if (rc)
                goto error;
}

Meaning, if you allocate an anonymous mapping as RWX, it will trip the execmem test. If you allocate an anonymous mapping as RW, it won't trip the execmem test, but if you then attempt to use mprotect() to change the anonymous mapping to RX, the mprotect() call will trip the execmem test.

So, the real question is: is using the two-phase approach that you outlined (compile into a RW mapping, then change it to RX) enough protection against malicious code injection for Fedora and/or RHEL to default the clamd_use_jit SELinux boolean to true?

Personally, unless someone (Drepper?) can illustrate how an attacker could trivially circumvent the two-phase approach, I would be satisfied enough by it to enable the JIT on the systems I control. (We primarily use ClamAV on our MX (incoming mail) servers, and we do *NOT* run clamd as root, so that would limit the damage of a potential attack.)

Furthermore, I'll note that Fedora and RHEL give other JIT compilers (e.g., Java) execmem credentials, and there are plenty of Java applications that handle possibly suspect data from the Internet (e.g., Azureus, a BitTorrent client). If we already just give every single Java application the execmem credential, aren't we coming down a little hard on ClamAV here?

Comment 30 Ulrich Drepper 2010-09-23 18:37:58 UTC
(In reply to comment #29)
> So, the real question is: is using the two-phase approach that you outlined
> (compile into a RW mapping, then change it to RX) enough protection against
> malicious code injection for Fedora and/or RHEL to default the clamd_use_jit
> SELinux boolean to true?
> 
> Personally, unless someone (Drepper?) can illustrate how an attacker could
> trivially circumvent the two-phase approach, I would be satisfied enough by it


You're kidding, right?

If you could change a RW mapping into a RX mapping with just a mprotect call you might just as well do nothing.

One of the most often used exploit techniques on system enforcing W^X is to use return-to-libc attacks.  Just return to mprotect in libc with appropriate arguments to change a mapping from RW to RX and the subsequent return could run code in the newly changed segment.

It is absolutely unacceptable to allow RW->RX transitions.  Just read any report/article on exploits.

Comment 31 Török Edwin 2010-09-23 19:39:33 UTC
(In reply to comment #29)
> The release of ClamAV 0.96.3 prompted me to peruse this bug again.

You can turn JIT on/off in clamd.conf via BytecodeMode, feature added in 0.96.2.

(In reply to comment #30)
> It is absolutely unacceptable to allow RW->RX transitions.  Just read any
> report/article on exploits.

There was a thread on the SELinux mailing list a while ago, one possible way around the RWX restrictions was suggested as a shared file mapping.
But ClamAV would  would need RWX access to the file, allowing that would probably be a greater security risk than 'execmem'.

I have some new ideas though, will resurrect that thread on the SELinux mailing list and discuss it there.

Comment 32 James Ralston 2010-09-23 20:33:16 UTC
(In reply to comment 30)
> One of the most often used exploit techniques on system enforcing
> W^X is to use return-to-libc attacks.  Just return to mprotect in
> libc with appropriate arguments to change a mapping from RW to RX
> and the subsequent return could run code in the newly changed
> segment.

Isn't this what address space layout randomization is designed to thwart, through?

(In reply to comment 31)
> There was a thread on the SELinux mailing list a while ago, one
> possible way around the RWX restrictions was suggested as a shared
> file mapping.  But ClamAV would would need RWX access to the file,
> allowing that would probably be a greater security risk than
> 'execmem'.

Actually, I'm not so sure about that. If you used mkstemp() to create a temporary file in /tmp, then unlinked the file while keeping the fd open, you should be able to create a shared mapping on the file using mmap() without triggering the SELinux execmem test.

The disadvantage of doing it this way is that it'd be a lot slower, because you'd be going through the filesystem. For an invocation of clamscan, the additional cost would probably outweigh the benefit of using the JIT compiler in the first place.

But for clamd, the additional start-up cost would be far outweighed by the savings obtained by being able to use the JIT for the life of the clamd process (until the next database reload, that is). That's the usage case I'm interested in.

Comment 33 James Ralston 2010-09-23 20:34:08 UTC
BTW, this link (in comment 2) is broken:

http://people.redhat.com/~drepper/selinux-mem.html

Does anyone have a fixed link?

Comment 34 Török Edwin 2010-09-23 20:48:53 UTC
(In reply to comment #31)
> 
> I have some new ideas though, will resurrect that thread on the SELinux mailing
> list and discuss it there.

Here we go: http://marc.info/?l=selinux&m=128527325116622&w=1
Idea no. 3 looks easiest, if possible on SELinux.

(In reply to comment #32)
> Actually, I'm not so sure about that. If you used mkstemp() to create a
> temporary file in /tmp, then unlinked the file while keeping the fd open, you
> should be able to create a shared mapping on the file using mmap() without
> triggering the SELinux execmem test.

Similar to the double mapping workaround originally suggested, problem is you end up with the wrong address and need to relocate the code.
Unless you perform the 2nd mapping after you unmap the 1st, and MMAP_FIXED. In which case it is similar to my idea #3 above, will have to try if it works with munmap + mmap(MAP_FIXED).

Comment 35 Daniel Walsh 2010-09-23 20:51:04 UTC
http://www.akkadia.org/drepper/selinux-mem.html

Comment 36 Ulrich Drepper 2010-09-24 01:00:50 UTC
(In reply to comment #32)
> Isn't this what address space layout randomization is designed to thwart,
> through?

No.  ASLR is just one more protection the attacker has to work around.  ASLR does not provide 100% protection.  You cannot use its existence as an excuse to do nothing else.  Security mechanisms only work in depth, all of them at the same time.

ASLR can be defeated if, by some mechanism, the addresses of the memory segments is disclosed.  Sometimes it's sufficient to find a single pointer.

Comment 37 Adam Williamson 2011-11-08 00:41:04 UTC
I'm getting a bug rather similar to this when trying to use the shiny new Shell-on-software-GL support in F17. If I have selinux enabled, it doesn't work, and glxinfo gives the "allocation failed when allocating new memory in the JIT" error. When I disable SELinux, it works. Should there be a new bug for this (since the issue obviously isn't in clamav), or should it be followed here? Thanks!



-- 
Fedora Bugzappers volunteer triage team
https://fedoraproject.org/wiki/BugZappers

Comment 38 Daniel Walsh 2011-11-08 17:22:41 UTC
Adam what AVC are you seeing?

sesearch -A -s clamd_t -p execmem
Found 1 semantic av rules:
   allow clamd_t clamd_t : process execmem ;

Comment 39 Carl G. 2011-11-10 20:50:49 UTC
(In reply to comment #37)
> I'm getting a bug rather similar to this when trying to use the shiny new
> Shell-on-software-GL support in F17. If I have selinux enabled, it doesn't
> work, and glxinfo gives the "allocation failed when allocating new memory in
> the JIT" error. When I disable SELinux, it works. Should there be a new bug for
> this (since the issue obviously isn't in clamav), or should it be followed
> here? Thanks!
> 
> 
> 
> -- 
> Fedora Bugzappers volunteer triage team
> https://fedoraproject.org/wiki/BugZappers

https://bugzilla.redhat.com/show_bug.cgi?id=752087#c4

Comment 40 Daniel Walsh 2011-11-11 15:44:26 UTC
Carl update to the latest selinux-policy

selinux-policy-3.10.0-55.1.fc17

Comment 41 Fedora End Of Life 2012-08-16 18:06:12 UTC
This message is a notice that Fedora 14 is now at end of life. Fedora 
has stopped maintaining and issuing updates for Fedora 14. It is 
Fedora's policy to close all bug reports from releases that are no 
longer maintained.  At this time, all open bugs with a Fedora 'version'
of '14' have been closed as WONTFIX.

(Please note: Our normal process is to give advanced warning of this 
occurring, but we forgot to do that. A thousand apologies.)

Package Maintainer: If you wish for this bug to remain open because you
plan to fix it in a currently maintained version, feel free to reopen 
this bug and simply change the 'version' to a later Fedora version.

Bug Reporter: Thank you for reporting this issue and we are sorry that 
we were unable to fix it before Fedora 14 reached end of life. If you 
would still like to see this bug fixed and are able to reproduce it 
against a later version of Fedora, you are encouraged to click on 
"Clone This Bug" (top right of this page) and open it against that 
version of Fedora.

Although we aim to fix as many bugs as possible during every release's 
lifetime, sometimes those efforts are overtaken by events.  Often a 
more recent Fedora release includes newer upstream software that fixes 
bugs or makes them obsolete.

The process we are following is described here: 
http://fedoraproject.org/wiki/BugZappers/HouseKeeping


Note You need to log in before you can comment on or make changes to this bug.