On Thu, Jun 27, 2019 at 11:56 AM Cedric Xing <cedric.xing@xxxxxxxxx> wrote: > > SGX enclaves are loaded from pages in regular memory. Given the ability to > create executable pages, the newly added SGX subsystem may present a backdoor > for adversaries to circumvent LSM policies, such as creating an executable > enclave page from a modified regular page that would otherwise not be made > executable as prohibited by LSM. Therefore arises the primary question of > whether an enclave page should be allowed to be created from a given source > page in regular memory. > > A related question is whether to grant/deny a mprotect() request on a given > enclave page/range. mprotect() is traditionally covered by > security_file_mprotect() hook, however, enclave pages have a different lifespan > than either MAP_PRIVATE or MAP_SHARED. Particularly, MAP_PRIVATE pages have the > same lifespan as the VMA while MAP_SHARED pages have the same lifespan as the > backing file (on disk), but enclave pages have the lifespan of the enclave’s > file descriptor. For example, enclave pages could be munmap()’ed then mmap()’ed > again without losing contents (like MAP_SHARED), but all enclave pages will be > lost once its file descriptor has been closed (like MAP_PRIVATE). That said, > LSM modules need some new data structure for tracking protections of enclave > pages/ranges so that they can make proper decisions at mmap()/mprotect() > syscalls. > > The last question, which is orthogonal to the 2 above, is whether or not to > allow a given enclave to launch/run. Enclave pages are not visible to the rest > of the system, so to some extent offer a better place for malicious software to > hide. Thus, it is sometimes desirable to whitelist/blacklist enclaves by their > measurements, signing public keys, or image files. > > To address the questions above, 2 new LSM hooks are added for enclaves. > - security_enclave_load() – This hook allows LSM to decide whether or not to > allow instantiation of a range of enclave pages using the specified VMA. It > is invoked when a range of enclave pages is about to be loaded. It serves 3 > purposes: 1) indicate to LSM that the file struct in subject is an enclave; > 2) allow LSM to decide whether or not to instantiate those pages and 3) > allow LSM to initialize internal data structures for tracking > origins/protections of those pages. > - security_enclave_init() – This hook allows whitelisting/blacklisting or > performing whatever checks deemed appropriate before an enclave is allowed > to run. An LSM module may opt to use the file backing the SIGSTRUCT as a > proxy to dictate allowed protections for anonymous pages. > > mprotect() of enclave pages continue to be governed by > security_file_mprotect(), with the expectation that LSM is able to distinguish > between regular and enclave pages inside the hook. For mmap(), the SGX > subsystem is expected to invoke security_file_mprotect() explicitly to check > protections against the requested protections for existing enclave pages. As > stated earlier, enclave pages have different lifespan than the existing > MAP_PRIVATE and MAP_SHARED pages, so would require a new data structure outside > of VMA to track their protections and/or origins. Enclave Memory Area (or EMA > for short) has been introduced to address the need. EMAs are maintained by the > LSM framework for all LSM modules to share. EMAs will be instantiated for > enclaves only so will not impose memory/performance overheads for regular > applications/files. Please see include/linux/lsm_ema.h and security/lsm_ema.c > for details. > > A new setup parameter – lsm.ema.cache_decisions has been introduced to offer > the choice between memory consumption and accuracy of audit logs. Enabling > lsm.ema.cache_decisions causes LSM framework NOT to keep backing files open for > EMAs. While that saves memory, it requires LSM modules to make and cache > decisions ahead of time, and makes it difficult for LSM modules to generate > accurate audit logs. System administrators are expected to run LSM in > permissive mode with lsm.ema.cache_decisions off to determine the minimal > permissions needed, and then turn it back on in enforcing mode for optimal > performance and memory usage. lsm.ema.cache_decisions is on by default and > could be turned off by appending “lsm.ema.cache_decisions=0” or > “lsm.ema.cache_decisions=off” to the kernel command line. Just on a very cursory review, this seems like it's creating a bunch of complexity (a whole new library and data structure), and I'm not convinced the result is any better than Sean's version.