I have an exercise about adding a system call in the Linux kernel, but I'm struggling to implement it. Below is the description:
The main part of this assignment is to implement a new system call that lets the user determine the information about current process, the parent and the oldest child process. I manage to do this much but i don't know how to find the the oldest child process.
This is my code:
#include <linux/unistd.h>
#include <linux/linkage.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/sched/signal.h>
struct proc_info {
pid_t pid;
char name[16];
};
struct procinfos {
long studentID;
struct proc_info proc;
struct proc_info parent_proc;
struct proc_info oldest_child_proc;
};
asmlinkage long sys_get_proc_info(pid_t pid, struct procinfos *info){
struct task_struct *task = pid_task ( find_vpid ( pid ) , PIDTYPE_PID);
printk("Finding...\n");
for_each_process(task) {
printk("[%d] ------- [%s]\n", task->pid, task->comm);
if(task->pid == pid) {
struct procinfos buff;
buff.studentID = 1952598;
buff.proc.pid = task->pid;
buff.parent_proc.pid = task->parent->pid;
int res = copy_to_user(info, &buff, sizeof(buff));
if(res == 0) printk("success!");
else printk("fail");
return 0;
//}
}
}
return -1;
}
How to implement this system call? Thanks
Related
There is a possibility that i found a bug in linux kernel. Let's consider application that write to /proc/self/loginuid from main thread and one auxiliary thread. The code is below:
#include <stdio.h>
#include <pthread.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
void write_loginuid(char *str)
{
int fd;
printf("%s\n", str);
fd = open("/proc/self/loginuid", O_RDWR);
if (fd < 0) {
perror(str);
return;
}
if (write(fd, "0", 2) != 2) {
printf("write\n");
perror(str);
}
close(fd);
}
void *thread_function(void *arg)
{
fprintf(stderr, "Hello from thread! my pid = %u, tid = %u, parent pid = %u\n", getpid(), syscall(SYS_gettid), getppid());
write_loginuid("thread");
return NULL;
}
int main()
{
pthread_t thread;
pthread_create(&thread, NULL, thread_function, NULL);
write_loginuid("main process");
fprintf(stderr, "test my pid = %u, tid = %u, parent pid = %u\n", getpid(), syscall(SYS_gettid), getppid());
pthread_join(thread, NULL);
return 0;
}
After executing this application we get:
main process
test my pid = 3487, tid = 3487, parent pid = 3283
Hello from thread! my pid = 3487, tid = 3488, parent pid = 3283
thread
write
thread: Operation not permitted
That tells us the thread write failed by -EPERM.
Looking at the kernel file fs/proc/base.c and function proc_loginuid_write() we see at the beginning check:
static ssize_t proc_loginuid_write(struct file * file, const char __user * buf,
size_t count, loff_t *ppos)
{
struct inode * inode = file_inode(file);
uid_t loginuid;
kuid_t kloginuid;
int rv;
/* this is the probably buggy check */
rcu_read_lock();
if (current != pid_task(proc_pid(inode), PIDTYPE_PID)) {
rcu_read_unlock();
return -EPERM;
}
rcu_read_unlock();
So, looking at the code above we see that only for exact PID (checked by me with printks) we pass through.Thread doesn't satisfy the condition, because compared pids differs.
So my question is: is this a bug ? Why to not allow thread's of particular process to change the loginuid? I encountered this in login application that spawned another thread for PAM login.
Whether this is bug or not i written a fix that extends writing permission to this file by threads:
rcu_read_lock();
/*
* I changed the condition that it checks now the tgid as returned in sys_getpid()
* rather than task_struct pointers
*/
if (task_tgid_vnr(current) != task_tgid_vnr(pid_task(proc_pid(inode), PIDTYPE_PID))) {
rcu_read_unlock();
return -EPERM;
}
rcu_read_unlock();
What do you think about it? Does it affects security?
Good day to all! I am just trying to learn more about parent and child processes in Linux using the fork () function.
I am trying to make a very simple program where after setting up the shared memory segment, i can get a result from a child and output it in the parent .
My problem is it does not seem to work. Here is what i have so far
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/types.h>
#define SZ 20
typedef struct
{
int size;
int cz[SZ];
}shared_data;
shared_data* Collatz(int);
int main (void)
{
pid_t pid;
int seg_id,size=sizeof(shared_data);
seg_id=shmget(IPC_PRIVATE,size,S_IRUSR | S_IWUSR);
shared_data *sd=(shared_data *)shmat(seg_id,NULL, 0);
int usr=-1,count,i;
while(usr<1 ||usr >9)
{
printf("Please Enter a Number between 1-9:");
scanf("%d",&usr);
}
pid=fork();
if(pid<0)
{
printf("Fork Failed");
return 1;
}
if(pid==0)
{
sd=Collatz(usr);
shmdt(sd);
}
else
{
wait(NULL);
printf("\nThe Sequence is: %d ",count);
for(i=0;i<sd->size;i++)
{
printf(" %d ",sd->cz[i]);
}
printf("\n");
}
return 0;
}
shared_data* Collatz(int val)
{
int i=0;
shared_data *data=malloc(sizeof(shared_data));
data->cz[i]=val;
while(val!=1)
{
i++;
if(val%2==0)
val=val/2;
else
val=(3*val)+1;
data->cz[i]=val;
}
data->size=i;
return data;
}
You are assigning to the memory allocated with malloc, not the memory allocated with shmget/shmat. I'm not 100% sure what you intended, but it may be that simply changing the assignment in the child to the following would do the trick. (This will overlay the shared memory with the mallocd content that you initialized in Collatz().)
*sd=Collatz(usr);
[Edit: I should add that your current code sd=Collatz(usr) is instead overwriting the pointer value you got back from the shmat() call rather than the pointed-to memory area.]
I have the following program, when I run the program, I feel really confused that why my program didn't excute
int num=i;
printf("it is No.%d !",num);
printf("hello , I will excute execvp!");
My program basically create 6 child processes to excute executionbode() function, and then use execvp to overload original program. However, everytime when I run the program, the string "hello, I will execute execvp" never shows up! Also I think those three sentences above also didn't execute in the running program? can someone tell me why? Here is my program
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include "makeargv.h"
#include "redirection.h"
#include <sys/wait.h>
int executionnode(int i);
int main(){
pid_t childpid;
int i;
int row=6;
for(i=0;i<row;i++)
{ childpid=fork();
if(childpid==0)
continue;
else if (childpid>0)
executionnode(i);
else {
perror("something wrong");
exit(1);
}
}
}
int executionnode(int i){
sleep(i);
printf("hello, I am process:%ld\n",(long)getpid());
wait(NULL);
char *execArgs[] = { "echo", "Hello, World!", NULL };
int num=i;
printf("it is No.%d !",num);
printf("hello , I will excute execvp!");
execvp("echo", execArgs);
}
Can someone tell me why? and how to fix it? I feel it is really strange? Is it because of execvp() functions? I just began to learn operating system,so I am really confused about it! Thank you for helping me!
As user3629249 said you have some confusion. You'll get many children of children of children... and that wait(NULL) is useless :).
I used this structure to got your goal in my OS subject excercises.
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#define N 5
int main(int argc, char const *argv[])
{
pid_t pid,pids[N];
int i, num_pids = 0;
int state = 0;
int prior[]={1,3,5,2,4};
pid_t parent_pid = getpid();
printf("Parent pid is %i\n",father_pid);
// This for loop is the key
for (i = 0; i < N && getppid() != parent_pid; i++)
{
if ((pid = fork()) < 0)
{
printf ("fork error\n");
exit(-1);
}
pids[num_pids++] = pid;
}
if (pid == 0) // Child processes
{
printf("I am the child %i\n",getpid());
}
else // Parent process
{
for (i = 0; i < N; i++)
{
int pid_index = prior[i]-1; // Array starts with 0
pid = waitpid(pids[pid_index]);
printf("Children %i ended\n",pids[indice_pid]);
printf("%i alive children\n",N-1-i);
}
}
return 0;
}
This structure works because you save the parent's pid in parent_pid variable and compare the parent of each process pid with getppid(). If this pid is different that parent_pid, this proccess is the parent. In another case the process is a child so it has to stop (these processes don't have to fork). With this way you can get only the forks you need.
The rest of the code is the same: Pid==0 is child process and any other is the parent. You can call executionnode(int i) in child processes block (remember, pid==0 !!! you have a mistake). i variable should have the right value in each call I think.
Good luck!
i am running valgrind in a bash script to use it for automated testing. I already added the option to return an exit code on error and to trace children.
/usr/bin/valgrind --error-exitcode=1 --trace-children=yes ./test_prog
My programm forks other processes and I can see the output of valgrind running the different processes in the terminal. The problem is, that the exit code option only seems to work when there is an error in the parent process. Because even though there is an error (SIGSEGV) in one of the child processes the exit code of valgrind is still 0, which means it is useless for the automated testing of several processes.
So is there any option, that would make the parent valgrind catch the error in the child and return it? I already looked into the man page. Maybe there would be another solution to this problem, like grepping the output of the children to the terminal for any error messages?
Thanks in advance.
it's important to implement a proper error handling in the code. Compare following two pieces of code.
A:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <signal.h>
#define BUFSIZE 1024
int incr=0;
int loop=1;
void runTicks(const char *n) {
time_t t;
char buf[BUFSIZE+1];
pid_t pid;
int counter;
pid=getpid();
counter=0;
while(loop) {
sleep(1);
t=time(NULL);
strftime(buf,BUFSIZE,"%Y.%m.%d %H:%M:%S",localtime(&t));
printf("%s[%d] %s\n",n,pid,buf);
counter+=incr;
if(counter>5) memcpy((void *)1,buf,1); /* this line is for causing SEGV */
}
}
void handler(int s) {
if(s==SIGCHLD) {
printf("Received SIGCHLD\n");
loop=0;
}
}
void setHandler() {
struct sigaction sa;
sa.sa_handler=handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags=SA_NOCLDSTOP;
if(sigaction(SIGCHLD,&sa,NULL)!=0) {
printf("Cannot set signal handler, there is no purpose in running the test\n");
exit(0);
}
}
int main() {
pid_t pid;
printf("start\n");
pid=fork();
if(pid==-1) {
printf("fork failed\n");
exit(10);
}
if(pid==0) {
printf("child\n");
incr=1;
usleep(500000);
runTicks("C");
exit(1);
} else {
printf("parent spawned child pid=%d\n",pid);
setHandler();
runTicks("P");
exit(0);
}
}
B:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#define BUFSIZE 1024
int incr=0;
int loop=1;
void runTicks(const char *n) {
time_t t;
char buf[BUFSIZE+1];
pid_t pid;
int counter;
pid=getpid();
counter=0;
while(loop) {
sleep(1);
t=time(NULL);
strftime(buf,BUFSIZE,"%Y.%m.%d %H:%M:%S",localtime(&t));
printf("%s[%d] %s\n",n,pid,buf);
counter+=incr;
if(counter>5) memcpy((void *)1,buf,1); /* this line is for causing SEGV */
}
}
void handler(int s) {
if(s==SIGCHLD) {
int status;
printf("Received SIGCHLD\n");
wait(&status);
printf("Exit code from child: %d\n",status);
if(status!=0) exit(status);
loop=0;
}
}
void setHandler() {
struct sigaction sa;
sa.sa_handler=handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags=SA_NOCLDSTOP;
if(sigaction(SIGCHLD,&sa,NULL)!=0) {
printf("Cannot set signal handler, there is no purpose in running the test\n");
exit(0);
}
}
int main() {
pid_t pid;
printf("start\n");
pid=fork();
if(pid==-1) {
printf("fork failed\n");
exit(10);
}
if(pid==0) {
printf("child\n");
incr=1;
usleep(500000);
runTicks("C");
exit(1);
} else {
printf("parent spawned child pid=%d\n",pid);
setHandler();
runTicks("P");
exit(0);
}
}
Run those first without valgrind and compare the exit code of both programs. Then run them under valgrind and enjoy.
Using such construction you even don't need to run it under valgrind, to catch segfaults from child processes.
I am trying to communicate asynchronously between a kernel driver and a user-space program (I know there are lots of questions here that ask for similar information, but I could find none that deal with sysfs_notify).
I am leaving Vilhelm's edit here, but adding the source to both a simple driver utilizing sysfs and a user-space program to poll it. The driver works fine (I got most of it from the net; it is missing the credits, but I couldn't find them when I went back to add them).
Unfortunately, the polling program does not work. It always returns success immediately. Interestingly, if I don't perform the two reads prior to the poll, the revents members are set to POLLERR | POLLIN instead of just POLLIN as seen in the program output.
Program output:
root#ubuntu:/home/wmulcahy/demo# ./readhello
triggered
Attribute file value: 74 (t) [0]
revents[0]: 00000001
revents[1]: 00000001
Here is the driver: hello.c (you can see where I started out...)
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/slab.h>
struct my_attr {
struct attribute attr;
int value;
};
static struct my_attr notify = {
.attr.name="notify",
.attr.mode = 0644,
.value = 0,
};
static struct my_attr trigger = {
.attr.name="trigger",
.attr.mode = 0644,
.value = 0,
};
static struct attribute * myattr[] = {
¬ify.attr,
&trigger.attr,
NULL
};
static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
{
struct my_attr *a = container_of(attr, struct my_attr, attr);
printk( "hello: show called (%s)\n", a->attr.name );
return scnprintf(buf, PAGE_SIZE, "%s: %d\n", a->attr.name, a->value);
}
static struct kobject *mykobj;
static ssize_t store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t len)
{
struct my_attr *a = container_of(attr, struct my_attr, attr);
sscanf(buf, "%d", &a->value);
notify.value = a->value;
printk("sysfs_notify store %s = %d\n", a->attr.name, a->value);
sysfs_notify(mykobj, NULL, "notify");
return sizeof(int);
}
static struct sysfs_ops myops = {
.show = show,
.store = store,
};
static struct kobj_type mytype = {
.sysfs_ops = &myops,
.default_attrs = myattr,
};
static struct kobject *mykobj;
static int __init hello_module_init(void)
{
int err = -1;
printk("Hello: init\n");
mykobj = kzalloc(sizeof(*mykobj), GFP_KERNEL);
if (mykobj) {
kobject_init(mykobj, &mytype);
if (kobject_add(mykobj, NULL, "%s", "hello")) {
err = -1;
printk("Hello: kobject_add() failed\n");
kobject_put(mykobj);
mykobj = NULL;
}
err = 0;
}
return err;
}
static void __exit hello_module_exit(void)
{
if (mykobj) {
kobject_put(mykobj);
kfree(mykobj);
}
printk("Hello: exit\n");
}
module_init(hello_module_init);
module_exit(hello_module_exit);
MODULE_LICENSE("GPL");
And here is the poll program: readhello.c
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <poll.h>
#define TEST_SYSFS_TRIGGER "/sys/hello/trigger"
#define TEST_SYSFS_NOTIFY "/sys/hello/notify"
int main(int argc, char **argv)
{
int cnt, notifyFd, triggerFd, rv;
char attrData[100];
struct pollfd ufds[2];
// Open a connection to the attribute file.
if ((notifyFd = open(TEST_SYSFS_NOTIFY, O_RDWR)) < 0)
{
perror("Unable to open notify");
exit(1);
}
// Open a connection to the attribute file.
if ((triggerFd = open(TEST_SYSFS_TRIGGER, O_RDWR)) < 0)
{
perror("Unable to open trigger");
exit(1);
}
ufds[0].fd = notifyFd;
ufds[0].events = POLLIN;
ufds[1].fd = triggerFd;
ufds[1].events = POLLIN;
// Someone suggested dummy reads before the poll() call
cnt = read( notifyFd, attrData, 100 );
cnt = read( triggerFd, attrData, 100 );
ufds[0].revents = 0;
ufds[1].revents = 0;
if (( rv = poll( ufds, 2, 10000)) < 0 )
{
perror("poll error");
}
else if (rv == 0)
{
printf("Timeout occurred!\n");
}
else if (ufds[0].revents & POLLIN)
{
printf("triggered\n");
cnt = read( notifyFd, attrData, 1 );
printf( "Attribute file value: %02X (%c) [%d]\n", attrData[0], attrData[0], cnt );
}
printf( "revents[0]: %08X\n", ufds[0].revents );
printf( "revents[1]: %08X\n", ufds[1].revents );
close( triggerFd );
close( notifyFd );
}
Some upcoming sysfs enhancements.
Internally, the patch adds a wait queue head to every kobject on the
system; that queue is inserted into a poll table in response to a
poll() call. The sysfs code has no way of knowing, however, when the
value of any given sysfs attribute has changed, so the subsystem
implementing a pollable attribute must make explicit calls to:
void sysfs_notify(struct kobject *kobj, char *dir, char *attr);
Thanks,
Lee
The blocking poll is from the user side. User code can simply tell the kernel which attributes it's interested in, then block in a poll() until one of them has changed.
The sysfs_notify() is a kernel-side call that releases the user-space poll(). After you adjust your kernel attribute value, just call sysfs_notify() to allow any user-space applications to respond to their outstanding poll().
Think of the poll() as "subscribing" to notices of a change in an attribute of interest, and sysfs_notify() as "publishing" the change to any subscribers.