Exemplo n.º 1
0
 def __init__(self, src, dst):
     self._src = src
     self._dst = dst
     self._header = FileHeader(src)
     self._is_binary = None
     self._content = None
     self._has_zero = None
Exemplo n.º 2
0
 def __init__(self, src, dst):
     self._src = src
     self._dst = dst
     self._header = FileHeader(src)
     self._is_binary = None
     self._content = None
     self._has_zero = None
Exemplo n.º 3
0
class InstallFile(object):
    def __init__(self, src, dst):
        self._src = src
        self._dst = dst
        self._header = FileHeader(src)
        self._is_binary = None
        self._content = None
        self._has_zero = None

    def is_binary(self):
        if self._is_binary is None:
            self._is_binary = self._header.is_binary()
        return self._is_binary

    def has_zero(self):
        if self._has_zero is None:
            self._has_zero = b'\0' in self.content()
        return self._has_zero

    def _make_user_rw(self, filename):
        st = os.stat(filename)
        os.chmod(filename, st.st_mode | stat.S_IREAD | stat.S_IWRITE)

    def copy(self):
        shutil.copy2(self._src, self._dst)
        self._make_user_rw(self._dst)

    def content(self):
        if self._content is None:
            with open(self._src, 'rb') as f:
                self._content = f.read()
        return self._content

    def find(self, marker):
        content = self.content()
        start = 0
        while True:
            start = content.find(marker, start)
            if start == -1:
                return
            yield start
            start += len(marker)  # cannot have overlapping markers

    def find_terminators(self, marker):
        """
        Find positions of marker in the file
        
        Returns:
            dict: the keys are the terminators (byte after the marker, see ``ALL_TERMINATORS``) and
            the corresponding value is a tuple of start indices. Lists the start indices of the
            marker with the given terminator.
        """
        result = dict()
        binary_terminator = False
        text_terminator = False
        for start in self.find(marker):
            term = self._find_terminator(marker, start, ALL_TERMINATORS)
            result[term] = result.get(term, ()) + (start, )
            if term is None:
                continue
            binary_terminator = binary_terminator or (
                term in BINARY_PATH_TERMINATORS)
            text_terminator = text_terminator or (term
                                                  in TEXT_PATH_TERMINATORS)
        if self.is_binary() and text_terminator and not binary_terminator:
            log.warn('Suspicious text terminators {0} in {1}'.format(
                list(result.keys()), self._src))
        if not self.is_binary() and not self.has_zero() and binary_terminator:
            log.warn('Suspicious binary terminators {0} in {1}'.format(
                list(result.keys()), self._src))
        if self.has_zero() and text_terminator and not binary_terminator:
            # The rpath can be /foo:/marker:/usr/lib, for example in gp
            log.warn('Contains zero-terminated strings but marker is not: {0}'.
                     format(self._src))
            # Pretend that we found zero terminators, see :meth:`find_patch`
            result[b'\0'] = tuple()
        return result

    def _find_terminator(self, marker, start, terminators):
        content = self.content()
        end = start + len(marker)
        assert content[start:end] == marker
        pos = end
        while pos < len(content):
            ch = content[pos:pos + 1]
            # print(pos, ch)
            if ch not in PATH_CHARS:
                if ch not in terminators:
                    log.error('At {0}'.format(content[start:pos + 1]))
                    log.error('path terminator {0} not allowed in {1}'.format(
                        ch, self._src))
                    raise SystemExit('invalid string terminator')
                # print('terminator')
                return ch
            pos += 1
        return None

    def find_zero_terminated(self, marker):
        """
        Returns pairs (start, end) of zero-terminated strings to search& replace
        """
        content = self.content()
        start = 0
        while True:
            start = content.find(marker, start)
            if start == -1:
                return
            end = start + len(marker)
            while end < len(content) and content[end:end + 1] != b'\0':
                end += 1
            yield (start, end)
            start = end + 1

    def find_patch(self, marker):
        occurences = self.find_terminators(marker)
        if not occurences:
            return
        if b'\0' in occurences.keys():
            return [
                BinaryPatch(start, end)
                for start, end in self.find_zero_terminated(marker)
            ]
        else:
            return SearchReplacePatch()
Exemplo n.º 4
0
class InstallFile(object):

    def __init__(self, src, dst):
        self._src = src
        self._dst = dst
        self._header = FileHeader(src)
        self._is_binary = None
        self._content = None
        self._has_zero = None

    def is_binary(self):
        if self._is_binary is None:
            self._is_binary = self._header.is_binary()
        return self._is_binary

    def has_zero(self):
        if self._has_zero is None:
            self._has_zero = b'\0' in self.content()
        return self._has_zero

    def _make_user_rw(self, filename):
        st = os.stat(filename)
        os.chmod(filename, st.st_mode | stat.S_IREAD | stat.S_IWRITE )
    
    def copy(self):
        shutil.copy2(self._src, self._dst)
        self._make_user_rw(self._dst)

    def content(self):
        if self._content is None:
            with open(self._src, 'rb') as f:
                self._content = f.read()
        return self._content
        
    def find(self, marker):
        content = self.content()
        start = 0
        while True:
            start = content.find(marker, start)
            if start == -1:
                raise StopIteration
            yield start
            start += len(marker)   # cannot have overlapping markers

    def find_terminators(self, marker):
        result = dict()
        binary_terminator = False
        text_terminator = False
        for start in self.find(marker):
            term = self._find_terminator(marker, start, ALL_TERMINATORS)
            result[term] = result.get(term, ()) + (start,)
            if term is None:
                continue
            binary_terminator = binary_terminator or (term in BINARY_PATH_TERMINATORS)
            text_terminator = text_terminator or (term in TEXT_PATH_TERMINATORS)
        if self.is_binary() and text_terminator and not binary_terminator:
            log.warn('Suspicious text terminators {0} in {1}'.format(
                list(result.keys()), self._src))
        if not self.is_binary() and not self.has_zero() and binary_terminator:
            log.warn('Suspicious binary terminators {0} in {1}'.format(
                list(result.keys()), self._src))
        if self.has_zero() and text_terminator and not binary_terminator:
            # The rpath can be /foo:/marker:/usr/lib, for example in gp
            log.warn('Contains zero-terminated strings but marker is not: {0}'
                     .format(self._src))
            return dict()
        return result
            
    def _find_terminator(self, marker, start, terminators):
        content = self.content()
        end = start + len(marker)
        assert content[start:end] == marker
        pos = end
        while pos < len(content):
            ch = content[pos:pos+1]
            # print(pos, ch)
            if ch not in PATH_CHARS:
                if ch not in terminators:
                    log.error('At {0}'.format(content[start:pos+1]))
                    log.error('path terminator {0} not allowed in {1}'.format(ch, self._src))
                    raise SystemExit('invalid string terminator')
                # print('terminator')
                return ch
            pos += 1
        return None
        
    def find_zero_terminated(self, marker):
        """
        Returns pairs (start, end) of zero-terminated strings to search& replace
        """
        content = self.content()
        start = 0
        while True:
            start = content.find(marker, start)
            if start == -1:
                raise StopIteration
            end = start + len(marker)
            while end < len(content) and content[end:end+1] != b'\0':
                end += 1
            yield (start, end)
            start = end+1

    def find_patch(self, marker):
        occurences = self.find_terminators(marker)
        if not occurences:
            return
        if b'\0' in occurences.keys():
            return [BinaryPatch(start, end)
                    for start, end in self.find_zero_terminated(marker)]
        else:
            return SearchReplacePatch()