Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 01 Nov 2003 17:12:01 -0800
From:      andi payn <andi_payn@speedymail.org>
To:        Terry Lambert <tlambert2@mindspring.com>
Cc:        freebsd-hackers@freebsd.org
Subject:   Re: O_NOACCESS?
Message-ID:  <1067732469.825.487.camel@verdammt.falcotronic.net>
In-Reply-To: <3FA42803.BA6EDF62@mindspring.com>
References:  <1067528798.36829.2128.camel@verdammt.falcotronic.net> <3FA22930.C6EC97A9@mindspring.com> <1067627608.825.56.camel@verdammt.falcotronic.net> <3FA42803.BA6EDF62@mindspring.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Sat, 2003-11-01 at 13:39, Terry Lambert wrote:
> andi payn wrote:
> > Now hold on. The standard (by which I you mean POSIX? or one of the UNIX
[...]
> A strictly conforming implementation can not expose things into
> the namespace that are not defined by the standard to be in the
> namespace, when a manifest constant specifying a conformance level
> is in scope.

Yes. As I mentioned at the beginning, you don't get O_NOACCESS in linux
by pulling in the standard headers, and I wasn't suggesting anything
different.

[...]
> Not just"not portable", but "fails to conform to standards".

Note that the Single UNIX Specification says that open _may_ fail with
EINVAL if the value of the oflag argument does not contain exactly one
of the three access modes. So, if you've written code (for some reason)
that expects that it _must_ fail in such a situation, that's
non-comforming code.

> > If O_NOACCESS happens to be == O_ACCMODE on FreeBSD--just as it is on
> > linux--and if that happens to also be == O_WRONLY | O_RDWR (with no
> > other flags set), I don't see how that changes anything.
> 
> Other than the security issues it raises, you mean, right?

Are you saying that having O_NOACCESS == O_ACCMODE raises security
issues beyond any raised by having O_NOACCESS at all?

Or is it the fact that it would the same value as in linux, so linux
code (whether recompiled for FreeBSD or run under ABI compatibility)
that expected to be able to open a file without getting read or write
access would be able to do so? Again, I don't see how this raises
security issues beyond whatever may be inherent in O_NOACCESS, if any.

Or are you just getting ahead of yourself?

> You nead to look at the implementation of VOP_OPEN in FreeBSD;
> specifically, you need to look at the fact that fp->f_flags is
> passed as one of its parameters, and that the FS is permitted
> to interpret these flags in an FS-dependent fashion.

Which version are you looking at? In 5.1, what gets passed if fmode,
which is ultimately the result of applying FFLAGS to the original flags
passed to open. 

As for the FS being permitted to interpret these flags in an
FS-dependent fashion: I'm pretty sure that a FS that interpreted FREAD
to mean write permission, or O_APPEND to mean truncate, would not be
considered good.

Any FS that assumes that it can read if FREAD is set, and it can write
if FWRITE is set, will work correctly when neither is set. And any
filesystem that doesn't work this way is already broken.

However, there may be some FS's with more subtle issues. For example, an
FS might assume that if it doesn't have FWRITE, it must have FREAD. This
is (probably) not guaranteed anywhere--but it is currently true, a fact
which is logically deducible from the values of the flags, the way
FFLAGS works, and the fact that O_ACCMODE returns EINVAL. If this ceases
to be true, such an FS might do things wrong.

I'd have no problem with providing for each filesystem to specify "I can
handle no-access opens," and for any FS that doesn't do so, the kernel
would return EINVAL before even talking to the FS (thus preserving
current behavior); only if the FS does so could it ever get an fmode
with neither FREAD nor FWRITE set.

[...]
> Really, it needs to be a bitmap internally in FreeBSD, as well,
> but that's a big step.

By "it needs to be a bitmap internally," you mean that fmode needs to be
a bitmap? Well, then, good news: It already is. In fact, I think the
equivalent parameter has been a bitmap for every *BSD and going back
into AT&T Unix.

Currently FFLAGS() is a macro that adds 1. Now, look at the original
flags. The low two bits are the O_ACCMODE mask. This part is not a
bitmap (O_RDONLY == 0, O_WRONLY == 1, and O_RDWR == 2). But once you add
1, the result is (FREAD == 1, FWRITE == 2, FREAD|FWRITE == 3 == 1|2).

The flags value with O_ACCMODE masked out is already a bitmap (not just
in FreeBSD; it's even defined to be one in the Single Unix Standard).
Adding 1 to flags could only change any of these bits if the two low
bits were both 1. But this is not possible, since we've already checked
that (flags & O_ACCMODE) != O_ACCMODE. Therefore, fmode is a bitmap.
QED.

Now, what I'm proposing would allow the low two bits to be 11, which
FFLAGS would map to 00 (as it does in linux). While adding 1 does this,
it would also affect the higher bits (O_NOACCESS | O_NOBLOCK + 1 is not
0 | O_NOBLOCK, it's 0 | O_APPEND). Therefore, a slightly more
complicated FFLAGS is needed if we want fmode to remain a bitmap. (The
alternative--the way linux does this--is to pass along both flags and
fflags, and using fflags only for the low two bits, which is ugly and
messy. I'd much prefer a slightly more complicated FFLAGS.)

> > Second, any platform that defines O_NOACCESS could do so differently. On
> > FreeBSD, as on linux, the most sensible definition is O_NOACCESS ==
> > O_WRONLY | O_RDWR == 3. Or a platform that defined O_RDONLY as 1 and
> > O_WRONLY as 2, the most sensible definition would be O_NOACCESS == 0.
> 
> I pray this flag never gets adopted outside of Linux...

Is this just a non-sequitur, or are you praying that it never gets
adopted because it could have different definitions or different
systems? 

In the same way that O_RDONLY can be 0 or 1 on two different platforms,
O_NOACCESS could be 3 or 0 on two different platforms. That seems like a
good thing, not a bad thing.

[...]
> Or deal with issues of privilege granted merely by open.  For
> example, on FreeBSD, an implementation of this would permit any
> normal user to do INB/OUTB to any I/O port on any hardare on the
> machine.
> 
> This is a can of worms.

You mean by opening /dev/io? There's already a thread about that. The
manpage says that "In addition to any file access permissions on
/dev/io, the kernel enforces that only the super-user may open this
device." 

Unfortunately, the kernel appears to not enforce any such thing.

That's the can of worms. Either the kernel needs to enforce it, or the
manpage needs to stop saying that it does.

Meanwhile, the manpage says that "even read-only access will grant the
full I/O privileges." I'd say that /dev/io should be changed to not
allow the privileges if neither FREAD or FWRITE is set (which would
require no change to the manpage, or to existing apps, and would open no
new security issues)--whichever way the other issue is fixed.

> > > Of course, allowing this on directories for which you
> > > are normally denied read/write permissions would be a neat way to
> > > escape from chroot'ed environments and compromise a host system...
> > 
> > How would it allow that? If you can open files outside your chroot
> > environment--even files you would otherwise have read access to--it's
> > not much of a chroot!
> 
> Mounted procfs within a chrooted environment.  Admittedly, FreeBSD
> is moving away from procfs, but on Linux, it's a serious issue,
> since such basic utilities as "ps" and so on won't work without it.

So, being able to open a file and then fchdir to it would provide you
with... exactly the same exploit that you can already get by chdir'd to
it. There's no new security issue here.

> > Actually, you'd be surprised at how much has been explicitly added to
> > the kernel (and, more, to the filesystem code, especially reiser) for
> > lilo's benefit.
> 
> I wouldn't.  I think it's "too much", and I'd hate to drag the same
> cruft into FreeBSD for the same reasons.

I agree completely. 

However, I don't think that adding O_NOACCESS is the same thing as
dragging in dozens of device-specific and fs-specific ioctl's and two
special flags values (if the flags == -1 or -2, it's no longer a
bitfield and instead has a special meaning), etc.

As opposed to those examples, NOACCESS is a single change, at a high
level, with an obvious meaning, with fully general semantics that are
the same on any fs/device that supports it.

(In fact, I suspect that one of the special flags values was added
because one of the lilo developers didn't know about NOACCESS, so
instead of opening a device file NOACCESS to call an ioctl, he got new
code added into the kernel to allow him to use a special value with open
to pass through ioctl's to the parent device....)

> One option for you would be to make this a kernel module... then it
> could be of use to the people who need it, while not bothering the
> rest of the world.

That's not a bad idea! The kernel itself would still have to be changed
to work through this module (when present), but it should be much easier
in that case to verify that the default behavior (without the module) is
identical to current behavior, than if the change were implemented
directly in the kernel.

Also, combining this with the idea of an fs being able to report whether
or not it can handle O_NOACCESS: You should be able to disable this
support for an fs at compile time or (for FS's which are in modules) at
load time. That should be trivial to add.

It might also be worth providing a mount option to disable it at mount
time even when it is compiled in and enabled at load time (so I could
have it on, say, /mnt/linux/usr, but not /mnt/linux, or on /usr but not
/, or whatever).




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?1067732469.825.487.camel>