Search code examples
clinux-kernelkernelkernel-module

Signal on Kernel parameter change


I want to use parameter inside a kernel (3.x) module:

static unsigned short param = 0xff;
module_param(param, ushort, S_IRUGO | S_IWUGO);
MODULE_PARM_DESC(param, "a parameter");

Is there any possibility to detect changes on this parameter? Is there a signal which can use to call a service routine?


Here a full code example:

#include <linux/init.h>    
#include <linux/module.h>  
#include <linux/kernel.h>  

MODULE_LICENSE("GPL");     
MODULE_AUTHOR("Alex"); 
MODULE_DESCRIPTION("test module."); 
MODULE_VERSION("0.1");             

static int param = 1;
module_param(param, int, S_IRUGO|S_IWUSR);

static int __init mod_init(void){
   printk(KERN_INFO "param %d\n", param);
   return 0;
}

static void __exit mod_exit(void){
   printk(KERN_INFO "Goodbye!\n");
}

module_init(mod_init);
module_exit(mod_exit);

Now you can find the parameter under /sys/module/<modulename>/parameters and you can change the parameter like this (with root privileges):

echo 2 > /sys/module/ebb/parameters/param

I want to be notified about that change.


next step regarding to @Tsyvarev

#include <linux/init.h>    
#include <linux/module.h>  
#include <linux/kernel.h>  

MODULE_LICENSE("GPL");     
MODULE_AUTHOR("Alex"); 
MODULE_DESCRIPTION("test module."); 
MODULE_VERSION("0.1");  

// int (*set)(const char *val, const struct kernel_param *kp);
// int (*get)(char *buffer, const struct kernel_param *kp);
int my_param_set_ushort(const char *val, const struct kernel_param *kp)
{
    unsigned short* pvalue = kp->arg; // Pointer to actual parameter variable.
    int res = param_set_ushort(val, kp); // Use helper for write variable
    printk(KERN_INFO "setter talks\n");
    if( res==0 )
    {
        // Here you may execute additional actions when you write parameter.
        printk(KERN_INFO "set param %d\n", *pvalue);
    }
    return res;
}

const struct kernel_param_ops my_param_ops_ushort = 
{
    .set = &my_param_set_ushort, // Use our setter ...
    .get = &param_get_ushort, // .. and standard getter
};

unsigned short param = 0xff;
module_param_cb(param,    /*filename*/
    &my_param_ops_ushort, /*operations*/
    &param,               /* pointer to variable, contained parameter's value */
    S_IRUGO | S_IWUSR     /*permissions on file*/
);


static int __init mod_init(void){
   printk(KERN_INFO "param %d\n", param);
   return 0;
}

static void __exit mod_exit(void){
   printk(KERN_INFO "Goodbye! (%d)\n",param);
}

module_init(mod_init);
module_exit(mod_exit);

as root I give this commands:

# insmod par.ko
# echo 146 > /sys/module/par/parameters/param
# rmmod par 

and the kernel log /var/log/kernel.log says:

Jan 23 14:27:37 alex-XMG kernel: [ 8332.492912] param 255
Jan 23 14:27:39 alex-XMG kernel: [ 8334.520044] setter talks
Jan 23 14:27:39 alex-XMG kernel: [ 8334.520052] set param 146
Jan 23 14:27:40 alex-XMG kernel: [ 8335.804338] Goodbye! (146)

Works like a charme!


Solution

  • Generic way for create kernel module parameter is using macro module_param_cb:

    /**
     * module_param_cb - general callback for a module/cmdline parameter
     * @name: a valid C identifier which is the parameter name.
     * @ops: the set & get operations for this parameter.
     * @perm: visibility in sysfs.
     *
     * The ops can have NULL set or get functions.
     */
    #define module_param_cb(name, ops, arg, perm)
    

    Parameter ops is a pointer to structure struct kernel_param_ops, which contains operations for given parameter. Functions called when parameter is written and read have followed definition in this structure:

    int (*set)(const char *val, const struct kernel_param *kp);
    int (*get)(char *buffer, const struct kernel_param *kp);
    

    Here char* parameter is a NULL-terminated string, which is written to/read from the sysfs file, denoted given parameter. And kp is a pointer to parameter descriptor, where the most interested field is .arg: it is a 3rd argument to macro module_param_cb call. Using this field, setter and getter can be implemented per-type of the module parameter, that is having 5 int parameters for module doesn't require to write setters and getters for each of them.

    Moreover, getters and setters for standard parameter types are already implemented, and they are actually used when you call module_param macro. So, if you want to add some functionality for the parameter's setter, you may reuse existed helpers:

    int my_param_set_ushort(const char *val, const struct kernel_param *kp)
    {
        unsigned short* pvalue = kp->arg; // Pointer to actual parameter variable.
        int res = param_set_ushort(val, kp); // Use helper for write variable
        if(!res)
        {
            // Here you may execute additional actions when you write parameter.
            printk(KERN_INFO "set param %d\n", *pvalue);
        }
        return res;
    }
    
    const struct kernel_param_ops my_param_ops_ushort = 
    {
        .set = &my_param_set_ushort,  // Use our setter ...
        .get = &param_get_ushort,     // .. and standard getter
    };
    
    // Usage
    unsigned short param = 0xff;
    module_param_cb(param, /*filename*/
        &my_param_ops_ushort, /*operations*/
        &param, /* pointer to variable, contained parameter's value */
        S_IRUGO | S_IWUSR /*permissions on file*/
    );
    

    Having module parameter's writable by non-priveledged user normally is not good for security reasons. And kernel macros, which create module parameters, check that. That is why you have cryptic error in your module parameter's definition. Note, that in the example above S_IWUSR is used instead of S_IWUGO.