diff --git a/Namcap/rules/__init__.py b/Namcap/rules/__init__.py index 525dbc6..ee400e2 100644 --- a/Namcap/rules/__init__.py +++ b/Namcap/rules/__init__.py @@ -44,6 +44,7 @@ from . import ( permissions, py_mtime, rpath, + runpath, scrollkeeper, shebangdepends, sodepends, diff --git a/Namcap/rules/runpath.py b/Namcap/rules/runpath.py new file mode 100644 index 0000000..053923e --- /dev/null +++ b/Namcap/rules/runpath.py @@ -0,0 +1,71 @@ +# namcap rules - runpath +# +# Copyright (C) 2019 Jelle van der Waa +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +from Namcap.util import is_elf +from Namcap.ruleclass import TarballRule + +from elftools.elf.elffile import ELFFile +from elftools.elf.dynamic import DynamicSection + +allowed = ('/usr/lib', '/usr/lib32', '/lib', '$ORIGIN', '${ORIGIN}') +allowed_toplevels = (s + '/' for s in allowed) +warn = ['/usr/local/lib'] + + +def get_runpaths(fileobj): + elffile = ELFFile(fileobj) + for section in elffile.iter_sections(): + if not isinstance(section, DynamicSection): + continue + for tag in section.iter_tags(): + if tag.entry.d_tag != 'DT_RUNPATH': + continue + for path in tag.runpath.split(':'): + yield path + + +class package(TarballRule): + name = "runpath" + description = "Verifies if RUNPATH is secure" + + def analyze(self, pkgingo, tar): + for entry in tar: + if not entry.isfile(): + continue + + fileobj = tar.extractfile(entry) + if not is_elf(fileobj): + continue + + for path in get_runpaths(fileobj): + path_ok = path in allowed + for allowed_toplevel in allowed_toplevels: + if path.startswith(allowed_toplevel): + path_ok = True + + if not path_ok: + self.errors.append(("insecure-runpath %s %s", + (path, entry.name))) + break + + if path in warn and entry.name not in insecure_rpaths: + self.warnings.append(("insecure-runpath %s %s", + (path, entry.name))) + + +# vim: set ts=4 sw=4 noet: diff --git a/namcap-tags b/namcap-tags index 84cc3f7..1f7bc69 100644 --- a/namcap-tags +++ b/namcap-tags @@ -44,6 +44,7 @@ incorrect-owner %s (%s:%s) :: File (%s) is owned by %s:%s invalid-filename :: File name %s contains non standard characters info-dir-file-present %s :: Info directory file (%s) should not be present insecure-rpath %s %s :: Insecure RPATH '%s' in file ('%s') +insecure-runpath %s %s :: Insecure RUNPATH '%s' in file ('%s') libtool-file-present %s :: File (%s) is a libtool file library-no-package-associated %s :: Referenced library '%s' is an uninstalled dependency link-level-dependence %s in %s :: Link-level dependence (%s) in file %s diff --git a/namcap.1 b/namcap.1 index fcea8ed..9243087 100644 --- a/namcap.1 +++ b/namcap.1 @@ -108,6 +108,9 @@ Checks basic file and and directory permissions. It returns warnings about worl .B rpath Gives an error if a binary has RPATH set to something other than /usr/lib .TP +.B runpath +Gives an error if a binary has RUNPATH set to something other than /usr/lib, /usr/lib32 +.TP .B scrollkeeper Verifies that there aren't any scrollkeeper directories .TP