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:
b849b481a0
This commit is contained in:
Oliver Smith 2017-06-23 17:04:49 +02:00
parent f547ff5c6e
commit fb1e8ec73b
No known key found for this signature in database
GPG Key ID: 5AE7F5513E0885CB
5 changed files with 39 additions and 8 deletions

View File

@ -18,10 +18,36 @@ along with pmbootstrap. If not, see <http://www.gnu.org/licenses/>.
""" """
import logging import logging
import pmb.chroot import pmb.chroot
import pmb.config
import pmb.parse.apkindex import pmb.parse.apkindex
import pmb.parse.other 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): def install(args, packages, suffix="native", build=True):
""" """
:param build: automatically build the package, when it does not exist yet :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! False!
""" """
# Initialize chroot # Initialize chroot
check_min_version(args, suffix)
pmb.chroot.init(args, suffix) pmb.chroot.init(args, suffix)
# Filter already installed packages # Filter already installed packages
@ -63,6 +90,7 @@ def upgrade(args, suffix="native", update_index=True):
""" """
Upgrade all packages installed in a chroot Upgrade all packages installed in a chroot
""" """
check_min_version(args, suffix)
pmb.chroot.init(args, suffix) pmb.chroot.init(args, suffix)
if update_index: if update_index:
pmb.chroot.root(args, ["apk", "update"], suffix) 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", :returns: { "hello-world": {"package": "hello-world-1-r2", "pkgrel": "2",
"pkgver": "1", "pkgname": "hello-world"}, ...} "pkgver": "1", "pkgname": "hello-world"}, ...}
""" """
ret = {} check_min_version(args, suffix)
list = pmb.chroot.user(args, ["apk", "info", "-vv"], suffix, list = pmb.chroot.user(args, ["apk", "info", "-vv"], suffix,
return_stdout=True) return_stdout=True)
# Parse the output into a dictionary
ret = {}
for line in list.split("\n"): for line in list.split("\n"):
if not line.rstrip(): if not line.rstrip():
continue continue

View File

@ -163,11 +163,11 @@ def init(args):
version_min = pmb.config.apk_tools_static_min_version version_min = pmb.config.apk_tools_static_min_version
apk_name = "apk-tools-static-" + version + ".apk" apk_name = "apk-tools-static-" + version + ".apk"
if pmb.parse.apkindex.compare_version(version, version_min) == -1: if pmb.parse.apkindex.compare_version(version, version_min) == -1:
raise RuntimeError("Server provides an outdated version of" raise RuntimeError("You have an outdated version of apk-tools-static"
" apk-tools-static: " + version + " (your version: " + version +
" (expected at least " + version_min + ", expected at least:"
"). Looks like a downgrade attack from a" " " + version_min + "). Delete your http cache and zap"
" malicious server! Switch the server (-m) and try again!") " all chroots, then try again: 'pmbootstrap zap -hc'")
apk_static = download(args, apk_name) apk_static = download(args, apk_name)
extract(args, version, apk_static) extract(args, version, apk_static)

View File

@ -36,7 +36,7 @@ apk_keys_path = pmb_src + "/keys"
# Update this frequently to prevent a MITM attack with an outdated version # Update this frequently to prevent a MITM attack with an outdated version
# (which may contain a vulnerable apk/libressl, and allows an attacker to # (which may contain a vulnerable apk/libressl, and allows an attacker to
# exploit the system!) # 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 # Config file/commandline default values
# $WORK gets replaced with the actual value for args.work (which may be # $WORK gets replaced with the actual value for args.work (which may be

View File

@ -201,7 +201,7 @@ def arguments():
setattr(args, "arch_native", pmb.parse.arch.alpine_native()) setattr(args, "arch_native", pmb.parse.arch.alpine_native())
# Add a caching dict # Add a caching dict
setattr(args, "cache", {"apkindex": {}}) setattr(args, "cache", {"apkindex": {}, "apk_min_version_checked": []})
# Add and verify the deviceinfo (only after initialization) # Add and verify the deviceinfo (only after initialization)
if args.action != "init": if args.action != "init":

View File

@ -66,6 +66,7 @@ def main():
elif args.action == "checksum": elif args.action == "checksum":
pmb.build.checksum(args, args.package) pmb.build.checksum(args, args.package)
elif args.action == "chroot": elif args.action == "chroot":
pmb.chroot.apk.check_min_version(args, args.suffix)
pmb.chroot.root(args, args.command, args.suffix, log=False) pmb.chroot.root(args, args.command, args.suffix, log=False)
elif args.action == "index": elif args.action == "index":
pmb.build.index_repo(args) pmb.build.index_repo(args)