summaryrefslogtreecommitdiffstats
path: root/pym
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2007-06-10 21:44:15 +0000
committerZac Medico <zmedico@gentoo.org>2007-06-10 21:44:15 +0000
commite209120b9862c490f7151d64c1b4ce0a82d95278 (patch)
treef031c918266e34efaccae8da97e9351d006b4039 /pym
parentccb58dbe01f8063f686ef2a686a460b8fe699b8a (diff)
downloadportage-e209120b9862c490f7151d64c1b4ce0a82d95278.tar.gz
portage-e209120b9862c490f7151d64c1b4ce0a82d95278.tar.bz2
portage-e209120b9862c490f7151d64c1b4ce0a82d95278.zip
For bug #81097, detect and report suspicious hardlinks to suid/sgid files. False positives are prevented by doing reference counts for each inode having suid/sgid bits and multiple hardlinks. The security check is done prior to each merge or unmerge phase and it will cause the phase to abort if a problem is found (so that the user can investigate before any files are removed).
svn path=/main/trunk/; revision=6792
Diffstat (limited to 'pym')
-rw-r--r--pym/portage/dbapi/vartree.py56
-rw-r--r--pym/portage/output.py1
2 files changed, 57 insertions, 0 deletions
diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py
index 5ddfc2f0f..73d2245f9 100644
--- a/pym/portage/dbapi/vartree.py
+++ b/pym/portage/dbapi/vartree.py
@@ -996,6 +996,17 @@ class dblink(object):
before and after this method.
"""
+ # When new_contents is supplied, the security check has already been
+ # done for this slot, so it shouldn't be repeated until the next
+ # replacement or unmerge operation.
+ if new_contents is None:
+ slot = self.vartree.dbapi.aux_get(self.mycpv, ["SLOT"])[0]
+ slot_matches = self.vartree.dbapi.match(
+ "%s:%s" % (dep_getkey(self.mycpv), slot))
+ retval = self._security_check(slot_matches)
+ if retval:
+ return retval
+
contents = self.getcontents()
# Now, don't assume that the name of the ebuild is the same as the
# name of the dir; the package may have been moved.
@@ -1458,6 +1469,47 @@ class dblink(object):
except OSError:
pass
+ def _security_check(self, slot_matches):
+ if not slot_matches:
+ return 0
+ file_paths = set()
+ for cpv in slot_matches:
+ file_paths.update(dblink(self.cat, catsplit(cpv)[1],
+ self.vartree.root, self.settings,
+ vartree=self.vartree).getcontents())
+ inode_map = {}
+ for path in file_paths:
+ try:
+ s = os.lstat(path)
+ except OSError, e:
+ if e.errno != errno.ENOENT:
+ raise
+ del e
+ continue
+ if s.st_nlink > 1 and \
+ s.st_mode & (stat.S_ISUID | stat.S_ISGID):
+ k = (s.st_dev, s.st_ino)
+ inode_map.setdefault(k, []).append((path, s))
+ suspicious_hardlinks = []
+ for path_list in inode_map.itervalues():
+ path, s = path_list[0]
+ if len(path_list) == s.st_nlink:
+ # All hardlinks seem to be owned by this package.
+ continue
+ suspicious_hardlinks.append(path_list)
+ if not suspicious_hardlinks:
+ return 0
+ from portage.output import colorize
+ prefix = colorize("SECURITY_WARN", "*") + " WARNING: "
+ writemsg(prefix + "suid/sgid file(s) " + \
+ "with suspicious hardlink(s):\n", noiselevel=-1)
+ for path_list in suspicious_hardlinks:
+ for path, s in path_list:
+ writemsg(prefix + " '%s'\n" % path, noiselevel=-1)
+ writemsg(prefix + "See the Gentoo Security Handbook " + \
+ "guide for advice on how to proceed.\n", noiselevel=-1)
+ return 1
+
def treewalk(self, srcroot, destroot, inforoot, myebuild, cleanup=0,
mydbapi=None, prev_mtimes=None):
"""
@@ -1507,6 +1559,10 @@ class dblink(object):
slot_matches = self.vartree.dbapi.match(
"%s:%s" % (self.mysplit[0], self.settings["SLOT"]))
+ retval = self._security_check(slot_matches)
+ if retval:
+ return retval
+
if slot_matches:
# Used by self.isprotected().
max_cpv = None
diff --git a/pym/portage/output.py b/pym/portage/output.py
index 83ff3f1c2..deb8c548b 100644
--- a/pym/portage/output.py
+++ b/pym/portage/output.py
@@ -127,6 +127,7 @@ codes["BRACKET"] = codes["blue"]
# Portage functions
codes["INFORM"] = codes["darkgreen"]
codes["UNMERGE_WARN"] = codes["red"]
+codes["SECURITY_WARN"] = codes["red"]
codes["MERGE_LIST_PROGRESS"] = codes["yellow"]
def parse_color_map():