views:

485

answers:

3

I compiled and ran the chardev.c example from the lkmpg and when writing to the device received an unexpected error:

anon@anon:~/lkmpg$ sudo echo "hi" > /dev/chardev
bash: /dev/chardev: Permission denied

The module write function looks like this:

/*  
 * Called when a process writes to dev file: echo "hi" > /dev/chardev 
 */
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;
}

I'm not getting the expected error of invalid operation and the error printed to /var/log/messages.

I can read from the device with no problem, receiving the expected results:

anon@anon:~/lkmpg$ cat /dev/chardev 
I already told you 6 times Hello world!

The device /dev/chardev is created manually using:

sudo mknod /dev/chardev c 252 0

What's the deal?

--Edit--

Apparently when I mknod to create the device it ends up with the following permissions:

crw-r--r-- 1 root root 252, 0 2009-10-30 09:27 /dev/chardev.

Once I did sudo chmod a+w /dev/chardev the driver worked as expected.

However, people have said it is not correct to do this.

What is the correct course of action and why?

A: 

May be udev is interfering, which results in you getting the "default" error message.

Amit
I don't think it would have anything to do with udev since I create the device path manually with mknod.
Robert S. Barnes
Yep. Agree. It was just a very wild uninformed guess.
Amit
actually, you're original answer regarding permission was correct. Apparently when I `sudo mknod /dev/chardev c 252 0` to create the device it ends up with the following permissions: `crw-r--r-- 1 root root 252, 0 2009-10-30 09:27 /dev/chardev`. Once I did `sudo chmod a+w /dev/chardev` it worked as expected.
Robert S. Barnes
ah! I shudn't have deleted it then. :) So, now you get your custom error message?
Amit
Nooo .. you should not change the permissions for such device entries. They only should be accessible to root uses. Normal user should not have write permissions to such devices. Please refer to my answer for correct solution.
vinit dhatrak
@Vinit Why not? Its just a toy character device :)
Amit
Because this is not how things are done while doing kernel programming. Surely if you are root then you can do anything but there are certain rules you should follow. If you want to learn something, learn it in correct way. Otherwise you may loose these minor details.
vinit dhatrak
@vinit dhatrak: According to your logic, ordinary users should not have access to /dev/modem, /dev/cdrom ? 9/10 times, a character device driver is written in order for ordinary users to access the device. USB gadgets, anyone?
Tim Post
If you check all entries in /dev, you will find that write access is not given to "other". Its given to just root or in some cases specific groups like tty, dialout, cdrom. Normal user will have to be a member of these groups to write to these devices. e.g. when you install a modem, the installer(which runs as root) adds ordinary user to dialout group and give write permissions of modem device to this group. It never gives write permissions to normal user.
vinit dhatrak
I want to clear here that I am not saying its not possible but its just not good practice to give such permissions.
vinit dhatrak
@vinit dhatrak: Yes, _group_ privileges are the way in his case, however you comments and answer does not reflect this.
Tim Post
+3  A: 

I think, actual problem is the command which you issued to write is incorrect. Try

#sudo sh -c "echo "hi" > /dev/chardev"

If you want to run multiple commands with sudo then you should use command as shown above. With this, you dont need to do chmod and change its permissions as well. Hope this helps.

vinit dhatrak
Where are the multiple commands? Its just "echo".
Amit
No, it not just "echo", there is also a shell running to redirect the output of echo. With your command, the /bin/echo program is running as root, because of sudo, but the shell that's redirecting echo's output to the root-only file is still running as you. Your current shell does the redirection before sudo starts.The solution is to run the whole pipeline under sudo.
vinit dhatrak
@vinit: Referring to your answer below, why should these devices only be accessible to root? Aren't there situations where I may want a device that can be written by anyone?
Robert S. Barnes
For security reasons. Please refer to my comment on other answer for further explanation.
vinit dhatrak
And a user space app that needs to open /dev/foo, get a FD and perform an ioctl() can do so using sudo how? Or, someone just hoping to use minicom to access a device attached to a serial port?
Tim Post
@vinit +1: even though it's not the answer I'm looking for it's still a very useful little trick to know. Thanks!
Robert S. Barnes
+3  A: 

A really, really, really straight forward and simple example of how to implement character drivers can be found in drivers/watchdog/softdog.c

You can compare your code to this example, which shows you how to do the following:

  • Read from the device
  • Write to the device
  • Present an ioctl interface via the device

While softdog is a very useful tool, its as much a tutorial as anything else. Alan Cox threw it together, so its a good example of more 'proper' implementation.

If you can post the whole source to your module, we can help you find out why your function is not being entered as expected.

Update:

It is perfectly acceptable to allow under privileged users to write to character devices! I repeat, it is perfectly acceptable to allow under privileged users to write to character devices! If this was not the case, stuff like FUSE, Modems, USB Gadgets, CD ROMS and other things would require root access to use.

What you can do is take advantage of group memberships. I.e., on Ubuntu, users permitted to use FUSE (file system in user space) should belong to the 'fuse' group, which permits granular access on who can and can not use that feature. Similarly, on some of my systems, a QRNG (quantum random number generator) is in use .. and is (you guessed it) a character device. I need to allow PHP to access that device , so I:

  • Create a QRNG group
  • Make sure PHP runs as the user (not anonymous system users)
  • Add users owning apps that need access to the device to the QRNG group

I hope that clears it up :)

Tim Post
The source is at the bottom of the linked page: http://tldp.org/LDP/lkmpg/2.6/html/x569.html
Robert S. Barnes
Exactly what is softdog supposed to do? Cause the system to reboot after a certain amount of time?
Robert S. Barnes
@Robert S Barnes: Once the watchdog device is opened, you will have to write to it every (xx) minutes, or the system reboots itself. You can also write a magic key "W" to it if you want to stop the watchdog from monitoring.
Tim Post