From 5d161cc9fd3c5b2a00252cb6d28d7e0e8e2bdc85 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Sat, 1 Sep 2018 12:08:37 +0200 Subject: [PATCH 1/4] validate appid when reading metadata files The metadata file must be named after the Application ID of the app it is describing, and Android Application IDs must be valid Java Package Names. --- fdroidserver/common.py | 14 +++++++++++++- fdroidserver/metadata.py | 3 +++ tests/common.TestCase | 18 ++++++++++++++++-- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/fdroidserver/common.py b/fdroidserver/common.py index 55cb2b65..acccf63a 100644 --- a/fdroidserver/common.py +++ b/fdroidserver/common.py @@ -1518,7 +1518,19 @@ def parse_androidmanifests(paths, app): def is_valid_package_name(name): - return re.match("[A-Za-z_][A-Za-z_0-9.]+$", name) + """Check whether name is a valid fdroid package name + + APKs and manually defined package names must use a valid Java + Package Name. Automatically generated package names for non-APK + files use the SHA-256 sum. + + """ + return re.match("^([a-f0-9]+|[A-Za-z_][A-Za-z_0-9.]+)$", name) + + +def is_valid_java_package_name(name): + """Check whether name is a valid Java package name aka Application ID""" + return re.match("^[A-Za-z_][A-Za-z_0-9.]+$", name) def getsrclib(spec, srclib_dir, subdir=None, basepath=False, diff --git a/fdroidserver/metadata.py b/fdroidserver/metadata.py index 02e7bc3d..273ecb80 100644 --- a/fdroidserver/metadata.py +++ b/fdroidserver/metadata.py @@ -805,6 +805,9 @@ def read_metadata(xref=True, check_vcs=[], refresh=True, sort_by_time=False): if metadatapath == '.fdroid.txt': warn_or_exception(_('.fdroid.txt is not supported! Convert to .fdroid.yml or .fdroid.json.')) appid, _ignored = fdroidserver.common.get_extension(os.path.basename(metadatapath)) + if appid != '.fdroid' and not fdroidserver.common.is_valid_package_name(appid): + warn_or_exception(_("{appid} from {path} is not a valid Java Package Name!") + .format(appid=appid, path=metadatapath)) if appid in apps: warn_or_exception(_("Found multiple metadata files for {appid}") .format(appid=appid)) diff --git a/tests/common.TestCase b/tests/common.TestCase index 1c75a411..ef614a56 100755 --- a/tests/common.TestCase +++ b/tests/common.TestCase @@ -158,9 +158,10 @@ class CommonTest(unittest.TestCase): self.assertFalse(debuggable, "debuggable APK state was not properly parsed!") - def testPackageNameValidity(self): + def test_is_valid_package_name(self): for name in ["org.fdroid.fdroid", - "org.f_droid.fdr0ID"]: + "org.f_droid.fdr0ID", + "05041684efd9b16c2888b1eddbadd0359f655f311b89bdd1737f560a10d20fb8"]: self.assertTrue(fdroidserver.common.is_valid_package_name(name), "{0} should be a valid package name".format(name)) for name in ["0rg.fdroid.fdroid", @@ -170,6 +171,19 @@ class CommonTest(unittest.TestCase): self.assertFalse(fdroidserver.common.is_valid_package_name(name), "{0} should not be a valid package name".format(name)) + def test_is_valid_java_package_name(self): + for name in ["org.fdroid.fdroid", + "org.f_droid.fdr0ID"]: + self.assertTrue(fdroidserver.common.is_valid_java_package_name(name), + "{0} should be a valid package name".format(name)) + for name in ["0rg.fdroid.fdroid", + ".f_droid.fdr0ID", + "org.fdroid/fdroid", + "/org.fdroid.fdroid", + "05041684efd9b16c2888b1eddbadd0359f655f311b89bdd1737f560a10d20fb8"]: + self.assertFalse(fdroidserver.common.is_valid_java_package_name(name), + "{0} should not be a valid package name".format(name)) + def test_prepare_sources(self): testint = 99999999 teststr = 'FAKE_STR_FOR_TESTING' From 11b3e5be3a30ced6377eb76ff455697445a33db0 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Sat, 1 Sep 2018 12:19:45 +0200 Subject: [PATCH 2/4] update: throw exception for APKs with invalid Application ID Android Application IDs must be valid Java Package Names. While the build tools likely validate the Application ID, it is possible to manually create a malicious APK. --- fdroidserver/common.py | 2 +- fdroidserver/update.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/fdroidserver/common.py b/fdroidserver/common.py index acccf63a..b07f080d 100644 --- a/fdroidserver/common.py +++ b/fdroidserver/common.py @@ -1511,7 +1511,7 @@ def parse_androidmanifests(paths, app): if max_version is None: max_version = "Unknown" - if max_package and not is_valid_package_name(max_package): + if max_package and not is_valid_java_package_name(max_package): raise FDroidException(_("Invalid package name {0}").format(max_package)) return (max_version, max_vercode, max_package) diff --git a/fdroidserver/update.py b/fdroidserver/update.py index a760a078..635f48ee 100644 --- a/fdroidserver/update.py +++ b/fdroidserver/update.py @@ -1064,6 +1064,10 @@ def scan_apk(apk_file): else: scan_apk_aapt(apk, apk_file) + if not common.is_valid_java_package_name(apk['packageName']): + raise BuildException(_("{appid} from {path} is not a valid Java Package Name!") + .format(appid=apk['packageName'], path=apk_file)) + # Get the signature, or rather the signing key fingerprints logging.debug('Getting signature of {0}'.format(os.path.basename(apk_file))) apk['sig'] = getsig(apk_file) From cf4c9cb4ee1fe4b0b21e98112fd3066f702f936c Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 3 Sep 2018 22:42:31 +0200 Subject: [PATCH 3/4] buildserver now needs python3-defusedxml 4d13a904f3877ff2502b619df3b9f8f714024698 means that defusedxml is required to be installed on the buildserver guest. --- buildserver/provision-apt-get-install | 1 + 1 file changed, 1 insertion(+) diff --git a/buildserver/provision-apt-get-install b/buildserver/provision-apt-get-install index c6b40e5e..8702c7de 100644 --- a/buildserver/provision-apt-get-install +++ b/buildserver/provision-apt-get-install @@ -89,6 +89,7 @@ packages=" python-lxml python-magic python-setuptools + python3-defusedxml python3-git/jessie-backports python3-gitdb/jessie-backports python3-gnupg From 9bccb2c73e6b31de4c62eeef29442029d07893b4 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 3 Sep 2018 23:02:31 +0200 Subject: [PATCH 4/4] temp fallback to built-in ElementTree if defusedxml is not there --- fdroidserver/common.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fdroidserver/common.py b/fdroidserver/common.py index b07f080d..ad056937 100644 --- a/fdroidserver/common.py +++ b/fdroidserver/common.py @@ -39,7 +39,12 @@ import base64 import zipfile import tempfile import json -import defusedxml.ElementTree as XMLElementTree + +# TODO change to only import defusedxml once its installed everywhere +try: + import defusedxml.ElementTree as XMLElementTree +except ImportError: + import xml.etree.ElementTree as XMLElementTree # nosec this is a fallback only from binascii import hexlify from datetime import datetime, timedelta