> On May 17, 2019, at 9:20 AM, Stephen Smalley <[email protected]> wrote:
>
>> On 5/17/19 11:09 AM, Sean Christopherson wrote:
>>> On Fri, May 17, 2019 at 09:53:06AM -0400, Stephen Smalley wrote:
>>>> On 5/16/19 6:23 PM, Xing, Cedric wrote:
>>>> I thought EXECMOD applied to files (and memory mappings backed by them) but
>>>> I was probably wrong. It sounds like EXECMOD applies to the whole process
>>>> so
>>>> would allow all pages within a process's address space to be modified then
>>>> executed, regardless the backing files. Am I correct this time?
>>>
>>> No, you were correct the first time I think; EXECMOD is used to control
>>> whether a process can make executable a private file mapping that has
>>> previously been modified (e.g. text relocation); it is a special case to
>>> support text relocations without having to allow full EXECMEM (i.e. execute
>>> arbitrary memory).
>>>
>>> SELinux checks relevant to W^X include:
>>>
>>> - EXECMEM: mmap/mprotect PROT_EXEC an anonymous mapping (regardless of
>>> PROT_WRITE, since we know the content has to have been written at some
>>> point) or a private file mapping that is also PROT_WRITE.
>>> - EXECMOD: mprotect PROT_EXEC a private file mapping that has been
>>> previously modified, typically for text relocations,
>>> - FILE__WRITE: mmap/mprotect PROT_WRITE a shared file mapping,
>>> - FILE__EXECUTE: mmap/mprotect PROT_EXEC a file mapping.
>>>
>>> (ignoring EXECSTACK and EXECHEAP here since they aren't really relevant to
>>> this discussion)
>>>
>>> So if you want to ensure W^X, then you wouldn't allow EXECMEM for the
>>> process, EXECMOD by the process to any file, and the combination of both
>>> FILE__WRITE and FILE__EXECUTE by the process to any file.
>>>
>>> If the /dev/sgx/enclave mappings are MAP_SHARED and you aren't using an
>>> anonymous inode, then I would expect that only the FILE__WRITE and
>>> FILE__EXECUTE checks are relevant.
>> Yep, I was just typing this up in a different thread:
>> I think we may want to change the SGX API to alloc an anon inode for each
>> enclave instead of hanging every enclave off of the /dev/sgx/enclave inode.
>> Because /dev/sgx/enclave is NOT private, SELinux's file_map_prot_check()
>> will only require FILE__WRITE and FILE__EXECUTE to mprotect() enclave VMAs
>> to RWX. Backing each enclave with an anon inode will make SELinux treat
>> EPC memory like anonymous mappings, which is what we want (I think), e.g.
>> making *any* EPC page executable will require PROCESS__EXECMEM (SGX is
>> 64-bit only at this point, so SELinux will always have default_noexec).
>
> I don't think we want to require EXECMEM (or equivalently both FILE__WRITE
> and FILE__EXECUTE to /dev/sgx/enclave) for making any EPC page executable,
> only if the page is also writable or previously modified. The intent is to
> prevent arbitrary code execution without EXECMEM (or
> FILE__WRITE|FILE__EXECUTE), while still allowing enclaves to be created
> without EXECMEM as long as the EPC page mapping is only ever mapped RX and
> its initial contents came from an unmodified file mapping that was PROT_EXEC
> (and hence already checked via FILE__EXECUTE).
That agrees with my thoughts. Actually plumbing everything together so this
works could be a bit interesting. I assume it’ll need a special case in
SELinux or maybe a new vm_op.