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

pax-utils: Out of bounds read fix #24186

Closed
wants to merge 1 commit into from
Closed

pax-utils: Out of bounds read fix #24186

wants to merge 1 commit into from

Conversation

ndowens
Copy link
Contributor

@ndowens ndowens commented Mar 21, 2017

Motivation for this change

CVE: NixOS/security#23

I created the patch by downloading current version and diff'ing it with upstream's master git copy. I asked if this is ok, but no answer. AFAIK the binaries work fine.

Things done
  • Tested using sandboxing
    (nix.useSandbox on NixOS,
    or option build-use-sandbox in nix.conf
    on non-NixOS)
  • Built on platform(s)
    • NixOS
    • macOS
    • Linux
  • Tested compilation of all pkgs that depend on this change using nix-shell -p nox --run "nox-review wip"
  • Tested execution of all binary files (usually in ./result/bin/)
  • Fits CONTRIBUTING.md.

@abbradar
Copy link
Member

I created the patch by downloading current version and diff'ing it with upstream's master git copy

Maybe then just use a git checkout as source?

@ndowens
Copy link
Contributor Author

ndowens commented Mar 21, 2017 via email

@abbradar
Copy link
Member

@ndowens No problem, thank you for help ^_^ If noone objects I can move pax-utils to a git checkout.

@joachifm
Copy link
Contributor

I prefer to wait for upstream or at least use their patch.

@grahamc
Copy link
Member

grahamc commented Mar 22, 2017

Nice problem solving with the diff!

Generally diffing between our current version and the upstream's master version will include way too much, and is equivalent to just switching to their unstable / git version. This isn't usually what we want to do.

Reading the report, I saw:

Commit fix
https://github.com/gentoo/pax-utils/commit/e577c5b7e230c52e5fc4fa40e4e9014c634b3c1d
https://github.com/gentoo/pax-utils/commit/858939ea6ad63f1acb4ec74bba705c197a67d559

We usually prefer to use patches directly from upstream, and if a report includes a fix, even better.

These commits can be accessed as patches directly, at:

Here we can use fetchpatch:

  patches = [
    (fetchpatch {
      name = "scanelf-check-range-of-hash-bucket.patch";
      url = "https://github.com/gentoo/pax-utils/commit/e577c5b7e230c52e5fc4fa40e4e9014c634b3c1d.patch";
      sha256 = "";
    })
    (fetchpatch {
      name = "checking-memory-elf-ranges.patch";
      url = "https://github.com/gentoo/pax-utils/commit/858939ea6ad63f1acb4ec74bba705c197a67d559.patch";
      sha256 = "";
    })
  ];

I'm now reminded that you tried this already, and ran in to the patches not applying cleanly.

Running nix-build . -A pax-utils --keep-failed outputs:

applying patch /nix/store/zpg4awvj8ngka1376i88xm9llhf2qv55-checking-memory-elf-ranges.patch
patching file dumpelf.c
Hunk #1 succeeded at 376 (offset -9 lines).
patching file paxelf.h
Hunk #1 FAILED at 39.
1 out of 1 hunk FAILED -- saving rejects to file paxelf.h.rej
patching file scanelf.c
Hunk #4 succeeded at 336 (offset -1 lines).
Hunk #5 succeeded at 482 (offset -1 lines).
Hunk #6 succeeded at 1500 (offset -1 lines).
note: keeping build directory ‘/tmp/nix-build-pax-utils-1.2.2.drv-1’

Looking at the rejected patch at /tmp/nix-build-pax-utils-1.2.2.drv-0/pax-utils-1.2.2/paxelf.h.rej, and the original version at /tmp/nix-build-pax-utils-1.2.2.drv-0/pax-utils-1.2.2/paxelf.h.orig, it looks like the patch fails because our version has no VALID_PHDR to be patched:

--- paxelf.h
+++ paxelf.h
@@ -39,17 +39,15 @@
 #define SYM32(ptr) ((Elf32_Sym *)(ptr))
 #define SYM64(ptr) ((Elf64_Sym *)(ptr))
 
+#define VALID_RANGE(elf, offset, size) \
+	((uint64_t)(size) <= (uint64_t)elf->len && \
+	 (uint64_t)(offset) <= (uint64_t)elf->len - (uint64_t)(size))
 #define VALID_SHDR(elf, shdr) \
 	(shdr && \
 	 EGET(shdr->sh_type) != SHT_NOBITS && \
-	 EGET(shdr->sh_offset) < (uint64_t)elf->len && \
-	 EGET(shdr->sh_size) < (uint64_t)elf->len && \
-	 EGET(shdr->sh_offset) <= elf->len - EGET(shdr->sh_size))
+	 VALID_RANGE(elf, EGET(shdr->sh_offset), EGET(shdr->sh_size)))
 #define VALID_PHDR(elf, phdr) \
-	(phdr && \
-	 EGET(phdr->p_filesz) < (uint64_t)elf->len && \
-	 EGET(phdr->p_offset) < (uint64_t)elf->len && \
-	 EGET(phdr->p_filesz) <= elf->len - EGET(phdr->p_offset))
+	(phdr && VALID_RANGE(elf, EGET(phdr->p_offset), EGET(phdr->p_filesz)))
 
 /* prototypes */
 extern char *pax_short_hf_flags(unsigned long flags);

vs:

#define SYM32(ptr) ((Elf32_Sym *)(ptr))
#define SYM64(ptr) ((Elf64_Sym *)(ptr))

#define VALID_SHDR(elf, shdr) \
        (shdr && \
         EGET(shdr->sh_type) != SHT_NOBITS && \
         EGET(shdr->sh_offset) < (uint64_t)elf->len && \
         EGET(shdr->sh_size) < (uint64_t)elf->len && \
         EGET(shdr->sh_offset) <= elf->len - EGET(shdr->sh_size))

/* prototypes */
extern char *pax_short_hf_flags(unsigned long flags);

At this point, we could fix the patch to work for us, but given:

(1) there is no CVE
(2) debian's security tracker marks this as "Unimportant": https://security-tracker.debian.org/tracker/TEMP-0856196-13C562

I think it is best to wait for a new release.

@7c6f434c
Copy link
Member

7c6f434c commented Mar 22, 2017

@grahamc Why not just take the upstream master? I read the patch, it seems reasonable.

I agree that the problem seems to be exploitable mainly if you process the ELF files under a more privileged (maybe in terms of accessible data) user account than the account that will run them afterwards. No such situation is encouraged in Nix*.

@joachifm
Copy link
Contributor

For context: these tools are typically used to check for build QA issues, so you're supposed to be feeding it output from your local tool chain, not random stuff from untrusted sources.

@ndowens
Copy link
Contributor Author

ndowens commented Mar 22, 2017

Now I know. Just thought maybe it would be ok. Since it had more than one commit to use to diff. I would have just used the commit as diff if it was one. So I didn't know how to exactly do two at one time

@ndowens
Copy link
Contributor Author

ndowens commented Mar 22, 2017

What if use the last commit point that should include the other as well?

@ndowens ndowens deleted the pax-utils branch March 26, 2017 23:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants