Michael Orlitzky [Fri, 23 Feb 2018 21:11:08 +0000 (16:11 -0500)]
Replace most path usage with file descriptors.
Before this commit, we were passing around paths everywhere to specify
the targets of operations. This is not optimal from a security
standpoint: the best we can do to avoid following hard links is to
check whether or not a given file has more than one name. There is a
race condition inherent in that approach -- between when you stat the
file and when you use it, the number of names may change -- but using
paths makes that window larger than it has to be. There's no guarantee
that a path used at the bottom of apply_default_acl() will refer to
the same file that we called stat() on at the top of the function.
To work around that, most of the path handling functions have been
replaced with versions that use file descriptors. Now we are able to
stat() our file descriptor immediately after opening it, and the
descriptor itself will always refer to the same file. There's still
the smallest of windows for an exploit, but this makes it much safer
to call apply_default_acl() when there may be hard links present.
Michael Orlitzky [Fri, 23 Feb 2018 16:39:07 +0000 (11:39 -0500)]
Remove pointless indirection in acl_entry_count() and acl_is_minimal().
The acl_t type is already a pointer to a structure, so there's no
reason to be passing around pointers to acl_t in acl_entry_count() and
acl_is_minimal(). This commit changes their signatures and call sites.
Michael Orlitzky [Fri, 23 Feb 2018 16:32:31 +0000 (11:32 -0500)]
Have acl_execute_masked() take an acl_t rather than a path as its argument.
We only call acl_execute_masked() in one place; and in that place, the
ACL of the path in question is already available. So, there's no
reason for us to re-retrieve it. Instead, the function has been
updated to take an acl_t (and not a path), simplifing the logic a bit.
Michael Orlitzky [Fri, 23 Feb 2018 16:15:22 +0000 (11:15 -0500)]
Rename inherit_default_acl() to assign_default_acl().
The inherit_default_acl() function was called with two path names, and
the default ACL of the second path was retrieved and applied to the
first path. However, the only situation in which the function was used
was when the default ACL of the parent path was already available -- so
we were wasting time re-retrieving it.
This commit changes the name of the function to assign_default_acl(),
and it now takes an acl_t as its second parameter rather than a
path. The one place it is used now passes it the (already-known)
parent's default ACL rather than that parent's path.
Michael Orlitzky [Thu, 22 Feb 2018 23:00:11 +0000 (18:00 -0500)]
Naively ignore hard links to avoid security mishaps.
If an attacker can introduce a hard link into a directory with a
default ACL, then he may be able to trick the user into applying that
default ACL to the target of the hard link which lives somewhere else
entirely. That can be exploited to gain access to the user's files,
and is hard to detect.
To avoid that problem entirely, great care must be taken. For now, a
naive check of the target path is implemented to ensure that (at the
start of the routine) it has only one name on the filesystem. This
still admits a race condition, but is an improvement.
The new behavior is now documented in the man page, and a test has
been added to ensure that pre-existing hard links are ignored.
There was kind of a big bug in previous versions: symlinks were
followed and they weren't supposed to be. This came down to a few
"stat" calls that should have been "lstat" calls. Those changes have
been made, and there's now a test for the correct behavior.
Unrelated: I capitalized the 'n' in the "No such file..." error.
Michael Orlitzky [Tue, 27 Sep 2016 19:23:33 +0000 (15:23 -0400)]
Print an error if any targets do not exist.
This commit fixes the last known bug, that apply-default-acl can be
called on a file that does not exist and no error is output.
A new function, path_accessible(), was added and it uses the
faccessat() POSIX call to check whether or not the current effective
user/group can access a path. We then call the new path_accessible()
on every target given on the command line. If any do not exist, an
error is printed:
$ ./apply-default-acl derp
./apply-default-acl: derp: no such file or directory
Along with this change comes a version bump to v0.0.5 in configure.ac.
Some minor reorganization was done in configure.ac as well.
Michael Orlitzky [Sat, 26 Jan 2013 01:05:12 +0000 (20:05 -0500)]
Bump configure.ac to version 0.0.4.
Add -Wall -Werror to the automake command line.
Add the test suite to Makefile.am (will generate a `make check` target).
Add the acl_execute_masked() function.
Rename any_can_execute to any_can_execute_or_dir().
Don't mask the execute bit if the target is a directory (more-closely follows setfacl's "X" behavior).
Michael Orlitzky [Tue, 14 Aug 2012 19:16:44 +0000 (15:16 -0400)]
Change all return types to int.
Add the has_minimal_default_acl() function.
Make group bits correct in the presence of minimal ACLs.
Begin fixing group execute with extended ACLs.