On Thu, Apr 09, 2015 at 07:09:06PM -0400, Jude Nelson wrote:
> > Supporting order=... deny=all means you're going to need a very long
> > shell script. It would be much nicer to have a C tool that can be used
> > thus:
> > vdev_allowpid <pid number>
> > echo $?
> > (returns 1 if it should be denied, 0 if it should succeed).
>
> Agreed.
Thanks.
What followed was an explanation of all the complications that result
from trying to do that in shell, without creating a massive number of
new processes.
[snip]
> > If the design is pursued, here's what I might do for mdev, based on the
> > following assumptions:
> > * I assume that only SUBSYSTEM=... can be used as a filter; allowing any
> > variable from the environment to be used requires some rather hideous
> > indirection and calling external tools that quickly cause the system to
> > grind to a halt.
>
> Is there a significant difference in complexity between filtering on
> SUBSYSTEM only, versus filtering on an arbitrary uevent key? I can see why
> someone might want to filter by PCI bus, USB bus, or USB device, for
> example (e.g. give one container a subset of a computer's hardware devices;
> give another container another disjoint subset).
I should clarify one detail here: when you run a hotplugger, rather
than reading a uevent file or a netlink message, the kernel runs the
hotplugger with an environment equivalent to the uevent. Thus,
"variable from the environment" may be treated as interchangeable with
"uevent key".
Assuming that I have to implement it in shell (which is the point of the
example), yes, there's a *very* significant difference between filtering
on a fixed key and filtering on an arbitrary key.
And that's part of the point: I can see why someone might filter by an
arbitrary key, but it's high-overhead for shell.
> > * libudev-compat only needs a unique filename, and uses inotify to check
> > if there's a new one. For the hotplugger, SEQNUM is a guaranteed unique
> > value.
> > * I can check /proc/self/exe directly to determine filename.
> > * The configuration for an executeable is in
> > /etc/libudev-compat/<`basename $exe`>.conf
> > If there is no way to resolve an exe pathname to a single filename, it
> > becomes nearly impossible.
>
>
> This makes it trivial to circumvent vdev_allowpid--if all you're filtering
> on is the basename, then an untrusted user can access any /dev/uevent/$PID
> with any binary by putting it in their $HOME and naming it after a trusted
> binary.
Again, this is a limitation of an efficient shell implementation
.
Also, the default behavior of udev is "allow all processes to access
anything", so there's no way to make a dropin replacement that's
completely interchangeable yet reliably restricts permissions.
> >
> > * /etc/mdev.conf includes this line:
> > $SEQNUM=.* root:root 660 @/lib/mdev/uevent-writer
> > # or the equivalent:
> > $ACTION=add root:root 660 @/lib/mdev/uevent-writer
> >
> > === head of /lib/mdev/uevent-writer ===
> > #!/bin/sh
> > allow_pid() {
> > EXE=`readlink /proc/$1/exe`
> > unset RETURN
> > [ -r /etc/libudev-compat/${EXE##*/}.conf ] || return 0
> >
> > { while read LINE; do
> > case $LINE in
> > (deny=all) RETURN=1 ;;
> > (allow=all) RETURN=0 ;;
> > (allow=*SUBSYSTEM=$SUBSYSTEM*) RETURN=0 ;;
> > (deny=*SUBSYSTEM=$SUBSYSTEM*) RETURN=1 ;;
> > esac
> > done
> > return $RETURN
> > } </etc/libudev-compat/${EXE##*/}.conf
> > return $?
> > }
> >
> > FILENAME=$SEQNUM
> >
> > for pid in /dev/uevent/*
> > do
> > allow_pid ${pid##*/} && env >${pid}/$FILENAME
> > done
> > === tail of /lib/mdev/uevent-writer ===
> I like the idea of using the SEQNUM better than the SHA256. It makes it
> easy for a user to see the order in which events are reported.
I think SEQNUM is only available for hotpluggers.
[snip]
> > > attribute. This, combined with the fact that we'd use runfs on
> > > /dev/uevents to ensure that only $PID directories for running processes
> > are
> > > visible on each readdir() and stat(), should ensure that the only way a
> > > process can get a uevent packet this way is if it is (1) running, and (2)
> > > allowed to receive it according to at least one policy file in
> > > /etc/libudev-compat.
...I see a problem with this approach:
libudev-compat should be a dropin replacement by default.
You can't achieve that and require a new configuration file, unless you
provide a default file containing something like this:
exe=*
allow=all
and then search for narrower matches.
> > > Again, I'd love to hear your thoughts, especially if there is a simpler
> > > approach.
> >
> > for pid in /dev/uevents/*; do
> > EXE=$(readlink /proc/${pid##*/}/exe)
> > done
> >
> > is simpler.
> >
>
> Agreed, but you need to be careful when parsing /proc/$$/exe, since it can
> be suffixed with " (deleted)" if the running binary was unlinked (e.g.
> through a package upgrade).
Then add
EXE=${EXE% (deleted)}
after setting EXE.
It's two lines of shell, or 4-10 lines of C depending how fancy you get;
I don't think a library or tool is called for just to get the name of the
executeable.
Thanks for the warning, though.
> Thanks,
> Jude
Thank you,
Isaac Dunham