Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 20 Oct 2010 16:18:48 -0700
From:      Devin Teske <dteske@vicor.com>
To:        Julian Elischer <julian@freebsd.org>
Cc:        freebsd-rc@freebsd.org, Pawel Jakub Dawidek <pjd@freebsd.org>
Subject:   Re: sysrc(8) -- a sysctl(8)-like utility for managing rc.conf(5)
Message-ID:  <1287616729.19873.215.camel@localhost.localdomain>
In-Reply-To: <1287593628.19873.41.camel@localhost.localdomain>
References:  <1286925182.32724.18.camel@localhost.localdomain> <1286996709.32724.60.camel@localhost.localdomain> <1287448781.5713.3.camel@localhost.localdomain> <1287510629.25599.2.camel@localhost.localdomain> <20101019195225.GB2127@garage.freebsd.pl> <1287540769.25599.73.camel@localhost.localdomain> <4CBE6F55.5040609@freebsd.org> <1287593628.19873.41.camel@localhost.localdomain>

next in thread | previous in thread | raw e-mail | index | archive | help
On Wed, 2010-10-20 at 09:53 -0700, Devin Teske wrote:
> On Tue, 2010-10-19 at 21:25 -0700, Julian Elischer wrote:
> >   On 10/19/10 7:12 PM, Devin Teske wrote:
> > > On Tue, 2010-10-19 at 21:52 +0200, Pawel Jakub Dawidek wrote:
> > >> On Tue, Oct 19, 2010 at 10:50:29AM -0700, Devin Teske wrote:
> > >>> I added `-j jail' for specifying a jail id or name to operate within
> > >>> (requires jls(8); overrides `-R dir').
> > >> [...]
> > >>
> > >> Note that operating on jail files from outside a jail is serious
> > >> security problem. The files from within the jail can be symbolic links
> > >> that point to files from outside a jail from your perspective.  Even
> > >> chroot(2) to jail's root is neither safe (running applications that can
> > >> be modified by jail's root is obvious security hole) nor reliable (jail
> > >> might not have all the commands). The only safe way is to jexec(8) into
> > >> a jail, but it of course has the same relialability issue as chroot(8).
> > >>
> > > I see the concern, and you're absolutely right.
> > >
> > > I did see the need to use either chroot(8) or jexec(8), but for exactly
> > > the same reasons you mention (handing execution off-to something that
> > > could have been modified by the jail's root-user), I ended up writing
> > > routines that just edited the files outside the jail.
> > >
> > > It appears that (due to the other aforementioned security problem,
> > > involving hand-crafted symbolic links with malicious-intent), the only
> > > proper solution would be:
> > >
> > > a. Copy ourselves into some temporary location within the jail
> > > b. Hand execution off to ourself using either jexec(8) or chroot(8)
> > >
> > can you fire off a shell in the jail and somehow shove yourself down 
> > it's throat?
> > I vaguely remember that one  could feed a shell script into the shell 
> > somehow..
> > but I forget the details.
> 
> You bet.
> 
> $ echo tail -2 /usr/include/osreldate.h | sudo chroot / /bin/sh
> #define __FreeBSD_version 801000
> #endif
> $ echo tail -2 /usr/include/osreldate.h | sudo chroot /usr/jail/foomaster /bin/sh
> #define __FreeBSD_version 492101
> #endif
> 
> A more complete (yet simplified) example of a shell-script shoving
> itself into a chroot'ed shell -- complete with custom-set of positional
> parameters:
> 
> ================================= BEGIN FILE: foo.sh
> #!/bin/sh
> jailed="$( sysctl -n security.jail.jailed )"
> echo "jailed: $jailed"
> echo -n "args: "
> for arg in "$@"; do
>         echo -n "'$arg' "
> done
> echo
> [ $jailed -eq 1 ] && exit
> ( echo 'set -- "a  b" "c  d" "e  f"'
>   cat $0
> ) | sudo jexec 8 /bin/sh
> ================================= END FILE
> 
> When executed:
> 
> $ uname -spr
> FreeBSD 8.1-RELEASE-p1 amd64
> 
> $ jls jid path
> 8 /usr/jail/foomaster
> 9 /usr/jail/foomaster.deluxe
> 
> $ ./foo.sh "1  2" "3  4" "5  6"
> jailed: 0
> args: '1  2' '3  4' '5  6'
> jailed: 1
> args: 'a  b' 'c  d' 'e  f'
> 
> This is of-course a simplified example. A productionized version should
> take into consideration that PATH expansion may have been performed.

Sorry... testing shows that when PATH expansion is performed, $0 has the
expanded form, not the unexpanded form.

For example:

============================== BEGIN FILE: foo.sh
#!/bin/sh
echo "0 = '$0'"
============================== END FILE

$ foo.sh
0 = '/usr/local/bin/foo.sh'



> [snip]
> 
> Unfortunately, there seems little way around this as even the following
> code fails in interesting ways:
> 
> myscript="$0"
> case "$myscript" in
> */*) : Do nothing (already an absolute or relative path)
>      ;;
> *)
> 	# $0 doesn't contain any slashes -- we were invoked in
> 	# one of two ways:
> 	#
> 	# 1. via $PATH expansion in the interactive shell

Wrong, PATH expansion leads to the absolute or relative path to the
program being in $0.


> 	# 2. via sh(1) and $0 truly is in the CWD
> 	#
> 	# NOTE: It is not possible to detect when we were invoked
> 	# via exec(3) versus sh(1) versus sh(1)-via-env(1) so
> 	# testing for #2 above is impossible.

Wrong, I found a way.

$_ directly after invocation holds a clue...


> 
> 	for dir in $PATH; do
> 		[ -x "$dir/$0" -a -f "$dir/$0" ] || continue
> 		myscript="$dir/$0"
> 		break
> 	done
> esac
> 
> 
> The comments in the above code-block explain why it won't work.
> 
> In the case of:
> 
> 	sh myscript
> 
> $0 will equal "myscript" but, when reverse-PATH expansion is performed,
> we may end up finding something with the same name and then end up
> executing something perhaps entirely different.

This has changed slightly because we don't need to perform reverse PATH
expansion.


> It seems clear that the only safe way to pass off execution to onself is
> to hard-code the path to yourself.
> 
> For example:
> 
> myscript=/usr/local/bin/foo
> ( echo 'set -- "a  b" "c  d" "e  f"'
>   cat $myscript
> ) | sudo jexec 8 /bin/sh
> 
> 
> Can anyone think of anything better?

I came up with this... (first to test)

============================== BEGIN FILE: foo.sh
#!/bin/sh
echo "_ = '$_'"
echo "0 = '$0'"
============================== END FILE

Then we test different invocations:

$ sh foo.sh
_ = '/bin/sh'
0 = 'foo.sh'

$ env sh foo.sh
_ = '/usr/bin/env'
0 = 'foo.sh'

$ ./foo.sh
_ = './foo.sh'
0 = './foo.sh'

$ /var/tmp/foo.sh
_ = '/var/tmp/foo.sh'
0 = '/var/tmp/foo.sh'

$ PATH="/var/tmp"
$ foo.sh
_ = '/var/tmp/foo.sh'
0 = '/var/tmp/foo.sh'

$ cd /var/tmp
$ PATH="."
$ foo.sh
_ = './foo.sh'
0 = './foo.sh'

$ PATH=":"
$ foo.sh
_ = './foo.sh'
0 = './foo.sh'

$ sh /var/tmp/foo.sh
_ = '/bin/sh'
0 = '/var/tmp/foo.sh'

And in analyzing each of the results...

$0 is perfectly acceptable in ALL results (as long as we don't change
the current working directory -- outside the protection of a subshell at
least, such as (...), $(...), `...`, or sh -c '...').

So this is the final answer...

( echo 'set -- "a  b" "c  d" "e  f"'
  cat $0
) | sudo jexec 8 /bin/sh

-- 
Cheers,
Devin Teske

-> CONTACT INFORMATION <-
Business Solutions Consultant II
FIS - fisglobal.com
510-735-5650 Mobile
510-621-2038 Office
510-621-2020 Office Fax
909-477-4578 Home/Fax
devin.teske@fisglobal.com

-> LEGAL DISCLAIMER <-
This message  contains confidential  and proprietary  information
of the sender,  and is intended only for the person(s) to whom it
is addressed. Any use, distribution, copying or disclosure by any
other person  is strictly prohibited.  If you have  received this
message in error,  please notify  the e-mail sender  immediately,
and delete the original message without making a copy.

-> FUN STUFF <-
-----BEGIN GEEK CODE BLOCK-----
Version 3.1
GAT/CS d(+) s: a- C++(++++) UB++++$ P++(++++) L++(++++) !E--- W++ N? o? K- w O
M+ V- PS+ PE Y+ PGP- t(+) 5? X+(++) R>++ tv(+) b+(++) DI+(++) D(+) G+>++ e>+ h
r>++ y+ 
------END GEEK CODE BLOCK------
http://www.geekcode.com/

-> END TRANSMISSION <-




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