isolating untrusted programs in ssh chroot jails

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

isolating untrusted programs in ssh chroot jails

dan mclaughlin
there seems to be some interest in this, so i thought i would post my notes,
made more presentable.

here i detail ways to use ssh to restrict access to the filesystem as well as
X, mitigating the 'security nightmare' that is X11, not to mention preventing
possible leaking of local data. this uses more proven code so may be better
than eg virtualization for some things.

comments/questions/corrections/etc welcome. i'm sure i missed something.

this subject of isolating untrusted programs has been coming up recently,
though mostly in regards to web browsers (firefox, xombrero). now i don't use
firefox (or any 'modern browser'), but other X programs i have tested work
fine (xpdf mplayer xloadimage djview4 feh).  there are some that don't seem
to work that i haven't tracked down the exact cause yet (qiv zathura; something
to do with glib). this works well with w3m+feh for me though.

if someone is ambitious enough to try firefox, for a start, they should read
faq 10.16 which has a basic method of working out dependences, though i've
expanded on that here.

also Johnathon Thornburg's work here saved me some time, and gets into the
security issues:
  http://marc.info/?l=openbsd-misc&m=141616701418506&w=1

still, i'm not sure you can do this for firefox, but this may get you started.
if not, your best bet may be J. Thornburg's method here:
  https://marc.info/?l=openbsd-misc&m=141867559504962&w=2
which you should read anyway.

much of the rest of the information is spread around various man pages (eg
sshd_config(5))

also note Xephyr is required for some programs using 'ssh -X' eg xpdf


0. intro

for simplicity, i will be setting up a single jail for multiple programs.
you could isolate each program with it's own user and jail. one issue though
would be that many dependencies would be duplicated. on the other hand you
could then use ssh's ForceCommand.

for future reference, i will assume there is a user:

/etc/passwd:
    _inmate:*:1111:1111:public jail account:/home/cell:/bin/sh

/etc/group:
    _chaingang:*:1111:


1. setting up ssh to chroot:

you need to add an entry like the following to /etc/ssh/sshd_config:

Match User _inmate
       ChrootDirectory /home/jail
       AuthorizedKeysFile /home/jail.authorized_keys
       X11Forwarding yes
       AllowTcpForwarding no
#       PermitTTY no
#       ForceCommand xpdf /tmp/*pdf
 
you may have to tweak this a bit depending on your use.

if you are using X11 programs you will need "X11Forwarding yes"

if you are using a terminal (eg a console web browser) you may need "PermitTTY
yes". (some X programs also require a terminal for some functions eg mplayer).

if you are using a single command, you will want to use ForceCommand.

remember also that the authorized_keys file must be owned by _inmate, but
in the above example i keep it outside of the jail so the user doesn't have
access.

N.B. remember that when the user's directory is processed, the home directory
in /etc/passwd will be appended to the above ChrootDirectory. in our example,
the ChrootDirectory is /home/jail and the user _inmate's home directory in
/etc/passwd is /home/cell, which ssh will be combine into /home/jail/home/cell.

example using ForceCommand:

Match User _inmate
       ChrootDirectory /home/jail
       AuthorizedKeysFile /home/jail.authorized_keys
       X11Forwarding no
       AllowTcpForwarding no
       PermitTTY yes
       ForceCommand w3m -B


2. setting up basic chroot filesystem

there are some files you need in the chroot in order for various programs to
function, at a minimum you need shared library support and the user's homedir:

essential user files
  /home/jail/home/cell/
  /home/jail.authorized_keys
(must be owned by user ie _inmate)

NOTE: all following files are relative to chroot directory ($_chroot), in
this case /home/jail. for the most part you can 'cp -p file $_chroot/file'.

to handle shared libs (required):
  /sbin/ldconfig
  /usr/libexec/ld.so
  /var/run/
after these files are installed, you will need to run ldconfig
  $ chroot $_chroot ldconfig /usr/{,X11R6,local}/lib
which will create /var/run/ld.so.hints.

basic directories that are needed:
  /bin
  /sbin
  /etc
  /usr/{,X11R6,local}/lib
  /tmp

and since we are going to be installing packages, create:
  /var/db/pkg/

to run X you will need a minimum:
  /etc/fonts/
  /usr/X11R6/lib/X11/fonts/
  /usr/X11R6/bin/xauth

you will also need the shared libraries xauth depends on:

  $ ldd /usr/X11R6/bin/xauth
  /usr/X11R6/bin/xauth:
          Start    End      Type Open Ref GrpRef Name
          1669e000 366a3000 exe  1    0   0      /usr/X11R6/bin/xauth
          09606000 2960a000 rlib 0    2   0      /usr/X11R6/lib/libXau.so.10.0
          0b3fd000 2b401000 rlib 0    1   0      /usr/X11R6/lib/libXext.so.13.0
          0e418000 2e41c000 rlib 0    1   0      /usr/X11R6/lib/libXmuu.so.6.0
          0092e000 209ad000 rlib 0    3   0      /usr/X11R6/lib/libX11.so.16.0
          0b40b000 2b43b000 rlib 0    1   0      /usr/lib/libc.so.77.3
          02b35000 22b3b000 rlib 0    3   0      /usr/X11R6/lib/libxcb.so.3.1
          02cbb000 22cbf000 rlib 0    1   0      /usr/X11R6/lib/libpthread-stubs.so.2.0
          0f995000 2f99a000 rlib 0    1   0      /usr/X11R6/lib/libXdmcp.so.11.0
          055bc000 055bc000 rtld 0    1   0      /usr/libexec/ld.so

so all entries of type 'rlib' above need to be copied to the proper place
under /home/jail, eg:

for _lib in $(ldd /usr/X11R6/bin/xauth | grep ' rlib ' | awk '{printf $7" "}')
do
  [ -f $_chroot/$_lib ] || cp -p $_lib $_chroot/$_lib
done

you need a shell (required by X):
  /bin/sh
(this is needed for xauth to function. ssh calls popen() which calls execle()
with /bin/sh in order to run it. i haven't found out how to do without a shell
yet)

for dns you will need:
  /etc/resolv.conf
and maybe:
  /etc/hosts
(i have local definitions in hosts)

if you want a terminal:
  /dev/tty
  /usr/share/misc/terminfo.db
(for a session sshd_config(5) recommends:
  /dev/{null,zero,tty,stdin,stdout,stderr,arandom}

(also, ssh complains without access to /dev/ttypX files, although nothing
significant seems to happen)

there may be some things that use time:
  $ cp -R /etc/localtime $_chroot/etc/

if you add programs like ls(1) that need user/group names, you need
  /etc/pwd.db
  /etc/group
(note: without pwd.db 'ls' lodges complaints in /var/log/message)

i also have a /home/jail/tmp/ dir same as /tmp/.
files for the commands i run are copied or linked here. they should be owned
by non-_inmate, but they need read permission to be useful.


3. adding packages/dependencies:

adding a package is a bit difficult, especially with dependencies. it is
complicated and tedious. (i wrote a script for this which i include at the
end for convenience).

one method i worked out is basically:

$ (cd /usr/ports/textproc/xpdf && make print-run-depends)

which gives:

This port requires package(s) "jpeg-9a libiconv-1.14p1 ghostscript-fonts-8.11p2
png-1.6.14 openmotif-2.3.4p0" to run.

this will give the proper order needed to install them.

problems:
there are some problems you might run into here. a version of mplayer i was
testing with required libgnutls (via ldd mplayer) but gnutls was not included
as a dependency (for a reason, it wasn't one. if gnutls was already installed
it got pulled in. this particular case only lasted a while.)

there are other methods to getting the dependences, which are in my script.


4. running programs

you should alread have X running, which will be on port 6000 (DISPLAY=:0)

first you want a copy of Xephyr running (some programs will not function using
'ssh -X' without Xephyr).

  $ Xephyr :1 &

Xephyr will be listening on DISPLAY=:1 (port 6001)

now you want to use ssh to login to the jailed user _inmate, creating a
secure X11 tunnel to the Xephyr instance:

  $ env DISPLAY=:1 ssh -X _inmate@localhost xpdf /tmp/file.pdf

ssh reads in DISPLAY to know where the local end of the tunnel is (the X
server). if you do not set it as above, it will be set to the current server
as specified in DISPLAY (probably :0) and will bypass Xephyr (:1).

this will set up an X11 tunnel, probably on DISPLAY=:10 (port 6010), which is
what all programs running in the jail will use (DISPLAY will be set by ssh
automatically)

you can also set ForceCommand to run just that program:
Match User _inmate
       ChrootDirectory /home/jail
       AuthorizedKeysFile /home/jail.authorized_keys
       X11Forwarding yes
       AllowTcpForwarding no
#       PermitTTY no
       ForceCommand xpdf /tmp/*pdf

which you can run using:

  $ env DISPLAY=:1 ssh -X _inmate@localhost


since the programs i use are for existing files, i need to copy or link them
into the jail. i use a script which looks something like this:

#!/bin/sh
_jailroot=/home/jail
[ ${#1} -eq 0 ] && { echo "nothing to do"; return 0; }
if [[ "$(df -k "$1")" = "$(df -k $_jailroot/tmp)" ]];then
  ln "$1" $_jailroot/tmp
else
  cp "$1" $_jailroot/tmp
fi
env DISPLAY=:1 ssh -X _inmate@localhost xpdf /tmp/"$1"
rm $_jailroot/tmp/"$1"


appendix 1. some package quirks

some packages require some special handling. these are a few things i ran
across, but there are certainly others. this should give you an idea of some
problems you may run across.

for gdk-pixbuf, you need to manually run:

  $ sudo chroot sh -c "gdk-pixbuf-query-loaders >/usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache"

or the equivalent for that version.

the problems with pango seem to me to indicate a bigger problem. inside the
jail, pango complains and requires:

  $ pango-querymodules > '/etc/pango/pango.modules'

i have the exact package installed outside the jail, and it functions fine
without 'pango.modules', which doesn't seem to get installed normally. to
get it to work in the jail you need to:

  $ sudo chroot sh -c "pango-querymodules >/etc/pango/pango.modules"


appendix 2. scripts.

i am sending these in a different mail, so that this one is not too long.

Reply | Threaded
Open this post in threaded view
|

Re: isolating untrusted programs in ssh chroot jails

dan mclaughlin
here are the scripts i wrote to make this easier. these really were made
for my own use, but i hope others may find them useful. i would be
interested to know if anyone else actually does find them useful. would
also be glad to know of any errors/problems/things that can go wrong i
didn't think of.


the first one (jail_new) creates a new jail (and possibly the user).
the second one (jail_pkgadd) adds a package and its dependencies to an
existing jail. they are expected to be in the same directory (jail_new
cannot add packages (-p) otherwise).

to relate to my earlier examples:

$ jail_new -tu _inmate:_chaingang /home/jail

will create the jail in /home/jail and also the user _inmate and group
_chaingang. this case it will be just be a regular shell account (just
chrooted).

$ jail_new -t _inmate:_chaingang /home/jail

will create the jail, but will not create the user:group.


a real case:

$ jail_new -tux -k /home/null/.ssh/id_rsa.pub -p w3m,feh:/usr/release/pkg browse /home/browse w3m -B

this command sets up the terminal (-t) and X (-x) in a directory (here
/home/browse), creates a user (-u) (in this case 'browse'), uses the given
key file (-k) for the authorized keys, installs the packages (-p) w3m and
feh (and all of their dependencies) from directory /usr/release/pkg, and
sets 'w3m -B' to run automatically via ForceCommand in sshd_config.

this is the equivalent of:

$ jail_new -tux -k /home/null/.ssh/id_rsa.pub browse /home/browse w3m -B
$ jail_pkgadd -p /usr/release/pkg w3m /home/browse
$ jail_pkgadd -p /usr/release/pkg feh /home/browse

if you want bzip2 in there as well, you can always add it later:

$ jail_pkgadd -p /usr/release/pkg bzip2 /home/browse

or, if PKG_PATH is set (and not remote) you can omit -p

$ jail_pkgadd bzip2 /home/browse

if PKG_PATH is set, and is remote, you need:

$ jail_pkgadd -r bzip2 /home/browse

(note: will only allow a single directory for PKG_PATH)

this can be used by running:

$ Xephyr :1 & env DISPLAY=:1 ssh -X browse@localhost

(side note: w3m runs 'display' to display an image, so i create a symlink
to feh to view images)


another case:

$ jail_new -tuxr -k /home/null/.ssh/id_rsa.pub -p xpdf:scp://null@node02/usr/release/pkg pdf /home/pdf

you need to specify -r (remote) directly to use remote pkg src.

which is the equivalent of:

$ jail_new -tux -k /home/null/.ssh/id_rsa.pub pdf /home/pdf
$ jail_pkgadd -r -p scp://null@node02/usr/release/pkg xpdf /home/pdf

which can be used:

$ cp test.pdf /home/pdf/tmp
$ Xephyr :1 & env DISPLAY=:1 ssh -X browse@localhost xpdf -fullscreen /tmp/test.pdf

(in this case it may be best not to use ForceCommand, since you may want to
open multiple documents.)


WARNING use at your own peril. if you can't read the scripts, you probably
shouldn't use them, and then i am certain there are other glaring security
flaws you need to know about. i include these because it is a dull pain in
the ass to do this manually, and hopefully someone may get some use out of
them.

other than that, do with it what you wish.

they are as fool-proof as i could make them, so that i don't shoot myself in
the foot accidently (and i have been around long enough to have done that a
few times, even while being careful). but you never know.

jail_new:
--------------------------------------------------
#!/bin/ksh
USAGE="${0##*/} [-jrtux] [-k authkeys] [-p pkg[,pkg2...][:pkgpath]] user[:group] path [cmd [args ...]]"
[[ "$1" = -h ]] && { echo "USAGE $USAGE"; return 0; }

#-t sets PermitTTY and copies files for term
#-x sets X11Forwarding and copies files for X (fonts,xauth)
#-u creates user; fails if user exists
#-j joins group; needed to join existing group
#-p pkg[,pkg2...][:pkgpath]
#-r allows remote pkg access
#uses existing PKG_PATH
#pkgpath arg overrides PKG_PATH

#only accepts a lone pkgpath

PATH=/sbin:/bin:/usr/sbin:/usr/bin

echov() {  eval echo \"\$$1\";  }
isemptyv() {  eval [ \${#$1} -eq 0 ];  }
notemptyv() {  eval [ \${#$1} -gt 0 ];  }
alias xt='set -o xtrace'
alias xt-='set +o xtrace'

if [ $(id -u) -eq 0 ];then
  echo "ERR cannot run as root"
  return 1
fi

_sshd_config=/etc/ssh/sshd_config
_sshd_config_tmp=/tmp/sshd_config

trap "rm -f $_sshd_config_tmp" 0 2

#for convenience
_fontdir=/usr/X11R6/lib/X11/fonts
_terminfo=/usr/share/misc/terminfo.db
_termcap=/usr/share/misc/termcap

_do_x=no
_do_tty=no
_do_useradd=
_do_joingrp=
_do_remote=
_authkeys=
_pkg=
_pkgpath=
_userhome=/home/cell
while getopts :jrtuxk:p: _opt;do
  case "$_opt" in
    j) _do_joingrp=yes ;;
    r) _do_remote=-r ;;
    t) _do_tty=yes ;;
    u) _do_useradd=yes ;;
    x) _do_x=yes ;;
    k) _authkeys=$OPTARG
       if [ ! -f "$_authkeys" ];then
         echo "ERR no such file '$_authkeys'"
         return 1
       fi
       ;;
    p) _pkg=$OPTARG
       if [[ "$_pkg" = *:* ]];then
         _pkgpath=${_pkg#*:}
         _pkg=${_pkg%%:*}
         export PKG_PATH=$_pkgpath
       else
         if isemptyv PKG_PATH;then
           echo "ERR PKG_PATH not set and none given"
           return 1
         fi
         _pkgpath=$PKG_PATH
       fi
       if [[ "$_pkgpath" = *://* ]];then
         if isemptyv _do_remote;then
           echo "ERR pkgpath is remote; use -r"
           return 1
         fi
         if [[ "$_pkgpath" = *:*:* ]];then
           echo "ERR invalid pkgpath '$_pkgpath'; only one dir permitted"
           return 1
         fi
       else
         if [[ "$_pkgpath" = *:* ]];then
           echo "ERR invalid pkgpath '$_pkgpath'; only one dir permitted"
           return 1
         fi
       fi
       if isemptyv _do_remote && [ ! -d "$_pkgpath" ];then
         echo "ERR no such dir '$_pkgpath'"
         return 1
       fi
       _cmd_jailpkgadd=$(dirname $0)/jail_pkgadd
       if [ ! -f $_cmd_jailpkgadd ];then
         echo "ERR cannot locate jail_pkgadd script"
         return 1
       fi
       ;;
    :) echo "ERR no arg for '-$OPTARG'"; return 1 ;;
    *) echo "ERR invalid arg '-$OPTARG'"; return 1 ;;
  esac
done
shift $((OPTIND-1))

_user=$1
_jailroot=$2
_cmd=$3

if isemptyv _user;then
  echo "ERR user not given"
  return 1
fi
if isemptyv _jailroot;then
  echo "ERR jailroot path not given"
  return 1
fi
shift 2
if [ -e $_jailroot ];then
  echo "ERR $_jailroot already exists"
  return 1
fi

_authkeysfile=$_jailroot.authkeys
_dbdir=$_jailroot/var/db/pkg

#check/setup user/group
getfreeuid() {
  local _uid=1000
  local _uid_list="$(awk -F : '{printf $3"\n"}' /etc/passwd)"
  local _gid_list="$(awk -F : '{printf $3"\n"}' /etc/group)"
  while [ $_uid -gt 900 ];do
    _uid=$((_uid-1))
    echov _uid_list | grep -q "^$_uid$" && continue
    echov _gid_list | grep -q "^$_uid$" && continue
    break
  done
  [ $_uid -lt 900 ] && return 1
  echo $_uid
}

_group=${_user#*:}
_user=${_user%:*}
if grep -q ^$_user: /etc/passwd;then
  if notemptyv _do_useradd;then
    echo "ERR user '$_user' already exists"
    return 1
  fi
  _userhome=$(grep ^$_user: /etc/passwd | awk -F : '{printf $4":"$6}')
  _group=${_userhome%:*}
  _userhome=${_userhome#*:}
  _jailhome=$_jailroot$_userhome
else
  if isemptyv _do_useradd;then
    echo "ERR user '$_user' does not exist; use -u to create"
    return 1
  fi
  _uid=$(getfreeuid) || {  echo "ERR no uid free";  return 1;  }
  if [[ "$_user" = "$_group" ]];then
    _group="=uid"
  else
    if grep -q ^$_group: /etc/group;then
      if isemptyv _do_joingrp;then
        echo "ERR group '$_group' exists; use -j to join"
        return 1
      fi
    else
      if notemptyv _do_joingrp;then
        echo "ERR group '$_group' doesn't exist; cannot use -j to join"
        return 1
      fi
      if ! sudo groupadd -g $_uid $_group;then
        echo "ERR failed to add group '$_group' gid '$_uid'"
        return 1
      fi
    fi fi
  if ! sudo useradd -u $_uid -g $_group -c "public jail" \
                    -s /bin/sh -d $_userhome $_user 2>&1
  then
    echo "ERR useradd failed"
    return 1
  fi | grep -v "Warning: home"
  _group=$_uid
fi

_jailhome=$_jailroot$_userhome

sudo mkdir -p $_jailhome || return 1


cat >$_sshd_config_tmp <<CONF
Match User $_user
    ChrootDirectory $_jailroot
    AuthorizedKeysFile $_authkeysfile
    X11Forwarding $_do_x
    PermitTTY $_do_tty
CONF
set -f
notemptyv _cmd && echo "    ForceCommand $*" >>$_sshd_config_tmp
set +f


#setup filesystem

isemptyv _authkeys && _authkeys=/dev/null
sudo sh -c "cat $_authkeys >$_authkeysfile" || return 1
sudo chown $_user:$_group $_jailhome $_authkeysfile || return 1

sudo mkdir -p $_jailroot/dev || return 1
if [[ "$_do_tty" = yes ]];then
  sudo mknod -m 644 $_jailroot/dev/arandom c 45 3 || return 1
  sudo mknod -m 666 $_jailroot/dev/null    c 2  2 || return 1
  sudo mknod -m 666 $_jailroot/dev/stderr  c 22 2 || return 1
  sudo mknod -m 666 $_jailroot/dev/stdin   c 22 0 || return 1
  sudo mknod -m 666 $_jailroot/dev/stdout  c 22 1 || return 1
  sudo mknod -m 666 $_jailroot/dev/tty     c 1  0 || return 1
  sudo mknod -m 666 $_jailroot/dev/zero    c 2 12 || return 1
  #sudo mknod -m 666 $_jailroot/dev/ttyp0    c 5 0 || return 1
  #might want to add ttypN to make sshd happy
fi

sudo mkdir -p $_jailroot/{bin,sbin,etc,tmp,var/run} $_dbdir
sudo mkdir -p $_jailroot/usr/{libexec,{,X11R6,local}/{bin,lib}}
sudo cp -p /sbin/ldconfig $_jailroot/sbin
sudo cp -p /usr/libexec/ld.so $_jailroot/usr/libexec
sudo chroot $_jailroot ldconfig /usr/{,X11R6,local}/lib
sudo chmod 1777 $_jailroot/tmp

sudo cp -p /bin/sh $_jailroot/bin

sudo cp -pR /etc/{hosts,resolv.conf,localtime} $_jailroot/etc


if [[ "$_do_x" = yes ]];then
  _xauth=/usr/X11R6/bin/xauth
  sudo cp -p /bin/sh $_jailroot/bin
  sudo cp -p $_xauth $_jailroot$_xauth
  for _lib in $(ldd $_xauth | grep ' rlib ' | awk '{printf $7" "}');do
    [ -f $_jailroot/$_lib ] && continue
    sudo cp -p $_lib $_jailroot/$_lib || return 1
  done
  sudo cp -rp /etc/fonts $_jailroot/etc || return 1
  sudo mkdir -p $_jailroot/${_fontdir%/*} || return 1
  sudo cp -rp $_fontdir $_jailroot/$_fontdir || return 1
fi

if [[ "$_do_tty" = yes ]];then
  #for terminal eg w3m
  sudo mkdir -p $_jailroot${_terminfo%/*} || return 1
  sudo cp -p $_terminfo $_termcap $_jailroot${_terminfo%/*} || return 1
  #may still need /etc/termcap
  #sudo cp -R /etc/termcap $_jailroot/etc || return 1
fi

echo "WARNING will update /etc/ssh/sshd_config with the following:\n"
cat $_sshd_config_tmp
echo
read _update_ssh?"update sshd_config and restart sshd? (type 'yes') "
if notemptyv _update_ssh && [[ "$_update_ssh" = yes ]];then
  sudo sh -c "cat $_sshd_config_tmp >>$_sshd_config"
  [ -f /var/run/sshd.pid ] && sudo kill -1 $(</var/run/sshd.pid)
fi
 
if notemptyv _pkg;then
  IFS=,
  for _thispkg in $_pkg;do
    $_cmd_jailpkgadd $_do_remote -p $_pkgpath $_thispkg $_jailroot
  done
fi

--------------------------------------------------


jail_pkgadd:
--------------------------------------------------
#!/bin/ksh
USAGE="${0##*/} [-r] [-p pkg_path] pkg [jailroot]"
[[ "$1" = -h ]] && { echo "USAGE $USAGE"; return 0; }

PATH=/sbin:/bin:/usr/sbin:/usr/bin

#a few functions of my own
#these are easier to type, and save me debugging time due to common things
#like quotes, $, etc
#takes a variable name as an arg, hence 'v' suffix
echov() {  eval echo \"\$$1\";  }
isemptyv() {  eval [ \${#$1} -eq 0 ];  }
notemptyv() {  eval [ \${#$1} -gt 0 ];  }
alias usage='echo "USAGE $USAGE"'
alias xt='set -o xtrace'
alias xt-='set +o xtrace'

if [ $(id -u) -eq 0 ];then
  echo "ERR should not run as root"
  return 1
fi
if [[ "$(id -nG)" != *wsrc* ]];then
  echo "ERR user not in wsrc; needed for pkg_add"
  return 1
fi

#_pkg_dir read from PKG_PATH
#-p overrides PKG_PATH
#if neither set, uses default

_do_remote=
_pkg_dir=$PKG_PATH
while getopts :rp: _opt;do
  case "$_opt" in
    r) _do_remote=true ;;
    p) _pkg_dir=$OPTARG
       ;;
    :) echo "ERR no arg for '-$OPTARG'";  return 1 ;;
    *) echo "ERR invalid arg '-$OPTARG'";  return 1 ;;
  esac
done
shift $((OPTIND-1))
_pkg_dir=${_pkg_dir:-/usr/ports/packages/`arch -s`/all}
_pkg_dbdir=/var/db/pkg
export PKG_PATH="$_pkg_dir"

if [[ "$_pkg_dir" = *://* ]];then
  if isemptyv _do_remote;then
    echo "ERR invalid pkg dir; need -r for remote"
    return 1
  fi
  if [[ "$_pkg_dir" = *:*:* ]];then
    echo "ERR invalid pkg dir; only one dir allowed"
    return 1
  fi
else
  _do_remote=
  if [[ "$_pkg_dir" = *:* ]];then
    echo "ERR invalid pkg dir; only one dir allowed"
    return 1
  fi
  if [ ! -d "$_pkg_dir" ];then
    echo "ERR pkg dir '$_pkg_dir' does not exist"
    return 1
  fi
fi

_pkg=$1
_jailroot=$2
if isemptyv _pkg;then
  echo "ERR no package given"
  usage
  return 1
fi
_jailroot=${_jailroot:-/home/jail}
if [ ! -d "$_jailroot" ];then
  echo "ERR no such dir '$_jailroot'"
  return 1
fi
_jail_dbdir=$_jailroot$_pkg_dbdir

#set to /tmp to ignore installed package and use PKG_PATH
_pkg_file=$(PKG_DBDIR=/tmp pkg_info -c $_pkg | sed -n 's!^Information for.*/!!p')
if isemptyv _pkg_file;then
  echo "ERR could not find pkg '$_pkg'"
  return 1
fi

##get list of required packages
##only works if /usr/ports is in sync with packages in PKG_PATH
#_pkgpath=$(pkg_info -P $_pkg | grep ^[a-z])
#if isemptyv _pkgpath;then
#  echo "ERR cannot find port '$_pkg'"
#  return 1
#fi
#_pkgpath=/usr/ports/$_pkgpath
#cd $_pkgpath
#_pkg_list=$(make print-run-depends) || return $?
#_pkg_list=$(echov _pkg_list | sed -e 's/.*"\([^"]*\)".*/\1 /' -e 's/ /.tgz /g')
#_pkg_list="${_pkg_list}$_pkg_file"

_depend_list=
function get_depends {
  local _pkg=$1 _depend
  for _depend in $(pkg_info -f $_pkg | sed -n 's/^@depend.*://p');do
    echo $_pkg $_depend
    [[ "$_depend_list" = *\ $_depend\ * ]] && continue
    get_depends $_depend
    _depend_list="$_depend_list $_depend "
  done
}
_pkg_list="$(get_depends ${_pkg_file%.tgz} | tsort -r)"
isemptyv _pkg_list && _pkg_list=${_pkg_file%.tgz}


#if local go thru list to make sure pkgs are all there
if isemptyv _do_remote;then
  for _pkg in $_pkg_list;do
    [ -f $_pkg_dir/$_pkg.tgz ] && continue
    echo "ERR pkg '$_pkg' not found"
    return 1
  done
fi

#keep list of libraries to avoid repeating find
_lib_tree=$(find /usr/{,X11R6}/lib -type f)

for _pkg in $_pkg_list;do
  #check if package already installed
  [ -d $_jail_dbdir/$_pkg ] && continue

  #get list of @wantlib's that need copying
  _lib_list=$(pkg_info -f $_pkg | sed -n 's/^@wantlib //p')

  #get list of binaries in the pkg to check for more dependencies
  _bin_list=$(pkg_info -f $_pkg | sed -n 's/^@bin //p')

  #hopefully this handles all the quicks for @lib
  for _lib in $_lib_list;do
    _lib_relpath=
    if [[ "$_lib" = */* ]];then
      _lib_relpath=${_lib%/*}
      _lib=${_lib##*/}
    fi
    _lib_ver_min=${_lib##*.}
    _lib_name=${_lib%.*}
    _lib_ver_maj=${_lib_name##*.}
    _lib_name=${_lib_name%.*}
    _lib_fn=lib$_lib_name.so.$_lib_ver_maj.$_lib_ver_min

    if isemptyv _lib_relpath;then
      #ASSUME want libraries only -maxdepth 1
      _lib_pathn=$(find $_jailroot/usr/{,X11R6,local}/lib -maxdepth 1 -name $_lib_fn)
    else
      _lib_pathn=$_jailroot/usr/local/$_lib_relpath/$_lib_fn
    fi
    [ -f "$_lib_pathn" ] && continue
    #lib not in jail
    _lib_pathn=$(echov _lib_tree | grep $_lib_fn$)
    if isemptyv _lib_pathn || notemptyv _lib_relpath;then
      #never copy from /usr/local
      echo "WARN could not find $_lib_fn"
    else
      sudo cp -p $_lib_pathn $_jailroot/$_lib_pathn
    fi
  done

  #ignore unsigned packages (-D unsigned) since i built them
  #sudo env PKG_DBDIR=$_jail_dbdir pkg_add -m -B $_jailroot -D unsigned $_pkg
  sudo env PKG_DBDIR=$_jail_dbdir pkg_add -m -B $_jailroot $_pkg

  #rebuild ld.so.hints with new libraries
  sudo chroot $_jailroot ldconfig /usr/{,X11R6,local}/lib

  #go thru binaries in package and get additional dependencies
  (cd $_jailroot/usr/local
   for _bin in $_bin_list;do
     for _lib in $(ldd $_bin | grep ' rlib ' | grep -v /usr/local/lib | awk '{printf $7" "}');do
        [ -f $_jailroot/$_lib ] || sudo cp -p $_lib $_jailroot/$_lib
     done
   done)
done

#env PKG_DBDIR=$_dbdir pkg_add -B /home/chroot $_pkg
#env PKG_DBDIR=$_dbdir pkg_delete -B /home/chroot $_pkg

jsg
Reply | Threaded
Open this post in threaded view
|

Re: isolating untrusted programs in ssh chroot jails

jsg
You said at beginning of your comments "now i don't use
firefox (or any 'modern browser)"
   may I ask which browser you like to use? And for what reasons?

thanks in advance

On Thu, Mar 19, 2015 at 7:56 PM, dan mclaughlin <[hidden email]>
wrote:

> here are the scripts i wrote to make this easier. these really were made
> for my own use, but i hope others may find them useful. i would be
> interested to know if anyone else actually does find them useful. would
> also be glad to know of any errors/problems/things that can go wrong i
> didn't think of.
>
>
> the first one (jail_new) creates a new jail (and possibly the user).
> the second one (jail_pkgadd) adds a package and its dependencies to an
> existing jail. they are expected to be in the same directory (jail_new
> cannot add packages (-p) otherwise).
>
> to relate to my earlier examples:
>
> $ jail_new -tu _inmate:_chaingang /home/jail
>
> will create the jail in /home/jail and also the user _inmate and group
> _chaingang. this case it will be just be a regular shell account (just
> chrooted).
>
> $ jail_new -t _inmate:_chaingang /home/jail
>
> will create the jail, but will not create the user:group.
>
>
> a real case:
>
> $ jail_new -tux -k /home/null/.ssh/id_rsa.pub -p w3m,feh:/usr/release/pkg
> browse /home/browse w3m -B
>
> this command sets up the terminal (-t) and X (-x) in a directory (here
> /home/browse), creates a user (-u) (in this case 'browse'), uses the given
> key file (-k) for the authorized keys, installs the packages (-p) w3m and
> feh (and all of their dependencies) from directory /usr/release/pkg, and
> sets 'w3m -B' to run automatically via ForceCommand in sshd_config.
>
> this is the equivalent of:
>
> $ jail_new -tux -k /home/null/.ssh/id_rsa.pub browse /home/browse w3m -B
> $ jail_pkgadd -p /usr/release/pkg w3m /home/browse
> $ jail_pkgadd -p /usr/release/pkg feh /home/browse
>
> if you want bzip2 in there as well, you can always add it later:
>
> $ jail_pkgadd -p /usr/release/pkg bzip2 /home/browse
>
> or, if PKG_PATH is set (and not remote) you can omit -p
>
> $ jail_pkgadd bzip2 /home/browse
>
> if PKG_PATH is set, and is remote, you need:
>
> $ jail_pkgadd -r bzip2 /home/browse
>
> (note: will only allow a single directory for PKG_PATH)
>
> this can be used by running:
>
> $ Xephyr :1 & env DISPLAY=:1 ssh -X browse@localhost
>
> (side note: w3m runs 'display' to display an image, so i create a symlink
> to feh to view images)
>
>
> another case:
>
> $ jail_new -tuxr -k /home/null/.ssh/id_rsa.pub -p xpdf:scp://null@node02/usr/release/pkg
> pdf /home/pdf
>
> you need to specify -r (remote) directly to use remote pkg src.
>
> which is the equivalent of:
>
> $ jail_new -tux -k /home/null/.ssh/id_rsa.pub pdf /home/pdf
> $ jail_pkgadd -r -p scp://null@node02/usr/release/pkg xpdf /home/pdf
>
> which can be used:
>
> $ cp test.pdf /home/pdf/tmp
> $ Xephyr :1 & env DISPLAY=:1 ssh -X browse@localhost xpdf -fullscreen
> /tmp/test.pdf
>
> (in this case it may be best not to use ForceCommand, since you may want to
> open multiple documents.)
>
>
> WARNING use at your own peril. if you can't read the scripts, you probably
> shouldn't use them, and then i am certain there are other glaring security
> flaws you need to know about. i include these because it is a dull pain in
> the ass to do this manually, and hopefully someone may get some use out of
> them.
>
> other than that, do with it what you wish.
>
> they are as fool-proof as i could make them, so that i don't shoot myself
> in
> the foot accidently (and i have been around long enough to have done that a
> few times, even while being careful). but you never know.
>
> jail_new:
> --------------------------------------------------
> #!/bin/ksh
> USAGE="${0##*/} [-jrtux] [-k authkeys] [-p pkg[,pkg2...][:pkgpath]]
> user[:group] path [cmd [args ...]]"
> [[ "$1" = -h ]] && { echo "USAGE $USAGE"; return 0; }
>
> #-t sets PermitTTY and copies files for term
> #-x sets X11Forwarding and copies files for X (fonts,xauth)
> #-u creates user; fails if user exists
> #-j joins group; needed to join existing group
> #-p pkg[,pkg2...][:pkgpath]
> #-r allows remote pkg access
> #uses existing PKG_PATH
> #pkgpath arg overrides PKG_PATH
>
> #only accepts a lone pkgpath
>
> PATH=/sbin:/bin:/usr/sbin:/usr/bin
>
> echov() {  eval echo \"\$$1\";  }
> isemptyv() {  eval [ \${#$1} -eq 0 ];  }
> notemptyv() {  eval [ \${#$1} -gt 0 ];  }
> alias xt='set -o xtrace'
> alias xt-='set +o xtrace'
>
> if [ $(id -u) -eq 0 ];then
>   echo "ERR cannot run as root"
>   return 1
> fi
>
> _sshd_config=/etc/ssh/sshd_config
> _sshd_config_tmp=/tmp/sshd_config
>
> trap "rm -f $_sshd_config_tmp" 0 2
>
> #for convenience
> _fontdir=/usr/X11R6/lib/X11/fonts
> _terminfo=/usr/share/misc/terminfo.db
> _termcap=/usr/share/misc/termcap
>
> _do_x=no
> _do_tty=no
> _do_useradd=
> _do_joingrp=
> _do_remote=
> _authkeys=
> _pkg=
> _pkgpath=
> _userhome=/home/cell
> while getopts :jrtuxk:p: _opt;do
>   case "$_opt" in
>     j) _do_joingrp=yes ;;
>     r) _do_remote=-r ;;
>     t) _do_tty=yes ;;
>     u) _do_useradd=yes ;;
>     x) _do_x=yes ;;
>     k) _authkeys=$OPTARG
>        if [ ! -f "$_authkeys" ];then
>          echo "ERR no such file '$_authkeys'"
>          return 1
>        fi
>        ;;
>     p) _pkg=$OPTARG
>        if [[ "$_pkg" = *:* ]];then
>          _pkgpath=${_pkg#*:}
>          _pkg=${_pkg%%:*}
>          export PKG_PATH=$_pkgpath
>        else
>          if isemptyv PKG_PATH;then
>            echo "ERR PKG_PATH not set and none given"
>            return 1
>          fi
>          _pkgpath=$PKG_PATH
>        fi
>        if [[ "$_pkgpath" = *://* ]];then
>          if isemptyv _do_remote;then
>            echo "ERR pkgpath is remote; use -r"
>            return 1
>          fi
>          if [[ "$_pkgpath" = *:*:* ]];then
>            echo "ERR invalid pkgpath '$_pkgpath'; only one dir permitted"
>            return 1
>          fi
>        else
>          if [[ "$_pkgpath" = *:* ]];then
>            echo "ERR invalid pkgpath '$_pkgpath'; only one dir permitted"
>            return 1
>          fi
>        fi
>        if isemptyv _do_remote && [ ! -d "$_pkgpath" ];then
>          echo "ERR no such dir '$_pkgpath'"
>          return 1
>        fi
>        _cmd_jailpkgadd=$(dirname $0)/jail_pkgadd
>        if [ ! -f $_cmd_jailpkgadd ];then
>          echo "ERR cannot locate jail_pkgadd script"
>          return 1
>        fi
>        ;;
>     :) echo "ERR no arg for '-$OPTARG'"; return 1 ;;
>     *) echo "ERR invalid arg '-$OPTARG'"; return 1 ;;
>   esac
> done
> shift $((OPTIND-1))
>
> _user=$1
> _jailroot=$2
> _cmd=$3
>
> if isemptyv _user;then
>   echo "ERR user not given"
>   return 1
> fi
> if isemptyv _jailroot;then
>   echo "ERR jailroot path not given"
>   return 1
> fi
> shift 2
> if [ -e $_jailroot ];then
>   echo "ERR $_jailroot already exists"
>   return 1
> fi
>
> _authkeysfile=$_jailroot.authkeys
> _dbdir=$_jailroot/var/db/pkg
>
> #check/setup user/group
> getfreeuid() {
>   local _uid=1000
>   local _uid_list="$(awk -F : '{printf $3"\n"}' /etc/passwd)"
>   local _gid_list="$(awk -F : '{printf $3"\n"}' /etc/group)"
>   while [ $_uid -gt 900 ];do
>     _uid=$((_uid-1))
>     echov _uid_list | grep -q "^$_uid$" && continue
>     echov _gid_list | grep -q "^$_uid$" && continue
>     break
>   done
>   [ $_uid -lt 900 ] && return 1
>   echo $_uid
> }
>
> _group=${_user#*:}
> _user=${_user%:*}
> if grep -q ^$_user: /etc/passwd;then
>   if notemptyv _do_useradd;then
>     echo "ERR user '$_user' already exists"
>     return 1
>   fi
>   _userhome=$(grep ^$_user: /etc/passwd | awk -F : '{printf $4":"$6}')
>   _group=${_userhome%:*}
>   _userhome=${_userhome#*:}
>   _jailhome=$_jailroot$_userhome
> else
>   if isemptyv _do_useradd;then
>     echo "ERR user '$_user' does not exist; use -u to create"
>     return 1
>   fi
>   _uid=$(getfreeuid) || {  echo "ERR no uid free";  return 1;  }
>   if [[ "$_user" = "$_group" ]];then
>     _group="=uid"
>   else
>     if grep -q ^$_group: /etc/group;then
>       if isemptyv _do_joingrp;then
>         echo "ERR group '$_group' exists; use -j to join"
>         return 1
>       fi
>     else
>       if notemptyv _do_joingrp;then
>         echo "ERR group '$_group' doesn't exist; cannot use -j to join"
>         return 1
>       fi
>       if ! sudo groupadd -g $_uid $_group;then
>         echo "ERR failed to add group '$_group' gid '$_uid'"
>         return 1
>       fi
>     fi fi
>   if ! sudo useradd -u $_uid -g $_group -c "public jail" \
>                     -s /bin/sh -d $_userhome $_user 2>&1
>   then
>     echo "ERR useradd failed"
>     return 1
>   fi | grep -v "Warning: home"
>   _group=$_uid
> fi
>
> _jailhome=$_jailroot$_userhome
>
> sudo mkdir -p $_jailhome || return 1
>
>
> cat >$_sshd_config_tmp <<CONF
> Match User $_user
>     ChrootDirectory $_jailroot
>     AuthorizedKeysFile $_authkeysfile
>     X11Forwarding $_do_x
>     PermitTTY $_do_tty
> CONF
> set -f
> notemptyv _cmd && echo "    ForceCommand $*" >>$_sshd_config_tmp
> set +f
>
>
> #setup filesystem
>
> isemptyv _authkeys && _authkeys=/dev/null
> sudo sh -c "cat $_authkeys >$_authkeysfile" || return 1
> sudo chown $_user:$_group $_jailhome $_authkeysfile || return 1
>
> sudo mkdir -p $_jailroot/dev || return 1
> if [[ "$_do_tty" = yes ]];then
>   sudo mknod -m 644 $_jailroot/dev/arandom c 45 3 || return 1
>   sudo mknod -m 666 $_jailroot/dev/null    c 2  2 || return 1
>   sudo mknod -m 666 $_jailroot/dev/stderr  c 22 2 || return 1
>   sudo mknod -m 666 $_jailroot/dev/stdin   c 22 0 || return 1
>   sudo mknod -m 666 $_jailroot/dev/stdout  c 22 1 || return 1
>   sudo mknod -m 666 $_jailroot/dev/tty     c 1  0 || return 1
>   sudo mknod -m 666 $_jailroot/dev/zero    c 2 12 || return 1
>   #sudo mknod -m 666 $_jailroot/dev/ttyp0    c 5 0 || return 1
>   #might want to add ttypN to make sshd happy
> fi
>
> sudo mkdir -p $_jailroot/{bin,sbin,etc,tmp,var/run} $_dbdir
> sudo mkdir -p $_jailroot/usr/{libexec,{,X11R6,local}/{bin,lib}}
> sudo cp -p /sbin/ldconfig $_jailroot/sbin
> sudo cp -p /usr/libexec/ld.so $_jailroot/usr/libexec
> sudo chroot $_jailroot ldconfig /usr/{,X11R6,local}/lib
> sudo chmod 1777 $_jailroot/tmp
>
> sudo cp -p /bin/sh $_jailroot/bin
>
> sudo cp -pR /etc/{hosts,resolv.conf,localtime} $_jailroot/etc
>
>
> if [[ "$_do_x" = yes ]];then
>   _xauth=/usr/X11R6/bin/xauth
>   sudo cp -p /bin/sh $_jailroot/bin
>   sudo cp -p $_xauth $_jailroot$_xauth
>   for _lib in $(ldd $_xauth | grep ' rlib ' | awk '{printf $7" "}');do
>     [ -f $_jailroot/$_lib ] && continue
>     sudo cp -p $_lib $_jailroot/$_lib || return 1
>   done
>   sudo cp -rp /etc/fonts $_jailroot/etc || return 1
>   sudo mkdir -p $_jailroot/${_fontdir%/*} || return 1
>   sudo cp -rp $_fontdir $_jailroot/$_fontdir || return 1
> fi
>
> if [[ "$_do_tty" = yes ]];then
>   #for terminal eg w3m
>   sudo mkdir -p $_jailroot${_terminfo%/*} || return 1
>   sudo cp -p $_terminfo $_termcap $_jailroot${_terminfo%/*} || return 1
>   #may still need /etc/termcap
>   #sudo cp -R /etc/termcap $_jailroot/etc || return 1
> fi
>
> echo "WARNING will update /etc/ssh/sshd_config with the following:\n"
> cat $_sshd_config_tmp
> echo
> read _update_ssh?"update sshd_config and restart sshd? (type 'yes') "
> if notemptyv _update_ssh && [[ "$_update_ssh" = yes ]];then
>   sudo sh -c "cat $_sshd_config_tmp >>$_sshd_config"
>   [ -f /var/run/sshd.pid ] && sudo kill -1 $(</var/run/sshd.pid)
> fi
>
> if notemptyv _pkg;then
>   IFS=,
>   for _thispkg in $_pkg;do
>     $_cmd_jailpkgadd $_do_remote -p $_pkgpath $_thispkg $_jailroot
>   done
> fi
>
> --------------------------------------------------
>
>
> jail_pkgadd:
> --------------------------------------------------
> #!/bin/ksh
> USAGE="${0##*/} [-r] [-p pkg_path] pkg [jailroot]"
> [[ "$1" = -h ]] && { echo "USAGE $USAGE"; return 0; }
>
> PATH=/sbin:/bin:/usr/sbin:/usr/bin
>
> #a few functions of my own
> #these are easier to type, and save me debugging time due to common things
> #like quotes, $, etc
> #takes a variable name as an arg, hence 'v' suffix
> echov() {  eval echo \"\$$1\";  }
> isemptyv() {  eval [ \${#$1} -eq 0 ];  }
> notemptyv() {  eval [ \${#$1} -gt 0 ];  }
> alias usage='echo "USAGE $USAGE"'
> alias xt='set -o xtrace'
> alias xt-='set +o xtrace'
>
> if [ $(id -u) -eq 0 ];then
>   echo "ERR should not run as root"
>   return 1
> fi
> if [[ "$(id -nG)" != *wsrc* ]];then
>   echo "ERR user not in wsrc; needed for pkg_add"
>   return 1
> fi
>
> #_pkg_dir read from PKG_PATH
> #-p overrides PKG_PATH
> #if neither set, uses default
>
> _do_remote=
> _pkg_dir=$PKG_PATH
> while getopts :rp: _opt;do
>   case "$_opt" in
>     r) _do_remote=true ;;
>     p) _pkg_dir=$OPTARG
>        ;;
>     :) echo "ERR no arg for '-$OPTARG'";  return 1 ;;
>     *) echo "ERR invalid arg '-$OPTARG'";  return 1 ;;
>   esac
> done
> shift $((OPTIND-1))
> _pkg_dir=${_pkg_dir:-/usr/ports/packages/`arch -s`/all}
> _pkg_dbdir=/var/db/pkg
> export PKG_PATH="$_pkg_dir"
>
> if [[ "$_pkg_dir" = *://* ]];then
>   if isemptyv _do_remote;then
>     echo "ERR invalid pkg dir; need -r for remote"
>     return 1
>   fi
>   if [[ "$_pkg_dir" = *:*:* ]];then
>     echo "ERR invalid pkg dir; only one dir allowed"
>     return 1
>   fi
> else
>   _do_remote=
>   if [[ "$_pkg_dir" = *:* ]];then
>     echo "ERR invalid pkg dir; only one dir allowed"
>     return 1
>   fi
>   if [ ! -d "$_pkg_dir" ];then
>     echo "ERR pkg dir '$_pkg_dir' does not exist"
>     return 1
>   fi
> fi
>
> _pkg=$1
> _jailroot=$2
> if isemptyv _pkg;then
>   echo "ERR no package given"
>   usage
>   return 1
> fi
> _jailroot=${_jailroot:-/home/jail}
> if [ ! -d "$_jailroot" ];then
>   echo "ERR no such dir '$_jailroot'"
>   return 1
> fi
> _jail_dbdir=$_jailroot$_pkg_dbdir
>
> #set to /tmp to ignore installed package and use PKG_PATH
> _pkg_file=$(PKG_DBDIR=/tmp pkg_info -c $_pkg | sed -n 's!^Information
> for.*/!!p')
> if isemptyv _pkg_file;then
>   echo "ERR could not find pkg '$_pkg'"
>   return 1
> fi
>
> ##get list of required packages
> ##only works if /usr/ports is in sync with packages in PKG_PATH
> #_pkgpath=$(pkg_info -P $_pkg | grep ^[a-z])
> #if isemptyv _pkgpath;then
> #  echo "ERR cannot find port '$_pkg'"
> #  return 1
> #fi
> #_pkgpath=/usr/ports/$_pkgpath
> #cd $_pkgpath
> #_pkg_list=$(make print-run-depends) || return $?
> #_pkg_list=$(echov _pkg_list | sed -e 's/.*"\([^"]*\)".*/\1 /' -e 's/
> /.tgz /g')
> #_pkg_list="${_pkg_list}$_pkg_file"
>
> _depend_list=
> function get_depends {
>   local _pkg=$1 _depend
>   for _depend in $(pkg_info -f $_pkg | sed -n 's/^@depend.*://p');do
>     echo $_pkg $_depend
>     [[ "$_depend_list" = *\ $_depend\ * ]] && continue
>     get_depends $_depend
>     _depend_list="$_depend_list $_depend "
>   done
> }
> _pkg_list="$(get_depends ${_pkg_file%.tgz} | tsort -r)"
> isemptyv _pkg_list && _pkg_list=${_pkg_file%.tgz}
>
>
> #if local go thru list to make sure pkgs are all there
> if isemptyv _do_remote;then
>   for _pkg in $_pkg_list;do
>     [ -f $_pkg_dir/$_pkg.tgz ] && continue
>     echo "ERR pkg '$_pkg' not found"
>     return 1
>   done
> fi
>
> #keep list of libraries to avoid repeating find
> _lib_tree=$(find /usr/{,X11R6}/lib -type f)
>
> for _pkg in $_pkg_list;do
>   #check if package already installed
>   [ -d $_jail_dbdir/$_pkg ] && continue
>
>   #get list of @wantlib's that need copying
>   _lib_list=$(pkg_info -f $_pkg | sed -n 's/^@wantlib //p')
>
>   #get list of binaries in the pkg to check for more dependencies
>   _bin_list=$(pkg_info -f $_pkg | sed -n 's/^@bin //p')
>
>   #hopefully this handles all the quicks for @lib
>   for _lib in $_lib_list;do
>     _lib_relpath=
>     if [[ "$_lib" = */* ]];then
>       _lib_relpath=${_lib%/*}
>       _lib=${_lib##*/}
>     fi
>     _lib_ver_min=${_lib##*.}
>     _lib_name=${_lib%.*}
>     _lib_ver_maj=${_lib_name##*.}
>     _lib_name=${_lib_name%.*}
>     _lib_fn=lib$_lib_name.so.$_lib_ver_maj.$_lib_ver_min
>
>     if isemptyv _lib_relpath;then
>       #ASSUME want libraries only -maxdepth 1
>       _lib_pathn=$(find $_jailroot/usr/{,X11R6,local}/lib -maxdepth 1
> -name $_lib_fn)
>     else
>       _lib_pathn=$_jailroot/usr/local/$_lib_relpath/$_lib_fn
>     fi
>     [ -f "$_lib_pathn" ] && continue
>     #lib not in jail
>     _lib_pathn=$(echov _lib_tree | grep $_lib_fn$)
>     if isemptyv _lib_pathn || notemptyv _lib_relpath;then
>       #never copy from /usr/local
>       echo "WARN could not find $_lib_fn"
>     else
>       sudo cp -p $_lib_pathn $_jailroot/$_lib_pathn
>     fi
>   done
>
>   #ignore unsigned packages (-D unsigned) since i built them
>   #sudo env PKG_DBDIR=$_jail_dbdir pkg_add -m -B $_jailroot -D unsigned
> $_pkg
>   sudo env PKG_DBDIR=$_jail_dbdir pkg_add -m -B $_jailroot $_pkg
>
>   #rebuild ld.so.hints with new libraries
>   sudo chroot $_jailroot ldconfig /usr/{,X11R6,local}/lib
>
>   #go thru binaries in package and get additional dependencies
>   (cd $_jailroot/usr/local
>    for _bin in $_bin_list;do
>      for _lib in $(ldd $_bin | grep ' rlib ' | grep -v /usr/local/lib |
> awk '{printf $7" "}');do
>         [ -f $_jailroot/$_lib ] || sudo cp -p $_lib $_jailroot/$_lib
>      done
>    done)
> done
>
> #env PKG_DBDIR=$_dbdir pkg_add -B /home/chroot $_pkg
> #env PKG_DBDIR=$_dbdir pkg_delete -B /home/chroot $_pkg

Reply | Threaded
Open this post in threaded view
|

Re: isolating untrusted programs in ssh chroot jails

Jorge Gabriel Lopez Paramount
In reply to this post by dan mclaughlin
Quoting dan mclaughlin <[hidden email]>:

> there seems to be some interest in this, so i thought i would post my notes,
> made more presentable.
>
> here i detail ways to use ssh to restrict access to the filesystem as well as
> X, mitigating the 'security nightmare' that is X11, not to mention preventing
> possible leaking of local data. this uses more proven code so may be better
> than eg virtualization for some things.

This looks interesting but really complicated. As I commented before I  
use a virtual machine for running Firefox due to security concerns,  
now with OpenBSD at last. I know that a virtual machine would not  
resist a targeted attack, but since it would be complicated breaking  
away from a virtual machine and this is not a common setup I do not  
think a generic attack/worm/trojan would be able to do any harm.

Also, I'm running Firefox for browsing but since it's common to get  
PDF files I have installed along a PDF viewer as well. And sometimes I  
want to print documents so I installed cups (fortunately everything  
works on OpenBSD as expected, thanks by the way!). Firefox, a PDF  
viewer and cups have a lot of dependencies, and I have not tried yet  
to forward sound so my Firefox is soundless. And Firefox alone eats  
lots of memory, I have reserved for this VM one gigabyte of RAM.

To me that's one of the biggest virtual machines I have, and very  
likely would make a big jail. If I wanted to do it the OpenBSD way  
(the one I imagine) I would reserve an old laptop or netbook and put  
there OpenBSD with Firefox and friends instead of setting up a big and  
complicated jail.

--
Best regards,
Jorge Lopez.



----------------------------------------------------------------
This message was sent using IMP, the Internet Messaging Program.

Reply | Threaded
Open this post in threaded view
|

Re: isolating untrusted programs in ssh chroot jails

dan mclaughlin
In reply to this post by dan mclaughlin
On Thu, 19 Mar 2015 20:08:34 +0800 "Jeff St. George" <[hidden email]> wrote:
> You said at beginning of your comments "now i don't use
> firefox (or any 'modern browser)"
>    may I ask which browser you like to use? And for what reasons?
>
> thanks in advance
>

like in the examples, i use w3m. which is one of the reasons i wanted to make
this jail, since i don't trust the code at all. the reasons why, well, i'm an
old unix guy, who still spends most of his time in a text console! there is
also the bloat. my machines are too old to run firefox even if i wanted to
(i tried some years ago with a livecd project i was doing, and i could not
believe how SLOW it was).

i use my computer mostly to read anyway, and unless there is a pdf i cannot
convert, i have little need of graphics at all (mostly my own nature photos/
videos). besides, its also much quicker without all of those pictures. if i
choose, i can view the one photo i want (which pops up in the Xephyr window).

Reply | Threaded
Open this post in threaded view
|

Re: isolating untrusted programs in ssh chroot jails

dan mclaughlin
In reply to this post by dan mclaughlin
On Thu, 19 Mar 2015 08:52:09 -0600 Jorge Gabriel Lopez Paramount <[hidden email]> wrote:

> Quoting dan mclaughlin <[hidden email]>:
>
> > there seems to be some interest in this, so i thought i would post my notes,
> > made more presentable.
> >
> > here i detail ways to use ssh to restrict access to the filesystem as well as
> > X, mitigating the 'security nightmare' that is X11, not to mention preventing
> > possible leaking of local data. this uses more proven code so may be better
> > than eg virtualization for some things.
>
> This looks interesting but really complicated. As I commented before I  
> use a virtual machine for running Firefox due to security concerns,  
> now with OpenBSD at last. I know that a virtual machine would not  
> resist a targeted attack, but since it would be complicated breaking  
> away from a virtual machine and this is not a common setup I do not  
> think a generic attack/worm/trojan would be able to do any harm.
>
> Also, I'm running Firefox for browsing but since it's common to get  
> PDF files I have installed along a PDF viewer as well. And sometimes I  
> want to print documents so I installed cups (fortunately everything  
> works on OpenBSD as expected, thanks by the way!). Firefox, a PDF  
> viewer and cups have a lot of dependencies, and I have not tried yet  
> to forward sound so my Firefox is soundless. And Firefox alone eats  
> lots of memory, I have reserved for this VM one gigabyte of RAM.
>
> To me that's one of the biggest virtual machines I have, and very  
> likely would make a big jail. If I wanted to do it the OpenBSD way  
> (the one I imagine) I would reserve an old laptop or netbook and put  
> there OpenBSD with Firefox and friends instead of setting up a big and  
> complicated jail.
>
> --
> Best regards,
> Jorge Lopez.

you have a point about it being complicated, which is why i said i don't think
it would work with firefox. i mention already that i had trouble with a few
simpler ports like qiv.

and physical separation on its own machine is probably the best practice anyway
(i use physical separation for security myself). but there may be cases where
one may not be able to dedicate a whole machine to it, and it's something. it
depends on one's use case. hence my statement above 'for some things'. firefox
isn't in my use case. phsical separation would be more difficult for one of my
main use cases, reading pdfs on my desktop. and not everybody always has access
to such resources.

the intent though was to make it possible to run any code, and also to use
openbsd base, as that is a more trusted code base to build upon (ssh -X,
chroot).

one use is xpdf for instance. (which is only about ~135M of space, a good half
of that X11 fonts). some do get bigger, like djview4 which has 70 packages
and ~712M space. (i also use it for w3m, since one must be particularly careful
with browsers given QUANTUMINSERT and the like.) as to RAM, this wouldn't take
hardly any more than is already used.

and it is much less complicated with scripts (i already invested time in them
so i don't have to invest it later setting them up (and making mistakes)). it's
a single command now. i also have scripts that automate starting up/taking down
Xephyr and launching the proper account/commands (i just type 'open file' and
everything is already done for me.)

the beauty of scripts (and unix).