Merge pull request #642 from euank/symlink-checker

check_root: add check for broken symlinks
This commit is contained in:
Euan Kemp 2017-02-17 16:18:45 -08:00 committed by GitHub
commit 18076b8bdb
2 changed files with 81 additions and 3 deletions

View File

@ -84,6 +84,22 @@ IGNORE_SHEBANG = (
b"*/doc/*",
)
IGNORE_SYMLINK = (
# symlinks to sdk chroot
b"/build/*",
b"/var/tmp/portage/*",
b"/etc/portage/*",
# symlinks to /run
b"/usr/share/baselayout/motd",
b"/etc/issue",
b"/etc/motd",
# Other
b"/etc/lsb-release" # set later in the build process
)
def provided_sonames():
for cpv in VARDB.cpv_all():
raw = VARDB.aux_get(cpv, ["PROVIDES"])[0]
@ -94,11 +110,13 @@ def provided_sonames():
for atom in VARDB.settings.soname_provided:
yield atom
def ignore_sonames(cpv):
for key in dep.match_to_list(cpv, IGNORE_MISSING.iterkeys()):
for atom in IGNORE_MISSING[key]:
yield atom
def missing_sonames():
provided = frozenset(provided_sonames())
for cpv in VARDB.cpv_all():
@ -109,6 +127,7 @@ def missing_sonames():
if missing:
yield (cpv, missing)
def usr_conflicts():
for cpv in VARDB.cpv_all():
raw = VARDB.aux_get(cpv, ["CONTENTS"])[0]
@ -141,6 +160,7 @@ def usr_conflicts():
if conflicts:
yield (cpv, conflicts)
def check_libs():
ok = True
for cpv, sonames in missing_sonames():
@ -150,6 +170,7 @@ def check_libs():
ok = False
return ok
def check_usr():
ok = True
for cpv, conflicts in usr_conflicts():
@ -159,11 +180,13 @@ def check_usr():
ok = False
return ok
def is_exe(path):
# just check other, assuming root or group only commands are not scripts.
perms = stat.S_IROTH|stat.S_IXOTH
perms = stat.S_IROTH | stat.S_IXOTH
mode = os.lstat(path).st_mode
return stat.S_ISREG(mode) and mode&perms == perms
return stat.S_ISREG(mode) and (mode & perms) == perms
def check_shebang():
ok = True
@ -171,7 +194,7 @@ def check_shebang():
root = os.environ.get("ROOT", b"/")
for parent, _, files in os.walk(root):
for path in [os.path.join(parent, f) for f in files]:
if any(fnmatch.fnmatchcase(path,i) for i in IGNORE_SHEBANG):
if any(fnmatch.fnmatchcase(path, i) for i in IGNORE_SHEBANG):
continue
if not is_exe(path):
continue
@ -201,16 +224,66 @@ def check_shebang():
ok = False
return ok
class chrooted():
"""
chrooted provides a context so that it can be used via with.
For example:
with chrooted("/some/rootfs"):
do_operations_in_rootfs()
do_operations_not_in_rootfs()
"""
def __init__(self, path):
self.path = path
def __enter__(self):
self.restore_fd = os.open(b"/", os.O_RDONLY)
self.working_dir = os.getcwd()
os.chroot(self.path)
def __exit__(self, type, value, traceback):
os.fchdir(self.restore_fd)
os.chroot(b".")
os.chdir(self.working_dir)
os.close(self.restore_fd)
def check_symlink():
if os.getuid() != 0:
error("symlink check must be run as root (chroot)")
return False
ok = True
root = os.environ.get("ROOT", b"/")
with chrooted(root):
for parent, dirs, files in os.walk(b"/"):
for path in [os.path.join(parent, p) for p in files + dirs]:
if any(fnmatch.fnmatchcase(path, i) for i in IGNORE_SYMLINK):
continue
if os.path.islink(path) and not os.path.exists(path):
ok = False
error("broken link: %s", path)
return ok
def error(fmt, *args):
sys.stderr.write(output.red(fmt % args))
sys.stderr.write("\n")
def main():
ok = True
check_funcs = {
"libs": check_libs,
"usr": check_usr,
"shebang": check_shebang,
"symlink": check_symlink,
}
if not sys.stderr.isatty():

View File

@ -56,6 +56,11 @@ test_image_content() {
#returncode=1
fi
if ! sudo ROOT="$root" "$check_root" symlink; then
error "test_image_content: Failed symlink check"
returncode=1
fi
if ! ROOT="$root" glsa_image; then
returncode=1
fi