mseal_all()
mseal_all()
Posted Jan 22, 2024 4:21 UTC (Mon) by NYKevin (subscriber, #129325)In reply to: mseal_all() by itsmycpu
Parent article: mseal() gets closer
There is no general way to do that. To explain why, I'm going to introduce two made-up terms:
* Some portion of memory is kernel-allocated if it belongs to a valid mapping of some kind. In other words, memory is kernel-allocated if it is possible to dereference a pointer to that memory without segfaulting.
* Some portion of memory is userspace-allocated if it is valid stack memory (as defined by the architecture etc.), if it is statically allocated, or if has been returned by malloc or some malloc-like function and not subsequently freed. In other words, memory is userspace-allocated if it would be "valid" for the program to actually use the memory for some purpose, without needing to do any malloc-like bookkeeping. The term "valid" is intentionally undefined, because the semantics of malloc and malloc-like functions will depend on the implementation and API, but in general, this is roughly synonymous with C's notion of pointer validity (i.e. you are not generally allowed to just make up your own pointers into the heap and do whatever you like with them).
The basic problem here is that the total amount of kernel-allocated memory is finite. Once the address space is sealed, you cannot add any more mappings, so you cannot kernel-allocate any more memory. Therefore, the only way to create more userspace-allocated memory is to use the kernel-allocated memory you already have, and you will eventually run out.
The other problem is that, in practice, glibc malloc tacitly assumes it can just mmap whatever it wants, whenever it wants. If you malloc a large amount of memory in one call, it will not fiddle around with the existing heap memory, it will just pass the arguments through to mmap, and give you a whole new mapping. This mapping may later be unmapped if you call free (or maybe it isn't, I haven't actually read the source code). It also calls mmap if it detects thread contention, which is probably difficult to predict in real applications. These are theoretically changeable behaviors, but I doubt the glibc people would be happy with the resulting performance regressions.
For these reasons, I think it would have to be a libc service, because only libc has the necessary userspace knowledge to figure out which mappings are safe to seal, which ones might need to be created in the future, and which ones might need to be unmapped in the future. But I think that starts to become redundant to "just automatically mseal everything that libc knows it can safely mseal," and you don't need a function for that, it can just automatically happen at startup.
