System.map file in Linux is generatied after OS is built. I am wondering whether using a "run-time" address randomization technique would make the addresses within system.map invalid.
There is not (yet), at least not fully. Only the base address for the kernel code segment is randomizable.
See this LWN article for details / more references.
The method mentioned there basically adds a constant (chosen randomly at boot time) to the kernel code segment load address; this means relative offsets in System.map stay valid, if you've got the real address for a single symbol you can derive all others.
Related
I am porting a large application to ARM32 Linux and splitting off the hardware stuff into a device driver. Nearly all of the extensive driver code uses absolute addresses to access buffers and I/O related variables and registers. I'd have to have to change all that to pointer relative addresses - a lot of code is in assembler as well.
From user space it is simple to use mmap to ask for a target virtual address for physical memory (via /dev/mem) so that side poses no issue.
But how can I do similar in kernel code ? IOremap and Memremap give you a random kernel virtual address, worse, loading a driver using INSMOD places both code and data (.bbs) in vmalloc memory.
remap_PFN_range can be used to map kernel memory to user space via mmap call (and with that ask for a given virtual address range) - but how can that be used from the kernel itself if at all ?
So for example, say I have a buffer at physical address 0x60000000 - how can I tell the Kernel to map that to a given kernel accessible virtual address (perhaps also 0x60000000 but could be anything as long as its known at compile time) ?
So far I have spent days surfing anything that mentions remapping but am not finding the "golden" answer. Anybody know if one exists ?
AFAIK there is no "easy" way to do that.
This document explains the memory layout of the Linux kernel memory, and as you see, modules has a specific mapping space which can't be changed as long as you load your code with init_module syscall, and dynamic memory that's allocated using stuff like kmalloc also has a specific range.
Maybe you'll be able to hack something together to create a buffer at a known address, but if my memory doesn't fool me, Linux kind of depends on the layout I mentioned above for some fundamental stuff (page faults etc...).
OK, I have the answer and it's embarrassingly simple.
In my case I am running a STM32MP157 chip under buildroot. It so happens 512MBytes of DRAM is placed at 0xC0000000 physical. This means kernel space virtual address = physical address. PAGE_OFFSET and PHYS_OFFSET are 0xC0000000 so they simply cancel out.
Right, to display a nice logo on startup a 3MByte framebuffer is allocated in CMA memory which starts at 0xD8000000. This is done in early kernel init and is the first thing in CMA. Later on I allocate more framebuffers via DRM but the first one stays.
It's unused after kernel boot - except it now isn't. It's my perfect solution - just read and write directly into 0xD8000000 to 0xD83FFFFF (physical location and size of that framebuffer). All the variables I need to have at locations known at compile time are located into that space. Directly accessible, no pointers needed. No need to modify my existing code other than tell the linker to place the variables at 0xD8000000.
I was reading an operating system book and I found the following information which I couldn't understand :
Logical and physical addresses are the same in compile-time and
load-time address-binding schemes; logical (virtual) and physical
addresses differ in execution-time address-binding scheme".
so does it mean that in the compile-time address-binding which converts symbolic addresses to physical address or to relocatable addresses and in load-time address-binding which converts relocatable addresses to physical address , the program deals with physical addresses and the CPU generates the physical address directly ?!
and in execution-time address-binding scheme in which the location of the program in main memory may change so there would be separated address spaces ?!
is that the idea or Am I missing something ?
Which operating system text are you reading from; ie. what date?
Traditional UNIX tools comprised a compiler (ccN), which converted source into asm; an assembler (as), which converted asm into either relocatable object code or executable; and a loader (ld) which combined object code files into a resolved executable.
Note that the assembler, if all symbols were resolved, could create an executable: the convention a.out is an artifact of this.
Other systems, notably IBM mainframes and later MSDOS, referred to loading as link editting, a difference without distinction.
When ld resolved (assigned) addresses to the executable, those addresses were virtual; although in practice might have been physical. Ld didn't care, its job was to combine N object files into a fully resolved executable, perhaps guided by rules like: .text = 0x0, .data = .text + size(.text), .... If I had an embedded system with only physical addresses, I could guide ld with other rules.
The resultant, a.out has a notion of the addresses of everything, and on modern equipment (where modern means any significant computer since 1978) these are virtual addresses, which the operating system which maps the executable into memory resolves to other physical memory addresses.
In more modern system, (since circa 2003), the a.out does not contain exact addresses, rather contains relative addresses and internal mapping tables. This enables operating systems to change a programs addresses each time they are run to thwart some simple malware attacks.
I am very new to kernel or system programming,
I have couple of questions related to virtual memory. Mostly related to static vs run time, [i.e. ELF and loading/Linking etc], Specific to linux-x86.
My understandings might be completely wrong...
I am aware of virtual memory and it's split 1G/3G. where process can not access address above PAGE_OFFSET in user mode - PAGE_OFFSET is virtual address.
At Static time ELF defines process Virtual space?
If ELF defines virtual address space then does ELF also defines kernel virtual address space? How?
[ I assume kernel virtual address space is dynamically mapped at run time?]
If kernel address space is mapped to process address space then why doesn't process size(virtual) includes kernel size also?
When and How this kernel address space is mapped/linked?
Like , In case of shared library the particular file is pointed by vm struct etc..
Is it when code flow hits system call? For example.
Does executable size determines process size (virtual) completely? in what context sizes differ or they are completely different.
Any article that explains overall flow?
Compile --> link/load --> virtual memory structure (kernel address space/shared objects etc)
I know its very vast but explanation on overall flow will work.
Most systems define logical address ranges for kernel and user address spaces. On some systems the range is entirely up to the operating system (how it sets up the page tables) on others it is done in hardware.
For the former, page tables are usually nested. In which case multiple page tables share identical entires.
For the latter, there are usually separate page tables for the user and kernel address spaces.
If ELF defines virtual address space then does ELF also defines kernel virtual address space? How? [ I assume kernel virtual address space is dynamically mapped at run time?]
The executable file only defines the initial layout of the user address space.
If kernel address space is mapped to process address space then why doesn't process size(virtual) includes kernel size also?
That would depend upon the system and how it does the counting.
When and How this kernel address space is mapped/linked? Like , In case of shared library the particular file is pointed by vm struct etc.
The kernel address space exists independent of any processes. As mentioned above, it is mapped to a process either by having a system page table shared by all processes or a set of nested page table entries shared by all processes.
Does executable size determines process size (virtual) completely? in what context sizes differ or they are completely different.'
Not really. Large executables are indicative of larger ranges of logical addresses required. However, a small EXE can easily describe a large number of demand zero pages. In addition, the application can map logical pages as it executes. The EXE only defines the initial state of the logical address space.
I've been trying to implement the attack described in this paper: https://eprint.iacr.org/2013/448.pdf . Unfortunately there is no source code nor enough details on how some very low-level details work.
For example they state that mmapping the executable of a process P1 in the virtual space of another process P2 makes the kernel (supposedly) merge the .text segment of P1 with the same .text segment that has been mmapped by P1 at the physical memory level (which to P2, of course, is just random data in memory, not an actual .text segment). But how can I make sure this actually happens?
Let's take address a in P1's .text. Its content in P2's virtual space will be at address a* (belonging to the mmapped space) with a != a* (obviously), even though they (should) both point to the same address in the physical memory. If I clflush a* how can I make sure I'm also flushing a (since the cache is mapped to the physical memory)? In other words: is there a way to know whether or not Linux has merged the two pages referred by a and a*?
Thank you in advance.
PS: I know you can't translate a virtual address into a physical address in user space but I can't write a driver or anything like that.
PPS: this is the excerpt of the paper that describes the mmapping phase (section 4):
The spy and the victim execute as two
processes within that system. To achieve sharing, the spy
mmaps the victim’s executable file into the spy’s virtual
address space. As the Linux loader maps executable files
into the process when executing them, the spy and the
victim share the memory image of the mapped file.
In answer to a question about mapping non-contiguous blocks of files into contiguous memory, here, it was suggested by one respondent that I should use VirtualAllocEx() with MEM_RESERVE in order to establish a 'safe' value for the final (lpBaseAddress) parameter for MapViewOfFileEx().
Further investigation revealed that this approach causes MapViewofFileEx() to fail with error 487: "Attempt to access invalid address." The MSDN page says:
"No other memory allocation can take place in the region that is used for mapping, including the use of the VirtualAlloc or VirtualAllocEx function to reserve memory."
While the documentation might be considered ambiguous with respect to valid sequences of calls, experimentation suggests that it is not valid to reserve memory for MapViewOfFileEx() using VirtualAllocEx().
On the web, I've found examples with hard-coded values - example:
#define BASE_MEM (VOID*)0x01000000
...
hMap = MapViewOfFileEx( hFile, FILE_MAP_WRITE, 0, 0, 0, BASE_MEM );
To me, this seems inadequate and unreliable... It is far from clear to me why this address is safe, or how many blocks can be safely be mapped there. It seems even more shaky given that I need my solution to work in the context of other allocations... and that I need my source to compile and work in both 32 and 64 bit contexts.
What I'd like to know is if there is any way to reliably reserve a pool of address space in order that - subsequently - it can be reliably used by MapViewOfFileEx to map blocks to explicit memory addresses.
You almost got to the solution by yourself but fell short of the last small step.
As you figured, use VirtualAlloc (with MEM_RESERVE) to find room in your address space, but after that (and before MapViewOfFileEx) use VirtualFree (with MEM_RELEASE). Now the address range will be free again. Then use the same memory address (returned by VirtualAlloc) with MapViewOfFileEx.
What you are trying to do is impossible.
From the MapViewOfFileEx docs, the pointer you supply is "A pointer to the memory address in the calling process address space where mapping begins. This must be a multiple of the system's memory allocation granularity, or the function fails."
The memory allocation granularity is 64K, so you cannot map disparate 4K pages from the file into adjacent 4K pages in virtual memory.
If you provide a base address, the function will try to map your file at that address. If it cannot use that base address (because something is already using all or part of the requested memory region), then the call will fail.
For most applications, there's no real point trying to fix the address yourself. If you're a sophisticated database process and you're trying to carefully manage your own memory layout on a machine with a known configuration for efficiency reasons, then it might be reasonable. But you'd have to be prepared for failure.
In 64-bit processes, the virtual address space is pretty wide open, so it might be possible to select a base address with some certainty, but I don't think I'd bother.
From MSDN:
While it is possible to specify an address that is safe now (not used by the operating system), there is no guarantee that the address will remain safe over time. Therefore, it is better to let the operating system choose the address.
I believe "over time" refers to future versions of the OS and whatever run-time libraries you're using (e.g., for memory allocation), which might take a different approach to memory layout.
Also:
If the lpBaseAddress parameter specifies a base offset, the function succeeds if the specified memory region is not already in use by the calling process. The system does not ensure that the same memory region is available for the memory mapped file in other 32-bit processes.
So basically, your instinct is right: specifying a base address is not reliable. You can try, but you must be prepared for failure.
So to directly answer your question:
What I'd like to know is if there is any way to reliably reserve a pool of address space in order that - subsequently - it can be reliably used by MapViewOfFileEx to map blocks to explicit memory addresses.
No, there isn't. Not without applying many constraints on the runtime environment (e.g., limiting to a specific version of the OS, setting base addresses for all of your DLLs, disallowing DLL injection, etc.).