How to copy data from other user address space then current task - c

I have kernel task that create kernel thread ,and I need to copy data to the user which call my kernel task ,from my kernel thread . So I can pass the current task as parameter to my kernel thread.
But how can I tell the copy_from_user function to copy from other process address space.
this my kernel task
asmlinkage int sys_daniel(struct pt_regs *r )
{
struct task_struct *ts1;
ts1 = kthread_run(kthread_func, current, "thread-1");
return 0;
}
and this the kernel thread I am tring to write
static int kthread_func(struct_task args)
{
spcail_copy_to_user(from,to,len,args->mm)
}
there is any way to edit the kernel thread current->mm or to set in the copy_from_user the address space.

ok so you first need to create a page object with the address you want so I used the
struct page *P
get_user_pages(current,current->mm,(unsigned long)buff,1,1,&p,NULL)
so this basically create page that now we can map to the kernel
so we can use
kernlBuff=(char*)kmap(p);//mapping it to the kernel
kunmap(p);//for unmapp it from the kernel

Related

How is thread stack created in C?

Let's say we have the following program:
int main() {
pthread_t tid;
Pthread_create(&tid, NULL, thread, NULL);
Pthread_join(tid, NULL);
... //do some other work
exit(0);
}
void *thread(void *vargp) {
...//do sth
return NULL;
}
Below is a picture that shows the main thread stack:
My question is, after a new thread is created, how does the new thread's own stack look like? does the beginning of the new stack start right after the main thread as:
or the new thread's stack's beginning address can be any random address, therefore leaving "splinters" as:
I know due to virtual address, the virual pages can be anywhere in the physical disk, but I just want to know if the virtual address itself is continuous or not.
This depends on the operating system.
For security reasons, the layout of the virtual address space is randomized in most modern operating systems. This is called Address Space Layout Randomization (ASLR).
Therefore, it is unlikely that the virtual memory reserved for the thread's main stack will be directly adjacent to that of another thread. Even without ASLR, there will probably be at least one guard page (probably more) between the two stacks to detect and protect against a stack overflow.

Implementing kernel level threads in xv6

I am trying to implement kernel level threads in xv6.
My main problem at the moment is to understand how the CPU gets its information about the current process and how to modify it to point to the current thread instead.
I know it is somehow linked to this line:
extern struct proc *proc asm("%gs:4");
in proc.h, but I do not fully understand how and why it works.
I found out %gs points to to the line struct cpu *cpu; in the struct cpu (defined at proc.h), and right below that line (+ 4 bytes after the cpu pointer)
the current process of the cpu is stored:
struct proc *proc; // The currently-running process.
so in order to add thread support one should either alter this line to point to the new thread struct instead of process struct or alternatively, add the thread below the "proc" line and perform the following changes:
add in proc.h the following decleration: extern struct thread *thread asm("%gs:8");
change in vm.c, in fucntion "seginit(void)" the line
c->gdt[SEG_KCPU] = SEG(STA_W, &c->cpu, 8, 0); to c->gdt[SEG_KCPU] = SEG(STA_W, &c->cpu, 12, 0); in order to allocate space for the extra thread pointer.

nonexistant memory in gdb

I'm working on an OS class project with a variant of HOCA system.
I'm trying to create the interrupt handler part of the OS where I/O device interrupts are detected and handled.
(If you have no idea about HOCA, that's fine) My question is really about the internal manipulation of C.
The whole system work like this:
Main function of the OS calls an init() where all the parts are initialized.
After initializing the OS, the root process is created and the first application is schedule()'ed to the specific application. Then the application processes are created and schedule()'ed in a tree structure which rooted from the root process.
void schedule(){
proc_t *front;
front = headQueue(RQ); //return the first available process in the Ready Queue
if (checkPointer(front)) {
intschedule(); // load a timeslice to the OS
LDST(&(front->p_s)); // load the state to the OS
// so that OS can process the application specified by p_s
// LDST() is system function to load a state to processor
}
else {
intdeadlock(); // unlock a process from the blocked list and put in RQ
}
}
Using gdb, I see everything is ok, until it processes right before if(checkPointer(front))
int checkPointer(void *p){
return ((p != (void *) ENULL)&&(p != (void *)NULL));
}
gdb respond:
trap: nonexistant memory address: -1 memory size: 131072 ERROR:
address greater than MEMORYSIZE
what's going wrong with this?
checkPointer() is located in another file.
Your help is much appreciated.

Signal handling in kernel-space

I've written a program that uses SIGALRM and a signal handler.
I'm now trying to add this as a test module within the kernel.
I found that I had to replace a lot of the functions that libc provides with their underlying syscalls..examples being timer_create with sys_timer_create timer_settime with sys_timer_settime and so on.
However, I'm having issues with sigaction.
Compiling the kernel throws the following error
arch/arm/mach-vexpress/cpufreq_test.c:157:2: error: implicit declaration of function 'sys_sigaction' [-Werror=implicit-function-declaration]
I've attached the relevant code block below
int estimate_from_cycles() {
timer_t timer;
struct itimerspec old;
struct sigaction sig_action;
struct sigevent sig_event;
sigset_t sig_mask;
memset(&sig_action, 0, sizeof(struct sigaction));
sig_action.sa_handler = alarm_handler;
sigemptyset(&sig_action.sa_mask);
VERBOSE("Blocking signal %d\n", SIGALRM);
sigemptyset(&sig_mask);
sigaddset(&sig_mask, SIGALRM);
if(sys_sigaction(SIGALRM, &sig_action, NULL)) {
ERROR("Could not assign sigaction\n");
return -1;
}
if (sigprocmask(SIG_SETMASK, &sig_mask, NULL) == -1) {
ERROR("sigprocmask failed\n");
return -1;
}
memset (&sig_event, 0, sizeof (struct sigevent));
sig_event.sigev_notify = SIGEV_SIGNAL;
sig_event.sigev_signo = SIGALRM;
sig_event.sigev_value.sival_ptr = &timer;
if (sys_timer_create(CLOCK_PROCESS_CPUTIME_ID, &sig_event, &timer)) {
ERROR("Could not create timer\n");
return -1;
}
if (sigprocmask(SIG_UNBLOCK, &sig_mask, NULL) == -1) {
ERROR("sigprocmask unblock failed\n");
return -1;
}
cycles = 0;
VERBOSE("Entering main loop\n");
if(sys_timer_settime(timer, 0, &time_period, &old)) {
ERROR("Could not set timer\n");
return -1;
}
while(1) {
ADD(CYCLES_REGISTER, 1);
}
return 0;
}
Is such an approach of taking user-space code and changing the calls alone sufficient to run the code in kernel-space?
Is such an approach of taking user-space code and changing the calls
alone sufficient to run the code in kernel-space?
Of course not! What are you doing is to call the implementation of a system call directly from kernel space, but there is not guarantee that they SYS_function has the same function definition as the system call. The correct approach is to search for the correct kernel routine that does what you need. Unless you are writing a driver or a kernel feature you don't nee to write kernel code. System calls must be only invoked from user space. Their main purpose is to offer a safe manner to access low level mechanisms offered by an operating system such as File System, Socket and so on.
Regarding signals. You had a TERRIBLE idea to try to use signal system calls from kernel space in order to receive a signal. A process sends a signal to another process and signal are meant to be used in user space, so between user space processes. Typically, what happens when you send a signal to another process is that, if the signal is not masked, the receiving process is stopped and the signal handler is executed. Note that in order to achieve this result two switches between user space and kernel space are required.
However, the kernel has its internal tasks which have exactly the same structure of a user space with some differences ( e.g. memory mapping, parent process, etc..). Of course you cannot send a signal from a user process to a kernel thread (imagine what happen if you send a SIGKILL to a crucial component). Since kernel threads have the same structure of user space thread, they can receive signal but its default behaviour is to drop them unless differently specified.
I'd recommend to change you code to try to send a signal from kernel space to user space rather than try to receive one. ( How would you send a signal to kernel space? which pid would you specify?). This may be a good starting point : http://people.ee.ethz.ch/~arkeller/linux/kernel_user_space_howto.html#toc6
You are having problem with sys_sigaction because this is the old definition of the system call. The correct definition should be sys_rt_sigaction.
From the kernel source 3.12 :
#ifdef CONFIG_OLD_SIGACTION
asmlinkage long sys_sigaction(int, const struct old_sigaction __user *,
struct old_sigaction __user *);
#endif
#ifndef CONFIG_ODD_RT_SIGACTION
asmlinkage long sys_rt_sigaction(int,
const struct sigaction __user *,
struct sigaction __user *,
size_t);
#endif
BTW, you should not call any of them, they are meant to be called from user space.
You're working in kernel space so you should start thinking like you're working in kernel space instead of trying to port a userspace hack into the kernel. If you need to call the sys_* family of functions in kernel space, 99.95% of the time, you're already doing something very, very wrong.
Instead of while (1), have it break the loop on a volatile variable and start a thread that simply sleeps and change the value of the variable when it finishes.
I.e.
void some_function(volatile int *condition) {
sleep(x);
*condition = 0;
}
volatile int condition = 1;
start_thread(some_function, &condition);
while(condition) {
ADD(CYCLES_REGISTER, 1);
}
However, what you're doing (I'm assuming you're trying to get the number of cycles the CPU is operating at) is inherently impossible on a preemptive kernel like Linux without a lot of hacking. If you keep interrupts on, your cycle count will be inaccurate since your kernel thread may be switched out at any time. If you turn interrupts off, other threads won't run and your code will just infinite loop and hang the kernel.
Are you sure you can't simply use the BogoMIPs value from the kernel? It is essentially what you're trying to measure but the kernel does it very early in the boot process and does it right.

how to have a child process forked through sys_fork() to have its kernel stack contain the trap frame?

I am working on the implementation of system call sys_fork() on the kernel level. I did the copying of the parent process to the child process as per requirements. The problem is how to copy the child's trapframe (copy of the parent trapframe) onto the child's kernel stack to pass the assertion in mips_usermode()?
I figured out my problem.
But what I am going to say is related to OS161 system. So anyone working on this system, this will be helpful.
Ok, there is a function on the kernel side which deals with context switch. This function stores all the data related to context switch frame onto the threads kernel stack.
So all you need to do is follow the same steps and instead of switch frame structure, you need to replace it with trap frame structure.
Here is the implementation for it:-
vaddr_t stacktop;
struct trapframe *tf;
stacktop = ((vaddr_t)thread->t_stack) + STACK_SIZE; //t_stack is the kernel stack
tf = ((struct trapframe *) stacktop) - 1;
t_stack is just a chunk of memory on the kernel side to store anything related to exceptions or context switch.
Be sure to first clean out the t_stack before you load it with trapframe as it will contain data related to context switch frame incase of sys_fork implementation.
Any corrections or comments on this are welcomed.
I'm working on OS161 too. Here is how I tackle the problem.
In sys_fork, I copy parent's trapframe into a kernel heap space allocated via kmalloc:
struct trapframe* ctf = (struct trapframe*)kmalloc(sizeof(struct trapframe));
*ctf = *tf; // tf points to parent's trapframe;
Then I use thread_fork to create a child thread:
// passing address space using the second parameter of
// child_forkentry, quite dirty
thread_fork(curthread->t_name, child_forkentry, ctf, (unsigned long)as, NULL);
In child_forkentry, which is the first function called by the child, I do the following:
struct trapframe tf; // tf will be allocated on child's kernel stack
tf = *ctf
misp_usermode(&tf);
This will pass the stack check in mips_usermode.

Resources