From fb1e8ec73b0946cfd90a0de125e8453aa30c80f6 Mon Sep 17 00:00:00 2001 From: Oliver Smith Date: Fri, 23 Jun 2017 17:04:49 +0200 Subject: [PATCH] Update min apk version/add more apk version checks * Minimum version: 2.7.2 (which fixes two CVEs) * Check the minimum apk version before doing something with apk and before entering the chroot manually (previously, it has just checked the apk-tools-static version, which gets used to set up the chroot) * Reword the message for an outdated APK version. Most likely it is just the outdated http cache, instead of a man-in-the-middle attack. See also: https://github.com/alpinelinux/aports/commit/b849b481a0446d7ef2458232a8819ce0b301e629 --- pmb/chroot/apk.py | 32 +++++++++++++++++++++++++++++++- pmb/chroot/apk_static.py | 10 +++++----- pmb/config/__init__.py | 2 +- pmb/parse/arguments.py | 2 +- pmbootstrap.py | 1 + 5 files changed, 39 insertions(+), 8 deletions(-) diff --git a/pmb/chroot/apk.py b/pmb/chroot/apk.py index 30f9a92d..dde27c29 100644 --- a/pmb/chroot/apk.py +++ b/pmb/chroot/apk.py @@ -18,10 +18,36 @@ along with pmbootstrap. If not, see . """ import logging import pmb.chroot +import pmb.config import pmb.parse.apkindex import pmb.parse.other +def check_min_version(args, suffix="native"): + """ + Check the minimum apk version, before running it the first time in the + current session (lifetime of one pmbootstrap call). + """ + # Skip if we already did this + if suffix in args.cache["apk_min_version_checked"]: + return + + # Read the version from apk and from the config + pkgver = pmb.chroot.root(args, ["apk", "--version"], suffix, + return_stdout=True) + pkgver = pkgver.split(" ")[1].split(",")[0] + pkgver_min = pmb.config.apk_tools_static_min_version.split("-")[0] + + # Compare + if pmb.parse.apkindex.compare_version(pkgver, pkgver_min) == -1: + raise RuntimeError("You have an outdated version of the 'apk' package" + " manager installed (your version: " + pkgver + + ", expected at least: " + pkgver_min + "). Delete" + " your http cache and zap all chroots, then try again:" + " 'pmbootstrap zap -hc'") + args.cache["apk_min_version_checked"].append(suffix) + + def install(args, packages, suffix="native", build=True): """ :param build: automatically build the package, when it does not exist yet @@ -30,6 +56,7 @@ def install(args, packages, suffix="native", build=True): False! """ # Initialize chroot + check_min_version(args, suffix) pmb.chroot.init(args, suffix) # Filter already installed packages @@ -63,6 +90,7 @@ def upgrade(args, suffix="native", update_index=True): """ Upgrade all packages installed in a chroot """ + check_min_version(args, suffix) pmb.chroot.init(args, suffix) if update_index: pmb.chroot.root(args, ["apk", "update"], suffix) @@ -77,9 +105,11 @@ def installed(args, suffix="native"): :returns: { "hello-world": {"package": "hello-world-1-r2", "pkgrel": "2", "pkgver": "1", "pkgname": "hello-world"}, ...} """ - ret = {} + check_min_version(args, suffix) list = pmb.chroot.user(args, ["apk", "info", "-vv"], suffix, return_stdout=True) + # Parse the output into a dictionary + ret = {} for line in list.split("\n"): if not line.rstrip(): continue diff --git a/pmb/chroot/apk_static.py b/pmb/chroot/apk_static.py index 9fc99a0e..cfc99031 100644 --- a/pmb/chroot/apk_static.py +++ b/pmb/chroot/apk_static.py @@ -163,11 +163,11 @@ def init(args): version_min = pmb.config.apk_tools_static_min_version apk_name = "apk-tools-static-" + version + ".apk" if pmb.parse.apkindex.compare_version(version, version_min) == -1: - raise RuntimeError("Server provides an outdated version of" - " apk-tools-static: " + version + - " (expected at least " + version_min + - "). Looks like a downgrade attack from a" - " malicious server! Switch the server (-m) and try again!") + raise RuntimeError("You have an outdated version of apk-tools-static" + " (your version: " + version + + ", expected at least:" + " " + version_min + "). Delete your http cache and zap" + " all chroots, then try again: 'pmbootstrap zap -hc'") apk_static = download(args, apk_name) extract(args, version, apk_static) diff --git a/pmb/config/__init__.py b/pmb/config/__init__.py index bbcdbf71..e4caef2d 100644 --- a/pmb/config/__init__.py +++ b/pmb/config/__init__.py @@ -36,7 +36,7 @@ apk_keys_path = pmb_src + "/keys" # Update this frequently to prevent a MITM attack with an outdated version # (which may contain a vulnerable apk/libressl, and allows an attacker to # exploit the system!) -apk_tools_static_min_version = "2.7.1-r0" +apk_tools_static_min_version = "2.7.2-r0" # Config file/commandline default values # $WORK gets replaced with the actual value for args.work (which may be diff --git a/pmb/parse/arguments.py b/pmb/parse/arguments.py index 57641ad4..8fe4f2a4 100644 --- a/pmb/parse/arguments.py +++ b/pmb/parse/arguments.py @@ -201,7 +201,7 @@ def arguments(): setattr(args, "arch_native", pmb.parse.arch.alpine_native()) # Add a caching dict - setattr(args, "cache", {"apkindex": {}}) + setattr(args, "cache", {"apkindex": {}, "apk_min_version_checked": []}) # Add and verify the deviceinfo (only after initialization) if args.action != "init": diff --git a/pmbootstrap.py b/pmbootstrap.py index 1366ca79..b52b2626 100755 --- a/pmbootstrap.py +++ b/pmbootstrap.py @@ -66,6 +66,7 @@ def main(): elif args.action == "checksum": pmb.build.checksum(args, args.package) elif args.action == "chroot": + pmb.chroot.apk.check_min_version(args, args.suffix) pmb.chroot.root(args, args.command, args.suffix, log=False) elif args.action == "index": pmb.build.index_repo(args)