How could I use `kallsyms_lookup_name` function to fix `unknown character` error when loading Linux kernel module? - hook

I'm trying to complete a hooking sample attachment in a program for my uni assignment. The task requires to get a system call sys_rt_sigaction hooked when initiating a loadable module in Linux kernel (I use Ubuntu 18.04 LTS, kernel version is 5.0.0-23-generic). So, the case I'm struggling originates from an error could not insert module <module name>: Unknown symbol in module once I started sudo insmod <my module name>.ko.
After some googling, I see clear this problem arises due to missing sys_call_table export to run inserting as smoothly as well. Following this post, I want to cope that invoking kallsyms_lookup_name call before kicking off init procedure.
There is .c-file which provides with definitions of operations accessible by module (file name is buffer.c):
#define __KERNEL__
#define MODULE
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/syscalls.h>
#include <linux/kallsyms.h>
#include <linux/unistd.h>
void * sys_call_table = (void *) kallsyms_lookup_name("sys_call_table");// some wrongness here, but what exactly?
MODULE_LICENSE("GPL");
int (*real_rt_sigaction)(const char * path); // true syscall prototype
static int __init buffer_init_module(void);
static void __exit buffer_exit_module(void);
static int device_open(struct inode *, struct file *); // driver file opening
static int device_release(struct inode *, struct file *); // return of system resource control
static ssize_t device_read(struct file *, char *, size_t, loff_t *); // reading from driver file
static ssize_t device_write(struct file *, const char *, size_t, loff_t *); // writing into driver file
#define DEVICE_NAME "buffer"
#define BUF_LEN 80
// to be called instead
int alter_rt_sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact, size_t sigsetsize) {
printk(KERN_INFO "Syscall function hooked - you've lost control of your experience");
return 0;
}
static int Major;
static int Device_Open = 0;
static int total_open = 1;
static char Buf[BUF_LEN + 1] = "Buffer is empty, add some input\n";
static char *Msg_ptr;
static int Buf_Char = 50;
static int Bytes_Read = 0;
static struct file_operations fops = {
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release
};
static int __init buffer_init_module(void)
{
printk(KERN_INFO
"Device initializing in progress...");
Major = register_chrdev(0, DEVICE_NAME, &fops);
if(Major < 0) {
printk("Major number hasn't been assigned - Driver registration failed\n");
return Major;
}
printk(KERN_INFO "Registration success - device major number: %d\n", Major);
real_rt_sigaction=sys_call_table[__NR_rt_sigaction];
sys_call_table[__NR_rt_sigaction]=alter_rt_sigaction; // hooking implementation
return 0;
}
static void __exit buffer_exit_module(void)
{
unregister_chrdev(Major, DEVICE_NAME);
printk(KERN_INFO "Outside the module - exit successfully completed\n");
sys_call_table[__NR_rt_sigaction]=real_rt_sigaction; // original call reset
}
static int device_open(struct inode *inode, struct file *file)
{
if(Device_Open)
return -EBUSY;
Device_Open++;
printk(KERN_INFO "Device file has been accessed %d time(s)\n", total_open++);
Msg_ptr = Buf;
try_module_get(THIS_MODULE);
Bytes_Read = 0;
return 0;
}
static int device_release(struct inode * node, struct file * filep)
{
Device_Open--;
module_put(THIS_MODULE);
printk(KERN_INFO "Device file gets close\n");
return 0;
}
static ssize_t device_read(struct file * filep, char * buffer, size_t len, loff_t * offset)
{
int got_read = Bytes_Read;
if(Bytes_Read >= Buf_Char)
return 0;
while(len && (Bytes_Read < Buf_Char)) {
put_user(Msg_ptr[Bytes_Read], buffer+Bytes_Read);
len--;
Bytes_Read++;
}
return Bytes_Read-got_read;
}
static ssize_t device_write(struct file * filep, const char * buffer, size_t len, loff_t * offset)
{
Buf_Char = 0;
if(Buf_Char >= BUF_LEN) {
return 0;
}
while(len && (Buf_Char < BUF_LEN))
{
get_user(Msg_ptr[Buf_Char], buffer+Buf_Char);
len--;
Buf_Char++;
}
return Buf_Char;
}
module_init(buffer_init_module);
module_exit(buffer_exit_module);
Additively, there is code in Makefile:
obj-m += buffer.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
The painful moment here is an error message initializer element is not constant whenever I was trying to build module via sudo make in my project folder. As I follow the beginner's tutorials and need for some basic insight, it might be highly appreciable to see any help with solution or even some ideas how to handle the same problem more effectively, indeed.

Related

Kernel throws error while writing to the character device file in 4.9.82-ti-r102 debian 9.3

I created the device file under /dev folder successfully, but writing to that device file makes kernel to throw following error messages.
kernel:[10090.943733] Internal error: : 1b [#3] PREEMPT SMP ARM
kernel:[10091.049020] Process echo (pid: 3728, stack limit = 0xdc40a218)
kernel:[10091.054880] Stack: (0xdc40be60 to 0xdc40c000)
kernel:[10091.059267] be60: c15491c6 00000022 dc5cb14c bf30430c dc40bedc dc40be88 c075312c c074fe5c
kernel:[10091.067488] be80: c0753018 ffffff04 ffff0a00 c140414c c0d407c8 bf30430c c140414c 40cfbcf3
kernel:[10091.075709] bea0: 00852878 ffffff04 ffff0a00 00040952 c01a7404 c140414c 00852878 00852878
Segmentation fault
I know very basic of Linux Device Drivers
can anyone help me regarding this??
I'm attaching the code for this character device driver
#include<linux/kernel.h>
#include<linux/init.h>
#include<linux/module.h>
#include<linux/fs.h>
#include<linux/uaccess.h>
#include<linux/device.h>
MODULE_AUTHOR("RUCHA");
MODULE_DESCRIPTION("Character Driver First test");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.0.1");
static int MajorNum;
static struct class* RetValOfClassRegistration = NULL;
static struct device* RetVal = NULL;
static char message[1024];
static int openDev(struct inode * , struct file *);
static int closeDev(struct inode * , struct file *);
static ssize_t readDev(struct file *, char *, size_t, loff_t *);
static ssize_t writeDev(struct file *, const char *, size_t, loff_t *);
static struct file_operations FileOps = {
.owner = THIS_MODULE,
.open = openDev,
.read = readDev,
.write = writeDev,
.release = closeDev,
};
static int registerCharDev(void){
return register_chrdev(0,"MyDev",&FileOps);
}
static int __init Loaded(void){
// registering device
MajorNum = registerCharDev();
if(MajorNum < 0){
printk("Can not register device\n");
return -1;
}
printk("Driver Loaded with %d \n",MajorNum);
// registering device class
RetValOfClassRegistration = class_create(THIS_MODULE,"MyCharacterDriver");
if(RetValOfClassRegistration < 0){
printk("can not register class for driver number : %d\n",MajorNum);
return 0;
}
// register the driver
RetVal = device_create(RetValOfClassRegistration,NULL,MKDEV(MajorNum,0),NULL,"MyDev");
return 0;
}
static void __exit Removed(void){
device_destroy(RetValOfClassRegistration,MKDEV(MajorNum,0));
class_unregister(RetValOfClassRegistration);
class_destroy(RetValOfClassRegistration);
unregister_chrdev(MajorNum,"MyDev");
printk("Driver Removed\n");
}
module_init(Loaded);
module_exit(Removed);
static int openDev(struct inode *inodep , struct file *filep){
printk("Device is now open to read write operations\n");
return 0;
}
static int closeDev(struct inode *inodep , struct file *filep){
printk("Device Closed\n");
return 0;
}
static ssize_t readDev(struct file *filep, char *c, size_t v, loff_t *lp){
printk("Read From the device\n");
return 0;
}
static ssize_t writeDev(struct file *file, const char __user *buf, size_t count, loff_t *offset)
{
sprintf(message, "%s(%zu letters)", buf, len);
return 0;
}
and the user input is
echo '1' > /dev/MyDev
You can't access a user data pointer (buf) directly. You need to use copy_from_user to copy the data into kernel memory first. Also, use snprintf instead of sprintf to avoid buffer overflows.
Also, compile with debugging enabled, especially CONFIG_DEBUG_INFO, to get more helpful error messages in the kernel log.

How to get the reference count on Linux driver level?

In the Linux kernel the opened file is indicated by struct file, and the file descriptor table contains a pointers which is point to struct file. f_count is an important member in the struct file. f_count, which means Reference Count. The system call dup() and fork() make other file descriptor point to same struct file.
As shown in the picture (sorry, my reputation is too low, the picture can not be uploaded), fd1 and fd2 point to the struct file, so the Reference Count is equal to 2, thus f_count = 2.
My question is how can i get the value of the f_count by programming.
UPDATE:ok,In order to make myself more clear i will show my code, both the char device driver,Makefile and my application.:D
deviceDriver.c
#include "linux/kernel.h"
#include "linux/module.h"
#include "linux/fs.h"
#include "linux/init.h"
#include "linux/types.h"
#include "linux/errno.h"
#include "linux/uaccess.h"
#include "linux/kdev_t.h"
#define MAX_SIZE 1024
static int my_open(struct inode *inode, struct file *file);
static int my_release(struct inode *inode, struct file *file);
static ssize_t my_read(struct file *file, char __user *user, size_t t, loff_t *f);
static ssize_t my_write(struct file *file, const char __user *user, size_t t, loff_t *f);
static char message[MAX_SIZE] = "-------congratulations--------!";
static int device_num = 0;//device number
static int counter = 0;
static int mutex = 0;
static char* devName = "myDevice";//device name
struct file_operations pStruct =
{ open:my_open, release:my_release, read:my_read, write:my_write, };
/* regist the module */
int init_module()
{
int ret;
/ **/
ret = register_chrdev(0, devName, &pStruct);
if (ret < 0)
{
printk("regist failure!\n");
return -1;
}
else
{
printk("the device has been registered!\n");
device_num = ret;
printk("<1>the virtual device's major number %d.\n", device_num);
printk("<1>Or you can see it by using\n");
printk("<1>------more /proc/devices-------\n");
printk("<1>To talk to the driver,create a dev file with\n");
printk("<1>------'mknod /dev/myDevice c %d 0'-------\n", device_num);
printk("<1>Use \"rmmode\" to remove the module\n");
return 0;
}
}
void cleanup_module()
{
unregister_chrdev(device_num, devName);
printk("unregister it success!\n");
}
static int my_open(struct inode *inode, struct file *file)
{
if(mutex)
return -EBUSY;
mutex = 1;//lock
printk("<1>main device : %d\n", MAJOR(inode->i_rdev));
printk("<1>slave device : %d\n", MINOR(inode->i_rdev));
printk("<1>%d times to call the device\n", ++counter);
try_module_get(THIS_MODULE);
return 0;
}
/* release */
static int my_release(struct inode *inode, struct file *file)
{
printk("Device released!\n");
module_put(THIS_MODULE);
mutex = 0;//unlock
return 0;
}
static ssize_t my_read(struct file *file, char __user *user, size_t t, loff_t *f)
{
if(copy_to_user(user,message,sizeof(message)))
{
return -EFAULT;
}
return sizeof(message);
}
static ssize_t my_write(struct file *file, const char __user *user, size_t t, loff_t *f)
{
if(copy_from_user(message,user,sizeof(message)))
{
return -EFAULT;
}
return sizeof(message);
}
Makefile:
# If KERNELRELEASE is defined, we've been invoked from the
# kernel build system and can use its language.
ifeq ($(KERNELRELEASE),)
# Assume the source tree is where the running kernel was built
# You should set KERNELDIR in the environment if it's elsewhere
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
# The current directory is passed to sub-makes as argument
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
.PHONY: modules modules_install clean
else
# called from kernel build system: just declare what our modules are
obj-m := devDrv.o
endif
application.c:
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#define MAX_SIZE 1024
int main(void)
{
int fd;
char buf[MAX_SIZE];
char get[MAX_SIZE];
char devName[20], dir[50] = "/dev/";
system("ls /dev/");
printf("Please input the device's name you wanna to use :");
gets(devName);
strcat(dir, devName);
fd = open(dir, O_RDWR | O_NONBLOCK);
if (fd != -1)
{
read(fd, buf, sizeof(buf));
printf("The device was inited with a string : %s\n", buf);
/* test fot writing */
printf("Please input a string :\n");
gets(get);
write(fd, get, sizeof(get));
/* test for reading */
read(fd, buf, sizeof(buf));
system("dmesg");
printf("\nThe string in the device now is : %s\n", buf);
close(fd);
return 0;
}
else
{
printf("Device open failed\n");
return -1;
}
}
Any idea to get the struct file's(char device file) f_count? Is it poassible get it by the way of printk?
You should divide reference counter to module from other module and from user-space application. lsmod show how many modules use your module.
sctp 247143 4
libcrc32c 12644 1 sctp
It is impossible load sctp without libcrc32c because sctp use exported function from libcrc32 to calculate control sum for packets.
The reference counter itself is embedded in the module data structure and can be obtained with the function uint module_refcount(struct module* module);
You can use:
printk("Module reference counter: %d\n", (int)module_refcount(THIS_MODULE));
THIS_MODULE it is a reference to current loadable module (for build-in module it is NULL) inside .owner field (inside struct file_operations).
If there is a need manually modify module's counter use:
int try_module_get(struct module* module);
void module_put(struct module* module);
If module unloaded it will return false. You also can move thru all modules. Modules linked via list.
File opening inside kernel it is bad idea. Inside kernel you can get access to inode. Try read man pages for dup and fork. In you system you can investigate lsof tools.

Miscellaneous Device Driver: Unable to open the device with open() system call

I am trying to implement a system call interception for sys_open() call via kernel module and for that I have defined a miscellaneous device driver MyDevice which can be inserted as kernel module. Below is the code for my kernel module:
#include <linux/version.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/highmem.h>
#include <asm/unistd.h>
MODULE_LICENSE("GPL");
// IOCTL commands
#define IOCTL_PATCH_TABLE 0x00000001
#define IOCTL_FIX_TABLE 0x00000004
//Global variables
int in_use = 0; //set to 1 in open handler and reset to zero in release handler
int is_set = 0; // flag to detect system call interception
unsigned long *sys_call_table = (unsigned long*)0xffffffff81801400; //hard coded address of sys_call_table from /boot/System.map
//function pointer to original sys_open
asmlinkage int (*real_open)(const char* __user, int, int);
//Replacement of original call with modified system call
asmlinkage int custom_open(const char* __user file_name, int flags, int mode)
{
printk("interceptor: open(\"%s\", %X, %X)\n", file_name,flags,mode);
return real_open(file_name,flags,mode);
}
/*
Make the memory page writable
This is little risky as directly arch level protection bit is changed
*/
int make_rw(unsigned long address)
{
unsigned int level;
pte_t *pte = lookup_address(address, &level);
if(pte->pte &~ _PAGE_RW)
pte->pte |= _PAGE_RW;
return 0;
}
/* Make the page write protected */
int make_ro(unsigned long address)
{
unsigned int level;
pte_t *pte = lookup_address(address, &level);
pte->pte = pte->pte &~ _PAGE_RW;
return 0;
}
/* This function will be invoked each time a user process attempts
to open my device. You should keep in mind that the prototype
of this function may change along different kernel versions. */
static int my_open(struct inode *inode, struct file *file)
{
/*Do not allow multiple processes to open this device*/
if(in_use)
return -EBUSY;
in_use++;
printk("MyDevice opened\n");
return 0;
}
/* This function, in turn, will be called when a process closes our device */
static int my_release(struct inode *inode, struct file *file)
{
in_use--;
printk("MyDevice closed\n");
return 0;
}
/*This static function handles ioctl calls performed on MyDevice*/
static int my_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int retval = 0;
switch(cmd)
{
case IOCTL_PATCH_TABLE:
make_rw((unsigned long)sys_call_table);
real_open = (void*)*(sys_call_table + __NR_open);
*(sys_call_table + __NR_open) = (unsigned long)custom_open;
make_ro((unsigned long)sys_call_table);
is_set=1;
break;
case IOCTL_FIX_TABLE:
make_rw((unsigned long)sys_call_table);
*(sys_call_table + __NR_open) = (unsigned long)real_open;
make_ro((unsigned long)sys_call_table);
is_set=0;
break;
default:
printk("sys_open not executed\n");
break;
}
return retval;
}
//populate data struct for file operations
static const struct file_operations my_fops = {
.owner = THIS_MODULE,
.open = &my_open,
.release = &my_release,
.unlocked_ioctl = (void*)&my_ioctl,
.compat_ioctl = (void*)&my_ioctl
};
//populate miscdevice data structure
static struct miscdevice my_device = {
MISC_DYNAMIC_MINOR,
"MyDevice",
&my_fops
};
static int __init init_my_module(void)
{
int retval;
printk(KERN_INFO "Inside kernel space\n");
retval = misc_register(&my_device);
return retval;
}
static void __exit cleanup_my_module(void)
{
if (is_set)
{
make_rw((unsigned long)sys_call_table);
*(sys_call_table + __NR_open) = (unsigned long)real_open;
make_ro((unsigned long)sys_call_table);
}
misc_deregister(&my_device);
printk(KERN_INFO "Exiting kernel space\n");
return;
}
module_init(init_my_module);
module_exit(cleanup_my_module);
The code for my test file is as follows:
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
/* Define ioctl commands */
#define IOCTL_PATCH_TABLE 0x00000001
#define IOCTL_FIX_TABLE 0x00000004
int main(void)
{
int device = open("/dev/MyDevice", O_RDWR);
printf("%d\n",device);
ioctl(device, IOCTL_PATCH_TABLE);
sleep(2);
ioctl(device, IOCTL_FIX_TABLE);
close(device);
return 0;
}
The problem is that in my test file open("/dev/MyDevice", O_RDWR); is always returning -1, why is it so ? Where am I going wrong ? I checked with ls -l /dev/MyDevice, MyDevice has been successfully registered with following details: crw------- 1 root root 10, 56 Dec 9 19:33 /dev/MyDevice
Sorry, seriously stupid mistake, that's what happens when rookies do things. I just needed to grant the read and write permissions for my miscellaneous char device driver.
sudo chmod a+r+w /dev/MyDevice

How to test your own Linux module?

Today I am getting started with developing Linux modules. It was rather hard to write, compile and work with Helloworld, but I've done it.
My second module with open, write, read functions is ready, but I really dont know how to test it. Write method just makes printk(). My module is loaded, its name is iamnoob. How to test this write(...) function and to find smth in var/log/syslog?
cat > iamnoob just writes a file to the dir. Same with cp and other.
Sorry for noob question, i've googled, but no answer has been found. Sorry for poor English.
A basic kernel module would normally include registering a character device.
Simple imlementation requires:
Register chrdev region with specific major & minor.
Allocate file operations structure and implement the basic read / write APIs.
Initialize and register character device with the file operations structure to the major / minor region.
See the following code snippet as a template of a module (only read / write APIs are imlemented):
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <asm-generic/uaccess.h>
#define MY_BUFFER_SIZE (1024 * 10)
#define MY_CHRDEV_MAJOR 217
#define MY_CHRDEV_MINOR 0
static struct cdev my_cdev;
static unsigned char *my_buf;
static dev_t my_dev = MKDEV(MY_CHRDEV_MAJOR, MY_CHRDEV_MINOR);
ssize_t my_read(struct file *file, char __user * buf, size_t count, loff_t * ppos)
{
int size;
size = MY_BUFFER_SIZE - 100 - (int)*ppos;
if (size > count)
size = count;
if (copy_to_user(buf, my_buf + *ppos, count))
return -EFAULT;
*ppos += size;
return size;
}
ssize_t my_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
int size;
size = MY_BUFFER_SIZE - 100 - (int)*ppos;
if (size > count)
size = count;
if (copy_from_user(my_buf + *ppos, buf, count))
return -EFAULT;
*ppos += size;
return size;
}
long my_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
printk ("%s!\n", __FUNCTION__);
return 0;
}
int my_mmap(struct file *f, struct vm_area_struct *vma)
{
printk ("%s!\n", __FUNCTION__);
return 0;
}
int my_open(struct inode *i, struct file *f)
{
printk ("%s!\n", __FUNCTION__);
return 0;
}
int my_release(struct inode *i, struct file *f)
{
printk ("%s!\n", __FUNCTION__);
return 0;
}
struct file_operations my_fops =
{
.owner = THIS_MODULE,
.read = &my_read,
.write = &my_write,
.unlocked_ioctl = &my_unlocked_ioctl,
.mmap = &my_mmap,
.open = &my_open,
.release = &my_release,
};
static int __init my_module_init(void)
{
int line = 0;
unsigned char *pos;
printk ("%s!\n", __FUNCTION__);
my_buf = (unsigned char *)kzalloc(MY_BUFFER_SIZE, 0);
if (my_buf == NULL) {
printk("%s - failed to kzallocate buf!\n", __FUNCTION__);
return -1;
}
pos = my_buf;
while (pos - my_buf < MY_BUFFER_SIZE - 100) {
sprintf(pos, "Line #%d\n", line++);
pos += strlen(pos);
}
cdev_init(&my_cdev, &my_fops);
if (register_chrdev_region(my_dev, 1, "my_dev")) {
pr_err("Failed to allocate device number\n");
}
cdev_add(&my_cdev, my_dev, 1);
printk ("%s - registered chrdev\n", __FUNCTION__);
return 0;
}
static void __exit my_module_exit(void)
{
printk ("my_module_exit.\n");
unregister_chrdev_region(my_dev, 1);
return;
}
module_init(my_module_init);
module_exit(my_module_exit);
MODULE_LICENSE("GPL");
This module uses a buffer for file operations, therefore can be tested on any machine, regardless of its HW. Make sure you avoid unnecessary printk's as loops may harm your kernel stability.
Once this is done, in user-space shell you should create a /dev node to represent your character device:
sudo mknod /dev/[dev_name] c [major] [minor]
for example:
sudo mknod /dev/my_dev c 217 0
Then you can test your read / write APIs with:
sudo insmod my_modult.ko
cat /dev/my_dev
less -f /dev/my_dev
sudo su
root> echo "This is a test" > /dev/my_dev
root> exit
cat /dev/my_dev
The shell commands listed above perform read, then login as root (to allow writing to device), write to the char dev, then exit and read again to see the changes.
Now you'd normally implement ioctl and mmap if needed.

Makefile for Linux kernel module?

I was just reading The Linux Kernel Module Programming Guide and and got stuck on character device drivers example.
Makefiles for previous examples were provided, but not for this one, so I'm trying to make one:
obj-m += chardev.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
The output I'm getting is:
maciej#jadwiga:~/Projects/os/chardev$ make
make -C /lib/modules/2.6.26-2-686/build M=/home/maciej/Projects/os/chardev modules
make[1]: Entering directory `/usr/src/linux-headers-2.6.26-2-686'
CC [M] /home/maciej/Projects/os/chardev/chardev.o
/home/maciej/Projects/os/chardev/chardev.c: In function ‘cleanup_module’:
/home/maciej/Projects/os/chardev/chardev.c:72: error: void value not ignored as it ought to be
make[2]: *** [/home/maciej/Projects/os/chardev/chardev.o] Error 1
make[1]: *** [_module_/home/maciej/Projects/os/chardev] Error 2
make[1]: Leaving directory `/usr/src/linux-headers-2.6.26-2-686'
make: *** [all] Error 2
Can anybody help?
The file I want to compile:
/*
* chardev.c: Creates a read-only char device that says how many times
* you've read from the dev file
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h> /* for put_user */
/*
* Prototypes - this would normally go in a .h file
*/
int init_module(void);
void cleanup_module(void);
static int device_open(struct inode *, struct file *);
static int device_release(struct inode *, struct file *);
static ssize_t device_read(struct file *, char *, size_t, loff_t *);
static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
#define SUCCESS 0
#define DEVICE_NAME "chardev" /* Dev name as it appears in /proc/devices */
#define BUF_LEN 80 /* Max length of the message from the device */
/*
* Global variables are declared as static, so are global within the file.
*/
static int Major; /* Major number assigned to our device driver */
static int Device_Open = 0; /* Is device open?
* Used to prevent multiple access to device */
static char msg[BUF_LEN]; /* The msg the device will give when asked */
static char *msg_Ptr;
static struct file_operations fops = {
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release
};
/*
* This function is called when the module is loaded
*/
int init_module(void)
{
Major = register_chrdev(0, DEVICE_NAME, &fops);
if (Major < 0) {
printk(KERN_ALERT "Registering char device failed with %d\n", Major);
return Major;
}
printk(KERN_INFO "I was assigned major number %d. To talk to\n", Major);
printk(KERN_INFO "the driver, create a dev file with\n");
printk(KERN_INFO "'mknod /dev/%s c %d 0'.\n", DEVICE_NAME, Major);
printk(KERN_INFO "Try various minor numbers. Try to cat and echo to\n");
printk(KERN_INFO "the device file.\n");
printk(KERN_INFO "Remove the device file and module when done.\n");
return SUCCESS;
}
/*
* This function is called when the module is unloaded
*/
void cleanup_module(void)
{
/*
* Unregister the device
*/
int ret = unregister_chrdev(Major, DEVICE_NAME);
if (ret < 0)
printk(KERN_ALERT "Error in unregister_chrdev: %d\n", ret);
}
/*
* Methods
*/
/*
* Called when a process tries to open the device file, like
* "cat /dev/mycharfile"
*/
static int device_open(struct inode *inode, struct file *file)
{
static int counter = 0;
if (Device_Open)
return -EBUSY;
Device_Open++;
sprintf(msg, "I already told you %d times Hello world!\n", counter++);
msg_Ptr = msg;
try_module_get(THIS_MODULE);
return SUCCESS;
}
/*
* Called when a process closes the device file.
*/
static int device_release(struct inode *inode, struct file *file)
{
Device_Open--; /* We're now ready for our next caller */
/*
* Decrement the usage count, or else once you opened the file, you'll
* never get get rid of the module.
*/
module_put(THIS_MODULE);
return 0;
}
/*
* Called when a process, which already opened the dev file, attempts to
* read from it.
*/
static ssize_t device_read(struct file *filp, /* see include/linux/fs.h */
char *buffer, /* buffer to fill with data */
size_t length, /* length of the buffer */
loff_t * offset)
{
/*
* Number of bytes actually written to the buffer
*/
int bytes_read = 0;
/*
* If we're at the end of the message,
* return 0 signifying end of file
*/
if (*msg_Ptr == 0)
return 0;
/*
* Actually put the data into the buffer
*/
while (length && *msg_Ptr) {
/*
* The buffer is in the user data segment, not the kernel
* segment so "*" assignment won't work. We have to use
* put_user which copies data from the kernel data segment to
* the user data segment.
*/
put_user(*(msg_Ptr++), buffer++);
length--;
bytes_read++;
}
/*
* Most read functions return the number of bytes put into the buffer
*/
return bytes_read;
}
/*
* Called when a process writes to dev file: echo "hi" > /dev/hello
*/
static ssize_t
device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
{
printk(KERN_ALERT "Sorry, this operation isn't supported.\n");
return -EINVAL;
}
obj-m += chardev.o
actually driver gets loaded by the macro MODULE_INIT(my_init);
here "my_init" can be the user specified function and
MUDULE_EXIT(my_cleanup);
here my_exit can be the user specified function . those two macros are missing in the above code.
Makefile:
the obj-m += chardev.o is to be replaced with obj-m := chardev.o.
I am also a beginner to LLD. If any mistake is there please let me know.
Because the function unregister_chrdev() don't return value. This is a helpful link. http://forum.kernelnewbies.org/read.php?17,1114

Resources