devfs: default permissions - SOLUTION

Kevin Lentin (kevinl@cs.monash.edu.au)
Fri, 9 Jan 1998 14:22:43 +1100


I have a proposal for solving almost all of the devfs permission problems.
It's got a touch long but I'm trying to forsee the questions. Please read
to the end if you're going to rip it apart :-)

The main complaint we see is that the kernel may choose defaults that a
sysadmin may not like. So I ask, how often does this happen? And the answer
seems to be: once per installation. So I propose the following:

- a .devperms file and a corresponding defdefperms file which work like
.config and defconfig
- a make devperms target which will allow you to edit .devperms (and
a make menudevperms and xdevperms as well).
- the file has the following format:
# driver owner group mode
hd 0 0 0600
lp root lp 0660

etc
- During kernel compile, a script converts this into a suitable devperms.h
file (just like the kernel compile turns .config into autoconf.h). That
process would involve converting username and groupnames into numbers and
creating a set of #defines.

- So we end up with a devperms.h containing something like:

/* hd 0 0 0600 */
#define DEVPERM_hd_owner 0
#define DEVPERM_hd_group 0
#define DEVPERM_hd_mode 0600

/* lp root lp 0660 */
#define DEVPERM_lp_owner 0
#define DEVPERM_lp_group 7
#define DEVPERM_lp_mode 0660

Now, each driver can #include <linux/devperm.h> or whatever and use those
values when it creates devices. And it can be guaranteed that they will be
there as long as appropriate entries are in defdevperms (which they should
be - it becomes one of the things you do when you write a driver).

So, now the quick sell... :-)

We have a few classes of machine out there. There is the single user single
machine. You setup /dev once on such a machine and live with it. You
usually accept the defaults in MAKEDEV. There should be exactly the same
amount of effort to customise devparms that there is to customize /dev. It
should actually be easier to do it via devparms.

The next class of machine is the less hackerish style machine which has a
standard distribution on it with a premade kernel. In this case, the
devparms file on that machine would contain the set of permissions the
distribution makers like. Again, the same, or less work than they would
have to put into customising /dev. And the contents of defdevparms will be
quite sensible, just as the defaults in MAKEDEV are (or should be).

Another class of machine is the network machine sharing a kernel with many
other machines. Your 'real' in-the-field style of machine. Again, they
probably live by a single set of access models. There would be very little
difference between device files on different machines that share a same
kernel.

So, it would seem that a worst case example might require one or two
(literally) chmod's in the startup scripts. Having used SCO Openserver a
lot, I have to deal with this kind of situation anyway. When you recompile
the kernel, it recreates the kernel environment which is SCO-speak for
delete and recreate all /dev/entries. And it uses permissions which are in
the kernel configuration directory. And they are _much_ harder to play with
than the devparms idea I'm proposing.

The only remaining issue is modules...

- Firstly, the devparms stuff works for modules just as much as it works
for in-kernel drivers. The modules would use the same defaults that they
would use if they were compiled in.

- It would be nice if insmod could change the defaults. That would allow
people to configure slightly different machines that share a common
kernel and set of modules. You put the changes in conf.modules instead of
rc.d. The same way they might have to configure a different IRQ or
different sound card or something between machines.

- So I propose that devparm.h contain a few more #defines when modules are
enabled. Something like this:

#define MODULE_DEVPARM(_drv) \
static int dev_owner = DEVPERM_##_drv##_owner; \
MODULE_PARM(dev_owner, "i"); \
static int dev_group = DEVPERM_##_drv##_group; \
MODULE_PARM(dev_group, "i"); \
static int dev_mode = DEVPERM_##_drv##_mode; \
MODULE_PARM(dev_mode, "i")

Then the driver only needs to do:
MODULE_DEVPARM(lp);

And all this gets generated:

static int dev_owner = DEVPERM_lp_owner;
const char __module_parm_dev_owner [] __attribute__((section(".modinfo"))) = "parm_" "dev_owner" "=" "i" ;
static int dev_group = DEVPERM_lp_group;
const char __module_parm_dev_group [] __attribute__((section(".modinfo"))) = "parm_" "dev_group" "=" "i" ;
static int dev_mode = DEVPERM_lp_mode;
const char __module_parm_dev_mode [] __attribute__((section(".modinfo"))) = "parm_" "dev_mode" "=" "i" ;

in addition to the #defines of DEVPERM_lp_* above, of course.

The module init routing then uses dev_owner, dev_group and dev_mode to
register the device and everyone is happy. If nobody does anything, those
will be equal to the defaults from .devparm
If, for some reason, the sysadmin wants to override a default then:
options lp dev_owner=205 dev_mode=666
will work fine, just like io= and irq= do. Same for the actual insmod or
modprobe command lines.

So what do people think? I argue that it is as much effort as setting up an
initial /dev and should almost entirely remove the need for storing /dev
and restoring it at reboot. AND it removes the thing I don't like which
is the need to set up devices at boot time, thus creating entries in a
virtual filesystem that is supposed to do it for you.

-- 
[======================================================================]
[     Kevin Lentin               Email: K.Lentin@cs.monash.edu.au      ]
[   finger kevinl@fangorn.cs.monash.edu.au for PGP public key block.   ]
[  KeyId: 06808EED    FingerPrint: 6024308DE1F84314  811B511DBA6FD596  ]
[======================================================================]