Bug 127532

Summary: [patch] install(1): install -S Not Safe in Jail with security.jail.chflags_allowed: 0
Product: Base System Reporter: Jason C. Wells <jcw>
Component: binAssignee: freebsd-bugs (Nobody) <bugs>
Status: Open ---    
Severity: Affects Only Me    
Priority: Normal    
Version: 6.2-RELEASE   
Hardware: Any   
OS: Any   
Attachments:
Description Flags
xinstall-unsafe--S.diff
none
install-S-safe.patch none

Description Jason C. Wells 2008-09-22 04:00:12 UTC
The install command deleted libc when it should not have.  Running the
install command with '-fschg -S' deletes the install target when
security.jail.chflags_allowed=0 inside a jail.  I observed this during
installworld.  The problem can be avoided by setting
security.jail.chflags_allowed=1 before running make installworld.

How-To-Repeat: (outside the jail)
~$ chflags noschg /usr/jails/cr/lib/libc.so.6

(inside the jail)
[root@s4cr /usr/src/lib/libc]# ls -lao /lib/libc.so.6
-rwxr-xr-x  1 root  wheel  - 981331 Sep 21 15:57 /lib/libc.so.6

[root@s4cr /usr/src/lib/libc]# sysctl -a | grep secur
kern.securelevel: -1
security.jail.chflags_allowed: 0

[root@s4cr /usr/src/lib/libc]#   make install
install -C -o root -g wheel -m 444   libc.a /usr/lib
install -C -o root -g wheel -m 444   libc_p.a /usr/lib
install -s -o root -g wheel -m 444   -fschg -S  libc.so.6 /lib
install: /lib/libc.so.6: chflags: Operation not permitted
*** Error code 71

Stop in /usr/src/lib/libc.

[root@s4cr /usr/src/lib/libc]# ls -lao /lib/libc.so.6
/libexec/ld-elf.so.1: Shared object "libc.so.6" not found, required by "ls"
[root@s4cr /usr/src/lib/libc]#
Comment 1 Jaakko Heinonen 2008-09-29 15:39:53 UTC
On 2008-09-22, Jason C. Wells wrote:
> The install command deleted libc when it should not have.  Running the
> install command with '-fschg -S' deletes the install target when
> security.jail.chflags_allowed=0 inside a jail.  I observed this during
> installworld.  The problem can be avoided by setting
> security.jail.chflags_allowed=1 before running make installworld.

This is a bug in install(1). Here's a stripped down way to reproduce it:

(in a jail)

# sysctl security.jail.jailed security.jail.chflags_allowed
security.jail.jailed: 1
security.jail.chflags_allowed: 0
# touch target
# ls -lo target
-rw-r--r--  1 root  wheel  - 0 Sep 29 09:54 target
# install -fschg -S /bin/cat target
install: target: chflags: Operation not permitted
# ls -lo target
ls: target: No such file or directory

The problem is that install(1) unlinks the target file if fchflags(2)
fails. This is not good especially with -S which is supposed to be safe.
There are also three more unsafe unlink(2) calls in install() function.
fstat(2) and fchown(2) and fchmod(2) are performed for the file after
rename. Failure on those calls causes the target to be unlinked. This is
how to reproduce the fchown(2) problem without jail:

(use a non-root user)

$ touch target
$ ls target
target
$ install -S -o root /bin/cat target
install: target: chown/chgrp: Operation not permitted
$ ls target
ls: target: No such file or directory


Attached patch does following changes:

* If safe copy is used perform fstat(2) and fchown(2) and fchmod(2)
  _before_ rename and on failure unlink the temporary copy instead of
  the target.
* On fchlags(2) failure don't unlink the target. We still exit with error
  status. fchflags(2) can't be performed before rename because
  immutable flags may prevent renaming.

-- 
Jaakko
Comment 2 Jilles Tjoelker freebsd_committer 2009-05-29 22:16:27 UTC
The patch works but introduces a new problem: install -S -m 0 src dst
(installing to an unreadable destination, probably as non-root) no
longer works.

I have fixed this particular issue (attachment and
http://www.stack.nl/~jilles/unix/install-S-safe.patch ), but I think the
code is too hard to understand. The install() function was already
fairly twisted and the patch has not improved it.

-- 
Jilles Tjoelker
Comment 3 Eitan Adler freebsd_committer freebsd_triage 2017-12-31 08:01:07 UTC
For bugs matching the following criteria:

Status: In Progress Changed: (is less than) 2014-06-01

Reset to default assignee and clear in-progress tags.

Mail being skipped