Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions test/tools/donate_cpu_lib_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import io
import tarfile

from donate_cpu_lib import *

def _test_library_includes(tmpdir, libs, content, libinc_obj=None):
Expand Down Expand Up @@ -66,3 +69,30 @@ def test_match_multiple_time(tmpdir):
# there was a bug that we would only match each library once successfully
_test_library_includes(tmpdir, ['posix', 'gnu', 'bsd', 'zlib'], '#include <zlib.h>', libinc)
_test_library_includes(tmpdir, ['posix', 'gnu', 'bsd', 'zlib'], '#include <zlib.h>', libinc)

def _add_tar_member(tf, name, linkname=None):
info = tarfile.TarInfo(name)
data = b''
if linkname is not None:
info.type = tarfile.SYMTYPE
info.linkname = linkname
else:
data = b'int x;\n'
info.size = len(data)
tf.addfile(info, io.BytesIO(data))

def test_unpack_package_outside_temp(tmpdir):
work_path = str(tmpdir)
outside_path = os.path.join(work_path, 'outside')
os.mkdir(outside_path)
tgz = os.path.join(work_path, 'temp.tgz')
with tarfile.open(tgz, 'w:gz') as tf:
_add_tar_member(tf, 'pkg/main.c')
_add_tar_member(tf, 'pkg/../../outside/dotdot.c')
_add_tar_member(tf, 'pkg/inc.h', linkname=outside_path)
_add_tar_member(tf, 'pkg/inc.h/symlink.c')

temp_path, source_found = unpack_package(work_path, tgz)
assert source_found
assert os.path.isfile(os.path.join(temp_path, 'pkg', 'main.c'))
assert os.listdir(outside_path) == []
28 changes: 24 additions & 4 deletions tools/donate_cpu_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
# Version scheme (MAJOR.MINOR.PATCH) should orientate on "Semantic Versioning" https://semver.org/
# Every change in this script should result in increasing the version number accordingly (exceptions may be cosmetic
# changes)
CLIENT_VERSION = "1.4.0"
CLIENT_VERSION = "1.4.1"

# Timeout for analysis with Cppcheck in seconds
CPPCHECK_TIMEOUT = 30 * 60
Expand Down Expand Up @@ -344,10 +344,19 @@ def download_package(work_path, package, bandwidth_limit):
return destfile


def __is_inside_path(base_path, path):
try:
return os.path.commonpath([base_path, path]) == base_path
except ValueError:
# paths are on different drives
return False


def unpack_package(work_path, tgz, cpp_only=False, c_only=False, skip_files=None):
temp_path = os.path.join(work_path, 'temp')
__remove_tree(temp_path)
os.mkdir(temp_path)
real_temp_path = os.path.realpath(temp_path)

header_endings = ('.hpp', '.h++', '.hxx', '.hh', '.h')
cpp_source_endings = ('.cpp', '.c++', '.cxx', '.cc', '.tpp', '.txx', '.ipp', '.ixx', '.qml')
Expand All @@ -367,10 +376,19 @@ def unpack_package(work_path, tgz, cpp_only=False, c_only=False, skip_files=None
total = 0
extracted = 0
skipped = 0
# Python versions with extraction filters reject members that leave temp_path as well
extract_args = {'filter': 'data'} if hasattr(tarfile, 'data_filter') else {}
for member in tf:
total += 1
if member.name.startswith(('/', '..')):
# Skip dangerous file names
member_path = os.path.realpath(os.path.join(temp_path, member.name))
link_path = None
if member.issym():
link_path = os.path.realpath(os.path.join(os.path.dirname(member_path), member.linkname))
elif member.islnk():
link_path = os.path.realpath(os.path.join(temp_path, member.linkname))
if not __is_inside_path(real_temp_path, member_path) or \
(link_path is not None and not __is_inside_path(real_temp_path, link_path)):
# Skip dangerous file names and links pointing outside of temp_path
# print('skipping dangerous file: ' + member.name)
skipped += 1
continue
Expand All @@ -388,14 +406,16 @@ def unpack_package(work_path, tgz, cpp_only=False, c_only=False, skip_files=None
skipped += 1
continue
try:
tf.extract(member.name, temp_path)
tf.extract(member.name, temp_path, **extract_args)
if is_source:
source_found = True
extracted += 1
except OSError:
pass
except AttributeError:
pass
except tarfile.TarError:
pass
print('extracted {} of {} files (skipped {}{})'.format(extracted, total, skipped, (' / only headers' if (extracted and not source_found) else '')))
return temp_path, source_found

Expand Down
Loading