I want to read file from kernel module which contains some parameters
I used the following source code
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/fs.h> // Needed by filp
#include <linux/rbtree.h>
#include <linux/time.h>
#include <linux/atomic.h>
#include <linux/proc_fs.h>
#include <linux/jiffies.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/icmp.h>
#include <linux/inetdevice.h>
#include <linux/if_ether.h>
int init_module(void)
{
// Create variables
struct file *f;
char buf[128];
mm_segment_t fs;
int i;
unsigned long long offset = 0;
// Init the buffer with 0
for(i=0;i<128;i++)
buf[i] = 0;
// To see in /var/log/messages that the module is operating
// I am using Fedora and for the test I have chosen following file
// Obviously it is much smaller than the 128 bytes, but hell with it =)
f = filp_open("/etc/lsb-release", O_RDONLY, 0);
if(f == NULL)
printk(KERN_ALERT "filp_open error!!.\n");
else{
// Get current segment descriptor
fs = get_fs();
// Set segment descriptor associated to kernel space
set_fs(get_ds());
// Read the file
f->f_op->read(f, buf, 128, &f->f_pos);
// Restore segment descriptor
set_fs(fs);
// See what we read from file
printk(KERN_INFO "buf:%s\n",buf);
}
filp_close(f,NULL);
return 0;
}
void cleanup_module(void)
{
printk(KERN_INFO "My module is unloaded\n");
}
But this function crash. I debug it and I found that f->f_op->read is NULL
My kernel version is 4.15 and my ubuntu is 16
What I am missing?
Why f->f_op->read is NULL ?
How to read some parameter from user space in the load of module ? I think better to use file. If so, How to read file in kernel ?
Related
I'm trying to make a custom system call for my OS course following these instructions from the link bellow:
https://uwnthesis.wordpress.com/2016/12/26/basics-of-making-a-rootkit-from-syscall-to-hook/
My kernel's version is 5.3.9.
This is my code so far:
My .c file (located in /usr/srclinux-5.3.9):
#include <linux/syscalls.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/tty.h>
#include <linux/string.h>
#include "pname.h"
asmlinkage long sys_process_name(char* process_name){
/*placeholder to print full string to tty*/
char name[32];
strcpy(name, process_name);
/*tasklist struct to use*/
struct task_struct *task;
/*tty struct*/
struct tty_struct *my_tty;
/*get current tty*/
my_tty = get_current_tty();
/*<sched.h> library method that iterates through list of processes from task_struct defined above*/
for_each_process(task){
printk("Task name: %s.\n",task->comm);
printk("Task ID: %ld.\n",task->pid);
printk("Task for compare: %s.\n", name);
printk("\n");
/*compares the current process name (defined in task->comm) to the passed in name*/
if(strcmp(task->comm, name) == 0){
printk("Process Found!\n");
/*convert to string and put into name[]*/
sprintf(name, "PID = %ld\n", (long)task_pid_nr(task));
/*show result to user that called the syscall*/
(my_tty->driver->ops->write) (my_tty, name, strlen(name)+1);
}
}
return 0;
}
My .h file:
asmlinkage long sys_process_name(char*process_name);
My Makefile:
obj-y := pname.o
I have included this system call to my syscalls_64.tbl and syscalls.h.
After successfully compiled the code above I tried this code to test the syscall testPname.c:
#include <stdio.h>
#include <linux/kernel.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <string.h>
int main(){
char name[32];
puts("Enter process to find");
scanf("%s",name);
strtok(name, "\n");
long int status = syscall(335, name); //syscall number 335 and passing in the string.}
printf("System call returned %ld\n", status);
return 0;
}
But when I put a bunch of printk into the pname.c file and notice that "char* process_name" was never pass from my testPname to the syscall, so the strcmp was never reached. I've tried browsing for a way to pass the parameter to the system call but haven't been able to get there.
I am trying to compile an simple application that uses the read-write hint, here is the code:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdint.h>
static char const filename[] = "./file.txt";
static char const message[] = "/mnt/pool/my_file\n";
int main(void)
{
int fp;
int cnt = 0;
errno = 0;
//uint64_t type = RWH_WRITE_LIFE_MEDIUM; <-- [!] not working
uint64_t type = 3;
fp = open(filename, O_WRONLY | O_CREAT);
if (fp == -1)
return 1;
//fcntl(fp, F_SET_RW_HINT, &type); <-- [!] not working
fcntl(fp, (1024+12), &type);
cnt = write(fp, message, sizeof(message));
if(cnt == -1)
return 1;
close(fp);
return 0;
}
I've found that the RWH_WRITE_LIFE_MEDIUM is defined at include/uapi/linux/fcntl.h, but I do not know what to do to be able to compile with this options.
Any ideas in how can I compile this without error?
EDIT 1:
Ok, I followed the instructions where I included the #include <linux/fcntl.h> and the #define _GNU_SOURCE and now I get this error:
$ gcc open_file_fcntl.c
In file included from /usr/include/fcntl.h:35:0,
from open_file_fcntl.c:7:
/usr/include/x86_64-linux-gnu/bits/fcntl.h:35:8: error: redefinition of ‘struct flock’
struct flock
^~~~~
In file included from /usr/include/x86_64-linux-gnu/asm/fcntl.h:1:0,
from /usr/include/linux/fcntl.h:5,
from open_file_fcntl.c:6:
/usr/include/asm-generic/fcntl.h:196:8: note: originally defined here
struct flock {
^~~~~
I am using kernel 5.0.0-23-generic, and gcc --version 7.4.0.
Also tested on a QEMU environment using kernel 4.14.78, and gcc --version 4.8.4.
The simplest solution is to define the _GNU_SOURCE macro before #include <fcntl.h>. As there may be other interactions, it is better to define it before any #include directives:
open_file_fcntl.c
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdint.h>
static char const filename[] = "./file.txt";
static char const message[] = "/mnt/pool/my_file\n";
int main(void)
{
int fp;
int cnt = 0;
errno = 0;
uint64_t type = RWH_WRITE_LIFE_MEDIUM;
fp = open(filename, O_WRONLY | O_CREAT);
if (fp == -1)
return 1;
fcntl(fp, F_SET_RW_HINT, &type);
cnt = write(fp, message, sizeof(message));
if(cnt == -1)
return 1;
close(fp);
return 0;
}
Alternatively, the #define _GNU_SOURCE can be removed from the source code (open_file_fcntl.c above) and the macro defined on the compiler command line:
$ gcc -D_GNU_SOURCE open_file_fcntl.c
These are Linux-specific flags, so you need to either pass -D_GNU_SOURCE to the compiler or put #define _GNU_SOURCE at the top of your source file.
After following the other answer, I got a different problem, and for that, I could reach the final solution.
By checking both definitions of the struct flock in the above-mentioned locations, there is a #define that can be set at the application layer to avoid the redefinition, which is the #define HAVE_ARCH_STRUCT_FLOCK.
It must be added in between the fcntl.h includes.
Here is the complete code:
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <fcntl.h>
#define HAVE_ARCH_STRUCT_FLOCK
#include <linux/fcntl.h>
static char const filename[] = "./file.txt";
static char const message[] = "/mnt/pool/my_file\n";
int main(void)
{
int fp;
int cnt = 0;
uint64_t type = RWH_WRITE_LIFE_MEDIUM;
fp = open(filename, O_WRONLY | O_CREAT);
if (fp == -1)
return 1;
fcntl(fp, F_SET_RW_HINT, &type);
cnt = write(fp, message, sizeof(message));
if(cnt == -1)
return 1;
close(fp);
return 0;
}
I tried many guides and for some reason, my syscall isn't even returning a 0 as it should. Where am I going wrong? Here are my steps to creating one:
inside "/linux/" folder:
I created a folder called "mycall" with files mycall.c, mycall.h, & Makefile
mycall.c:
#include <linux/kernel.h>
#include <linux/init.h>
#include <sched.h>
#include <syscalls.h>
#include <linux/unistd.h>
#include "mycall.h"
asmlinkage long sys_mysyscall(int *id, int username, int *size)
{
printk("hello");
return 0;
}
mycall.h:
asmlinkage long sys_mysyscall(int *id, int username, int *size);
Makefile:
obj-y := mycall.o
then I went into all of the places where I THOUGHT i should declare the syscall.
// inside of /linux/include/linux/syscalls.h
asmlinkage long sys_mysyscall(int __user *myid, int username, int __user *size);
then to
// inside of /linux/arch/arm/tools/syscall.tbl
398 common mysyscall sys_mysyscall
finally i added
// inside of /linux/Makefile
core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypt/ block/ mycall/
thats my set up. then the final thing I do is make a userspace in /linux directory
userspace.c:
#include <linux/kernel.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <pwd.h>
int main ()
{
int id = 0;
int username = 7;
int size = 2;
int ret_val = syscall(398, &id, username, &size);
printf("%d\n", ret_val);
return 0;
}
the return value is -1 so this doesn't work. please let me know what I'm doing wrong. I have read several implementation guides.
ERRNO is 38 . Function not implemented.
I am trying to map a kernel buffer in user space using mmap method in linux 3.10.10. But it is returning MAP_FAILED. Why it is failed to map the buffer.
Kernel module
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_ALERT */
#include <linux/init.h> /* Needed for the macros */
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <linux/interrupt.h>
#include <linux/io.h>
//#include <linux/malloc.h>
#include <linux/mm.h> /* mmap related stuff */
long long *buf1;
long long* buf;
static int driver_mmap(struct file *file, struct vm_area_struct *vma)
{
vma->vm_flags |= VM_LOCKED|VM_SHARED;
int i = remap_pfn_range(vma, vma->vm_start,
virt_to_phys(buf) >> PAGE_SHIFT,
vma->vm_end-vma->vm_start, vma->vm_page_prot);
SetPageReserved(virt_to_page(buf));
printk("MMAP \n");
return 0;
}
struct file_operations proc_fops =
{
mmap:driver_mmap,
};
int init_module_test(void)
{
int i;
buf1 = kmalloc(4096, __GFP_COLD|GFP_DMA);
buf = ((int)buf1 + PAGE_SIZE -1) & PAGE_MASK;
printk("<1>Hello world1\n");
for (i = 0; i < 512; i++)
{
buf[i] = (long long) i + 1;
}
proc_create ("mmap_example",0,NULL, &proc_fops);
printk("<1>Hello world3\n");
printk("<1>BUF1 = 0x%08x\n BUF = 0x%08x\n", buf1,buf);
return 0;
}
void cleanup_module_test(void)
{
remove_proc_entry ("mmap_example", NULL);
kfree(buf1);
printk("Goodbye world\n");
}
module_init(init_module_test);
module_exit(cleanup_module_test);
Application code
#include<stdio.h>
#include<stdlib.h>
#include<sys/mman.h>
int main(void)
{
int fd, i;
long long *msg = NULL;
if ((fd = fopen("/proc/mmap_example", "r")) < 0)
{
printf("File not opened");
}
msg = mmap(NULL, 4096, PROT_READ, MAP_SHARED, fd, 0);
if (msg == MAP_FAILED)
{
printf("MAP failed");
return 0;
}
for (i = 0; i < 512; i++)
printf("0x%llx,", msg[i]);
fclose(fd);
return 0;
}
I always end up seing "MAP failed".
Is there something wrong with my code?
The first problem is that you are attempting to use fopen to open a file and placing the return value in an integer, but fopen doesn't return an integer. It returns FILE *. This tells me you are ignoring compiler warnings and errors. That's a bad idea: they're produced for a reason.
The second problem is that you actually do need an integer file handle in order to provide it as an argument to mmap(2). For that, you should be calling open(2) (not fopen(3)).
There may well be additional problems with this code, but that's a start.
well, i can't comment so i post an answer that is not one, but i hope it will be still useful:
i'm not sure about the driver, but you can use the errno method (http://man7.org/linux/man-pages/man3/errno.3.html) on mmap to have a better answer on why it's failing:
add in your application code at the right place:
#include <errno.h>
printf("%i",errno);
or you could maybe use the following if you don't want to print the errno :
cpp -dM /usr/include/errno.h | grep 'define E' | sort -n -k 3
from How to know what the 'errno' means?
debugfs can't handle mmap
I know this is not your exact case, but it also makes mmap fail with MAP_FAILED, and it may help future Googlers: https://patchwork.kernel.org/patch/9252557/
And here is a fully working procfs example with an userland test.
I'm trying to write a linux driver. The kernel version is 2.4.18 and the distribution is Red Hat linux 8.0.
The code of my driver is:
#define LINUX
#include <linux/kernel.h> /* We're doing kernel work */
#include <linux/module.h> /* Specifically, a module */
#include <linux/fs.h>
#include <asm-i386/semaphore.h>
#include "rng.h"
#include <linux/random.h>
#include <linux/slab.h>
#define DEVICE_NAME "rng"
#define BUF_LEN 80
static int major;
int init_module();
void cleanup_module();
static int device_open(struct inode *, struct file *);
static int device_release(struct inode *, struct file *);
struct file_operations my_fops = {
open: device_open,
release: device_release,
};
/* Init and Cleanup */
int init_module() {
SET_MODULE_OWNER(&my_fops);
major = register_chrdev(0, DEVICE_NAME, &my_fops);
return 0;
}
void cleanup_module() {
int ret = unregister_chrdev(major, DEVICE_NAME);
if (ret < 0)
printk("Error in unregister_chrdev: %d\n", ret);
}
static int device_open(struct inode *inode, struct file *file) {
file->f_op=&my_fops;
return 1;
}
static int device_release(struct inode *inode, struct file *file) {
return 0;
}
And the code I'm using in order to test my driver is:
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
int openTest() {
int game1 = open("/dev/game1", O_RDONLY); // SEGMENTATION FAULT
int retValue=1;
close(game1);
return retValue;
}
int main() {
int res;
if (openTest() < 1) {
fprintf(stderr, "open didnt work\n");
return -1;
}
fprintf(stderr, "everything works :)\n");
return 0;
}
In the code above, I'm getting a segmentation fault when I'm trying to open the device. Can somebody explain to me why I'm getting this segmentation fault? I really don't understand.
Thanks a lot!
In Linux kernel land, it is convention to return a 0 (zero) when there are no errors. Your device_open() routine is hardcoded to return a 1 (one), which may be causing your segfault.
This Linux Device Drivers book may be helpful to you. The linked edition is written for kernel 2.0.x - 2.4.x, so the information should be appropriate for the dusty and ancient kernel you are using.
This line seems to be wrong file->f_op=&my_fops;
Basically when writing a linux driver operations are setup at build time itself.