sane-sandboxed: expand symlinks before binding them into the sandbox
This commit is contained in:
parent
89135d08cb
commit
d148b19767
|
@ -135,6 +135,19 @@ usage() {
|
||||||
|
|
||||||
## UTILITIES/BOILERPLATE
|
## UTILITIES/BOILERPLATE
|
||||||
|
|
||||||
|
# `relativeTo base-dir path`
|
||||||
|
# if `path` is absolute, returns `path`
|
||||||
|
# otherwise, joins `path` onto `base-dir`
|
||||||
|
relativeTo() {
|
||||||
|
local base="$1"
|
||||||
|
local path="$2"
|
||||||
|
if [ "${path:0:1}" == "/" ]; then
|
||||||
|
echo "$path"
|
||||||
|
else
|
||||||
|
echo "$base/$path"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# `normPath outVar "$path"`
|
# `normPath outVar "$path"`
|
||||||
# remove duplicate //, reduce '.' and '..' (naively).
|
# remove duplicate //, reduce '.' and '..' (naively).
|
||||||
# expects a full path as input
|
# expects a full path as input
|
||||||
|
@ -226,6 +239,19 @@ urldecode() {
|
||||||
declare -g "$outVar"="$(echo -e "${i//%/\\x}")"
|
declare -g "$outVar"="$(echo -e "${i//%/\\x}")"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# `contains needle ${haystack[0]} ${haystack[1]} ...`
|
||||||
|
# evals `true` if the first argument is equal to any of the other args
|
||||||
|
contains() {
|
||||||
|
local needle="$1"
|
||||||
|
shift
|
||||||
|
for item in "$@"; do
|
||||||
|
if [ "$needle" = "$item" ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
## HELPERS
|
## HELPERS
|
||||||
|
|
||||||
|
@ -769,41 +795,57 @@ maybeAutodetectPaths() {
|
||||||
# for more sophisticated (i.e. complex) backends like firejail, this may break subpaths which were blacklisted earlier.
|
# for more sophisticated (i.e. complex) backends like firejail, this may break subpaths which were blacklisted earlier.
|
||||||
canonicalizePaths() {
|
canonicalizePaths() {
|
||||||
# remove '//' and simplify '.', '..' paths, into canonical absolute logical paths.
|
# remove '//' and simplify '.', '..' paths, into canonical absolute logical paths.
|
||||||
_normPaths=()
|
local normPaths=()
|
||||||
for _path in "${paths[@]}"; do
|
for path in "${paths[@]}"; do
|
||||||
normPath _canonPath "$_path"
|
normPath _canonPath "$path"
|
||||||
_normPaths+=("$_canonPath")
|
normPaths+=("$_canonPath")
|
||||||
done
|
done
|
||||||
|
paths=("${normPaths[@]}")
|
||||||
|
}
|
||||||
|
expandLink() {
|
||||||
|
local target="$(readlink "$1")"
|
||||||
|
if [ -n "$target" ]; then
|
||||||
|
# make absolute
|
||||||
|
target="$(relativeTo "$(dirname "$1")" "$target")"
|
||||||
|
# add + expand the symlink further, but take care to avoid infinite recursion
|
||||||
|
normPath _canonTarget "$target"
|
||||||
|
if ! $(contains "$_canonTarget" "${paths[@]}"); then
|
||||||
|
paths+=("$_canonTarget")
|
||||||
|
expandLink "$_canonTarget"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
### expand `paths` until it contains no symlinks whose target isn't also in `paths`
|
||||||
|
expandLinks() {
|
||||||
|
for _path in "${paths[@]}"; do
|
||||||
|
expandLink "$_path"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
removeSubpaths() {
|
||||||
# remove subpaths, but the result might include duplicates.
|
# remove subpaths, but the result might include duplicates.
|
||||||
_toplevelPaths=()
|
local toplevelPaths=()
|
||||||
for _path in "${_normPaths[@]}"; do
|
for _path in "${paths[@]}"; do
|
||||||
_isSubpath=
|
local isSubpath=
|
||||||
for _other in "${_normPaths[@]}"; do
|
for _other in "${paths[@]}"; do
|
||||||
if [[ "$_path" =~ ^$_other/.* ]] || [ "$_other" = "/" ] && [ "$_path" != "/" ]; then
|
if [[ "$_path" =~ ^$_other/.* ]] || [ "$_other" = "/" ] && [ "$_path" != "/" ]; then
|
||||||
# N.B.: $_path lacks a trailing slash, so this never matches self.
|
# N.B.: $_path lacks a trailing slash, so this never matches self.
|
||||||
# UNLESS $_path or $_other is exactly `/`, which we special-case.
|
# UNLESS $_path or $_other is exactly `/`, which we special-case.
|
||||||
_isSubpath=1
|
isSubpath=1
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
if [ -z "$_isSubpath" ]; then
|
if [ -z "$isSubpath" ]; then
|
||||||
_toplevelPaths+=("$_path")
|
toplevelPaths+=("$_path")
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# remove duplicated paths.
|
# remove duplicated paths.
|
||||||
canonicalizedPaths=()
|
local canonicalizedPaths=()
|
||||||
for _path in "${_toplevelPaths[@]}"; do
|
for _path in "${toplevelPaths[@]}"; do
|
||||||
_isAlreadyListed=
|
if ! $(contains "$_path" "${canonicalizedPaths[@]}"); then
|
||||||
for _other in "${canonicalizedPaths[@]}"; do
|
|
||||||
if [ "$_path" = "$_other" ]; then
|
|
||||||
_isAlreadyListed=1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [ -z "$_isAlreadyListed" ]; then
|
|
||||||
canonicalizedPaths+=("$_path")
|
canonicalizedPaths+=("$_path")
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
paths=("${canonicalizedPaths[@]}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -826,7 +868,7 @@ parseArgsAndEnvironment() {
|
||||||
### convert generic args into sandbox-specific args
|
### convert generic args into sandbox-specific args
|
||||||
# order matters: for firejail, early args override the later --profile args
|
# order matters: for firejail, early args override the later --profile args
|
||||||
ingestForBackend() {
|
ingestForBackend() {
|
||||||
for _path in "${canonicalizedPaths[@]}"; do
|
for _path in "${paths[@]}"; do
|
||||||
"$method"IngestPath "$_path"
|
"$method"IngestPath "$_path"
|
||||||
done
|
done
|
||||||
|
|
||||||
|
@ -872,6 +914,8 @@ if [ -z "$isDisable" ]; then
|
||||||
"$method"Setup
|
"$method"Setup
|
||||||
maybeAutodetectPaths
|
maybeAutodetectPaths
|
||||||
canonicalizePaths
|
canonicalizePaths
|
||||||
|
expandLinks
|
||||||
|
removeSubpaths
|
||||||
|
|
||||||
ingestForBackend
|
ingestForBackend
|
||||||
"$method"GetCli
|
"$method"GetCli
|
||||||
|
|
Loading…
Reference in New Issue
Block a user