How to create proc entry under /proc/driver? - linux-kernel

I want to create a file under a /proc/driver directory. I would like to use a macro like proc_root_driver (or something else provided) rather than use "driver/MODULE_NAME" explicitly. I use create_proc_entry :
struct proc_dir_entry *simpleproc_fops_entry;
simpleproc_fops_entry = create_proc_entry(MODULE_NAME, 0400, NULL /* proc_root_dir */);
After googling, I found suggestion to use proc_root_driver, but when I use it, I get the error
proc_root_driver undeclared in this function
And also, proc_root_driver is not available in linux/proc_fs.h.
I have tried to declare structure like this:
struct proc_dir_entry proc_root;
struct proc_dir_entry *proc_root_driver = &proc_root;
The compilation errors gone, but the file didn't appear under /proc/driver or /proc. How can I make create an entry in /proc?

Looking at proc_fs.h, proc_root_driver is defined as :
extern struct proc_dir_entry *proc_root_driver;
so long as CONFIG_PROC_FS is enabled. If you have CONFIG_PROC_FS selected when you configure your kernel, you should be able to use it as you suggested yourself i.e. :
#include <linux/proc_fs.h>
struct proc_dir_entry * procfile
procfile = create_proc_entry("myprocfile", 0400, proc_root_driver);
If this does not work, check that you have CONFIG_PROC_FS set. To make sure, you can compile your source file with the -E option and check that the create_proc_entry call includes a non NULL parameter as the last parameter. If it is NULL, or the call is not there at all, then CONFIG_PROC_FS is not enabled.

/* proc entries for ayyaz */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/major.h>
#include <linux/fs.h>
#include <linux/err.h>
#include <linux/ioctl.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#ifdef CONFIG_PROC_FS
/*====================================================================*/
/* Support for /proc/ayyaz */
static struct proc_dir_entry *proc_ayyaz;
DEFINE_MUTEX(ayyaz_table_mutex);
/*====================================================================*/
/* Init code */
static int ayyaz_read_proc (char *page, char **start, off_t off, int count,
int *eof, void *data_unused)
{
int len, l, i;
off_t begin = 0;
mutex_lock(&ayyaz_table_mutex);
len = sprintf(page, "hello ayyaz here\n");
mutex_unlock(&ayyaz_table_mutex);
if (off >= len+begin)
return 0;
*start = page + (off-begin);
return ((count < begin+len-off) ? count : begin+len-off);
}
static int __init init_ayyaz(void)
{
if ((proc_ayyaz = create_proc_entry( "ayyaz_maps", 0, NULL )))
proc_ayyaz->read_proc = ayyaz_read_proc;
return 0;
}
static void __exit cleanup_ayyaz(void)
{
if (proc_ayyaz)
remove_proc_entry( "ayyaz", NULL);
}
module_init(init_ayyaz);
module_exit(cleanup_ayyaz);
#else
#error "Please add CONFIG_PROC_FS=y in your .config "
#endif /* CONFIG_PROC_FS */
MODULE_LICENSE("proprietary");
MODULE_AUTHOR("Md.Ayyaz A Mulla <md.ayyaz#gmail.com>");
MODULE_DESCRIPTION("proc files for ayyaz");
Compile this driver. If it compiles sucessfully, then you will see /proc/ayyaz.

#define PROC_ENTRY_NAME "driver/XX"
static struct proc_dir_entry *proc_XX;
static int XX_read_proc (char *page, char **start, off_t off, int count,
int *eof, void *data_unused)
{
return 0;
}
static int XX_write_proc (struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
return 0;
}
static int __init XX_add_driver(void)
{
if ((proc_flash = XX_entry(PROC_ENTRY_NAME, 0, NULL))) {
proc_XX->read_proc = XX_read_proc;
proc_XX->write_proc = XX_write_proc;
}
...
}
static void __exit XX_remove(void)
{
if (proc_flash)
remove_proc_entry(PROC_ENTRY_NAME, NULL);
return;
}
Then you can find the /proc/driver/XX entry.

Related

How to get the return value of the shell command executed in a linux kernel module?

everyone!
I want to get the return value of the shell command "ls" in a kernel module.
the following is the source code of my kernel module.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kmod.h>
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("yuuyuu");
MODULE_DESCRIPTION("kernel module hello");
MODULE_VERSION("1.0");
static int hello_init(void)
{
char * envp[] = { "HOME=/", NULL };
char * argv[] = { "/bin/ls","/home", NULL };
call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
printk(KERN_ALERT "hello_init() start\n");
return 0;
}
static void hello_exit(void)
{
printk(KERN_ALERT "hello_exit() start\n");
}
module_init(hello_init);
module_exit(hello_exit);
Is there anyone know how to get the output of "ls /home"?
Thanks!

Network hooks hanging the system

I was testing the network hook code given in https://en.wikipedia.org/wiki/Hooking . My kernel version is 3.11.
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <net/ip.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/in.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
/* Port we want to drop packets on */
static const uint16_t port = 25;
/* This is the hook function itself */
static unsigned int hook_func(unsigned int hooknum,
struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *)){
struct iphdr *iph = ip_hdr(*pskb);
struct tcphdr *tcph, tcpbuf;
if (iph->protocol != IPPROTO_TCP)
return NF_ACCEPT;
tcph = skb_header_pointer(*pskb, ip_hdrlen(*pskb), sizeof(*tcph), &tcpbuf);
if (tcph == NULL)
return NF_ACCEPT;
return (tcph->dest == port) ? NF_DROP : NF_ACCEPT;
}
/* Used to register our hook function */
static struct nf_hook_ops nfho = {
.hook = hook_func,
.hooknum = NF_INET_PRE_ROUTING,
.pf = NFPROTO_IPV4,
.priority = NF_IP_PRI_FIRST,
};
static __init int my_init(void)
{
return nf_register_hook(&nfho);
}
static __exit void my_exit(void)
{
nf_unregister_hook(&nfho);
}
module_init(my_init);
module_exit(my_exit);
But after loading , the above code is freezing the system. Can anybody please tell, what is the reason for that?. I think that the above code might have already tested in some lower versions of kernel. So I doubt, some kernel parameters or features have been changed.

register_kretprobe fails with a return value of -2

I have written a kretprobe to hook on to the randomize_stack_top() function mentioned in fs/binfmt_elf.c file. On loading the LKM with insmod the register_kretprobe() call fails with a return value of -2. How do I go about debugging/rectifying that in order to get my module started ?
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kprobes.h>
#include <linux/binfmts.h>
#include <linux/elf.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
#include <asm/current.h>
#include <asm/param.h>
/* Global variables */
int randomize_stack_retval;
// randomize_stack_top() kretprobe specific declarations
static char stack_name[NAME_MAX] = "randomize_stack_top";
static int randomize_stack_top_entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
{
return 0;
}
static int randomize_stack_top_ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
{
randomize_stack_retval = regs_return_value(regs); //store in global variable
printk(KERN_INFO "%d\n",randomize_stack_retval);
return 0;
}
//randomize_stack_top return probe
static struct kretprobe randomize_kretprobe = {
.handler = randomize_stack_top_ret_handler,
.entry_handler = randomize_stack_top_entry_handler,
.maxactive = NR_CPUS,
};
/* Register kretprobe */
static int __init kretprobe_init(void)
{
int ret;
randomize_kretprobe.kp.symbol_name = stack_name;
ret = register_kretprobe(&randomize_kretprobe);
if (ret < 0) {
printk(KERN_INFO "register_kretprobe failed, returned %d\n",
ret);
return -1;
}
printk(KERN_INFO "Planted return probe at %s: %p\n",
randomize_kretprobe.kp.symbol_name, randomize_kretprobe.kp.addr);
return 0;
}
/* Unregister kretprobe */
static void __exit kretprobe_exit(void)
{
unregister_kretprobe(&randomize_kretprobe);
printk(KERN_INFO "kretprobe at %p unregistered\n",
randomize_kretprobe.kp.addr);
// nmissed > 0 suggests that maxactive was set too low.
printk(KERN_INFO "Missed probing %d instances of %s\n",
randomize_kretprobe.nmissed, randomize_kretprobe.kp.symbol_name);
}
module_init(kretprobe_init);
module_exit(kretprobe_exit);
MODULE_LICENSE("GPL");
-2 corresponds to -ENOENT (you can check that in include/uapi/asm-generic/errno-base.h). Probably, it means that kprobe cannot find symbol with given name.
Note, that randomize_stack_top is static function with a short implementation and it is used only once. So it can be inlined by the gcc.

device_create(...) argument 'void * drvdata'

The function
struct device * device_create ( struct class * class,
struct device * parent,
dev_t devt,
void * drvdata,
const char * fmt,
...);
[link to documentation] takes an argument "void * drvdata". It is described as "the data to be added to the device for callbacks". What callbacks exactly are meant here? The file-operation-functions?
SysFS is one example of where this could be useful: whenever userspace communicates with the driver using SysFS (see "Reading/Writing Attribute Data" in the documentation), the kernel calls the corresponding callbacks. The void * drvdata pointer supplied during device_create can then be obtained by calling dev_get_drvdata(dev). The pointer could be used to refer to a structure containing driver's state for example.
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/init.h> /* Needed for the macros */
#include <linux/device.h>
#include <linux/err.h>
MODULE_LICENSE("GPL");
static ssize_t show_period(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t set_period(struct device* dev,
struct device_attribute* attr,
const char* buf,
size_t count);
static DEVICE_ATTR(period, S_IWUSR | S_IRUSR, show_period, set_period);
static struct device *s_pDeviceObject;
static struct class *s_pDeviceClass;
static struct pwm_device_state
{
int m_Period;
} s_DeviceState;
static int __init pwmdriver_init(void)
{
int result;
s_pDeviceClass = class_create(THIS_MODULE, "pwmdriver");
BUG_ON(IS_ERR(s_pDeviceClass));
s_pDeviceObject = device_create(s_pDeviceClass, NULL, 0, &s_DeviceState, "channel");
result = device_create_file(s_pDeviceObject, &dev_attr_period);
BUG_ON(result < 0);
return result;
}
static ssize_t show_period(struct device *dev, struct device_attribute *attr, char *buf)
{
struct pwm_device_state *pwm_device_data;
pwm_device_data = dev_get_drvdata(dev);
return scnprintf(buf, PAGE_SIZE, "%d\n", pwm_device_data->m_Period);
}
static ssize_t set_period(struct device* dev,
struct device_attribute* attr,
const char* buf,
size_t count)
{
long period_value = 0;
struct pwm_device_state *pwm_device_data;
if (kstrtol(buf, 10, &period_value) < 0)
return -EINVAL;
if (period_value < 10) //Safety check
return -EINVAL;
pwm_device_data = dev_get_drvdata(dev);
pwm_device_data->m_Period = period_value;
return count;
}
static void __exit pwmdriver_exit(void)
{
device_remove_file(s_pDeviceObject, &dev_attr_period);
device_destroy(s_pDeviceClass, 0);
class_destroy(s_pDeviceClass);
}
module_init(pwmdriver_init);
module_exit(pwmdriver_exit);

Copy data into buffer to print at stdout

I am writing a linux kernel module that creates a block device which lists the process list.
I am able to display the list in the kernel log file but now I am trying to display the output to stdout. My aim is to create a big string in dev_open() that contains all the processes and then copy that string to the buffer which goes to the dev_read() function.
However, I am trying the following code but I get a message to stdout saying "Killed".
What does this mean ? How can I solve this.
Code ::
#include <linux/module.h>
#include<linux/sched.h>
#include <linux/string.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/proc_fs.h>
#include <linux/kernel.h>
static int dev_open(struct inode *, struct file *);
static int dev_rls(struct inode *, struct file *);
static ssize_t dev_read(struct file *, char *, size_t, loff_t *);
int len,temp;
char msg[1000];
int tem;
static struct file_operations fops =
{
.read = dev_read,
.open = dev_open,
.release = dev_rls,
};
int init_module(void)
{
int t = register_chrdev(81,"tempo",&fops);
if(t<0) printk(KERN_ALERT "Device failed to register!");
else printk(KERN_ALERT "Registered device...\n");
return t;
}
static int dev_open(struct inode *inod, struct file *fil)
{
struct task_struct *task;
for_each_process(task)
{
printk("%s [%d]\n",task->comm, task->pid);
strcat(&msg[0],task->comm);
len=strlen(msg);
temp=len;
tem++;
}
printk("%s [%d]\n",task->comm , task->pid);
return 0;
}
void cleanup_module(void)
{
unregister_chrdev(81,"tempo");
}
static ssize_t dev_read(struct file *filp,char *buf,size_t count,loff_t *offp)
{
printk("Hi\n");
if(count>temp)
{
count=temp;
}
temp=temp-count;
copy_to_user(buf,msg, count);
if(count==0)
temp=len;
return count;
//return 0;
}
static int dev_rls(struct inode *inod, struct file *fil)
{
printk(KERN_ALERT"Done with device\n");
return 0;
}

Resources