On fork() in Linux - fork

#include<stdio.h>
int giCtr0;
int main(void){
int iPid;
iPid = fork();
if (iPid == 0){
giCtr0++;
printf("In Child\n");
printf("Addr\t%x Value\t%d\n",&giCtr0,giCtr0);
}
else{
giCtr0+=2;
printf("In Parent\n");
printf("Addr\t%x Value\t%d\n",&giCtr0,giCtr0);
}
return 0;
}
The output from Ubuntu is as follows:
In Parent
Addr 601054 Value 2
In Child
Addr 601054 Value 1
The Value is proper and as expected.
How does address of the variable remain same in child and parent process?
Is there anything wrong in this code? Please suggest.

Memory addresses in a Unix-like VM system are per-process. The address you obtain with the C & operator is an OS-level construct, not the addressing scheme that maps directly to bits in RAM chips (or swapped-out VM pages). Thus, it's possible for the same address in two different processes to refer to two different locations in "real" memory.
fork spawns a clone of the parent process. For both processes to continue operating as they had before the fork, the entire memory image of the parent process is copied to create that of the child process... so, from each process' perspective, the memory addresses of all variables still point to the same things they did before. (But since the processes are now separate, changes in one affect a different underlying storage than is used by the other.)

How does address of the variable remain same in child and parent process?
To add to the comment from mkimball
Linux implements virtual memory. That means it sets up the hardware so each process sees a 'virtual' memory map instead of the 'real'/physical memory map.
Because of this the memory address 0x601054 of one process does not necessarily correspond to the same real memory 'cell' as the same address 0x601054 inside another process.

Related

Question about VirtualQueryEx() lpAdress variable

I am building a Memory Scanner to find malware strings in a process.
Btw, when I was searching about the VirtualQueryEx dll, I saw that people starts its variable lpAdress ( which is supposed to be the Base Address of the process) with a NULL/0 value
LPVOID lpAdress = 0
and in each loop they increase the adress value by the size of the page they just read, so that way they go to the next page and can map all process virtual memory
lpAdress += mbi.RegionSize # mbi is a variable with MEMORY_BASIC_INFORMATION structure
So, is lpAdress the value of memory considering 0 as a start of the own process virtual memory and you dont need to get the actual base adress of the process in memory ? Sorry if my question looks dumb, but the MSDN documentation is confusing me.
Each process has it's own virtual address space that starts at 0. The various executable files (.exe / .dll / whatever) are loaded either at addresses specified in the file or more recently at random addresses for security purposes.
A process can easily have mapped memory regions at addresses lower than where the process executable is loaded. For this reason, if you want to examine a process' entire memory space you need to start at 0.

In node* newNode=new node() , whose address is exactly getting returned by new here?

node* newNode=new node();
Here node is a typical linked list node class and newNode is the pointer used to dynamically create a new node containing int data and node* next attributes. Please tell exactly which address gets returned by the new keyword and getting stored in the newNode here?
For instance in int* p = arr[n]; , the address of arr or arr[0] is stored specifically.
There is lot of behind the scenes are happening when you are specifying new keyword. The context of "which address gets returned by the new keyword" is not the primary thing to focus, rather you need to know how a program (more specifically a process) deals with memory via Operating System.
what is process?
a process is more than a program code, which sometimes referred as text section; it also includes current activity as represented by the value of program counter and contents of the processor's registers.
a process generally includes:
the process stack, which contains temporary data such as function parameters, return addresses and local variables.
the data section, which contains global variables.
a process also include a heap area (which is important for your question), which is memory that is dynamically allocated during process runtime.
How memory allocated dynamically?
The new operator creates the object using that memory, and then returns a pointer containing the address of the memory that has been allocated.
new int; // dynamically allocate an integer.
Most often, we’ll assign the return value to our own pointer variable so we can access the allocated memory later.
int *ptr{ new int };
We can then perform indirection through the pointer to access the memory:
*ptr = 7;
Also some points to mention:
when you are requesting some memory by new keyword, the Operating System first search for free memory needed to fulfill your requirement from heap area (as mentioned above), if OS finds the memory, it is allocated to your variable/s.
when you are done with your process, the process itself return the memory back to the OS, so that it can be used by another program's process.
REFERENCE: OPERATING SYSTEM CONCEPTS BY SILBERSCHATZ, GALVIN AND GAGNE.

How to get the physical address in macosx kernel for a virtual address for a particular process?

I was wondering if there is an existing system call/API for accessing getting the physical address of the virtual address?
If there is none then some direction on how to get that working ?
Also, how to get the physical address of MMIO which is non-pageable physical memory ?
The answer lies in IOMemoryDescriptor and IODMACommand objects.
If the memory in question is kernel-allocated, it should be allocated by creating an IOBufferMemoryDescriptor in the first place. If that's not possible, or if it's a buffer allocated in user space, you can wrap the relevant pointer using IOMemoryDescriptor::withAddressRange(address, length, options, task) or one of the other factory functions. In the case of withAddressRange, the address passed in must be virtual, in the address space of task.
You can directly grab physical address ranges from an IOMemoryDescriptor by calling the getPhysicalSegment() function (only valid between prepare()…complete() calls). However, normally you would do this for creating scatter-gather lists (DMA), and for this purpose Apple strongly recommends the IODMACommand. You can create these using IODMACommand::withSpecification(). Then use the genIOVMSegments() function to generate the scatter-gather list.
Modern Macs, and also some old PPC G5s contain an IOMMU (Intel calls this VT-d), so the system memory addresses you pass to PCI/Thunderbolt devices are not in fact physical, but IO-Mapped. IODMACommand will do this for you, as long as you use the "system mapper" (the default) and set mappingOptions to kMapped. If you're preparing addresses for the CPU, not a device, you will want to turn off mapping - use kIOMemoryMapperNone in your IOMemoryDescriptor options. Depending on what exactly you're trying to do, you probably don't need IODMACommand in this case either.
Note: it's often wise to pool and reuse your IODMACommand objects, rather than freeing and reallocating them.
Regarding MMIO, I assume you mean PCI BARs and similar - for IOPCIDevice, you can grab an IOMemoryDescriptor representing the memory-mapped device range using getDeviceMemoryWithRegister() and similar functions.
Example:
If all you want are pure CPU-space physical addresses for a given virtual memory range in some task, you can do something like this (untested as a complete kext that uses it would be rather large):
// INPUTS:
mach_vm_address_t virtual_range_start = …; // start address of virtual memory
mach_vm_size_t virtual_range_size_bytes = …; // number of bytes in range
task_t task = …; // Task object of process in which the virtual memory address is mapped
IOOptionBits direction = kIODirectionInOut; // whether the memory will be written or read, or both during the operation
IOOptionBits options =
kIOMemoryMapperNone // we want raw physical addresses, not IO-mapped
| direction;
// Process for getting physical addresses:
IOMemoryDescriptor* md = IOMemoryDescriptor::withAddressRange(
virtual_range_start, virtual_range_size_bytes, direction, task);
// TODO: check for md == nullptr
// Wire down virtual range to specific physical pages
IOReturn result = md->prepare(direction);
// TODO: do error handling
IOByteCount offset = 0;
while (offset < virtual_range_size_bytes)
{
IOByteCount segment_len = 0;
addr64_t phys_addr = md->getPhysicalSegment(offset, &len, kIOMemoryMapperNone);
// TODO: do something with physical range of segment_len bytes at address phys_addr here
offset += segment_len;
}
/* Unwire. Call this only once you're done with the physical ranges
* as the pager can change the physical-virtual mapping outside of
* prepare…complete blocks. */
md->complete(direction);
md->release();
As explained above, this is not suitable for generating DMA scatter-gather lists for device I/O. Note also this code is only valid for 64-bit kernels. You'll need to be careful if you still need to support ancient 32-bit kernels (OS X 10.7 and earlier) because virtual and physical addresses can still be 64-bit (64-bit user processes and PAE, respectively), but not all memory descriptor functions are set up for that. There are 64-bit-safe variants available to be used for 32-bit kexts.

Allocate swappable memory in linux kernel

Memory in the Linux kernel is usually unswappable (Do Kernel pages get swapped out?). However, sometimes it is useful to allow memory to be swapped out. Is it possible to explicitly allocate swappable memory inside the Linux kernel? One method I thought of was to create a user space process and use its memory. Is there anything better?
You can create a file in the internal shm shared memory filesystem.
const char *name = "example";
loff_t size = PAGE_SIZE;
unsigned long flags = 0;
struct file *filp = shmem_file_setup(name, size, flags);
/* assert(!IS_ERR(filp)); */
The file isn't actually linked, so the name isn't visible. The flags may include VM_NORESERVE to skip accounting up-front, instead accounting as pages are allocated. Now you have a shmem file. You can map a page like so:
struct address_space *mapping = filp->f_mapping;
pgoff_t index = 0;
struct page *p = shmem_read_mapping_page(mapping, index);
/* assert(!IS_ERR(filp)); */
void *data = page_to_virt(p);
memset(data, 0, PAGE_SIZE);
There is also shmem_read_mapping_page_gfp(..., gfp_t) to specify how the page is allocated. Don't forget to put the page back when you're done with it.
put_page(p);
Ditto with the file.
fput(filp);
Answer to your question is a simple No, or Yes with a complex modification to kernel source.
First, to enable swapping out, you have to ask yourself what is happening when kswapd is swapping out. Essentially it will walk through all the processes and make a decision whether its memory can be swapped out or not. And all these memory have the hardware mode of ring 3. So SMAP essentially forbid it from being read as data or executed as program in the kernel (ring 0):
https://en.wikipedia.org/wiki/Supervisor_Mode_Access_Prevention
And check your distros "CONFIG_X86_SMAP", for mine Ubuntu it is default to "y" which is the case for past few years.
But if you keep your memory as a kernel address (ring 0), then you may need to consider changing the kswapd operation to trigger swapout of kernel addresses. Whick kernel addresses to walk first? And what if the address is part of the kswapd's kernel operation? The complexities involved is huge.
And next is to consider the swap in operation: When the memory read is attempted and it's "not present" bit is enabled, then hardware exception will trigger linux kernel memory fault handler (which is __do_page_fault()).
And looking into __do_page_fault:
https://elixir.bootlin.com/linux/latest/source/arch/x86/mm/fault.c#L1477
and there after how it handler the kernel addresses (do_kern_address_fault()):
https://elixir.bootlin.com/linux/latest/source/arch/x86/mm/fault.c#L1174
which essentially is just reporting as error for possible scenario. If you want to enable kernel address pagefaulting, then this path has to be modified.
And note too that the SMAP check (inside smap_violation) is done in the user address pagefaulting (do_usr_addr_fault()).

Shared Memory between User Space and Kernel Threads

I am developing a kernel application which involves kthreads. I create an array of structure and allocate memory using malloc in user-space. Then I call a system call (which I implemented) and pass the address of array to kernel-space. In the handler of system-call I create I create 2 kthreads which will monitor the array. kthread can change some value and user-space threads can also change some values. The idea is to use the array as a shared memory. But some when I access the memory in kernel space (using copy_from_user) the data are somehow changed. I can verify that the address are same when it was assigned and in kernel. But when using copy_from_user it is giving various values like garbage values.
Also is the following statement ok?
int kthread_run_function(void* data){
struct entry tmp;
copy_from_user(&tmp, data, sizeof(struct entry));
}
This is not OK because copy_from_user() copies from the current user process (which should be obvious, since there's no way to tell it which user process to copy from).
In a syscall invoked by your userspace process this is OK, because the current process is your userspace process. However, within the kernel thread the current process could be any other process on the system - so you're copying from a random process's memory, which is why you get garbage.
If you want to share memory between the kernel and a userspace process, the right way to do this is to have the kernel allocate it, then allow the userspace process to map it into its address space with mmap(). The kernel thread and the userspace process will use different pointers to refer to the memory region - the kernel thread will use a pointer to the memory allocated within the kernel address space, and the userspace process will use a pointer to the memory region returned by mmap().
No, generally it's not OK since data is kernel virtual address, not a user virtual address.
However, IFF you called kthread_create with the data argument equal to an __user pointer, this should be ok.

Resources