builtins.c: Don't require file open() for chmod/chown

42a9349dc4e98019d27d7f8d19bc6c431695d7e1 modified init's
builtin chmod, chown, and mkdir calls to avoid following
symlinks. This addressed a number of attacks we were seeing
at the time where poorly written init scripts were following
attacker supplied symlinks resulting in rooting vulnerabilities.

To avoid race conditions, the previous implementation only ran
fchown / fchmod on file descriptors opened with open(O_NOFOLLOW).
Unfortunately, unlike the normal "chown" or "chmod" calls, this
requires read or write access to the underlying file. This
isn't ideal, as opening some files may have side effects, or
init may not have permission to open certain files (such as when
SELinux is enabled).

Instead of using open(O_NOFOLLOW) + fchown(), use lchown() instead.
As before, the target of the symlink won't be modified by chown.
This also supports setting the ownership of symlinks.

Instead of using open(O_NOFOLLOW) + fchmod(), use
fchmodat(AT_SYMLINK_NOFOLLOW) instead. As before, the target of the
symlink won't be modified by chmod.

This change will continue to ensure that chown/chmod/mkdir doesn't
follow symlinks, without requiring init to open every file in
read-only or read-write mode.

This change depends on bionic commit I1eba0cdb2c509d9193ceecf28f13118188a3cfa7

Addresses the following mako/occam SELinux denial:

  audit(1422770408.951:6): avc:  denied  { write } for  pid=1 comm="init" name="smd7" dev="tmpfs" ino=7207 scontext=u:r:init:s0 tcontext=u:object_r:radio_device:s0 tclass=chr_file

Change-Id: I14fde956784d65c44e7aa91dd7eea9a004df3081
1 file changed