Bug in auditing of sys_symlink

Alexander Viro aviro at redhat.com
Tue Dec 31 10:19:52 UTC 2013


On Fri, Dec 27, 2013 at 01:13:32PM +0800, Aaron Lewis wrote:
> Hi,
> 
> Looks like on 2.6.32 kernel there was a bug with sys_symlink,
> 
> I'm trying to monitor all symlinks that points to a specific dir, so I added:
> 
> -a exit,always -F arch=b64 -S symlink -F success=1 -F dir=/secure
> 
> But  "ln -s /secure/file /tmp/file" doesn't trigger alert
> And "cd /secure; ln -s /bin/ls" does.
> 
> So I guess the auditing implementation is somehow incomplete?

No, but your understanding of the symlinks does not match the reality.
Symlink target is a _string_, not a location.  It is resolved every
time you traverse that symlink and result of such resolution depends
upon the state of filesystem(s) at that moment.

In other words, "symlink that points to a specific dir" is not well-defined.
Moreover, consider the following example:

ln -s foo/secure /tmp/bar

Does the resulting symlink satisfy your condition?  No?  It doesn't resolve
to anything, unless /tmp/foo existed already.  Now

ln -s / /tmp/foo

and suddenly /tmp/bar resolves to /tmp/foo/secure, which resolves to /secure.

At which point did an interesting symlink appear in that scenario?  Note also
that mv /tmp/a/b/c/ /tmp/x might very well have turned a symlink somewhere
under /tmp/a/b/c/something/else into one that resolves to /secure - all it
takes is something like  "../../../../../../secure" as target.  Would you
have rename(2) scan the entire directory tree in search of such beasts?
Worse, a symlink to /proc/self/cwd/secure will resolve to different things
for different processes and simple cd / will suffice to turn it into something
that will (for that process) resolve to /secure.

And all of the above can be combined, of course.

So if you need to prevent/catch the appearance of symlinks that will
resolve to something in given directory, you are SOL.  Symlinks simply do
not work that way - the location some symlink resolves to is not a function
of that symlink alone and unless you are seriously proposing to rescan
the entire filesystem upon each rename(2) (and, worse yet, each chdir(2)),
you can not catch the moment when such symlinks appear.

Watching for creation of symlinks with bodies matching .*/secure(/.*|$)
would theoretically be feasible, but it'll yield tons of false positives.
And I seriously doubt that we want to open that can of worms, anyway -
regex matching isn't something you want in the kernel *and* restricting
to e.g. some subtree won't work - offending symlink could've been created
anywhere.  Logging all symlink(2) and filtering out non-interesting target
names in userland is feasible right now, but you'll
	a) get your logs spammed to hell and back (symlink(2) isn't
that rare a syscall) and
	b) even after filtering the rate of false positives (i.e. symlinks
that might eventually resolve to something in /secure, but never will)
will be quite high.

Kernel-side filtering on substrings of symlink(2) target might deal with
(a), but (b) can't be helped at all.




More information about the Linux-audit mailing list