3 ms·
Validate pointers with the msync() Linux system call
- wahern 6y ago> [msync] checks whether this range is in the allocated virtual memory region. .... [L]et's write a function that will check whether the memory area is allocated by the process or not. The range of memory mmap'd into a process is a superset of ranges allocated by the process--e.g. returned by malloc. Furthermore, even if you queried the process' internal allocation state, it would only be useful, if at all, for diagnostic purposes. In a threaded program it poses a TOCTTOU race; for example, it could asynchronously become "invalid" immediately after the test but before actually operating on the data. More generally, what use is it knowing alone whether a pointer is part of an allocated region or not? You have no idea of its type or logical validity. Reading it might accidentally result in divulging sensitive secrets, and writing to it (which you could attempt using read(2)) might corrupt your program state. Please, do not employ a trick like this. It's very typical for new C programmers to take an interest in low-level memory semantics and play around with the possibilities, but it's just as typical to go off the rails and implement a solution (as in this case) which is wrong and broken in almost every conceivable way. Both the technique and the premise (that the technique can be gainfully employed) are fatally flawed. Coarse validity checks can have a role in bug and exploit mitigation, but 1) the example technique is woefully inadequate, and 2) such techniques must be applied, if they're to be effectively applied at all, outside the logical structure of the program, as part of a compiler or runtime (e.g. malloc/free implementation) or, at least, whatever component has a distinct, special relationship to the data.
- sh1r4s3 6y agoThanks for the comment! > The range of memory mmap'd into a process is a superset of ranges allocated by the process--e.g. returned by malloc. Yes, and this approach, in general, would not work with malloc/free. In this little article I didn't tell anything about malloc, but probably I should explicitly mention it in an update. I'm not talking about any particular implementation here. The example at the end is just a toy model to demonstrate how it could be used, and it is not the real scenario. The purpose of this is just to tell that it is possible to check the pointer using this specific system call. For the real use-case scenario, this method is used by the ROOT framework to check the pointer in the C++ interpreter [1]. [1] https://github.com/root-project/root/commit/8f8c786cc491438548da4a29385cca4f470d2d29 https://github.com/root-project/root/commit/8f8c786cc4914385...
- rurban 6y agoProbably only useful for a non precise GC with ffi calls, when you don't know if the value on the stack is a large integer or a pointer. (For tagged values you know it, but for ffi callbacks the stack can have non-tagged ptrs). But for this it would need more validations, if we own the vma region of not. Like inspecting the /proc/<pid>/map_files Windows has a similar hack via IsBadreadPtr() https://stackoverflow.com/questions/4595675/determining-whether-pointer-is-valid https://stackoverflow.com/questions/4595675/determining-whet... has some other answers for this problem.
- bcrl 6y agoAs a kernel developer who has been in the depths of mm/... just.. no. msync() is way too expensive to use in any reasonable codebase. And it is in no way a reliable base for which good software should be built upon. You don't control where the kernel will plop newly allocated memory regions from mmap() unless you start specifying addressess, in which case why do you need to validate them? And what if it's "valid" but it points somewhere it shouldn't? Please, never ever do this in anything that has to run in production.