Fixing zlib CVE-2023-45853 in a Nix-fied Java app docker container

Hi All,

I know a bit of Nix, but not enough to track down the source of the zlib dependency that is setting off grype scanner on my Nix container, wondering if someone can chime in and help me work backwards to identify and fix the source of CVE-2023-45853 (Nix source will be included below in 3rd section).

Any assistance in troubleshooting would be greatly appreciated.

This is the scan that has flagged the vulnerability:

# grype my-springboot-app-docker:0.0.1 
 βœ” Vulnerability DB                [no update available]  
 βœ” Loaded image                                                                                                                                                 my-springboot-docker:0.0.1
 βœ” Parsed image                                                                                                    sha256:a00c4d81ff0bf24as45ac3647c9a08d33b893563ce52c4e196eb59d798df3aa9
 βœ” Cataloged contents                                                                                                     744769e40df51165fa16878994b13eff379f4ccf222784f79b7bd4261bd14784
   β”œβ”€β”€ βœ” Packages                        [112 packages]  
   β”œβ”€β”€ βœ” File digests                    [1,483 files]  
   β”œβ”€β”€ βœ” File metadata                   [1,483 locations]  
   └── βœ” Executables                     [330 executables]  
 βœ” Scanned for vulnerabilities     [1 vulnerability matches]  
   β”œβ”€β”€ by severity: 1 critical, 0 high, 0 medium, 0 low, 0 negligible
   └── by status:   0 fixed, 1 not-fixed, 0 ignored 
NAME  INSTALLED  FIXED-IN  TYPE  VULNERABILITY   SEVERITY 
zlib  1.3                  nix   CVE-2023-45853  Critical

This is the dive of the container’s packages (arch = arm64):

+─ nix                                                                            
└── store                                                                      
    β”œβ”€βŠ• 0l8m0dfsdfsdfkssz2yyfwkdn739h6ad-my-springboot-app-0.0.1            
    β”œβ”€βŠ• 2ac40x9r5nnpbprn9lds1nx4129h1sbs-gcc-12.3.0-lib                        
    β”œβ”€βŠ• 2ww2l3vz6ir4c9v58jwkvdhbi62pwlj0-libunistring-1.1                      
    β”œβ”€βŠ• 3bjvd4rmifnk31qj5m0jxlf85mr87p8v-alsa-lib-1.2.9                        
    β”œβ”€βŠ• 3xkjm07513fsj6xh8wn1hkj1d720bhjy-xgcc-12.3.0-libgcc                    
    β”œβ”€βŠ• 57dmbr3wqsmmfwn6gvaf97jaiim0w7j1-libpng-apng-1.6.40                    
    β”œβ”€βŠ• 8nj2b7hfqky7ma4c5hl2jxsc863iqc23-libjpeg-turbo-2.1.5.1                 
    β”œβ”€βŠ• 9gghrpwiplyi1s2czws4jl28y3gcan2m-alsa-ucm-conf-1.2.10                  
    β”œβ”€β”€ a43p2cn7mzrwy6d6j6nrkzam2cl08did-zlib-1.3                              
    β”‚   β”œβ”€β”€ lib                                                                
    β”‚   β”‚   β”œβ”€β”€ libz.so β†’ libz.so.1.3                                          
    β”‚   β”‚   β”œβ”€β”€ libz.so.1 β†’ libz.so.1.3                                        
    β”‚   β”‚   └── libz.so.1.3                                                    
    β”‚   └── share                                                              
    β”‚       └── man                                                            
    β”‚           └── man3                                                       
    β”‚               └── zlib.3.gz                                              
    β”œβ”€βŠ• b0a4w2rls0bzav0zlz4kimb7gcasvksx-libidn2-2.3.4                         
    β”œβ”€βŠ• b5kq5kqw0qxjiyrl6ws74r98nspxlc2v-brotli-1.1.0-lib                      
    β”œβ”€βŠ• j9qfhr3bq705rai1vhjid6bn3pqkq1xc-lcms2-2.15                            
    β”œβ”€βŠ• vh78i6729d9kfv97q2id2z2cn8kzm5ay-glibc-2.38-44                         
    β”œβ”€βŠ• wrr5xnycsy8vlcjar8qbhlar9faw9ayj-alsa-topology-conf-1.2.5.1            
    β”œβ”€βŠ• xd6yxkl270syr2raam6lr48bpsa2x3bv-freetype-2.13.2                       
    β”œβ”€βŠ• zvlrvpz3hcwaqnhrrxwnkwxh0x3x1kkw-gcc-12.3.0-libgcc                     
    β””β”€βŠ• zx3hg7xk5vpajky8xfwdlla72q2fcwsw-bzip2-1.0.8    

Here is the Nix code I used to build the Java app and create the docker container my-springboot-app-docker.nix; it expects a maven built java application with a pom.xml file:

{ pkgs ? import <nixpkgs> {} }:

let
  # Package name will be based off of these
  artifactId = "my-springboot-app";
  artifactVersion = "0.0.1";

  # Build our project
  mavenPackage = pkgs.maven.buildMavenPackage ({
    pname = artifactId;
    version = artifactVersion;
    src = ./.;
    buildInputs = [ pkgs.maven pkgs.jdk21_headless ];
    installPhase = ''
      mkdir $out
      cp target/*.jar $out/app.jar
      # Build a custom minimal JRE
      jlink --module-path $JAVA_HOME/jmods --add-modules java.base,java.naming,java.management,java.desktop --strip-debug --no-header-files --no-man-pages --output $out/jre
    '';
    mvnHash = ""; # FIXME: first run will download and spit out the maven hash to be put here
  });

  # Build our Docker image
  dockerImage = pkgs.dockerTools.buildLayeredImage {
    name = "${artifactId}-docker";
    tag = "${artifactVersion}";
    contents = [
      mavenPackage
    ];

    config = {
      Cmd = [ "${mavenPackage}/jre/bin/java" "-jar" "${mavenPackage}/app.jar" ];
      ExposedPorts = {
        "8080/tcp" = {};
      };
    };
  };
in
  dockerImage
nix-build my-springboot-app-docker.nix
docker load < result
grype my-springboot-app-docker:0.0.1
dive my-springboot-app-docker:0.0.1

Thanks for your reply @Sandro, I did see the latest in packages search is 1.3.1 which is why I’m puzzled 1.3 is still being pulled in, but wasn’t aware there was a patch for it possibly applied.

If I present the grype scan result (this is hopefully going to be a demo of why we should look at Nix for docker builds), the infosec ppl will ask how we can verify that it’s a false positive/patch has been applied… for this particular instance of zlib 1.3, I don’t yet know how we can; though it’s helpful I can point to these PRs to suggest it probably has been mitigated.

As a side quest I extracted the libz.so.1.3 binary and it’s man page from the docker image layer to see if I could find some mention of a patch, alas no luck.

I will keep hunting, maybe there are some debug flags for nix-build that will give a bit more insight.

Thanks again :beers:

The easiest way to verify if a patch is applied, is to get the commit from which the Dockerfile was built and inspect the nix code or patches from the package attribute if the patch exists there.

Nix doesn’t bump version numbers or modifies the packages or man pages in any way because we don’t rely on version comparisons to update packages and want to ship packages as close as possible to upstream if possible.

There is no good way to know when to bump the version number other than when the source changes because nix doesn’t require it to update a package. This also avoids back workarounds like +real which Debian must use to downgrade a package.

Took me a while but I figured out my problem, I was producing a non-deterministic build on an older docker image that’s base libraries had the zlib problem…

Specifically:

# FIXME: non-deterministic build - this will use whatever system packages are installed:
{ pkgs ? import <nixpkgs> {} }: 

Doing a docker pull refreshed the docker image and the problem disappeared, then I was able to recreate it using this even on systems with newer libs that don’t reference zlib-1.3:

# NixOS 23.11 - FIXME: Shipped with zlib 1.3 which has CVE-2023-45853
{ pkgs ? import (builtins.fetchGit {
   url = "https://github.com/nixos/nixpkgs.git";
   rev = "219951b495fc2eac67b1456824cc1ec1fd2ee659";
}) {} }:

I was pretty confused at first because attempting to figure out via nix why-depends didn’t explain why different versions were needed on different systems (they were at different nixpkgs commits is why)… Anyway all sorted now.

Thanks again for the assist. :beers:

1 Like