0

In our system we use mmap() on the /dev/mem file to access a memory mapped hardware device. However, using this device file requires running the application in superuser mode (sudo) in order to write to the physical device. We are looking for a way to get rid of this limitation.

Supposedly, one can change the access permissions on the device file. However, this is not a recommended solution.

One suggestion we had is, instead of writing a new, full kernel mode device driver for the hardware, we can duplicate the /dev/mem device, changing its write permission, and use mmap() on the new device.

Reading a few manual pages, I found the mknod command. So I used it to create a special file, emem, with similar attributes to the /dev/mem file (esp., the major and Minor versions of the device) . Using the new file in my program, I still needed the duso. So, I changed its attributes to full r/w permissions, but it did not change the need for sudo.

Next, I tried changing the permissions of dev/mem itself to 0777, but it did not help either.

Which leads to the following questions:

  1. Is the need for sudo privilege comes from using mmap() or from the specific devices it maps?

  2. If the former, how to eliminate this?

  3. If the latter, how can I duplicate the /dev/mem functionality, with full permissions?

ysap
  • 7,723
  • 7
  • 59
  • 122
  • 1
    The right way to do this is to either make a kernel stub driver which allows access **only** to the specific resources needed, or to run a userspace daemon as root which proxies requests filtered with the same limitation. – Chris Stratton May 07 '13 at 14:38
  • @ChrisStratton - thanks. In the long term, writing a proper driver is my intention. Right now, due to lack of time (and experience in kernel mode programming), I am looking for a convenient workaround. – ysap May 07 '13 at 17:46
  • Duplicating the device node is pointless, since it would have all of the same issues and consequences as modifying the permissions of the existing node. – Chris Stratton Sep 08 '13 at 14:57

1 Answers1

2

According to http://www.raspberrypi.org/phpBB3/viewtopic.php?f=29&t=22515

To open /dev/mem you need both regular access permissions on the device file and the security capability CAP_SYS_RAWIO, or to be root. There is no getting around this, because full access to memory allows a lot more than just GPIO. It has huge security implications.

This is presumably checked inside the mem device driver.

The solution is to give the users that need to be able to access /dev/mem the CAP_SYS_RAWIO capability, and also put them in the kmem user group (which has read access to the device).

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • Correct: in current kernels, the `open` call on `/dev/mem` is checked with: `return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;`. See `drivers/char/mem.c`. –  May 06 '13 at 19:52
  • Thanks. so, this means that I cannot use `/dev/mem` for this purpose. Then, how can I duplicate the device driver itself, and set it to my needs? – ysap May 06 '13 at 20:16
  • .. wait - according to @duskwuff, if I understand correctly, this protection is assimilated in the driver code itself, right? – ysap May 06 '13 at 20:17
  • You could recompile your kernel with that line modified. But see my updated answer. – Barmar May 06 '13 at 20:20
  • I am not familiar with this `CAP_SYS_*` stuff. How do you grant a user with this capability? Also, you mention the `kmem` group, which has read access to the device. My device requires read and write access. Will this work for writes as well? – ysap May 06 '13 at 20:23
  • Google "linux capabilities". See http://stackoverflow.com/questions/1956732/is-it-possible-to-configure-linux-capabilities-per-user for example – Barmar May 06 '13 at 20:28
  • By default `/dev/mem` only has group read access, you could `chmod g+w /dev/mem`. You could also try using ACLs for more fine-grained access control. – Barmar May 06 '13 at 20:29
  • @Barmar: **THAT WILL NOT WORK.** Regardless of permissions, you cannot open `/dev/mem` unless you are root (or have the `CAP_SYS_RAWIO` capability). Please read the answer you are commenting on! –  May 06 '13 at 21:08
  • @duskwuff That's what I said in my answer: give them the capability AND give them the kmem group. – Barmar May 06 '13 at 21:08
  • I **wrote** the answer I'm commenting on. – Barmar May 06 '13 at 21:09
  • Derp derp derp. Anyways, the only practical way of going about this is to just be root. [CAP_SYS_RAWIO is root-equivalent already](http://lwn.net/Articles/542327/); there's really no point in trying to grant it separately from full root. –  May 06 '13 at 21:11
  • @duskwuff - the reason is that when `sudo`-ing an executable, I seem to be losing some important parts of the environment, specifically `LD_LIBRARY_PATH`, which I need for that executable. – ysap May 06 '13 at 21:13
  • @ysap: That's intentional. `LD_LIBRARY_PATH` is dangerous. If you need it, run: `sudo env LD_LIBRARY_PATH=... myExecutable`. –  May 06 '13 at 21:23
  • @duskwuff - yes, I know it is intentional, but adding that assignment to all executables that use that device is tiresome, and usually requires maintaining "run" scripts. We just want to get rid of that. – ysap May 06 '13 at 21:35
  • @ysap: So put the library on a default search path (e.g, `/usr/local/lib`) so you don't need to override it anymore? –  May 06 '13 at 22:29
  • Yes, that is a possibility, but we prefer to leave it at this place. Anyway, it will not eliminate the need for `sudo`, which is genuinely annoying when you have to do it repeatedly in order to run innocent applications. We just want to get rid of that! – ysap May 06 '13 at 23:18
  • 2
    Allowing LD_LIBRARY_PATH through setuid/sudo is a huge security hole, since it would allow you to replace the standard C library with a version that does whatever you want. You should encapsulate what you need inside programs, and make them setuid. – Barmar May 06 '13 at 23:23