monadef
monadef

Reputation: 65

Why do some functions in the Linux kernel work differently for string variables and string literals?

In Ubuntu 16.04 kernel version 4.4, the loadable kernel module has the following behavior:

(Use string literal)

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h> 
#include <linux/mount.h>
#include <linux/path.h>
#include <linux/namei.h>
#include <linux/fs.h>

static int __init myinit(void)
{
    char *path_name = "~/microsoft.gpg";
    struct path path;

    printk("Module Init\n");

    if (kern_path(path_name, LOOKUP_FOLLOW, &path) < 0)
    {
        printk("kern_path fail\n");
        return 0;
    }
    printk("kern_path success\n");
    return 0;
}


static void __exit myexit(void)
{
    printk("Module Exit\n");
    return;
}

module_init(myinit); 
module_exit(myexit);

MODULE_LICENSE("GPL");

The result of dmesg is

Module Init

kern_path success

(Use string variable)

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h> 
#include <linux/mount.h>
#include <linux/path.h>
#include <linux/namei.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <asm/segment.h>

#define MAX_PATH_LEN 256

static char path_name[MAX_PATH_LEN];

static struct proc_dir_entry *proc_file;

static int myopen(struct inode *inode, struct file *file)
{
    printk("Module Open\n");
    return 0;
}

static ssize_t mywrite(struct file *file, const char __user *user_buffer, size_t count, loff_t *ppos)
{
    struct path path;
    ssize_t bytes = count < (MAX_PATH_LEN - (*ppos)) ? count : (MAX_PATH_LEN - (*ppos));

    if (copy_from_user(path_name, user_buffer, bytes))
        return -EFAULT;

    path_name[bytes] = '\0';

    printk("Module Write\n");

    if (kern_path(path_name, LOOKUP_FOLLOW, &path) < 0)
    {
        printk("kern_path fail\n");
        (*ppos) += bytes;
        return bytes;
    }
    printk("kern_path success\n");

    (*ppos) += bytes;
    return bytes;
}

static const struct file_operations fops = 
{
    .owner = THIS_MODULE,
    .open = myopen,
    .write = mywrite,
};

static int __init myinit(void)
{
    printk("Module Init\n");
    proc_file = proc_create("mymodule", 0644, NULL, &fops);
    return 0;
}


static void __exit myexit(void)
{
    printk("Module Exit\n");
    remove_proc_entry("mymodule", NULL);
    return;
}

module_init(myinit); 
module_exit(myexit);

MODULE_LICENSE("GPL");

Commands entered in the shell are

echo ~/microsoft.gpg > /proc/mymodule

The result of dmesg is

Module Init

Module Open

Module Write

kern_path fail

I did not have a similar problem when writing user application code, but I am really embarrassed because there is a problem with the kernel module.

Why did the problem appear in the second code? How do I fix it?


Answer completed

Upvotes: 1

Views: 511

Answers (2)

Tsyvarev
Tsyvarev

Reputation: 65898

Mainly used for write into a "kernel file", echo command appends newline symbol at the end of the string (this is explicitly mentioned in the documentation for echo).

Kernel module can easily process this case by discarding the last input symbol if it is newline:

if(path_name[bytes - 1] == '\n')
    path_name[bytes - 1] = '\0';

Upvotes: 1

monadef
monadef

Reputation: 65

In comments, @Tsyvarev gave me the correct answer. The string I pass to echo contains a newline character. I put the -n option and removed it.

Thanks, @Tsyvarev!

Upvotes: 0

Related Questions