Freebsd page level premission with in a user space process - linker

Is there a way in FreeBSD by which we can restrict few contiguous instruction pages to read and write to only to few data segment pages? Basically I am trying to restrict dynamically linked libraries to read and write only pages linked due to dynamically linked library and only few pages of the global data in the rest of the process address space.
Can this be done using linker directives or by modifying page level bits within the kernel?
Regards,
Mahesh

You can set the protection level of pages (e.g. make them read-only) within the virtual address space of a process with mprotect(2).

Related

mlockall & shared libs

I am bit confused about the following sentence which appears in the manual of mlockall.
mlockall() locks all pages mapped into the address space of the calling process. This includes the pages of the code, data and stack segment, as well as shared libraries, user space kernel data, shared memory, and memory-mapped files.
Does this mean that mlockall(MCL_CURRENT | MCL_FUTURE) will read in advance all the pages of a shared library and lock them into memory when the function is invoked? Or when those pages are actually needed by the process?
No. Just when the pages are needed by the process. The only thing mlockall does is stop pages from being loaded into swap space (swapped).

What is the difference between vm_insert_page() and remap_pfn_range()?

I want to map device memory (NIC) to the kernel space memory region by using ioremap_wc(). And then I want to remap memory region from kernel space to user space, and I can use 2 functions for this: vm_insert_page() and remap_pfn_range()
POSIX mmap(3) usually use the second: remap_pfn_range()
What is the difference between vm_insert_page() and remap_pfn_range(), and when do I need to use vm_insert_page() instead of remap_pfn_range()?
As their name suggest vm_insert_page() map a single page, while remap_pfn_range() maps a consecutive block of kernel memory. Check the prototypes and comments vm_insert_page, remap_pfn_range
For example, you can use vm_insert_page to map vmalloc aree
do {
page = vmalloc_to_page(vaddr);
vm_insert_page(vma, uaddr, page);
vaddr += PAGE_SIZE;
} while(/* there is something to map */);
it is not possible using remap_pfn_range because it maps only a consecutive block of kernel memory.
Another difference is that with remap_pfn_range you can map not only RAM buffers, but other ranges. With vm_inser_page you can map only RAM buffers
An explanation from Linus
vm_insert_page() allows drivers to insert individual pages they've allocated into a user vma. The page has to be allocate within the kernel independently. It requires the page be an order-zero allocation obtained for this purpose. It does not put out warnings, and does not require that PG_reserved be set.
Traditionally, this was done with remap_pfn_range() which took an arbitrary page protection parameter. vm_insert_page() doesn't allow that. Your vma protection will have to be set up correctly, which means that if you want a shared writeable mapping, you'd better ask for a shared writeable mapping!
remap_pfn_range() is used for mapping or remapping a group of pages into the memory.
Refer
In short,
use remap_pfn_range if you don't need struct page for the physical page frames.
use vm_insert_page for memory you need struct page for the physical page frame.
(note that there is also vm_insert_pages which can insert multiple pages into vma)
If you hope to do direct I/O from this region, then you need to use vm_insert_page/vm_insert_pages because direct I/O will invoke get_user_page to get struct page and the following ext4/scatterlist codes also need struct page.

Windows shared memory segments

I've been googling this a little bit and haven't been able to find a clear answer so I'm hoping someone has some insight into shared memory segments in windows VS linux.
In Linux there are 2 ways of creating shared memory for IPC: shared memory segments (shmget, et al) and memory mapped files (mmap). From my brief understanding mmap requires you to have an actual file somewhere in the OS to map whereas shared memory segments are just name based segments in memory that can be attached to by processes.
In Windows there only seems to be the equivalent of memory mapped files where you have to have an actual file floating around somewhere.
My question: Is this actually the only kind of shared memory in Windows or does it have an api for creating non file based shared memory segments.
The Unix mmap() API is practically equivalent to the CreateFileMapping/MapViewOfFile Windows API. Both can map files and/or can create shared (anonymous) maps that are backed by the swap device (if any). As a matter of fact, glibc uses anonymous mmap() to implement malloc() when the requested memory size is sufficiently large.
Windows supports one additional mechanism - shared data sections in the executable file, something that is not implemented in Linux. First you create a named data section using the #pragma data_seg(".somename") and put the shared variables inside. Then you tell the linker to mark the section as read/write/shared with the following option: /SECTION:.somename,RWS. The whole process is described in MSDN. This only works for copies of the same module, either EXE or DLL file. Same module means same file in the same file system location: processes created from different copies of the same executable but located in different places won't see each others named sections as shared.
Yes, you can use non file-based shared memory segments in Windows.
#pragma comment(linker, "/SECTION:.shared,RWS")
#pragma data_seg(".shared")
int g_iShared = 0;
#pragma data_seg()
This might be a bit late.
Windows shared memory is not the same as Linux only some things are similar.
The biggest difference is the memory allocation granularity size. Linux is 4K and Windows is 64K. If it's important to have say arbitrary 8K pages mapped into specific 8K destinations well you are stuck on Windows and it just can't be done. (If someone figures this out then please let me know).
Another difference is you can mmap a new page over the top of an existing page effectively replacing the first page mapping. In windows you can't do this but instead must destroy the entire view and rebuild the entire view in what ever new layout that is required. So if the "view" contains 1024 pages and 1 page changes then in Linux you can just change that one page. In Windows you must drop all 1024 pages and re-view the same 1023 pages + the one new page!
On Linux you can share memory without a backing file by using ANONYMOUS memory but then it becomes hard to share or you can use shm_opn to create a shared memory file descriptor and pass that to mmap. Here is a good link.
http://nullprogram.com/blog/2016/04/10/
I've used this and it works.

Exchange the mapping to two physical pages of two pages in virtual memory

Here is the situation:
A process has two pages vp1 and vp2. These two pages are mapped to 2 physical pages or 2 pages in the swap. Let's call these physical (or in swap) pages pp1 and pp2. The mapping is:
vp1->pp1
vp2->pp2
Now, if I want to change the mapping to:
vp1->pp2
vp2->pp1
That means, reading from vp2 by the process will get the content originally in vp1. Is there a method to do this without changing the kernel on Linux?
Yes, but you have to do some work first. One way to accomplish this is to create two shared memory objects. Then you can map and unmap the shared memory objects in the process address space. See the system calls shmat, shmdt, shmget, and shmctl for details.
Mapping and unmapping is likely to take considerable time, so it may not save time over using some pointer scheme to choose which addresses a process uses to access data.
No. Not in the general case if you want to keep your system working. But if you control how the mappings are created you can create them with mmap of a file or an object from shm_open and when you need to swap them just overwrite them with mmap(... MAP_FIXED ...).

Manage virtual memory from userspace

What I actually want to do is to redirect writes in a certain memory area to a separate memory area which is shared between two processes. Can this be done at user level? For example, for some page X. What I want to do is to change its (virtual to physical) mapping to some shared mapping when it's written. Is this achievable? I need to do it transparently too, that is the program still uses the variables in page X by their names or pointers, but behind the scenes, we are using a different page.
Yes, it is possible to replace memory mappings in Linux, though it is not advisable to do it since it is highly non-portable.
First, you should find out in what page the X variable is located by taking its address and masking out the last several bits - query the system page size with sysconf(_SC_PAGE_SIZE) in order to know how many bits to mask out. Then you can create a shared memory mapping that overlaps this page using the MAP_FIXED | MAP_SHARED flag to mmap(2) or mmap2(2). You should copy the initial content of the page and restore it after the new mapping. Since other variables may reside in the same page, you should be very careful about memory layout and better use a dedicated shared memory object.
What you're trying to do isn't entirely possible, because, at least on x86, memory cannot be remapped on that fine-grained of a scale. The smallest quantum that you can remap memory on is a 4k page, and the page containing any given variable (e.g, X) is likely to contain other variables or program data.
That being said, you can share memory between processes using the mmap() system call.

Resources