chiark / gitweb /
check all APKs for old versions of OpenSSL
authorHans-Christoph Steiner <hans@eds.org>
Thu, 3 Nov 2016 13:14:08 +0000 (14:14 +0100)
committerHans-Christoph Steiner <hans@eds.org>
Mon, 5 Dec 2016 19:16:54 +0000 (20:16 +0100)
This scans all APKs for old versions of OpenSSL libraries that are known to
be vulnerable to issues, or fully unsupported.

This really should be implemented as a per-APK AntiFeature, so that it can
apply to any version that is vulnerable.  Since AntiFeatures are currently
only per-App, this instead sets the AntiFeature only if the latest APK is
vulnerable.

Google also enforces this:
https://support.google.com/faqs/answer/6376725?hl=en

apk['antiFeatures'] has the first letter small, since all build fields
start with a lowercase letter.  app.AntiFeatures has the first
uppercase since all App fields are that way.

fdroidserver/metadata.py
fdroidserver/update.py
wp-fdroid/wp-fdroid.php

index 986d240ad9021ae6595454cdb9d224923f8d248d..a48f48c16ecb71a2d5d22723df31866edc2e9fae 100644 (file)
@@ -499,7 +499,7 @@ valuetypes = {
                    []),
 
     FieldValidator("Anti-Feature",
-                   r'^(Ads|Tracking|NonFreeNet|NonFreeDep|NonFreeAdd|UpstreamNonFree|NonFreeAssets)$',
+                   r'^(Ads|Tracking|NonFreeNet|NonFreeDep|NonFreeAdd|UpstreamNonFree|NonFreeAssets|KnownVuln)$',
                    ["AntiFeatures"],
                    []),
 
index fcf9c0929efb6bb1d6f5e0a01b8faa14ab969dc0..f18cf49a7d64e760afcf61ce31406c1fc46084d7 100644 (file)
@@ -440,6 +440,34 @@ def sha256sum(filename):
     return sha.hexdigest()
 
 
+def has_old_openssl(filename):
+    '''checks for known vulnerable openssl versions in the APK'''
+
+    # statically load this pattern
+    if not hasattr(has_old_openssl, "pattern"):
+        has_old_openssl.pattern = re.compile(b'.*OpenSSL ([01][0-9a-z.-]+)')
+
+    with zipfile.ZipFile(filename) as zf:
+        for name in zf.namelist():
+            if name.endswith('libcrypto.so') or name.endswith('libssl.so'):
+                lib = zf.open(name)
+                while True:
+                    chunk = lib.read(4096)
+                    if chunk == b'':
+                        break
+                    m = has_old_openssl.pattern.search(chunk)
+                    if m:
+                        version = m.group(1).decode('ascii')
+                        if version.startswith('1.0.1') and version[5] >= 'r' \
+                           or version.startswith('1.0.2') and version[5] >= 'f':
+                            logging.debug('"%s" contains recent %s (%s)', filename, name, version)
+                        else:
+                            logging.warning('"%s" contains outdated %s (%s)', filename, name, version)
+                            return True
+                        break
+    return False
+
+
 def insert_obbs(repodir, apps, apks):
     """Scans the .obb files in a given repo directory and adds them to the
     relevant APK instances.  OBB files have versionCodes like APK
@@ -639,6 +667,9 @@ def scan_apks(apkcache, repodir, knownapks, use_date_from_apk=False):
             apk['features'] = set()
             apk['icons_src'] = {}
             apk['icons'] = {}
+            apk['antiFeatures'] = set()
+            if has_old_openssl(apkfile):
+                apk['antiFeatures'].add('KnownVuln')
             p = SdkToolsPopen(['aapt', 'dump', 'badging', apkfile], output=False)
             if p.returncode != 0:
                 if options.delete_unknown:
@@ -1109,10 +1140,6 @@ def make_index(apps, sortedids, apks, repodir, archive, categories):
         addElement('marketversion', app.CurrentVersion, doc, apel)
         addElement('marketvercode', app.CurrentVersionCode, doc, apel)
 
-        if app.AntiFeatures:
-            af = app.AntiFeatures
-            if af:
-                addElementNonEmpty('antifeatures', ','.join(af), doc, apel)
         if app.Provides:
             pv = app.Provides.split(',')
             addElementNonEmpty('provides', ','.join(pv), doc, apel)
@@ -1123,6 +1150,11 @@ def make_index(apps, sortedids, apks, repodir, archive, categories):
         # doesn't have to do any work by default...
         apklist = sorted(apklist, key=lambda apk: apk['versioncode'], reverse=True)
 
+        if 'antiFeatures' in apklist[0]:
+            app.AntiFeatures.extend(apklist[0]['antiFeatures'])
+        if app.AntiFeatures:
+            addElementNonEmpty('antifeatures', ','.join(app.AntiFeatures), doc, apel)
+
         # Check for duplicates - they will make the client unhappy...
         for i in range(len(apklist) - 1):
             if apklist[i]['versioncode'] == apklist[i + 1]['versioncode']:
index 4d62f0b8a9b1d42a6608715c2a2842e183dcc31b..f225232fceab26026113c8c8d974551b114ea87e 100644 (file)
@@ -695,6 +695,8 @@ class FDroid
                $antifeatureDescription['UpstreamNonFree']['description'] = 'The upstream source code is non-free.';
                $antifeatureDescription['NonFreeAssets']['name'] = 'Non-Free Assets';
                $antifeatureDescription['NonFreeAssets']['description'] = 'This application contains non-free assets.';
+               $antifeatureDescription['KnownVuln']['name'] = 'Known Vulnerability';
+               $antifeatureDescription['KnownVuln']['description'] = 'This application known security vulnerabilities.';
 
                if(isset($antifeatureDescription[$antifeature])) {
                        return $antifeatureDescription[$antifeature];