--- portage.py 2005-02-07 19:31:24.000000000 +0000 +++ /usr/lib/portage/pym/portage.py 2005-02-09 19:17:32.000000000 +0000 @@ -6082,6 +6082,7 @@ self.updateprotect() + nlinkobjs=[] #process symlinks second-to-last, directories last. mydirs=[] mysyms=[] @@ -6108,6 +6109,7 @@ lstatobj=os.lstat(obj) lmtime=str(lstatobj[stat.ST_MTIME]) + lmode=lstatobj[stat.ST_MODE] if (pkgfiles[obj][0] not in ("dir","fif","dev","sym")) and (lmtime != pkgfiles[obj][1]): print "--- !mtime", pkgfiles[obj][0], obj continue @@ -6128,6 +6130,11 @@ continue mymd5=portage_checksum.perform_md5(obj, calc_prelink=1) + # keep track of suid/sgid binaries with multiple links + if lmode & stat.S_ISUID or lmode & stat.S_ISGID: + if lstatobj[stat.ST_NLINK] > 1: + nlinkobjs.append(obj) + # string.lower is needed because db entries used to be in upper-case. The # string.lower allows for backwards compatibility. if mymd5 != string.lower(pkgfiles[obj][2]): @@ -6281,6 +6288,11 @@ writemsg("!!! FAILED postrm: "+str(a)+"\n") sys.exit(123) + if nlinkobjs: + for x in nlinkobjs: + print red("*"), "WARNING: suid/sgid file", x, "has remaining hardlinks." + print red("*"), "WARNING: see gentoo security guide for advice on how to proceed." + self.unlockdb() def isowner(self,filename,destroot): @@ -6553,6 +6565,9 @@ else: mergelist=stufftomerge offset="" + # nlinkdest lists suid/sgid files that have multiple hardlinks. + # this is for security purposes. + nlinkdest=[] for x in mergelist: mysrc=os.path.normpath("///"+srcroot+offset+x) mydest=os.path.normpath("///"+destroot+offset+x) @@ -6587,13 +6602,14 @@ # handy variables; mydest is the target object on the live filesystems; # mysrc is the source object in the temporary install dir try: - mydmode=os.lstat(mydest)[stat.ST_MODE] + mydstat=os.lstat(mydest) + mydmode=mydstat[stat.ST_MODE] except SystemExit, e: raise except: #dest file doesn't exist mydmode=None - + if stat.S_ISLNK(mymode): # we are merging a symbolic link myabsto=abssymlink(mysrc) @@ -6809,6 +6825,12 @@ os.utime(myrealdest,(thismtime,thismtime)) if mymtime!=None: + # check if we're replacing a suid/sgid file with + # more than one hardlink for security reasons. + if mydmode: + if mydmode & stat.S_ISUID or mydmode & stat.S_ISGID: + if mydstat[stat.ST_NLINK] > 1: + nlinkdest.append(myrealdest) zing=">>>" outfile.write("obj "+myrealdest+" "+mymd5+" "+str(mymtime)+"\n") print zing,mydest @@ -6826,6 +6848,10 @@ else: sys.exit(1) print zing+" "+mydest + if nlinkdest: + for x in nlinkdest: + print red("*"), "WARNING: replaced suid/sgid file", x, "had remaining hardlinks." + print red("*"), "WARNING: see gentoo security guide for advice on how to proceed." def merge(self,mergeroot,inforoot,myroot,myebuild=None,cleanup=0): return self.treewalk(mergeroot,myroot,inforoot,myebuild,cleanup=cleanup)