From 0ebd7fdb55fc5923e929d6cf9c0efade5fc94940 Mon Sep 17 00:00:00 2001 From: rpe Date: Sun, 14 Jan 2018 12:12:52 +0000 Subject: [PATCH] Prefetched sets are stored by root, but are read by an unprivileged user during the actual install phase. Add a check to the selection of the prefetch area to ensure the unprivleged user can read files from there. Move the selection logic to its own function prefetcharea_fs_list() which returns a unique list of candidate filesystems, or with rc=1. While at it, remove /var/tmp from the potential list of candidates because it's a symbolic link to /tmp since 2014. Change install_files() to loop over the candidates and check if it can read a test file, otherwise clean up and skip this filesystem. Problem found by benno@ whose upgrade failed due to /usr/obj being owned by build:wobj and permissions that prevented the unprivileged user to read the prefetched set files from there. discussed with and OK benno@ halex@ tb@ --- distrib/miniroot/install.sub | 77 +++++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 27 deletions(-) diff --git a/distrib/miniroot/install.sub b/distrib/miniroot/install.sub index 06630c0ef6f..1c106b3d73b 100644 --- a/distrib/miniroot/install.sub +++ b/distrib/miniroot/install.sub @@ -1,5 +1,5 @@ #!/bin/ksh -# $OpenBSD: install.sub,v 1.1053 2018/01/03 10:22:38 rpe Exp $ +# $OpenBSD: install.sub,v 1.1054 2018/01/14 12:12:52 rpe Exp $ # # Copyright (c) 1997-2015 Todd Miller, Theo de Raadt, Ken Westerback # Copyright (c) 2015, Robert Peichaer @@ -1458,12 +1458,41 @@ unpriv2() { do_as _file "$@" } +# Find filesystems to store prefetched sets. +# Prefer filesystems which are not used during extraction with 512M free space. +# Otherwise use any other filesystem with 2 GB free space to prevent overflow +# during extraction. +prefetcharea_fs_list() { + local _fs_list + + _fs_list=$( ( + for fs in /mnt/{tmp,home,usr{/local,}}; do + df -k $fs 2>/dev/null | grep " $fs\$" + done + df -k + ) | ( + while read a a a a m m; do + [[ $m == /mnt/@(tmp|home|usr/@(src,obj,xobj))@(|/*) ]] && + ((a > 524288)) && echo $m && continue + [[ $m == /mnt@(|/*) ]] && + ((a > 524288 * 4)) && echo $m + done + ) | ( + while read fs; do + isin "$fs" $list || list="$list${list:+ }$fs" + done + echo $list + ) ) + + [[ -n $_fs_list ]] && echo $_fs_list || return 1 +} + # Install a user-selected subset of the files in $2 from the source # named in $1. Display an error message for failed installs so the # user will know to try again. install_files() { - local _src=$1 _files=$2 _f _sets _get_sets _n _col=$COLUMNS \ - _tmpfs _tmpsrc _cfile=/tmp/SHA256 _fsrc _unver _t _issue + local _src=$1 _files=$2 _f _sets _get_sets _n _col=$COLUMNS _tmpfs \ + _tmpfs_list _tmpsrc _cfile=/tmp/SHA256 _fsrc _unver _t _issue local _srclocal=false _unpriv=unpriv # Fetch sets from local sources (disk, cdrom, nfs) as root. @@ -1516,38 +1545,32 @@ install_files() { ! isin SHA256.sig $_files && _issue="Directory does not contain SHA256.sig" && break - # For non-local sources find a filesystem to store the prefetched - # sets. Prefer filesystems which are not used during extraction. - # They need to have 512 MB free space. Otherwise use any other - # filesystem having 2 GB free space to prevent overflow during - # extraction. - $_srclocal || _tmpfs=$( ( - for fs in /mnt/{{,var/}tmp,home,usr{/local,}}; do - df -k $fs 2>/dev/null | grep " $fs\$" - done - df -k - ) | ( - while read a a a a m m; do - [[ $m == /mnt/@(@(|var/)tmp|home|usr/@(src,obj,xobj))@(|/*) ]] && - ((a > 524288)) && echo $m && exit - [[ $m == /mnt@(|/*) ]] && - ((a > 524288 * 4)) && echo $m && exit - done - ) ) - if ! $_srclocal; then - if [[ -d $_tmpfs ]]; then + ! _tmpfs_list=$(prefetcharea_fs_list) && + _issue="Cannot determine prefetch area" && break + + for _tmpfs in $_tmpfs_list; do # Try to clean up from previous runs, assuming # the _tmpfs selection yields the same mount # point. for _tmpsrc in $_tmpfs/sets.+([0-9]).+([0-9]); do [[ -d $_tmpsrc ]] && rm -r $_tmpsrc done - ! _tmpsrc=$(tmpdir "$_tmpfs/sets") && + + # Create a download directory for the sets and + # check that the _sndio user can read files from + # it. Otherwise cleanup and skip the filesystem. + if _tmpsrc=$(tmpdir "$_tmpfs/sets"); then + ( + >$_tmpsrc/t && + $_unpriv cat $_tmpsrc/t + ) >/dev/null 2>&1 && break || + rm -r $_tmpsrc + fi + done + + [[ ! -d $_tmpsrc ]] && _issue="Cannot create prefetch area" && break - else - _issue="Cannot determine prefetch area" && break - fi fi # Cleanup from previous runs. -- 2.20.1