Rolling Back Packages on Ubuntu/Debian

Published: 2024-04-16
Last Updated: 2024-04-16 09:28:11 UTC
by Yee Ching Tok (Version: 1)
0 comment(s)

Package updates/upgrades by maintainers on the Linux platforms are always appreciated, as these updates are intended to offer new features/bug fixes. However, in rare circumstances, there is a need to downgrade the packages to a prior version due to unintended bugs or potential security issues, such as the recent xz-utils backdoor. Consistently backing up your data before significant updates is one good countermeasure against grief. However, what if one was not diligently practicing such measures and urgently needed to simply roll back to a prior version of the said package? I was recently put in this unenviable position when configuring one of my systems, and somehow, the latest version of Proton VPN (version 4.3.0) would not work and displayed the following output after I executed it:
 

Traceback (most recent call last):
  File "/usr/bin/protonvpn-app", line 33, in <module>
    sys.exit(load_entry_point('proton-vpn-gtk-app==4.3.0', 'console_scripts', 'protonvpn-app')())
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/bin/protonvpn-app", line 25, in importlib_load_entry_point
    return next(matches).load()
           ^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/importlib/metadata/__init__.py", line 202, in load
    module = import_module(match.group('module'))
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<frozen importlib._bootstrap>", line 1204, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1147, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 940, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/usr/lib/python3/dist-packages/proton/vpn/app/gtk/__main__.py", line 25, in <module>
    from proton.vpn.app.gtk.app import App
  File "/usr/lib/python3/dist-packages/proton/vpn/app/gtk/app.py", line 28, in <module>
    from proton.vpn.app.gtk.controller import Controller
  File "/usr/lib/python3/dist-packages/proton/vpn/app/gtk/controller.py", line 29, in <module>
    from proton.vpn.core.api import ProtonVPNAPI, VPNAccount
  File "/usr/lib/python3/dist-packages/proton/vpn/core/api.py", line 33, in <module>
    from proton.vpn.core.usage import UsageReporting, usage_reporting
  File "/usr/lib/python3/dist-packages/proton/vpn/core/usage.py", line 19, in <module>
    import sentry_sdk
  File "/usr/lib/python3/dist-packages/sentry_sdk/__init__.py", line 1, in <module>
    from sentry_sdk.hub import Hub, init
  File "/usr/lib/python3/dist-packages/sentry_sdk/hub.py", line 8, in <module>
    from sentry_sdk.scope import Scope
  File "/usr/lib/python3/dist-packages/sentry_sdk/scope.py", line 7, in <module>
    from sentry_sdk.attachments import Attachment
  File "/usr/lib/python3/dist-packages/sentry_sdk/attachments.py", line 5, in <module>
    from sentry_sdk.envelope import Item, PayloadRef
  File "/usr/lib/python3/dist-packages/sentry_sdk/envelope.py", line 7, in <module>
    from sentry_sdk.session import Session
  File "/usr/lib/python3/dist-packages/sentry_sdk/session.py", line 5, in <module>
    from sentry_sdk.utils import format_timestamp
  File "/usr/lib/python3/dist-packages/sentry_sdk/utils.py", line 1305, in <module>
    HAS_REAL_CONTEXTVARS, ContextVar = _get_contextvars()
                                       ^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/sentry_sdk/utils.py", line 1275, in _get_contextvars
    if not _is_contextvars_broken():
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/sentry_sdk/utils.py", line 1228, in _is_contextvars_broken
    from eventlet.patcher import is_monkey_patched  # type: ignore
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/eventlet/__init__.py", line 6, in <module>
    from eventlet import convenience
  File "/usr/lib/python3/dist-packages/eventlet/convenience.py", line 7, in <module>
    from eventlet.green import socket
  File "/usr/lib/python3/dist-packages/eventlet/green/socket.py", line 21, in <module>
    from eventlet.support import greendns
  File "/usr/lib/python3/dist-packages/eventlet/support/greendns.py", line 78, in <module>
    setattr(dns, pkg, import_patched('dns.' + pkg))
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/eventlet/support/greendns.py", line 60, in import_patched
    return patcher.import_patched(module_name, **modules)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/eventlet/patcher.py", line 132, in import_patched
    return inject(
           ^^^^^^^
  File "/usr/lib/python3/dist-packages/eventlet/patcher.py", line 109, in inject
    module = __import__(module_name, {}, {}, module_name.split('.')[:-1])
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/dns/asyncquery.py", line 32, in <module>
    import dns.quic
  File "/usr/lib/python3/dist-packages/dns/quic/__init__.py", line 37, in <module>
    import trio
  File "/usr/lib/python3/dist-packages/trio/__init__.py", line 22, in <module>
    from ._core import TASK_STATUS_IGNORED as TASK_STATUS_IGNORED  # isort: split
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/trio/_core/__init__.py", line 21, in <module>
    from ._local import RunVar, RunVarToken
  File "/usr/lib/python3/dist-packages/trio/_core/_local.py", line 9, in <module>
    from . import _run
  File "/usr/lib/python3/dist-packages/trio/_core/_run.py", line 2787, in <module>
    from ._io_epoll import (
  File "/usr/lib/python3/dist-packages/trio/_core/_io_epoll.py", line 202, in <module>
    class EpollIOManager:
  File "/usr/lib/python3/dist-packages/trio/_core/_io_epoll.py", line 203, in EpollIOManager
    _epoll: select.epoll = attr.ib(factory=select.epoll)
                                           ^^^^^^^^^^^^
AttributeError: module 'eventlet.green.select' has no attribute 'epoll'

I had to get the VPN working, and I felt that rolling back to a known good version was the quickest way. After thinking hard and with some consulting on online documentation, I managed to rollback to the previous version (4.2.0). I will share the steps I took below.

1. Check your dpkg.log for the dates and packages that were upgraded

cat /var/log/dpkg.log


2. After determining the date range, shorten the log file to double check the entries and uncover the old and new version numbers of the affected packages [in this example, the date used is 2024-04-15 (YYYY-MM-DD) in the first field of dpkg.log, and upgrade is used in the third field of the dpkg.log]

awk '$1=="2024-04-15" && $3=="upgrade"' /var/log/dpkg.log


3. Determine if the cached package files are still on disk (hopefully sudo apt autoclean was not executed!)

awk '$1=="2024-04-15" && $3=="upgrade" {gsub(/:/, "%3a", $5); split($4, f, ":"); print "/var/cache/apt/archives/" f[1] "_" $5 "_" f[2] ".deb"}' /var/log/dpkg.log | xargs -r ls -ld


4. I still had my cached files (thankfully!). I ran the following command to force install the older package files:

sudo dpkg -i /var/cache/apt/archives/proton-vpn-gtk-app_4.2.0_all.deb /var/cache/apt/archives/python3-proton-keyring-linux-secretservice_0.0.1_all.deb /var/cache/apt/archives/python3-proton-keyring-linux_0.0.1_all.deb /var/cache/apt/archives/python3-proton-vpn-api-core_0.21.0_all.deb /var/cache/apt/archives/python3-proton-vpn-connection_0.14.2_all.deb /var/cache/apt/archives/python3-proton-vpn-network-manager-openvpn_0.0.4_all.deb /var/cache/apt/archives/python3-proton-vpn-network-manager_0.4.0_all.deb /var/cache/apt/archives/python3-proton-vpn-session_0.6.5_all.deb


After the install process was completed, I rebooted the machine and was glad to have ProtonVPN working again. Admittedly, it does not solve the mystery why version 4.3.0 could not work on Debian, but at least I can have connectivity and do work.

-----------
Yee Ching Tok, Ph.D., ISC Handler
Personal Site
Mastodon
Twitter

0 comment(s)

Comments


Diary Archives