Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions private/util/validate_usr_symlinks.awk
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,15 @@ BEGIN {
sub(/^(\.\/|\/)+/, "", path)

if (path in expected) {
if ($0 !~ /type=link/) {
# Match `type=link` only as a whole mtree field — bounded by whitespace
# on the left and whitespace or end-of-line on the right. A naive
# substring match was tricked by other mtree field values that happened
# to contain the literal string "type=link" (for example a uname,
# gname, or flags value), silently skipping the symlink check for a
# non-symlink entry at /bin, /sbin, /lib, etc.
if ($0 !~ /[[:space:]]type=link([[:space:]]|$)/) {
VIOLATIONS[original_path] = original_path " is not a symlink (must link to " expected[path] ")"
} else if (match($0, / link=([^ \t]+)/, dest) && dest[1] != expected[path]) {
} else if (match($0, /[[:space:]]link=([^[:space:]]+)/, dest) && dest[1] != expected[path]) {
VIOLATIONS[original_path] = original_path " symlinks to '" dest[1] "' instead of '" expected[path] "'"
}
} else if (path ~ ("^(" prefixes ")/")) {
Expand Down
23 changes: 23 additions & 0 deletions private/util/validate_usr_symlinks_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,27 @@ run "/lib/libfoo.so.1 type=file mode=0644 nlink=1 uid=0 gid=0 size=4096" \
run "./bin/ls type=file mode=0755 nlink=1 uid=0 gid=0 size=12345" \
&& fail "content under ./bin/ should fail" || true

# --- substring-match regression cases ---
# An earlier version of this check used `$0 !~ /type=link/`, which matched the
# string "type=link" anywhere on the line, including inside other mtree field
# values. A non-symlink entry whose uname/gname/flags happened to contain that
# substring would silently pass. The check is now field-bounded.

run "./bin type=dir uname=type=link gname=root mode=0755 uid=0 gid=0" \
&& fail "./bin as a dir with uname=type=link should fail (substring bypass)" || true

run "./bin type=dir uname=root gname=type=link mode=0755 uid=0 gid=0" \
&& fail "./bin as a dir with gname=type=link should fail (substring bypass)" || true

run "./bin type=dir flags=type=link mode=0755 uid=0 gid=0" \
&& fail "./bin as a dir with flags=type=link should fail (substring bypass)" || true

run "./lib type=dir uname=type=link mode=0755 uid=0 gid=0" \
&& fail "./lib as a dir with uname=type=link should fail (substring bypass)" || true

# A legitimate symlink that happens to carry extra trailing fields must keep
# working under the field-bounded check.
run "./bin type=link mode=0777 nlink=1 uid=0 gid=0 link=usr/bin extra=ignored" \
|| fail "./bin -> usr/bin with extra trailing field should pass"

echo "All tests passed."
Loading