I'm doing some test with a kernel module for change a file open mode of a process from write to readonly with the following code, I take the file descriptor number from lsof -p <pid of process> and compile the module && insmod changefilemode.ko it works on fedora 19, but if Ido it on RedHat 5, the file descriptor is closed.
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/file.h>
#include <linux/fs.h>
struct files_struct *get_files_struct(struct task_struct *task)
{
struct files_struct *files;
task_lock(task);
files = task->files;
if (files)
atomic_inc(&files->count);
task_unlock(task);
return files;
}
MODULE_LICENSE("GPL");
static int __init myinit(){
struct task_struct *tsk;
for_each_process(tsk){
if(tsk->pid == 11923){
struct files_struct *files = get_files_struct(tsk);
task_lock(tsk);
printk("\tpid %d - file mode %d\n",tsk->pid, files->fd_array[6]->f_mode);
files->fd_array[6]->f_mode = FMODE_READ;
printk("\tpid %d - file mode %d\n",tsk->pid, files->fd_array[6]->f_mode);
task_unlock(tsk);
}
}
return 0;
}
static void __exit myexit(){
printk("Good Bye from exit");
}
module_init(myinit);
module_exit(myexit);
Exact PID values are dependent on the exact chronology of process launch during startup.
There is no way to insure the exact chronology of process launch is deterministic across distributions, unless you are carefully tweaking things to your exact needs, and assuming init process is exactly the same.
Also fd number depends on the chronology of open() during process execution.
Related
I need to write a module that creates a file and outputs an inscription with a certain frequency. I implemented it. But when this module is running, at some point the system crashes and no longer turns on.
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/kernel.h>
#include <linux/timer.h>
MODULE_LICENSE("GPL");
#define BUF_LEN 255
#define TEXT "Hello from kernel mod\n"
int g_timer_interval = 10000;
static struct file *i_fp;
struct timer_list g_timer;
loff_t offset = 0;
char buff[BUF_LEN + 1] = TEXT;
void timer_rest(struct timer_list *timer)
{
mod_timer(&g_timer, jiffies + msecs_to_jiffies(g_timer_interval));
i_fp = filp_open("/home/hajol/Test.txt", O_RDWR | O_CREAT, 0644);
kernel_write(i_fp, buff, strlen(buff), &offset);
filp_close(i_fp, NULL);
}
static int __init kernel_init(void)
{
timer_setup(&g_timer, timer_rest, 0);
mod_timer(&g_timer, jiffies + msecs_to_jiffies(g_timer_interval));
return 0;
}
static void __exit kernel_exit(void)
{
pr_info("Ending");
del_timer(&g_timer);
}
module_init(kernel_init);
module_exit(kernel_exit);
When the system crashes, you should get a very detailed error message from the kernel, letting you know where and why this happened (the "oops" message):
Read that error message
Read it again
Understand what it means (this often requires starting over from step 1 a couple of times :-) )
One thing that jumps out at me is that you're not going any error checking on the return value of filp_open. So you could very well be feeding a NULL pointer (or error pointer) into kernel_write.
In the book Operating System Concepts, it designs a kernel module, the module seems to create an additional entry named hello in the /proc file system in Linux, the module code is shown below, then it uses cat /proc/hello command, it says "Each time the /proc/hello file is read, the proc_read() function is called repeatedly until it returns 0", I can't understand why proc_read() is called repeatedly, also I don't know who is the caller of the function proc_read().
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#define BUFFER_SIZE 128
#define PROC_NAME "hello"
ssize_t proc_read(struct file *file, char _user *usr_buf, size_t count, loff_t *pos);
static struct file_operations proc_ops = {
.owner = THIS MODULE,
.read = proc_read,
};
/* This function is called when the module is loaded. */
int proc_init(void)
{
/* creates the /proc/hello entry */
proc_create(PROC_NAME, 0666, NULL, &proc_ops);
return 0;
}
/* This function is called when the module is removed. */
void proc_exit(void)
{
/* removes the /proc/hello entry */
remove_proc_entry(PROC_NAME, NULL);
}
My goal is to implement a system call in linux kernel that enables/disables a CPU core.
First, I implemented a system call that disbales CPU3 in a 4-core system.
The system call code is as follows:
#include <linux/kernel.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
#include <linux/cpumask.h>
asmlinkage long sys_new_syscall(void)
{
unsigned int cpu3 = 3;
set_cpu_online (cpu3, false) ; /* clears the CPU in the cpumask */
printk ("CPU%u is offline\n", cpu3);
return 0;
}
The system call was registered correctly in the kernel and I enabled 'cpu hotplug' feature during kernel configuration ( See picture )
Kernel configuration:
The kernel was build . But when I check the system call using test.c :
#include <stdio.h>
#include <linux/kernel.h>
#include <sys/syscall.h>
#include <unistd.h>
long new_syscall(void)
{
return syscall(394);
}
int main(int argc, char *argv[])
{
long int a = new_syscall();
printf("System call returned %ld\n", a);
return 0;
}
The OS frezzes !
What am I doing wrong ?
why would you want to implement a dedicated syscall? the standard way of offlining cpus is through writes to sysfs. in the extremely unlikely case there is a valid reason to create a dedicated syscall you will have to check how offlining works under the hood and repeat that.
set_cpu_online (cpu3, false) ; /* clears the CPU in the cpumask */
your own comment strongly suggests this is too simplistic. for instance what if the thread executing this is running on said cpu? what about threads which are queued on it?
and so on
This is kind of an old topic, but you can put a CPU up/down in kernel land by using the functions cpu_up(cpu_id) and cpu_down(cpu_id), from include/linux/cpu.h.
It seems that set_cpu_online is not exported since it doesn't seems to be safe from other kernel parts stand point (it doesn't consider process affinity and other complexities, for example).
So, your system call could be written as:
asmlinkage long sys_new_syscall(void)
{
unsigned int cpu3 = 3;
cpu_down(cpu3) ; /* clears the CPU in the cpumask */
printk ("CPU%u is offline\n", cpu3);
return 0;
}
I have an example module using those methods here: https://github.com/pappacena/cpuautoscaling.
I'm trying to learn the IPC UNIX APIs, specifically shared memory. I have created this small program that tries to either access the shared memory segment or create one.
This is what I do:
gcc -Wall -Wextra *.c
# in one terminal
./a.out
# in another
/a.out
The shared.mem file you can see in the source IS present in the same directory from which I launch the executable.
However, it seems like I'm never actually accessing a previously created shared memory segment (error is "No such file or directory"). I always create a new one - as seen via the ipcs command line, even though the IPC key stays the same.
What am I doing wrong ?
Below is the code I used, for reference. It compiles at least on Linux.
#include <signal.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define exit_error(what) exit_error_func(what, __FILE__, __LINE__)
#define SHM_SIZE (64)
#define UNUSED(x) (void)(x)
void *shm_addr = NULL;
void exit_error_func(const char *what, const char *file, int line)
{
fprintf(stderr, "Error in %s at line %d: %s. Reason: %s.\n", file, line, what, strerror(errno));
exit(1);
}
void sigint_handler(int sig)
{
shmdt(shm_addr);
UNUSED(sig);
}
int main(void)
{
key_t ipc_key;
int shm_id;
if ((ipc_key = ftok("shared.mem", 1)) == -1)
exit_error("could not get IPC key");
printf("IPC key is %d\n", ipc_key);
if ((shm_id = shmget(ipc_key, SHM_SIZE, 0600)) == -1)
{
printf("could not get SHM id, trying to create one now\n");
if ((shm_id = shmget(ipc_key, SHM_SIZE, IPC_EXCL | IPC_CREAT | 0600)) == -1)
exit_error("could not create or get shared memory segment");
else
printf("created SHM id\n");
}
else
printf("got already existing SHM id\n");
printf("SHM id is %d\n", shm_id);
if ((shm_addr = shmat(shm_id, NULL, 0)) == (void *)-1)
exit_error("could not attach to segment");
signal(SIGINT, sigint_handler);
if (shmctl(shm_id, IPC_RMID, NULL) == -1)
exit_error("could not flag shared memory for deletion");
printf("SHM flagged for deletion\n");
while (1)
sleep(1);
return (0);
}
It appears that it is not possible to shmget a shared memory segment that is flagged for deletion. Therefore, the shared memory segment must be marked for deletion once no process needs to shmget it anymore.
Disclaimer: I am no UNIX expert. Although the proposed solution works for me, I am still learning and cannot guarantee accuracy of the information given here.
i want to catch information from user defined function using ptrace() calls.
but function address is not stable(because ASLR).
how can i get another program's function information like gdb programmatically?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <dlfcn.h>
#include <errno.h>
void error(char *msg)
{
perror(msg);
exit(-1);
}
int main(int argc, char **argv)
{
long ret = 0;
void *handle;
pid_t pid = 0;
struct user_regs_struct regs;
int *hackme_addr = 0;
pid = atoi(argv[1]);
ret = ptrace(PTRACE_ATTACH, pid, NULL, NULL);
if(ret<0)
{
error("ptrace() error");
}
ret = waitpid(pid, NULL, WUNTRACED);
if(ret<0)
{
error("waitpid ()");
}
ret = ptrace(PTRACE_GETREGS, pid, NULL, ®s);
if(ret<0)
{
error("GETREGS error");
}
printf("EIP : 0x%x\n", (int)regs.eip);
ptrace(PTRACE_DETACH, pid, NULL, NULL);
return 0;
}
ptrace is a bit ugly, but it can be useful.
Here's a ptrace example program; it's used to make I/O-related system calls pause.
http://stromberg.dnsalias.org/~strombrg/slowdown/
You could of course also study gdb, but ISTR it's pretty huge.
You might also check out strace and ltrace, perhaps especially ltrace since it lists symbols.
HTH
You probably want to call a function that resides in a specific executable (probably, a shared object). So, first, you will have to find the base address this executable is mapped on using
/proc/pid/maps
After that, you need to find the local offset of the function you are interested in, and you can do this in two ways:
Understand the ELF file format (Linux native executable format), and searching the desired function using the mapped file (This requires some specialty)
Using a ready to use elfparser (probably readelf tool) to get the function offset under the executable. Note that you will have to figure out the real local offset since this tool usually gives you the address as if the executable was mapped to a specific address