Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

In Azure Linux, installing packages does not automatically upgrade package dependencies #5940

Open
lbussell opened this issue Oct 2, 2024 · 3 comments

Comments

@lbussell
Copy link
Contributor

lbussell commented Oct 2, 2024

Describe the Bug

This situation is very similar to #4776.

TDNF ("tiny" version of DNF), the package manager in CBL Mariner 2.0 and Azure Linux 3.0, has some incompatibilities with the way we aim to update packages in our Dockerfiles.

Assume that we have package $a which is already installed in the base image, and package $b which depends on package $a.

  1. Running tdnf install -y $a upgrades package $a to the latest version, even when it's already installed (this is good)
  2. If package $b is not installed, and we run tdnf install -y $b, package $a is not upgraded to the latest version.
  3. If package $b is already installed, and there is no update for package $b, and we run tdnf install -y $b, then package $a is still not upgraded to the latest version.
  4. I don't have an example for what happens if package $b has an update.

Steps to Reproduce

This situation is happening between git and expat today. git does not have an update available, but expat does. I'm using this aspnet image to simulate what happens in our sdk Dockerfile.

$image = "mcr.microsoft.com/dotnet/aspnet:8.0-cbl-mariner2.0@sha256:f333342acc31b8bb78c5dc4931417685fe1f5e805b4d71ee32c227671c8ac35d"

First, check for package upgrades (current version of expat is 2.6.2-2.cm2):

docker run --rm $image /bin/sh -c 'tdnf check-update'

Loaded plugin: tdnfrepogpgcheck
Refreshing metadata for: 'CBL-Mariner Official Microsoft 2.0 x86_64'
Refreshing metadata for: 'CBL-Mariner Official Extras 2.0 x86_64'
Refreshing metadata for: 'CBL-Mariner Official Base 2.0 x86_64'
curl.x86_64                                  8.8.0-2.cm2   mariner-official-base
curl-libs.x86_64                             8.8.0-2.cm2   mariner-official-base
expat.x86_64                                 2.6.3-1.cm2   mariner-official-base
expat-libs.x86_64                            2.6.3-1.cm2   mariner-official-base
krb5.x86_64                                 1.21.3-2.cm2   mariner-official-base
krb5.x86_64                                 1.19.4-3.cm2   mariner-official-base

Scenario 1:

PS C:\s\dotnet-docker> docker run --rm $image /bin/sh -c 'printf "\nUpdates available:\n"; tdnf check-update -q; printf "\nInstalling expat...\n"; tdnf install -yq expat; printf "\nUpdates available:\n"; tdnf check-update -q'

Updates available:
curl.x86_64                                  8.8.0-2.cm2   mariner-official-base
curl-libs.x86_64                             8.8.0-2.cm2   mariner-official-base
expat.x86_64                                 2.6.3-1.cm2   mariner-official-base
expat-libs.x86_64                            2.6.3-1.cm2   mariner-official-base
krb5.x86_64                                 1.21.3-2.cm2   mariner-official-base
krb5.x86_64                                 1.19.4-3.cm2   mariner-official-base

Installing expat...

Updates available:
curl.x86_64                                  8.8.0-2.cm2   mariner-official-base
curl-libs.x86_64                             8.8.0-2.cm2   mariner-official-base
krb5.x86_64                                 1.21.3-2.cm2   mariner-official-base
krb5.x86_64                                 1.19.4-3.cm2   mariner-official-base

Scenario 2:

docker run --rm $image /bin/sh -c 'printf "\nUpdates available:\n"; tdnf check-update -q; printf "\nInstalling git...\n"; tdnf install -yq git; printf "\nExpat history:\n"; tdnf list history expat; printf "\nWhat requires expat:\n"; rpm -q --whatrequires expat; printf "\nUpdates available:\n"; tdnf check-update -q'

Updates available:
curl.x86_64                                  8.8.0-2.cm2   mariner-official-base
curl-libs.x86_64                             8.8.0-2.cm2   mariner-official-base
expat.x86_64                                 2.6.3-1.cm2   mariner-official-base
expat-libs.x86_64                            2.6.3-1.cm2   mariner-official-base
krb5.x86_64                                 1.21.3-2.cm2   mariner-official-base
krb5.x86_64                                 1.19.4-3.cm2   mariner-official-base

Installing git...
using empty dict to provide pw_dict
switching pw_dict to cracklib-dicts
ownership of '/var/lib/sshd' retained as root:sys

Expat history:
Loaded plugin: tdnfrepogpgcheck
expat.x86_64                                 2.6.2-2.cm2               @System
expat.x86_64                                 2.4.8-1.cm2          mariner-official-base
expat.x86_64                                 2.4.8-2.cm2          mariner-official-base
expat.x86_64                                 2.5.0-1.cm2          mariner-official-base
expat.x86_64                                 2.6.2-1.cm2          mariner-official-base
expat.x86_64                                 2.6.2-2.cm2          mariner-official-base
expat.x86_64                                 2.6.3-1.cm2          mariner-official-base

What requires expat:
core-packages-container-2.0-8.cm2.x86_64
apr-util-1.6.3-1.cm2.x86_64
python3-libs-3.9.19-5.cm2.x86_64
git-2.39.4-1.cm2.x86_64

Updates available:
curl.x86_64                                  8.8.0-2.cm2   mariner-official-base
curl-libs.x86_64                             8.8.0-2.cm2   mariner-official-base
expat.x86_64                                 2.6.3-1.cm2   mariner-official-base
expat-libs.x86_64                            2.6.3-1.cm2   mariner-official-base
krb5.x86_64                                 1.21.3-2.cm2   mariner-official-base
krb5.x86_64                                 1.19.4-3.cm2   mariner-official-base

Scenario 3:

To simulate what happens when git is already installed I'm using the exact same command as scenario 2, but with the SDK image instead since it has git installed.

`$image = "mcr.microsoft.com/dotnet/sdk:8.0-cbl-mariner2.0@sha256:5ccee344ce708fadab98dd7b561a15495cc3a9ac7aa51d3b03efe45e24cabd80"`

docker run --rm $image /bin/sh -c 'printf "\nUpdates available:\n"; tdnf check-update -q; printf "\nInstalling git...\n"; tdnf install -yq git; printf "\nExpat history:\n"; tdnf list history expat; printf "\nWhat requires expat:\n"; rpm -q --whatrequires expat; printf "\nUpdates available:\n"; tdnf check-update -q'

Updates available:
curl.x86_64                                  8.8.0-2.cm2   mariner-official-base
curl-libs.x86_64                             8.8.0-2.cm2   mariner-official-base
expat.x86_64                                 2.6.3-1.cm2   mariner-official-base
expat-libs.x86_64                            2.6.3-1.cm2   mariner-official-base
krb5.x86_64                                 1.21.3-2.cm2   mariner-official-base
krb5.x86_64                                 1.19.4-3.cm2   mariner-official-base
python3.x86_64                              3.9.19-5.cm2   mariner-official-base
python3-libs.x86_64                         3.9.19-5.cm2   mariner-official-base

Installing git...
Package git is already installed.
Nothing to do.

Expat history:
Loaded plugin: tdnfrepogpgcheck
expat.x86_64                                 2.6.2-2.cm2               @System
expat.x86_64                                 2.4.8-1.cm2          mariner-official-base
expat.x86_64                                 2.4.8-2.cm2          mariner-official-base
expat.x86_64                                 2.5.0-1.cm2          mariner-official-base
expat.x86_64                                 2.6.2-1.cm2          mariner-official-base
expat.x86_64                                 2.6.2-2.cm2          mariner-official-base
expat.x86_64                                 2.6.3-1.cm2          mariner-official-base

What requires expat:
core-packages-container-2.0-8.cm2.x86_64
apr-util-1.6.3-1.cm2.x86_64
python3-libs-3.9.19-4.cm2.x86_64
git-2.39.4-1.cm2.x86_64

Updates available:
curl.x86_64                                  8.8.0-2.cm2   mariner-official-base
curl-libs.x86_64                             8.8.0-2.cm2   mariner-official-base
expat.x86_64                                 2.6.3-1.cm2   mariner-official-base
expat-libs.x86_64                            2.6.3-1.cm2   mariner-official-base
krb5.x86_64                                 1.21.3-2.cm2   mariner-official-base
krb5.x86_64                                 1.19.4-3.cm2   mariner-official-base
python3.x86_64                              3.9.19-5.cm2   mariner-official-base
python3-libs.x86_64                         3.9.19-5.cm2   mariner-official-base

What does this mean

This means that when an indirect dependency of .NET or any of the tools in a .NET image has a vulnerability, simply re-building the image won't resolve that vulnerability. In this case, git is the tool and expat is its dependency.

@lbussell
Copy link
Contributor Author

lbussell commented Oct 2, 2024

I found a couple other interesting tdnf commands that may be relevant here.

tdnf check-update --security is supposed to list only security updates:

curl.x86_64                                  8.8.0-2.cm2   mariner-official-base
curl-libs.x86_64                             8.8.0-2.cm2   mariner-official-base
expat.x86_64                                 2.6.3-1.cm2   mariner-official-base
expat-libs.x86_64                            2.6.3-1.cm2   mariner-official-base
krb5.x86_64                                 1.21.3-2.cm2   mariner-official-base
krb5.x86_64                                 1.19.4-3.cm2   mariner-official-base
python3.x86_64                              3.9.19-5.cm2   mariner-official-base
python3-libs.x86_64                         3.9.19-5.cm2   mariner-official-base

OK, that's the same list of packages. Maybe they're all security updates. I checked with Trivy, and noticed that all were reported as vulnerable except krb5.

There's another option, --sec-security that's supposed to let you filter by severity. I checked Critical, and it listed all available package updates again. Same deal for High, Medium, and Low. So I'm not sure there's any valid metadata here.

# tdnf check-update --sec-severity Low
Loaded plugin: tdnfrepogpgcheck
curl.x86_64                                  8.8.0-2.cm2   mariner-official-base
curl-libs.x86_64                             8.8.0-2.cm2   mariner-official-base
expat.x86_64                                 2.6.3-1.cm2   mariner-official-base
expat-libs.x86_64                            2.6.3-1.cm2   mariner-official-base
krb5.x86_64                                 1.21.3-2.cm2   mariner-official-base
krb5.x86_64                                 1.19.4-3.cm2   mariner-official-base
python3.x86_64                              3.9.19-5.cm2   mariner-official-base
python3-libs.x86_64                         3.9.19-5.cm2   mariner-official-base

And tdnf updateinfo is supposed to report package changelogs and vulnerabilities. However, it doesn't seem to be working as intended:

# tdnf updateinfo

0 updates.
No data available

@omajid, do you have any advice here? We'd like to transparently upgrade the dependencies of packages we explicitly install (and obviously the packages themselves as well). But we want to avoid upgrading all packages. With other package managers it's trivial - e.g. apt-get install and apk add --upgrade. With dnf/tdnf it doesn't seem that simple.

@omajid
Copy link
Member

omajid commented Oct 3, 2024

Hey, @lbussell! My experience with yum/dnf/tdnf in this area has shown that --security is a essentially a footgun for users.

Like you noticed, this feature depends on the distro providing good metadata for packages.

RHEL, for example, produces this metadata and keeps older versions of packages around. And so this mostly works there. And as another example, this doesn't do anything sensible on Fedora. I have run across examples in Fedora where package version 1.0.0 is installed, 1.0.1 is a security update, and 1.0.2 is a bugfix, and then yum/dnf/tdnf see the installed version (1.0.0) and the latest version (1.0.2, bugfix) and decide there's nothing to update because 1.0.2 isn't a security fix.


I don't know of a clean solution to your general problem off the top of my head, but I will try and dig around. It might involve resolving dependencies usingrepoquery and then installing/upgrading those specifically.

@lbussell lbussell removed the untriaged label Oct 7, 2024
@lbussell
Copy link
Contributor Author

lbussell commented Oct 7, 2024

[Triage] We should see if there's a known issue on dnf for this scenario and open one if there's not. Optionally we could file an issue directly on tdnf.

@lbussell lbussell self-assigned this Oct 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Backlog
Development

No branches or pull requests

2 participants