linuxchrootdebian-basedmultiarch

Identifying architecture dependent location of nsswitch libraries


I have a DEB package which dynamically creates a chroot filesystem in package postinst helper script. The package works fine for x86, amd64, and arm64 on Debian Stretch/Buster/Bullseye and Ubuntu Bionic/Focal/Jammy. However, I recently tried to install it on Raspbian arm32 and it failed.

The problem is that the pathname of the nsswitch libraries is constructed differently than on the other platforms. In other words, the piece meal assembly of the library path using uname -m is not matching what's present in the file-system.

#!/bin/bash -eu

U=chroot_user
UHOME=/home/$U
ARCH=$(uname -m)

function add_executable () {
  FROM="$1"; shift
  TO="$(basename $FROM)"
  if [ $# -ge 1 ]; then
    TO=$1; shift
  fi
  cp "$FROM" "$UHOME/bin/$TO"
  ldd "$FROM" | grep "=> /" | awk '{print $3}' | xargs -I '{}' cp '{}' $UHOME/lib/

  LIBNAME="ld-linux-$(echo $ARCH | tr '_' '-').so*"
  if compgen -G "/lib64/${LIBNAME}" > /dev/null; then
    cp /lib64/${LIBNAME} $UHOME/lib64/
  elif compgen -G "/lib/${LIBNAME}" > /dev/null; then
    cp /lib/${LIBNAME} $UHOME/lib/
  fi
}

if [ "$1" = "configure" ]; then

  # Create a system user that has restricted bash as its login shell.
  IS_USER=$(grep $U /etc/passwd || true)
  if [ ! -z "$IS_USER" ]; then
    killall -u $U || true
    userdel -f $U > /dev/null 2>&1 || true
  fi
  adduser --system --home ${UHOME} --no-create-home --group --shell /bin/rbash ${U}

  # Create a clean usable chroot
  rm -rf $UHOME
  mkdir -p $UHOME
  mkdir -p $UHOME/dev/
  mknod -m 666 $UHOME/dev/null c 1 3
  mknod -m 666 $UHOME/dev/tty c 5 0
  mknod -m 666 $UHOME/dev/zero c 1 5
  mknod -m 666 $UHOME/dev/random c 1 8
  mknod -m 644 $UHOME/dev/urandom c 1 9
  chown root:root $UHOME
  chmod 0755 $UHOME
  mkdir -p $UHOME/bin
  mkdir -p $UHOME/etc
  mkdir -p $UHOME/lib
  mkdir -p $UHOME/usr
  cd $UHOME/usr
  ln -s ../bin bin
  cd - > /dev/null
  cd $UHOME
  ln -s lib lib64
  cd - > /dev/null
  mkdir $UHOME/lib/${ARCH}-linux-gnu
  cp /lib/${ARCH}-linux-gnu/libnss* $UHOME/lib/${ARCH}-linux-gnu
  cat <<EOT>$UHOME/etc/nsswitch.conf
passwd: files
group:  files
EOT
  chmod 0444 $UHOME/etc/nsswitch.conf
  echo "127.0.0.1 localhost" > $UHOME/etc/hosts
  chmod 0444 $UHOME/etc/hosts
  if [ -d /etc/terminfo/ ]; then
    cp -R /etc/terminfo $UHOME/etc
  fi
  if [ -d /lib/terminfo/ ]; then
    cp -R /lib/terminfo $UHOME/lib
  fi

  # Add restricted bash and ssh/scp executables into the chroot. There is no
  # need for any other executable.
  add_executable /bin/bash rbash
  add_executable /usr/bin/ssh
  add_executable /usr/bin/scp
  add_executable /bin/date
  add_executable /bin/ls
  add_executable /bin/rm
  add_executable /bin/mv
  add_executable /bin/cp

  grep $U /etc/passwd > $UHOME/etc/passwd
  grep $U /etc/group > $UHOME/etc/group

  mkdir -p $UHOME/.ssh
  chmod 700 $UHOME/.ssh
  chown -R $U:$U $UHOME/.ssh

  # When using SSH to get out of the jail onto localhost machine, we don't want
  # to be constantly told about fingerprints and permanently added hosts
  mkdir -p $UHOME/home/$U/.ssh
  chmod 0700 $UHOME/home/$U/.ssh
  chown -R $U:$U $UHOME/home/$U

fi

#DEBHELPER#

exit 0

# vim: set ts=2 sw=2 tw=0 et :

Solution

  • Not in the expected location ... well, more like: the architecture type in uname's output doesn't match the directory name you want to construct ...

    But you could find the directory in a different way, since you're on apt based distros.

    dpkg -L libnss3 | awk '/libnss3.so/{gsub(/\/libnss3.so/,"",$0);print}'

    This worked for me on both Ubuntu 20.04 and Raspbian GNU/Linux 10 (buster)

    Raspbian:

    $ dpkg -L libnss3  | awk '/libnss3.so/{gsub(/\/libnss3.so/,"",$0);print}'
    /usr/lib/arm-linux-gnueabihf
    

    Ubuntu:

    $ dpkg -L libnss3  | awk '/libnss3.so/{gsub(/\/libnss3.so/,"",$0);print}'
    /usr/lib/x86_64-linux-gnu