C programming with system calls Write a system call to report statistics of a pr
ID: 3701037 • Letter: C
Question
C programming with system calls
Write a system call to report statistics of a process's virtual address space. The system call should take a process ID as input and outputs the following information about the process 1. The size of the process's virtual address space 2. Each virtual memory area's access permissions 3. The names of files mapped to these virtual memory areas Write two user-level programs to test your system call. One test program just calls the new system call and report the calling process's statistics. The other test program should create multiple threads and report information about individual threads. The purpose of the second test program is to study if threads share the same address space. Hints The Linux kernel uses the memory descriptor data structure to represent a process's address space. The mem ory descriptor struct mm_struct is defined in and included in a process's task_struct. In mm_struct the mm users field is the number of processes using this address space and the mm_count field is the reference count for this mm_struct. The vm_area_struct describes a single memory area over a con- tiguous interval in an address space space. To calculate the size of a virtual address space, one only needs to sum the sizes of individual virtual memory areas (VMA). The VMAs in a process can be accessed in two ways. mmap in mm_struct points toa sorted linked list of all VMAs of a process. mm_rb points to a red-black tree of VMAs, which can be used to search for a given VMA. You can verify your result using pmap All the virtual memory areas together form a process's virtual addressExplanation / Answer
Defining the system call:
1. Create a new directory in your linux directory, say ‘stats’ and change to this directory. We’ll maintain the necessary header file(s) and implementation file(s) for the system call in this directory.
mkdir stats
cd stats/
2. Create a header file ‘vmaStats.h’ that will contain the necessary function declarations, structure declarations, macros, etc. For this example, we will only be using it to declare the function prototype.
3. Include the following line in the header file. Here, asmlinkage tells the compiler to look at the CPU’s stack for the function parameters, and, long is generally used as a return type in kernel space for functions that return an int in user space.
asmlinkage long sys_vma_stats(int pid);
4. Now, let’s define our system call in ‘reportVMAStats.c’.
reportVMAStats.c :
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/mm_types.h>
#include <linux/fs.h>
#include <asm/page.h>
#include <asm/mman.h>
#include "vmaStats.h"
asmlinkage long sys_vma_stats(int pid)
{
struct task_struct *this_task;
struct mm_struct *this_mem;
struct vm_area_struct *all_vmas;
struct vm_area_struct this_vma;
int num_vmas;
unsigned long prot=0;
unsigned long start=0;
int count=0;
int total_size=0;
char *name;
this_task = find_task_by_vpid(pid);
this_mem = this_task->active_mm;
all_vmas = this_mem->mmap;
num_vmas = this_mem->map_count;
this_vma = *all_vmas;
start=this_vma.vm_start;
printk(" There are %i virtual memory areas (VMAs). ", num_vmas);
for (this_vma = *all_vmas; count < num_vmas; count++)
{
printk("----------------------------- ");
printk("VMA #%i: ", count+1);
printk("-> Start address: 0x%lx ", this_vma.vm_start);
printk("-> End address: 0x%lx ", this_vma.vm_end);
printk("-> Total size (End - Start): %lu ", this_vma.vm_end - this_vma.vm_start);
prot = this_vma.vm_flags;
printk("-> Access permissions: ");
printk("Read permission: %s ", prot&PROT_READ?"yes":"no");
printk("Write permission: %s ", prot&PROT_WRITE?"yes":"no");
printk("Execute permission: %s ", prot&PROT_EXEC?"yes":"no");
if (this_vma.vm_file != NULL) {
name = d_path(&this_vma.vm_file->f_path, (char*)__get_free_page(GFP_TEMPORARY), PAGE_SIZE);
printk("-> Mapped file: %s ", name);
}
total_size += this_vma.vm_end - this_vma.vm_start;
if (count != num_vmas-1) { this_vma = *(this_vma.vm_next); }
}
printk(" Total VMA space size (all VMAs): %i ", total_size);
return 1;
}
5. Write a Makefile in the same directory(i.e., stats/) with the following contents:
obj-y:=reportVMAStats.o
This is to ensure that the reportVMAStats.c file is compiled and included in the kernel source code.
Now, we’re all set to link our system call implementation with the existing kernel!
Modifying necessary kernel files to integrate our system call:
1. Add the new ‘stats’ directory to the kernel’s Makefile.
For this, open the kernel's Makefile (found in the linux directory) and look for the following line:
core -y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
And, change it to include stats/.
It should read:
core -y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ stats/
This tells the compiler that the source files of our new system call can be found in the stats/ directory.
Now, we’ll have to alter the syscall_64.tbl.
In kernel 4.7.1, it is present in /arch/x86/entry/syscalls/syscall_64.tbl.
You can look for in your respective kernel version by using find command as:
find -name syscall_64.tbl
Now, edit the file as follows to include the new system call number(in this case 323) and its entry point. Just note the system call number for reference.
323 common reportVMAStats sys_vma_stats
2. Finally, we’ll have to alter the syscalls.h file.
In kernel 4.7.1, it is found in /include/linux/. Add the following line to the end of the file (before the #endif) as shown:
asmlinkage long sys_vma_stats(int pid)
And, we’re done!
Recompile and Reboot:
To integrate the system call and to be able to actually use it, we’ll need to recompile the kernel :
sudo make -j 4 && sudo make modules_install -j 4 && sudo make install -j 4
Once this is done, restart the system.
Testing the system call:
Following are the two test files you need to run this test this system call:
user_test1.c:
#include <linux/unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <stdio.h>
#define __NR_vma_stats 323
int main(int argc, char *argv[])
{
int pid;
printf("Enter a process id: ");
scanf("%d", &pid);
syscall(__NR_vma_stats, pid);
return 0;
}
userTest2.c:
#include <linux/unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <stdio.h>
#include <pthread.h>
#include <linux/kernel.h>
#define __NR_vma_stats 323
pthread_mutex_t mutex_lock;
void * sub_thread( void *arg){
pthread_mutex_lock(&mutex_lock);
syscall(__NR_vma_stats, getpid());
pthread_mutex_unlock(&mutex_lock);
}
int main(int argc, char *argv[]){
int i;
int num_threads = 2;
pthread_mutex_init(&mutex_lock, NULL);
pthread_t thread_mem[num_threads];
for( i = 0; i < num_threads; i++ ){
pthread_create(&(thread_mem[i]), NULL, (void *) sub_thread, NULL);
}
for( i = 0; i < num_threads; i++ ){
if(thread_mem[i] != 0) {
pthread_join(thread_mem[i],NULL);
}
}
return 0;
}
Compile and execute this program. If it runs successfully, then, it should give the corresponding prompt and you can now use ‘dmesg’ to check the kernel log and actually verify if the process information has been logged.
So that's all from my side. Please rate if this solves your query :)
Thanks.
Related Questions
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.