apt.Cache.clear() may set apt.Package.is_auto_removable to False
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
unattended-upgrades (Ubuntu) |
Fix Released
|
High
|
Balint Reczey | ||
Xenial |
Fix Released
|
High
|
Unassigned | ||
Bionic |
Fix Released
|
High
|
Unassigned | ||
Cosmic |
Fix Released
|
High
|
Unassigned |
Bug Description
[Impact]
* Originally autoremovable packages can be removed as newly autoremovable ones by unattended-upgrades
* This can surprise users potentially removing packages which are needed for the system's operation.
[Test Case]
* The buggy u-u version will remove the previously autoremovable zsh at the end, the fixed one does not.
$ sudo debootstrap bionic uu-test-
...
$ sudo chroot uu-test-
# apt install unattended-upgrades zsh
# apt-mark auto zsh
...
# echo "Unattended-
# echo "deb http://
# echo "deb http://
# apt update -qq
# unattended-upgrades --dry-run --verbose --debug
...
All upgrades installed
marking zsh for removal
marking zsh-common for removal
Packages that were successfully auto-removed:
Packages that are kept back:
InstCount=0 DelCount=0 BrokenCount=0
#
[Regression Potential]
* Unattended-upgrades may use more CPU-time for operation but I did not observe a significant increase. Autopkgtest measures u-u's performance thus if this regression occurs, we can observe it easily.
* Due to the code changes u-u may still remove already autoremovable packages or fail to remove newly autoremovable ones in default configuration, but since the code became simpler with the change by eliminating an optimization this regression is unlikely to take place.
[Original Bug Text]
While triaging LP: #1803587 I found that originally autoremovable packages were handled as newly autoremovable ones by unattended-upgrades due to not finding all of them at the beginning of u-u's run.
The root cause seems to be cache.clear() resetting pkg.is_
Set up a Bionic (or later) system with autoremovable packages, packages upgradable from -security and blacklist at least one upgradable package and apply the following patch to u-u:
root@bb-1803587:~# diff -Naur /usr/bin/
--- /usr/bin/
+++ /usr/bin/
@@ -948,7 +948,9 @@
def rewind_cache(cache, pkgs_to_upgrade):
# type: (apt.Cache, List[apt.Package]) -> None
""" set the cache back to the state with packages_to_upgrade """
+ print([pkg.name for pkg in cache if pkg.is_
cache.clear()
+ print([pkg.name for pkg in cache if pkg.is_
for pkg2 in pkgs_to_upgrade:
if cache.broken_count > 0:
Run u-u to observe cache.clear() resetting the list of autoremovable packages:
~# /usr/bin/
Initial blacklisted packages: systemd
Initial whitelisted packages:
Starting unattended upgrades script
Allowed origins are: o=Ubuntu,a=bionic, o=Ubuntu,
Using (^linux-
Using (^linux-
Checking: apport ([<Origin component:'main' archive:
adjusting candidate version: apport=
...
Checking: libnss-systemd ([<Origin component:'main' archive:
skipping blacklisted package systemd
pkg systemd package has been blacklisted
sanity check failed
['libfreetype6']
[]
...
description: | updated |
description: | updated |
Changed in unattended-upgrades (Ubuntu Xenial): | |
importance: | Undecided → High |
Changed in unattended-upgrades (Ubuntu Bionic): | |
importance: | Undecided → High |
Changed in unattended-upgrades (Ubuntu Cosmic): | |
importance: | Undecided → High |
This is caused by unattended-upgrades having an ActionGroup during the clear. So, UnattendedUpgrades cache should likely overwrite clear() and make it reset the action group, for example (after making actiongroup global):
def clear(self): .release( ) # pyflakes Cache.clear( self) ActionGroup( cache._ depcache)
global actiongroup
actiongroup
apt.
actiongroup = apt_pkg.