mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-08-25 17:55:21 +00:00
Merge branch 'staging-23.11' into staging-next-23.11
This commit is contained in:
@@ -86,9 +86,9 @@ One advantage is that when `pkgs.zlib` is updated, it will automatically update
|
||||
|
||||
postPatch = pkgs.lib.optionalString pkgs.stdenv.isDarwin ''
|
||||
substituteInPlace configure \
|
||||
--replace '/usr/bin/libtool' 'ar' \
|
||||
--replace 'AR="libtool"' 'AR="ar"' \
|
||||
--replace 'ARFLAGS="-o"' 'ARFLAGS="-r"'
|
||||
--replace-fail '/usr/bin/libtool' 'ar' \
|
||||
--replace-fail 'AR="libtool"' 'AR="ar"' \
|
||||
--replace-fail 'ARFLAGS="-o"' 'ARFLAGS="-r"'
|
||||
'';
|
||||
})
|
||||
```
|
||||
|
||||
@@ -700,7 +700,7 @@ with import <nixpkgs> {};
|
||||
hello = attrs: lib.optionalAttrs (lib.versionAtLeast attrs.version "1.0") {
|
||||
postPatch = ''
|
||||
substituteInPlace lib/zoneinfo.rs \
|
||||
--replace "/usr/share/zoneinfo" "${tzdata}/share/zoneinfo"
|
||||
--replace-fail "/usr/share/zoneinfo" "${tzdata}/share/zoneinfo"
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
@@ -54,7 +54,7 @@ Some common issues when packaging software for Darwin:
|
||||
# ...
|
||||
prePatch = ''
|
||||
substituteInPlace Makefile \
|
||||
--replace '/usr/bin/xcrun clang' clang
|
||||
--replace-fail '/usr/bin/xcrun clang' clang
|
||||
'';
|
||||
}
|
||||
```
|
||||
|
||||
@@ -230,9 +230,9 @@ stdenv.mkDerivation rec {
|
||||
|
||||
postInstall = ''
|
||||
substituteInPlace $out/bin/solo5-virtio-mkimage \
|
||||
--replace "/usr/lib/syslinux" "${syslinux}/share/syslinux" \
|
||||
--replace "/usr/share/syslinux" "${syslinux}/share/syslinux" \
|
||||
--replace "cp " "cp --no-preserve=mode "
|
||||
--replace-fail "/usr/lib/syslinux" "${syslinux}/share/syslinux" \
|
||||
--replace-fail "/usr/share/syslinux" "${syslinux}/share/syslinux" \
|
||||
--replace-fail "cp " "cp --no-preserve=mode "
|
||||
|
||||
wrapProgram $out/bin/solo5-virtio-mkimage \
|
||||
--prefix PATH : ${lib.makeBinPath [ dosfstools mtools parted syslinux ]}
|
||||
@@ -1217,9 +1217,20 @@ postInstall = ''
|
||||
|
||||
Performs string substitution on the contents of \<infile\>, writing the result to \<outfile\>. The substitutions in \<subs\> are of the following form:
|
||||
|
||||
#### `--replace` \<s1\> \<s2\> {#fun-substitute-replace}
|
||||
#### `--replace-fail` \<s1\> \<s2\> {#fun-substitute-replace-fail}
|
||||
|
||||
Replace every occurrence of the string \<s1\> by \<s2\>.
|
||||
Will error if no change is made.
|
||||
|
||||
#### `--replace-warn` \<s1\> \<s2\> {#fun-substitute-replace-warn}
|
||||
|
||||
Replace every occurrence of the string \<s1\> by \<s2\>.
|
||||
Will print a warning if no change is made.
|
||||
|
||||
#### `--replace-quiet` \<s1\> \<s2\> {#fun-substitute-replace-quiet}
|
||||
|
||||
Replace every occurrence of the string \<s1\> by \<s2\>.
|
||||
Will do nothing if no change can be made.
|
||||
|
||||
#### `--subst-var` \<varName\> {#fun-substitute-subst-var}
|
||||
|
||||
@@ -1233,8 +1244,8 @@ Example:
|
||||
|
||||
```shell
|
||||
substitute ./foo.in ./foo.out \
|
||||
--replace /usr/bin/bar $bar/bin/bar \
|
||||
--replace "a string containing spaces" "some other text" \
|
||||
--replace-fail /usr/bin/bar $bar/bin/bar \
|
||||
--replace-fail "a string containing spaces" "some other text" \
|
||||
--subst-var someVar
|
||||
```
|
||||
|
||||
|
||||
@@ -73,6 +73,27 @@ in
|
||||
variant = "mainline";
|
||||
rev = "28.2";
|
||||
hash = "sha256-4oSLcUDR0MOEt53QOiZSVU8kPJ67GwugmBxdX3F15Ag=";
|
||||
patches = fetchpatch: [
|
||||
# CVE-2022-45939
|
||||
(fetchpatch {
|
||||
url = "https://git.savannah.gnu.org/cgit/emacs.git/patch/?id=d48bb4874bc6cd3e69c7a15fc3c91cc141025c51";
|
||||
hash = "sha256-TiBQkexn/eb6+IqJNDqR/Rn7S7LVdHmL/21A5tGsyJs=";
|
||||
})
|
||||
|
||||
# https://lists.gnu.org/archive/html/emacs-devel/2024-03/msg00611.html
|
||||
(fetchpatch {
|
||||
url = "https://gitweb.gentoo.org/proj/emacs-patches.git/plain/emacs/28.2/10_all_org-macro-eval.patch?id=af40e12cb742510e5d40a06ffc6dfca97e340dd6";
|
||||
hash = "sha256-OdGt4e9JGjWJPkfJhbYsmQQc6jart4BH5aIKPIbWKFs=";
|
||||
})
|
||||
(fetchpatch {
|
||||
url = "https://gitweb.gentoo.org/proj/emacs-patches.git/plain/emacs/28.2/11_all_untrusted-content.patch?id=af40e12cb742510e5d40a06ffc6dfca97e340dd6";
|
||||
hash = "sha256-wa2bsnCt5yFx0+RAFZGBPI+OoKkbrfkkMer/KBEc/wA=";
|
||||
})
|
||||
(fetchpatch {
|
||||
url = "https://gitweb.gentoo.org/proj/emacs-patches.git/plain/emacs/28.2/12_all_org-remote-unsafe.patch?id=af40e12cb742510e5d40a06ffc6dfca97e340dd6";
|
||||
hash = "sha256-b6WU1o3PfDV/6BTPfPNUFny6oERJCNsDrvflxX3Yvek=";
|
||||
})
|
||||
];
|
||||
});
|
||||
|
||||
emacs29 = import ./make-emacs.nix (mkArgs {
|
||||
|
||||
@@ -46,11 +46,11 @@ let
|
||||
in
|
||||
stdenv.mkDerivation (finalAttrs: {
|
||||
pname = "go";
|
||||
version = "1.21.8";
|
||||
version = "1.21.9";
|
||||
|
||||
src = fetchurl {
|
||||
url = "https://go.dev/dl/go${finalAttrs.version}.src.tar.gz";
|
||||
hash = "sha256-3IBs91qH4UFLW0w9y53T6cyY9M/M7EK3r2F9WmWKPEM=";
|
||||
hash = "sha256-WPDFztRaABK84v96nfA+Eoq8yIGOur5QJ7uSuv4g5CE=";
|
||||
};
|
||||
|
||||
strictDeps = true;
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
sourceVersion = {
|
||||
major = "3";
|
||||
minor = "10";
|
||||
patch = "13";
|
||||
patch = "14";
|
||||
suffix = "";
|
||||
};
|
||||
hash = "sha256-XIiEhmhkDT4VKzW0U27xwjsspL0slX7x7LsFP1cd0/Y=";
|
||||
hash = "sha256-nFBIH6qMKDIym6D8iGjQpgamgPxPYOxI0mzo4HZ1H9o=";
|
||||
};
|
||||
|
||||
python311 = {
|
||||
|
||||
@@ -23,13 +23,13 @@
|
||||
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "at-spi2-core";
|
||||
version = "2.50.0";
|
||||
version = "2.50.2";
|
||||
|
||||
outputs = [ "out" "dev" ];
|
||||
|
||||
src = fetchurl {
|
||||
url = "mirror://gnome/sources/${pname}/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
|
||||
sha256 = "6fWoyCNcndljshcd6RIDARKcZ33ekzlV4d9hi5ScStw=";
|
||||
hash = "sha256-W4GxRhpi3Y++0aJ2+p71txEvmuX/huHjKtlkS2VP94w=";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [
|
||||
|
||||
@@ -16,13 +16,13 @@
|
||||
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "libopenmpt";
|
||||
version = "0.7.3";
|
||||
version = "0.7.6";
|
||||
|
||||
outputs = [ "out" "dev" "bin" ];
|
||||
|
||||
src = fetchurl {
|
||||
url = "https://lib.openmpt.org/files/libopenmpt/src/libopenmpt-${version}+release.autotools.tar.gz";
|
||||
hash = "sha256-LPg2m3kWsJJk8/FLn7bO81pum+4DKN7E9J2YIRzP1yI=";
|
||||
hash = "sha256-Fi1yowa7LhFMJPolJn0NCgrBbzn9laXA38daZm7l5PU=";
|
||||
};
|
||||
|
||||
enableParallelBuilding = true;
|
||||
|
||||
@@ -51,6 +51,74 @@ stdenv.mkDerivation rec {
|
||||
url = "https://github.com/lathiat/avahi/commit/a2696da2f2c50ac43b6c4903f72290d5c3fa9f6f.patch";
|
||||
sha256 = "sha256-BEYFGCnQngp+OpiKIY/oaKygX7isAnxJpUPCUvg+efc=";
|
||||
})
|
||||
# CVE-2023-38470
|
||||
# https://github.com/lathiat/avahi/pull/457 merged Sep 19
|
||||
(fetchpatch {
|
||||
name = "CVE-2023-38470.patch";
|
||||
url = "https://github.com/lathiat/avahi/commit/94cb6489114636940ac683515417990b55b5d66c.patch";
|
||||
sha256 = "sha256-Fanh9bvz+uknr5pAmltqijuUAZIG39JR2Lyq5zGKJ58=";
|
||||
})
|
||||
# https://github.com/avahi/avahi/pull/480 merged Sept 19
|
||||
(fetchpatch {
|
||||
name = "bail-out-unless-escaped-labels-fit.patch";
|
||||
url = "https://github.com/avahi/avahi/commit/20dec84b2480821704258bc908e7b2bd2e883b24.patch";
|
||||
sha256 = "sha256-p/dOuQ/GInIcUwuFhQR3mGc5YBL5J8ho+1gvzcqEN0c=";
|
||||
})
|
||||
# CVE-2023-38473
|
||||
# https://github.com/lathiat/avahi/pull/486 merged Oct 18
|
||||
(fetchpatch {
|
||||
name = "CVE-2023-38473.patch";
|
||||
url = "https://github.com/lathiat/avahi/commit/b448c9f771bada14ae8de175695a9729f8646797.patch";
|
||||
sha256 = "sha256-/ZVhsBkf70vjDWWG5KXxvGXIpLOZUXdRkn3413iSlnI=";
|
||||
})
|
||||
# CVE-2023-38472
|
||||
# https://github.com/lathiat/avahi/pull/490 merged Oct 19
|
||||
(fetchpatch {
|
||||
name = "CVE-2023-38472.patch";
|
||||
url = "https://github.com/lathiat/avahi/commit/b024ae5749f4aeba03478e6391687c3c9c8dee40.patch";
|
||||
sha256 = "sha256-FjR8fmhevgdxR9JQ5iBLFXK0ILp2OZQ8Oo9IKjefCqk=";
|
||||
})
|
||||
# CVE-2023-38471
|
||||
# https://github.com/lathiat/avahi/pull/494 merged Oct 24
|
||||
(fetchpatch {
|
||||
name = "CVE-2023-38471.patch";
|
||||
url = "https://github.com/lathiat/avahi/commit/894f085f402e023a98cbb6f5a3d117bd88d93b09.patch";
|
||||
sha256 = "sha256-4dG+5ZHDa+A4/CszYS8uXWlpmA89m7/jhbZ7rheMs7U=";
|
||||
})
|
||||
# https://github.com/lathiat/avahi/pull/499 merged Oct 25
|
||||
(fetchpatch {
|
||||
name = "CVE-2023-38471-2.patch";
|
||||
url = "https://github.com/avahi/avahi/commit/b675f70739f404342f7f78635d6e2dcd85a13460.patch";
|
||||
sha256 = "sha256-uDtMPWuz1lsu7n0Co/Gpyh369miQ6GWGyC0UPQB/yI8=";
|
||||
})
|
||||
# CVE-2023-38469
|
||||
# https://github.com/lathiat/avahi/pull/500 merged Oct 25
|
||||
(fetchpatch {
|
||||
name = "CVE-2023-38469.patch";
|
||||
url = "https://github.com/avahi/avahi/commit/61b9874ff91dd20a12483db07df29fe7f35db77f.patch";
|
||||
sha256 = "sha256-qR7scfQqhRGxg2n4HQsxVxCLkXbwZi+PlYxrOSEPsL0=";
|
||||
excludes = [ ".github/workflows/smoke-tests.sh" ];
|
||||
})
|
||||
# https://github.com/avahi/avahi/pull/515 merged Nov 3
|
||||
(fetchpatch {
|
||||
name = "fix-compare-rrs-with-zero-length-rdata.patch";
|
||||
url = "https://github.com/avahi/avahi/commit/177d75e8c43be45a8383d794ce4084dd5d600a9e.patch";
|
||||
sha256 = "sha256-uwIyruAWgiWt0yakRrvMdYjjhEhUk5cIGKt6twyXbHw=";
|
||||
})
|
||||
# https://github.com/avahi/avahi/pull/519 merged Nov 8
|
||||
(fetchpatch {
|
||||
name = "reject-non-utf-8-service-names.patch";
|
||||
url = "https://github.com/avahi/avahi/commit/2b6d3e99579e3b6e9619708fad8ad8e07ada8218.patch";
|
||||
sha256 = "sha256-lwSA3eEQgH0g51r0i9/HJMJPRXrhQnTIEDxcYqUuLdI=";
|
||||
excludes = [ "fuzz/fuzz-domain.c" ];
|
||||
})
|
||||
# https://github.com/avahi/avahi/pull/523 merged Nov 12
|
||||
(fetchpatch {
|
||||
name = "core-no-longer-supply-bogus-services-to-callbacks.patch";
|
||||
url = "https://github.com/avahi/avahi/commit/93b14365c1c1e04efd1a890e8caa01a2a514bfd8.patch";
|
||||
sha256 = "sha256-VBm8vsBZkTbbWAK8FI71SL89lZuYd1yFNoB5o+FvlEU=";
|
||||
excludes = [ ".github/workflows/smoke-tests.sh" "fuzz/fuzz-packet.c" ];
|
||||
})
|
||||
];
|
||||
|
||||
depsBuildBuild = [
|
||||
|
||||
1450
pkgs/development/libraries/expat/CVE-2023-52425.patch
Normal file
1450
pkgs/development/libraries/expat/CVE-2023-52425.patch
Normal file
File diff suppressed because it is too large
Load Diff
86
pkgs/development/libraries/expat/CVE-2024-28757.patch
Normal file
86
pkgs/development/libraries/expat/CVE-2024-28757.patch
Normal file
@@ -0,0 +1,86 @@
|
||||
From c645f5996f3a8cff10606182a8031d3c3ade6ea3 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Pipping <sebastian@pipping.org>
|
||||
Date: Sun, 3 Mar 2024 02:19:58 +0100
|
||||
Subject: [PATCH 1/2] lib/xmlparse.c: Reject directly recursive parameter
|
||||
entities
|
||||
|
||||
(cherry picked from commit a4c86a395ee447c59175c762af3d17f7107b2261)
|
||||
---
|
||||
lib/xmlparse.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/xmlparse.c b/lib/xmlparse.c
|
||||
index b6c2eca9..2858946d 100644
|
||||
--- a/lib/xmlparse.c
|
||||
+++ b/lib/xmlparse.c
|
||||
@@ -6139,7 +6139,7 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
|
||||
dtd->keepProcessing = dtd->standalone;
|
||||
goto endEntityValue;
|
||||
}
|
||||
- if (entity->open) {
|
||||
+ if (entity->open || (entity == parser->m_declEntity)) {
|
||||
if (enc == parser->m_encoding)
|
||||
parser->m_eventPtr = entityTextPtr;
|
||||
result = XML_ERROR_RECURSIVE_ENTITY_REF;
|
||||
--
|
||||
2.44.0
|
||||
|
||||
|
||||
From b2170839eab38624df1d9842d738e4a2b6a08a2b Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Pipping <sebastian@pipping.org>
|
||||
Date: Mon, 4 Mar 2024 23:49:06 +0100
|
||||
Subject: [PATCH 2/2] lib/xmlparse.c: Detect billion laughs attack with
|
||||
isolated external parser
|
||||
|
||||
When parsing DTD content with code like ..
|
||||
|
||||
XML_Parser parser = XML_ParserCreate(NULL);
|
||||
XML_Parser ext_parser = XML_ExternalEntityParserCreate(parser, NULL, NULL);
|
||||
enum XML_Status status = XML_Parse(ext_parser, doc, (int)strlen(doc), XML_TRUE);
|
||||
|
||||
.. there are 0 bytes accounted as direct input and all input from `doc` accounted
|
||||
as indirect input. Now function accountingGetCurrentAmplification cannot calculate
|
||||
the current amplification ratio as "(direct + indirect) / direct", and it did refuse
|
||||
to divide by 0 as one would expect, but it returned 1.0 for this case to indicate
|
||||
no amplification over direct input. As a result, billion laughs attacks from
|
||||
DTD-only input were not detected with this isolated way of using an external parser.
|
||||
|
||||
The new approach is to assume direct input of length not 0 but 22 -- derived from
|
||||
ghost input "<!ENTITY a SYSTEM 'b'>", the shortest possible way to include an external
|
||||
DTD --, and do the usual "(direct + indirect) / direct" math with "direct := 22".
|
||||
|
||||
GitHub issue #839 has more details on this issue and its origin in ClusterFuzz
|
||||
finding 66812.
|
||||
|
||||
(cherry picked from commit 1d50b80cf31de87750103656f6eb693746854aa8)
|
||||
---
|
||||
lib/xmlparse.c | 6 +++++-
|
||||
1 file changed, 5 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/xmlparse.c b/lib/xmlparse.c
|
||||
index 2858946d..9458b092 100644
|
||||
--- a/lib/xmlparse.c
|
||||
+++ b/lib/xmlparse.c
|
||||
@@ -7655,6 +7655,8 @@ copyString(const XML_Char *s, const XML_Memory_Handling_Suite *memsuite) {
|
||||
|
||||
static float
|
||||
accountingGetCurrentAmplification(XML_Parser rootParser) {
|
||||
+ // 1.........1.........12 => 22
|
||||
+ const size_t lenOfShortestInclude = sizeof("<!ENTITY a SYSTEM 'b'>") - 1;
|
||||
const XmlBigCount countBytesOutput
|
||||
= rootParser->m_accounting.countBytesDirect
|
||||
+ rootParser->m_accounting.countBytesIndirect;
|
||||
@@ -7662,7 +7664,9 @@ accountingGetCurrentAmplification(XML_Parser rootParser) {
|
||||
= rootParser->m_accounting.countBytesDirect
|
||||
? (countBytesOutput
|
||||
/ (float)(rootParser->m_accounting.countBytesDirect))
|
||||
- : 1.0f;
|
||||
+ : ((lenOfShortestInclude
|
||||
+ + rootParser->m_accounting.countBytesIndirect)
|
||||
+ / (float)lenOfShortestInclude);
|
||||
assert(! rootParser->m_parentParser);
|
||||
return amplificationFactor;
|
||||
}
|
||||
--
|
||||
2.44.0
|
||||
|
||||
@@ -23,6 +23,11 @@ stdenv.mkDerivation rec {
|
||||
sha256 = "1gnwihpfz4x18rwd6cbrdggmfqjzwsdfh1gpmc0ph21c4gq2097g";
|
||||
};
|
||||
|
||||
patches = [
|
||||
./CVE-2023-52425.patch
|
||||
./CVE-2024-28757.patch
|
||||
];
|
||||
|
||||
strictDeps = true;
|
||||
|
||||
outputs = [ "out" "dev" ]; # TODO: fix referrers
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
{lib, stdenv, fetchurl}:
|
||||
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "giflib";
|
||||
version = "4.1.6";
|
||||
|
||||
src = fetchurl {
|
||||
url = "mirror://sourceforge/giflib/giflib-${version}.tar.bz2";
|
||||
sha256 = "1v9b7ywz7qg8hli0s9vv1b8q9xxb2xvqq2mg1zpr73xwqpcwxhg1";
|
||||
};
|
||||
|
||||
hardeningDisable = [ "format" ];
|
||||
|
||||
meta = with lib; {
|
||||
description = "A library for reading and writing gif images";
|
||||
branch = "4.1";
|
||||
license = licenses.mit;
|
||||
platforms = platforms.unix;
|
||||
};
|
||||
}
|
||||
|
||||
26
pkgs/development/libraries/giflib/CVE-2021-40633.patch
Normal file
26
pkgs/development/libraries/giflib/CVE-2021-40633.patch
Normal file
@@ -0,0 +1,26 @@
|
||||
From ccbc956432650734c91acb3fc88837f7b81267ff Mon Sep 17 00:00:00 2001
|
||||
From: "Eric S. Raymond" <esr@thyrsus.com>
|
||||
Date: Wed, 21 Feb 2024 18:55:00 -0500
|
||||
Subject: [PATCH] Clean up memory better at end of run (CVE-2021-40633)
|
||||
|
||||
---
|
||||
gif2rgb.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/gif2rgb.c b/gif2rgb.c
|
||||
index d51226d..fc2e683 100644
|
||||
--- a/gif2rgb.c
|
||||
+++ b/gif2rgb.c
|
||||
@@ -517,6 +517,9 @@ static void GIF2RGB(int NumFiles, char *FileName, bool OneFileFlag,
|
||||
DumpScreen2RGB(OutFileName, OneFileFlag, ColorMap, ScreenBuffer,
|
||||
GifFile->SWidth, GifFile->SHeight);
|
||||
|
||||
+ for (i = 0; i < GifFile->SHeight; i++) {
|
||||
+ (void)free(ScreenBuffer[i]);
|
||||
+ }
|
||||
(void)free(ScreenBuffer);
|
||||
|
||||
{
|
||||
--
|
||||
2.44.0
|
||||
|
||||
@@ -4,31 +4,20 @@
|
||||
, fetchpatch
|
||||
, fixDarwinDylibNames
|
||||
, pkgsStatic
|
||||
, imagemagick_light
|
||||
}:
|
||||
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "giflib";
|
||||
version = "5.2.1";
|
||||
version = "5.2.2";
|
||||
|
||||
src = fetchurl {
|
||||
url = "mirror://sourceforge/giflib/giflib-${version}.tar.gz";
|
||||
sha256 = "1gbrg03z1b6rlrvjyc6d41bc8j1bsr7rm8206gb1apscyii5bnii";
|
||||
hash = "sha256-vn/70FfK3r4qoURUL9kMaDjGoIO16KkEi47jtmsp1fs=";
|
||||
};
|
||||
|
||||
patches = [
|
||||
(fetchpatch {
|
||||
name = "CVE-2022-28506.patch";
|
||||
url = "https://src.fedoraproject.org/rpms/giflib/raw/2e9917bf13df114354163f0c0211eccc00943596/f/CVE-2022-28506.patch";
|
||||
sha256 = "sha256-TBemEXkuox8FdS9RvjnWcTWPaHRo4crcwSR9czrUwBY=";
|
||||
})
|
||||
] ++ lib.optionals stdenv.hostPlatform.isDarwin [
|
||||
# https://sourceforge.net/p/giflib/bugs/133/
|
||||
(fetchpatch {
|
||||
name = "darwin-soname.patch";
|
||||
url = "https://sourceforge.net/p/giflib/bugs/_discuss/thread/4e811ad29b/c323/attachment/Makefile.patch";
|
||||
sha256 = "12afkqnlkl3n1hywwgx8sqnhp3bz0c5qrwcv8j9hifw1lmfhv67r";
|
||||
extraPrefix = "./";
|
||||
})
|
||||
./CVE-2021-40633.patch
|
||||
] ++ lib.optionals stdenv.hostPlatform.isMinGW [
|
||||
# Build dll libraries.
|
||||
(fetchurl {
|
||||
@@ -40,7 +29,9 @@ stdenv.mkDerivation rec {
|
||||
./mingw-install-exes.patch
|
||||
];
|
||||
|
||||
nativeBuildInputs = lib.optionals stdenv.isDarwin [
|
||||
nativeBuildInputs = [
|
||||
imagemagick_light
|
||||
] ++ lib.optionals stdenv.isDarwin [
|
||||
fixDarwinDylibNames
|
||||
];
|
||||
|
||||
@@ -50,10 +41,11 @@ stdenv.mkDerivation rec {
|
||||
|
||||
postPatch = lib.optionalString stdenv.hostPlatform.isStatic ''
|
||||
# Upstream build system does not support NOT building shared libraries.
|
||||
sed -i '/all:/ s/libgif.so//' Makefile
|
||||
sed -i '/all:/ s/libutil.so//' Makefile
|
||||
sed -i '/-m 755 libgif.so/ d' Makefile
|
||||
sed -i '/ln -sf libgif.so/ d' Makefile
|
||||
sed -i '/all:/ s/$(LIBGIFSO)//' Makefile
|
||||
sed -i '/all:/ s/$(LIBUTILSO)//' Makefile
|
||||
sed -i '/-m 755 $(LIBGIFSO)/ d' Makefile
|
||||
sed -i '/ln -sf $(LIBGIFSOVER)/ d' Makefile
|
||||
sed -i '/ln -sf $(LIBGIFSOMAJOR)/ d' Makefile
|
||||
'';
|
||||
|
||||
passthru.tests = {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{ config, lib, stdenv, fetchurl, zlib, lzo, libtasn1, nettle, pkg-config, lzip
|
||||
{ config, lib, stdenv, fetchurl, fetchpatch, zlib, lzo, libtasn1, nettle, pkg-config, lzip
|
||||
, perl, gmp, autoconf, automake, libidn2, libiconv
|
||||
, texinfo
|
||||
, unbound, dns-root-data, gettext, util-linux
|
||||
@@ -49,6 +49,16 @@ stdenv.mkDerivation rec {
|
||||
|
||||
patches = [
|
||||
./nix-ssl-cert-file.patch
|
||||
(fetchpatch {
|
||||
name = "CVE-2024-28834.patch";
|
||||
url = "https://gitlab.com/gnutls/gnutls/-/commit/1c4701ffc342259fc5965d5a0de90d87f780e3e5.patch";
|
||||
hash = "sha256-QMqeEdpNy5MCuZwTPRVKnWMvGkZvIlumigvH3JgcjE4=";
|
||||
})
|
||||
(fetchpatch {
|
||||
name = "CVE-2024-28835.patch";
|
||||
url = "https://gitlab.com/gnutls/gnutls/-/commit/e369e67a62f44561d417cb233acc566cc696d82d.patch";
|
||||
hash = "sha256-K8wqypFKfoB7hiFWJPSVVEC7Aei7NGRijorK/tkou9o=";
|
||||
})
|
||||
];
|
||||
|
||||
# Skip some tests:
|
||||
|
||||
@@ -44,6 +44,11 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
url = "https://github.com/libarchive/libarchive/commit/3bd918d92f8c34ba12de9c6604d96f9e262a59fc.patch";
|
||||
hash = "sha256-RM3xFM6S2DkM5DJ0kAba8eLzEXuY5/7AaU06maHJ6rM=";
|
||||
})
|
||||
(fetchpatch {
|
||||
name = "fix-suspicious-commit-from-known-bad-actor.patch";
|
||||
url = "https://github.com/libarchive/libarchive/commit/6110e9c82d8ba830c3440f36b990483ceaaea52c.patch";
|
||||
hash = "sha256-/j6rJ0xWhtXU0YCu1LOokxxNppy5Of6Q0XyO4U6la7M=";
|
||||
})
|
||||
];
|
||||
|
||||
outputs = [ "out" "lib" "dev" ];
|
||||
|
||||
826
pkgs/development/libraries/qpdf/11.6.1-CVE-2024-24246.patch
Normal file
826
pkgs/development/libraries/qpdf/11.6.1-CVE-2024-24246.patch
Normal file
@@ -0,0 +1,826 @@
|
||||
Based on upstream cb0f390cc1f98a8e82b27259f8f3cd5f162992eb, adjusted to
|
||||
apply to 11.6.1
|
||||
|
||||
diff --git a/libqpdf/QPDF_json.cc b/libqpdf/QPDF_json.cc
|
||||
index f8fd689a..7a712010 100644
|
||||
--- a/libqpdf/QPDF_json.cc
|
||||
+++ b/libqpdf/QPDF_json.cc
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
// This chart shows an example of the state transitions that would occur in parsing a minimal file.
|
||||
|
||||
-// | st_initial
|
||||
+// |
|
||||
// { | -> st_top
|
||||
// "qpdf": [ | -> st_qpdf
|
||||
// { | -> st_qpdf_meta
|
||||
@@ -47,7 +47,7 @@
|
||||
// } | <- st_objects
|
||||
// } | <- st_qpdf
|
||||
// ] | <- st_top
|
||||
-// } | <- st_initial
|
||||
+// } |
|
||||
|
||||
static char const* JSON_PDF = (
|
||||
// force line break
|
||||
@@ -99,7 +99,7 @@ is_indirect_object(std::string const& v, int& obj, int& gen)
|
||||
}
|
||||
obj = QUtil::string_to_int(o_str.c_str());
|
||||
gen = QUtil::string_to_int(g_str.c_str());
|
||||
- return true;
|
||||
+ return obj > 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
@@ -250,7 +250,6 @@ class QPDF::JSONReactor: public JSON::Reactor
|
||||
|
||||
private:
|
||||
enum state_e {
|
||||
- st_initial,
|
||||
st_top,
|
||||
st_qpdf,
|
||||
st_qpdf_meta,
|
||||
@@ -262,28 +261,35 @@ class QPDF::JSONReactor: public JSON::Reactor
|
||||
st_ignore,
|
||||
};
|
||||
|
||||
+ struct StackFrame
|
||||
+ {
|
||||
+ StackFrame(state_e state) :
|
||||
+ state(state){};
|
||||
+ StackFrame(state_e state, QPDFObjectHandle&& object) :
|
||||
+ state(state),
|
||||
+ object(object){};
|
||||
+ state_e state;
|
||||
+ QPDFObjectHandle object;
|
||||
+ };
|
||||
+
|
||||
void containerStart();
|
||||
- void nestedState(std::string const& key, JSON const& value, state_e);
|
||||
+ bool setNextStateIfDictionary(std::string const& key, JSON const& value, state_e);
|
||||
void setObjectDescription(QPDFObjectHandle& oh, JSON const& value);
|
||||
QPDFObjectHandle makeObject(JSON const& value);
|
||||
void error(qpdf_offset_t offset, std::string const& message);
|
||||
- void
|
||||
- replaceObject(QPDFObjectHandle to_replace, QPDFObjectHandle replacement, JSON const& value);
|
||||
+ void replaceObject(QPDFObjectHandle&& replacement, JSON const& value);
|
||||
|
||||
QPDF& pdf;
|
||||
std::shared_ptr<InputSource> is;
|
||||
bool must_be_complete{true};
|
||||
std::shared_ptr<QPDFValue::Description> descr;
|
||||
bool errors{false};
|
||||
- bool parse_error{false};
|
||||
bool saw_qpdf{false};
|
||||
bool saw_qpdf_meta{false};
|
||||
bool saw_objects{false};
|
||||
bool saw_json_version{false};
|
||||
bool saw_pdf_version{false};
|
||||
bool saw_trailer{false};
|
||||
- state_e state{st_initial};
|
||||
- state_e next_state{st_top};
|
||||
std::string cur_object;
|
||||
bool saw_value{false};
|
||||
bool saw_stream{false};
|
||||
@@ -291,9 +297,10 @@ class QPDF::JSONReactor: public JSON::Reactor
|
||||
bool saw_data{false};
|
||||
bool saw_datafile{false};
|
||||
bool this_stream_needs_data{false};
|
||||
- std::vector<state_e> state_stack{st_initial};
|
||||
- std::vector<QPDFObjectHandle> object_stack;
|
||||
std::set<QPDFObjGen> reserved;
|
||||
+ std::vector<StackFrame> stack;
|
||||
+ QPDFObjectHandle next_obj;
|
||||
+ state_e next_state{st_top};
|
||||
};
|
||||
|
||||
void
|
||||
@@ -316,8 +323,12 @@ QPDF::JSONReactor::anyErrors() const
|
||||
void
|
||||
QPDF::JSONReactor::containerStart()
|
||||
{
|
||||
- state_stack.push_back(state);
|
||||
- state = next_state;
|
||||
+ if (next_obj.isInitialized()) {
|
||||
+ stack.emplace_back(next_state, std::move(next_obj));
|
||||
+ next_obj = QPDFObjectHandle();
|
||||
+ } else {
|
||||
+ stack.emplace_back(next_state);
|
||||
+ }
|
||||
}
|
||||
|
||||
void
|
||||
@@ -329,20 +340,19 @@ QPDF::JSONReactor::dictionaryStart()
|
||||
void
|
||||
QPDF::JSONReactor::arrayStart()
|
||||
{
|
||||
- containerStart();
|
||||
- if (state == st_top) {
|
||||
+ if (stack.empty()) {
|
||||
QTC::TC("qpdf", "QPDF_json top-level array");
|
||||
throw std::runtime_error("QPDF JSON must be a dictionary");
|
||||
}
|
||||
+ containerStart();
|
||||
}
|
||||
|
||||
void
|
||||
QPDF::JSONReactor::containerEnd(JSON const& value)
|
||||
{
|
||||
- auto from_state = state;
|
||||
- state = state_stack.back();
|
||||
- state_stack.pop_back();
|
||||
- if (state == st_initial) {
|
||||
+ auto from_state = stack.back().state;
|
||||
+ stack.pop_back();
|
||||
+ if (stack.empty()) {
|
||||
if (!this->saw_qpdf) {
|
||||
QTC::TC("qpdf", "QPDF_json missing qpdf");
|
||||
error(0, "\"qpdf\" object was not seen");
|
||||
@@ -365,26 +375,16 @@ QPDF::JSONReactor::containerEnd(JSON const& value)
|
||||
}
|
||||
}
|
||||
}
|
||||
- } else if (state == st_objects) {
|
||||
- if (parse_error) {
|
||||
- QTC::TC("qpdf", "QPDF_json don't check object after parse error");
|
||||
- } else if (cur_object == "trailer") {
|
||||
- if (!saw_value) {
|
||||
- QTC::TC("qpdf", "QPDF_json trailer no value");
|
||||
- error(value.getStart(), "\"trailer\" is missing \"value\"");
|
||||
- }
|
||||
- } else if (saw_value == saw_stream) {
|
||||
+ } else if (from_state == st_trailer) {
|
||||
+ if (!saw_value) {
|
||||
+ QTC::TC("qpdf", "QPDF_json trailer no value");
|
||||
+ error(value.getStart(), "\"trailer\" is missing \"value\"");
|
||||
+ }
|
||||
+ } else if (from_state == st_object_top) {
|
||||
+ if (saw_value == saw_stream) {
|
||||
QTC::TC("qpdf", "QPDF_json value stream both or neither");
|
||||
error(value.getStart(), "object must have exactly one of \"value\" or \"stream\"");
|
||||
}
|
||||
- object_stack.clear();
|
||||
- this->cur_object = "";
|
||||
- this->saw_dict = false;
|
||||
- this->saw_data = false;
|
||||
- this->saw_datafile = false;
|
||||
- this->saw_value = false;
|
||||
- this->saw_stream = false;
|
||||
- } else if (state == st_object_top) {
|
||||
if (saw_stream) {
|
||||
if (!saw_dict) {
|
||||
QTC::TC("qpdf", "QPDF_json stream no dict");
|
||||
@@ -408,11 +408,7 @@ QPDF::JSONReactor::containerEnd(JSON const& value)
|
||||
}
|
||||
}
|
||||
}
|
||||
- } else if ((state == st_stream) || (state == st_object)) {
|
||||
- if (!parse_error) {
|
||||
- object_stack.pop_back();
|
||||
- }
|
||||
- } else if ((state == st_top) && (from_state == st_qpdf)) {
|
||||
+ } else if (from_state == st_qpdf) {
|
||||
// Handle dangling indirect object references which the PDF spec says to treat as nulls.
|
||||
// It's tempting to make this an error, but that would be wrong since valid input files may
|
||||
// have these.
|
||||
@@ -423,16 +419,27 @@ QPDF::JSONReactor::containerEnd(JSON const& value)
|
||||
}
|
||||
}
|
||||
}
|
||||
+ if (!stack.empty()) {
|
||||
+ auto state = stack.back().state;
|
||||
+ if (state == st_objects) {
|
||||
+ this->cur_object = "";
|
||||
+ this->saw_dict = false;
|
||||
+ this->saw_data = false;
|
||||
+ this->saw_datafile = false;
|
||||
+ this->saw_value = false;
|
||||
+ this->saw_stream = false;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
void
|
||||
-QPDF::JSONReactor::replaceObject(
|
||||
- QPDFObjectHandle to_replace, QPDFObjectHandle replacement, JSON const& value)
|
||||
+QPDF::JSONReactor::replaceObject(QPDFObjectHandle&& replacement, JSON const& value)
|
||||
{
|
||||
- auto og = to_replace.getObjGen();
|
||||
+ auto& tos = stack.back();
|
||||
+ auto og = tos.object.getObjGen();
|
||||
this->pdf.replaceObject(og, replacement);
|
||||
- auto oh = pdf.getObject(og);
|
||||
- setObjectDescription(oh, value);
|
||||
+ next_obj = pdf.getObject(og);
|
||||
+ setObjectDescription(tos.object, value);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -442,22 +449,26 @@ QPDF::JSONReactor::topLevelScalar()
|
||||
throw std::runtime_error("QPDF JSON must be a dictionary");
|
||||
}
|
||||
|
||||
-void
|
||||
-QPDF::JSONReactor::nestedState(std::string const& key, JSON const& value, state_e next)
|
||||
+bool
|
||||
+QPDF::JSONReactor::setNextStateIfDictionary(std::string const& key, JSON const& value, state_e next)
|
||||
{
|
||||
// Use this method when the next state is for processing a nested dictionary.
|
||||
if (value.isDictionary()) {
|
||||
this->next_state = next;
|
||||
- } else {
|
||||
- error(value.getStart(), "\"" + key + "\" must be a dictionary");
|
||||
- this->next_state = st_ignore;
|
||||
- this->parse_error = true;
|
||||
+ return true;
|
||||
}
|
||||
+ error(value.getStart(), "\"" + key + "\" must be a dictionary");
|
||||
+ return false;
|
||||
}
|
||||
|
||||
bool
|
||||
QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value)
|
||||
{
|
||||
+ if (stack.empty()) {
|
||||
+ throw std::logic_error("stack is empty in dictionaryItem");
|
||||
+ }
|
||||
+ next_state = st_ignore;
|
||||
+ auto state = stack.back().state;
|
||||
if (state == st_ignore) {
|
||||
QTC::TC("qpdf", "QPDF_json ignoring in st_ignore");
|
||||
// ignore
|
||||
@@ -467,51 +478,48 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value)
|
||||
if (!value.isArray()) {
|
||||
QTC::TC("qpdf", "QPDF_json qpdf not array");
|
||||
error(value.getStart(), "\"qpdf\" must be an array");
|
||||
- next_state = st_ignore;
|
||||
- parse_error = true;
|
||||
} else {
|
||||
next_state = st_qpdf;
|
||||
}
|
||||
} else {
|
||||
// Ignore all other fields.
|
||||
QTC::TC("qpdf", "QPDF_json ignoring unknown top-level key");
|
||||
- next_state = st_ignore;
|
||||
}
|
||||
} else if (state == st_qpdf_meta) {
|
||||
if (key == "pdfversion") {
|
||||
this->saw_pdf_version = true;
|
||||
- bool version_okay = false;
|
||||
std::string v;
|
||||
+ bool okay = false;
|
||||
if (value.getString(v)) {
|
||||
std::string version;
|
||||
char const* p = v.c_str();
|
||||
if (QPDF::validatePDFVersion(p, version) && (*p == '\0')) {
|
||||
- version_okay = true;
|
||||
this->pdf.m->pdf_version = version;
|
||||
+ okay = true;
|
||||
}
|
||||
}
|
||||
- if (!version_okay) {
|
||||
+ if (!okay) {
|
||||
QTC::TC("qpdf", "QPDF_json bad pdf version");
|
||||
- error(value.getStart(), "invalid PDF version (must be x.y)");
|
||||
+ error(value.getStart(), "invalid PDF version (must be \"x.y\")");
|
||||
}
|
||||
} else if (key == "jsonversion") {
|
||||
this->saw_json_version = true;
|
||||
- bool version_okay = false;
|
||||
std::string v;
|
||||
+ bool okay = false;
|
||||
if (value.getNumber(v)) {
|
||||
std::string version;
|
||||
if (QUtil::string_to_int(v.c_str()) == 2) {
|
||||
- version_okay = true;
|
||||
+ okay = true;
|
||||
}
|
||||
}
|
||||
- if (!version_okay) {
|
||||
+ if (!okay) {
|
||||
QTC::TC("qpdf", "QPDF_json bad json version");
|
||||
- error(value.getStart(), "invalid JSON version (must be 2)");
|
||||
+ error(value.getStart(), "invalid JSON version (must be numeric value 2)");
|
||||
}
|
||||
} else if (key == "pushedinheritedpageresources") {
|
||||
bool v;
|
||||
if (value.getBool(v)) {
|
||||
- if ((!this->must_be_complete) && v) {
|
||||
+ if (!this->must_be_complete && v) {
|
||||
this->pdf.pushInheritedAttributesToPage();
|
||||
}
|
||||
} else {
|
||||
@@ -521,7 +529,7 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value)
|
||||
} else if (key == "calledgetallpages") {
|
||||
bool v;
|
||||
if (value.getBool(v)) {
|
||||
- if ((!this->must_be_complete) && v) {
|
||||
+ if (!this->must_be_complete && v) {
|
||||
this->pdf.getAllPages();
|
||||
}
|
||||
} else {
|
||||
@@ -532,103 +540,95 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value)
|
||||
// ignore unknown keys for forward compatibility and to skip keys we don't care about
|
||||
// like "maxobjectid".
|
||||
QTC::TC("qpdf", "QPDF_json ignore second-level key");
|
||||
- next_state = st_ignore;
|
||||
}
|
||||
} else if (state == st_objects) {
|
||||
int obj = 0;
|
||||
int gen = 0;
|
||||
if (key == "trailer") {
|
||||
this->saw_trailer = true;
|
||||
- nestedState(key, value, st_trailer);
|
||||
this->cur_object = "trailer";
|
||||
+ setNextStateIfDictionary(key, value, st_trailer);
|
||||
} else if (is_obj_key(key, obj, gen)) {
|
||||
this->cur_object = key;
|
||||
- auto oh = pdf.reserveObjectIfNotExists(QPDFObjGen(obj, gen));
|
||||
- object_stack.push_back(oh);
|
||||
- nestedState(key, value, st_object_top);
|
||||
+ if (setNextStateIfDictionary(key, value, st_object_top)) {
|
||||
+ next_obj = pdf.reserveObjectIfNotExists(QPDFObjGen(obj, gen));
|
||||
+ }
|
||||
} else {
|
||||
QTC::TC("qpdf", "QPDF_json bad object key");
|
||||
error(value.getStart(), "object key should be \"trailer\" or \"obj:n n R\"");
|
||||
- next_state = st_ignore;
|
||||
- parse_error = true;
|
||||
}
|
||||
} else if (state == st_object_top) {
|
||||
- if (object_stack.size() == 0) {
|
||||
- throw std::logic_error("no object on stack in st_object_top");
|
||||
+ if (stack.empty()) {
|
||||
+ throw std::logic_error("stack empty in st_object_top");
|
||||
+ }
|
||||
+ auto& tos = stack.back();
|
||||
+ if (!tos.object.isInitialized()) {
|
||||
+ throw std::logic_error("current object uninitialized in st_object_top");
|
||||
}
|
||||
- auto tos = object_stack.back();
|
||||
- QPDFObjectHandle replacement;
|
||||
if (key == "value") {
|
||||
- // Don't use nestedState since this can have any type.
|
||||
+ // Don't use setNextStateIfDictionary since this can have any type.
|
||||
this->saw_value = true;
|
||||
+ replaceObject(makeObject(value), value);
|
||||
next_state = st_object;
|
||||
- replacement = makeObject(value);
|
||||
- replaceObject(tos, replacement, value);
|
||||
} else if (key == "stream") {
|
||||
this->saw_stream = true;
|
||||
- nestedState(key, value, st_stream);
|
||||
- this->this_stream_needs_data = false;
|
||||
- if (tos.isStream()) {
|
||||
- QTC::TC("qpdf", "QPDF_json updating existing stream");
|
||||
+ if (setNextStateIfDictionary(key, value, st_stream)) {
|
||||
+ this->this_stream_needs_data = false;
|
||||
+ if (tos.object.isStream()) {
|
||||
+ QTC::TC("qpdf", "QPDF_json updating existing stream");
|
||||
+ } else {
|
||||
+ this->this_stream_needs_data = true;
|
||||
+ replaceObject(pdf.reserveStream(tos.object.getObjGen()), value);
|
||||
+ }
|
||||
+ next_obj = tos.object;
|
||||
} else {
|
||||
- this->this_stream_needs_data = true;
|
||||
- replacement = pdf.reserveStream(tos.getObjGen());
|
||||
- replaceObject(tos, replacement, value);
|
||||
+ // Error message already given above
|
||||
+ QTC::TC("qpdf", "QPDF_json stream not a dictionary");
|
||||
}
|
||||
} else {
|
||||
// Ignore unknown keys for forward compatibility
|
||||
QTC::TC("qpdf", "QPDF_json ignore unknown key in object_top");
|
||||
- next_state = st_ignore;
|
||||
- }
|
||||
- if (replacement.isInitialized()) {
|
||||
- object_stack.pop_back();
|
||||
- object_stack.push_back(replacement);
|
||||
}
|
||||
} else if (state == st_trailer) {
|
||||
if (key == "value") {
|
||||
this->saw_value = true;
|
||||
- // The trailer must be a dictionary, so we can use nestedState.
|
||||
- nestedState("trailer.value", value, st_object);
|
||||
- this->pdf.m->trailer = makeObject(value);
|
||||
- setObjectDescription(this->pdf.m->trailer, value);
|
||||
+ // The trailer must be a dictionary, so we can use setNextStateIfDictionary.
|
||||
+ if (setNextStateIfDictionary("trailer.value", value, st_object)) {
|
||||
+ this->pdf.m->trailer = makeObject(value);
|
||||
+ setObjectDescription(this->pdf.m->trailer, value);
|
||||
+ }
|
||||
} else if (key == "stream") {
|
||||
// Don't need to set saw_stream here since there's already an error.
|
||||
QTC::TC("qpdf", "QPDF_json trailer stream");
|
||||
error(value.getStart(), "the trailer may not be a stream");
|
||||
- next_state = st_ignore;
|
||||
- parse_error = true;
|
||||
} else {
|
||||
// Ignore unknown keys for forward compatibility
|
||||
QTC::TC("qpdf", "QPDF_json ignore unknown key in trailer");
|
||||
- next_state = st_ignore;
|
||||
}
|
||||
} else if (state == st_stream) {
|
||||
- if (object_stack.size() == 0) {
|
||||
- throw std::logic_error("no object on stack in st_stream");
|
||||
+ if (stack.empty()) {
|
||||
+ throw std::logic_error("stack empty in st_stream");
|
||||
}
|
||||
- auto tos = object_stack.back();
|
||||
- if (!tos.isStream()) {
|
||||
- throw std::logic_error("top of stack is not stream in st_stream");
|
||||
+ auto& tos = stack.back();
|
||||
+ if (!tos.object.isStream()) {
|
||||
+ throw std::logic_error("current object is not stream in st_stream");
|
||||
}
|
||||
auto uninitialized = QPDFObjectHandle();
|
||||
if (key == "dict") {
|
||||
this->saw_dict = true;
|
||||
- // Since a stream dictionary must be a dictionary, we can use nestedState to transition
|
||||
- // to st_value.
|
||||
- nestedState("stream.dict", value, st_object);
|
||||
- auto dict = makeObject(value);
|
||||
- if (dict.isDictionary()) {
|
||||
- tos.replaceDict(dict);
|
||||
+ if (setNextStateIfDictionary("stream.dict", value, st_object)) {
|
||||
+ tos.object.replaceDict(makeObject(value));
|
||||
} else {
|
||||
- // An error had already been given by nestedState
|
||||
+ // An error had already been given by setNextStateIfDictionary
|
||||
QTC::TC("qpdf", "QPDF_json stream dict not dict");
|
||||
- parse_error = true;
|
||||
}
|
||||
} else if (key == "data") {
|
||||
this->saw_data = true;
|
||||
std::string v;
|
||||
if (!value.getString(v)) {
|
||||
+ QTC::TC("qpdf", "QPDF_json stream data not string");
|
||||
error(value.getStart(), "\"stream.data\" must be a string");
|
||||
+ tos.object.replaceStreamData("", uninitialized, uninitialized);
|
||||
} else {
|
||||
// The range includes the quotes.
|
||||
auto start = value.getStart() + 1;
|
||||
@@ -636,32 +636,40 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value)
|
||||
if (end < start) {
|
||||
throw std::logic_error("QPDF_json: JSON string length < 0");
|
||||
}
|
||||
- tos.replaceStreamData(provide_data(is, start, end), uninitialized, uninitialized);
|
||||
+ tos.object.replaceStreamData(
|
||||
+ provide_data(is, start, end), uninitialized, uninitialized);
|
||||
}
|
||||
} else if (key == "datafile") {
|
||||
this->saw_datafile = true;
|
||||
std::string filename;
|
||||
- if (value.getString(filename)) {
|
||||
- tos.replaceStreamData(QUtil::file_provider(filename), uninitialized, uninitialized);
|
||||
- } else {
|
||||
+ if (!value.getString(filename)) {
|
||||
+ QTC::TC("qpdf", "QPDF_json stream datafile not string");
|
||||
error(
|
||||
value.getStart(),
|
||||
- "\"stream.datafile\" must be a string containing a file "
|
||||
- "name");
|
||||
+ "\"stream.datafile\" must be a string containing a file name");
|
||||
+ tos.object.replaceStreamData("", uninitialized, uninitialized);
|
||||
+ } else {
|
||||
+ tos.object.replaceStreamData(
|
||||
+ QUtil::file_provider(filename), uninitialized, uninitialized);
|
||||
}
|
||||
} else {
|
||||
// Ignore unknown keys for forward compatibility.
|
||||
QTC::TC("qpdf", "QPDF_json ignore unknown key in stream");
|
||||
- next_state = st_ignore;
|
||||
}
|
||||
} else if (state == st_object) {
|
||||
- if (!parse_error) {
|
||||
- auto dict = object_stack.back();
|
||||
- if (dict.isStream()) {
|
||||
- dict = dict.getDict();
|
||||
- }
|
||||
- dict.replaceKey(key, makeObject(value));
|
||||
+ if (stack.empty()) {
|
||||
+ throw std::logic_error("stack empty in st_object");
|
||||
+ }
|
||||
+ auto& tos = stack.back();
|
||||
+ auto dict = tos.object;
|
||||
+ if (dict.isStream()) {
|
||||
+ dict = dict.getDict();
|
||||
+ }
|
||||
+ if (!dict.isDictionary()) {
|
||||
+ throw std::logic_error(
|
||||
+ "current object is not stream or dictionary in st_object dictionary item");
|
||||
}
|
||||
+ dict.replaceKey(key, makeObject(value));
|
||||
} else {
|
||||
throw std::logic_error("QPDF_json: unknown state " + std::to_string(state));
|
||||
}
|
||||
@@ -671,25 +679,24 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value)
|
||||
bool
|
||||
QPDF::JSONReactor::arrayItem(JSON const& value)
|
||||
{
|
||||
+ if (stack.empty()) {
|
||||
+ throw std::logic_error("stack is empty in arrayItem");
|
||||
+ }
|
||||
+ next_state = st_ignore;
|
||||
+ auto state = stack.back().state;
|
||||
if (state == st_qpdf) {
|
||||
if (!this->saw_qpdf_meta) {
|
||||
this->saw_qpdf_meta = true;
|
||||
- nestedState("qpdf[0]", value, st_qpdf_meta);
|
||||
+ setNextStateIfDictionary("qpdf[0]", value, st_qpdf_meta);
|
||||
} else if (!this->saw_objects) {
|
||||
this->saw_objects = true;
|
||||
- nestedState("qpdf[1]", value, st_objects);
|
||||
+ setNextStateIfDictionary("qpdf[1]", value, st_objects);
|
||||
} else {
|
||||
QTC::TC("qpdf", "QPDF_json more than two qpdf elements");
|
||||
error(value.getStart(), "\"qpdf\" must have two elements");
|
||||
- next_state = st_ignore;
|
||||
- parse_error = true;
|
||||
- }
|
||||
- }
|
||||
- if (state == st_object) {
|
||||
- if (!parse_error) {
|
||||
- auto tos = object_stack.back();
|
||||
- tos.appendItem(makeObject(value));
|
||||
}
|
||||
+ } else if (state == st_object) {
|
||||
+ stack.back().object.appendItem(makeObject(value));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -714,10 +721,12 @@ QPDF::JSONReactor::makeObject(JSON const& value)
|
||||
bool bool_v = false;
|
||||
if (value.isDictionary()) {
|
||||
result = QPDFObjectHandle::newDictionary();
|
||||
- object_stack.push_back(result);
|
||||
+ next_obj = result;
|
||||
+ next_state = st_object;
|
||||
} else if (value.isArray()) {
|
||||
result = QPDFObjectHandle::newArray();
|
||||
- object_stack.push_back(result);
|
||||
+ next_obj = result;
|
||||
+ next_state = st_object;
|
||||
} else if (value.isNull()) {
|
||||
result = QPDFObjectHandle::newNull();
|
||||
} else if (value.getBool(bool_v)) {
|
||||
diff --git a/qpdf/qtest/qpdf-json.test b/qpdf/qtest/qpdf-json.test
|
||||
index 2867f8a7..4982d440 100644
|
||||
--- a/qpdf/qtest/qpdf-json.test
|
||||
+++ b/qpdf/qtest/qpdf-json.test
|
||||
@@ -37,6 +37,8 @@ my @badfiles = (
|
||||
'obj-key-errors',
|
||||
'bad-data',
|
||||
'bad-datafile',
|
||||
+ 'bad-data2',
|
||||
+ 'bad-datafile2',
|
||||
);
|
||||
|
||||
$n_tests += scalar(@badfiles);
|
||||
diff --git a/qpdf/qtest/qpdf/qjson-bad-data2.json b/qpdf/qtest/qpdf/qjson-bad-data2.json
|
||||
new file mode 100644
|
||||
index 00000000..80206086
|
||||
--- /dev/null
|
||||
+++ b/qpdf/qtest/qpdf/qjson-bad-data2.json
|
||||
@@ -0,0 +1,71 @@
|
||||
+{
|
||||
+ "qpdf": [
|
||||
+ {
|
||||
+ "jsonversion": 2,
|
||||
+ "pdfversion": "1.3",
|
||||
+ "maxobjectid": 6
|
||||
+ },
|
||||
+ {
|
||||
+ "obj:1 0 R": {
|
||||
+ "value": {
|
||||
+ "/Pages": "2 0 R",
|
||||
+ "/Type": "/Catalog"
|
||||
+ }
|
||||
+ },
|
||||
+ "obj:2 0 R": {
|
||||
+ "value": {
|
||||
+ "/Count": 1,
|
||||
+ "/Kids": [
|
||||
+ "3 0 R"
|
||||
+ ],
|
||||
+ "/Type": "/Pages"
|
||||
+ }
|
||||
+ },
|
||||
+ "obj:3 0 R": {
|
||||
+ "value": {
|
||||
+ "/Contents": ["4 0 R", "7 0 R"],
|
||||
+ "/MediaBox": [
|
||||
+ 0,
|
||||
+ 0,
|
||||
+ 612,
|
||||
+ 792
|
||||
+ ],
|
||||
+ "/Parent": "2 0 R",
|
||||
+ "/Resources": {
|
||||
+ "/Font": {
|
||||
+ "/F1": "6 0 R"
|
||||
+ },
|
||||
+ "/ProcSet": "5 0 R"
|
||||
+ },
|
||||
+ "/Type": "/Page"
|
||||
+ }
|
||||
+ },
|
||||
+ "obj:4 0 R": {
|
||||
+ "stream": {
|
||||
+ "data": [[]],
|
||||
+ "dict": {}
|
||||
+ }
|
||||
+ },
|
||||
+ "obj:5 0 R": {
|
||||
+ "value": [
|
||||
+ "/PDF",
|
||||
+ "/Text"
|
||||
+ ]
|
||||
+ },
|
||||
+ "obj:6 0 R": {
|
||||
+ "value": {
|
||||
+ "/BaseFont": "/Helvetica",
|
||||
+ "/Encoding": "/WinAnsiEncoding",
|
||||
+ "/Subtype": "/Type1",
|
||||
+ "/Type": "/Font"
|
||||
+ }
|
||||
+ },
|
||||
+ "trailer": {
|
||||
+ "value": {
|
||||
+ "/Root": "1 0 R",
|
||||
+ "/Size": 7
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ ]
|
||||
+}
|
||||
diff --git a/qpdf/qtest/qpdf/qjson-bad-data2.out b/qpdf/qtest/qpdf/qjson-bad-data2.out
|
||||
new file mode 100644
|
||||
index 00000000..47c83c8e
|
||||
--- /dev/null
|
||||
+++ b/qpdf/qtest/qpdf/qjson-bad-data2.out
|
||||
@@ -0,0 +1,2 @@
|
||||
+WARNING: qjson-bad-data2.json (obj:4 0 R, offset 846): "stream.data" must be a string
|
||||
+qpdf: qjson-bad-data2.json: errors found in JSON
|
||||
diff --git a/qpdf/qtest/qpdf/qjson-bad-datafile2.json b/qpdf/qtest/qpdf/qjson-bad-datafile2.json
|
||||
new file mode 100644
|
||||
index 00000000..b5c99820
|
||||
--- /dev/null
|
||||
+++ b/qpdf/qtest/qpdf/qjson-bad-datafile2.json
|
||||
@@ -0,0 +1,71 @@
|
||||
+{
|
||||
+ "qpdf": [
|
||||
+ {
|
||||
+ "jsonversion": 2,
|
||||
+ "pdfversion": "1.3",
|
||||
+ "maxobjectid": 6
|
||||
+ },
|
||||
+ {
|
||||
+ "obj:1 0 R": {
|
||||
+ "value": {
|
||||
+ "/Pages": "2 0 R",
|
||||
+ "/Type": "/Catalog"
|
||||
+ }
|
||||
+ },
|
||||
+ "obj:2 0 R": {
|
||||
+ "value": {
|
||||
+ "/Count": 1,
|
||||
+ "/Kids": [
|
||||
+ "3 0 R"
|
||||
+ ],
|
||||
+ "/Type": "/Pages"
|
||||
+ }
|
||||
+ },
|
||||
+ "obj:3 0 R": {
|
||||
+ "value": {
|
||||
+ "/Contents": ["4 0 R", "7 0 R"],
|
||||
+ "/MediaBox": [
|
||||
+ 0,
|
||||
+ 0,
|
||||
+ 612,
|
||||
+ 792
|
||||
+ ],
|
||||
+ "/Parent": "2 0 R",
|
||||
+ "/Resources": {
|
||||
+ "/Font": {
|
||||
+ "/F1": "6 0 R"
|
||||
+ },
|
||||
+ "/ProcSet": "5 0 R"
|
||||
+ },
|
||||
+ "/Type": "/Page"
|
||||
+ }
|
||||
+ },
|
||||
+ "obj:4 0 R": {
|
||||
+ "stream": {
|
||||
+ "datafile": [[]],
|
||||
+ "dict": {}
|
||||
+ }
|
||||
+ },
|
||||
+ "obj:5 0 R": {
|
||||
+ "value": [
|
||||
+ "/PDF",
|
||||
+ "/Text"
|
||||
+ ]
|
||||
+ },
|
||||
+ "obj:6 0 R": {
|
||||
+ "value": {
|
||||
+ "/BaseFont": "/Helvetica",
|
||||
+ "/Encoding": "/WinAnsiEncoding",
|
||||
+ "/Subtype": "/Type1",
|
||||
+ "/Type": "/Font"
|
||||
+ }
|
||||
+ },
|
||||
+ "trailer": {
|
||||
+ "value": {
|
||||
+ "/Root": "1 0 R",
|
||||
+ "/Size": 7
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ ]
|
||||
+}
|
||||
diff --git a/qpdf/qtest/qpdf/qjson-bad-datafile2.out b/qpdf/qtest/qpdf/qjson-bad-datafile2.out
|
||||
new file mode 100644
|
||||
index 00000000..41949a21
|
||||
--- /dev/null
|
||||
+++ b/qpdf/qtest/qpdf/qjson-bad-datafile2.out
|
||||
@@ -0,0 +1,2 @@
|
||||
+WARNING: qjson-bad-datafile2.json (obj:4 0 R, offset 850): "stream.datafile" must be a string containing a file name
|
||||
+qpdf: qjson-bad-datafile2.json: errors found in JSON
|
||||
diff --git a/qpdf/qtest/qpdf/qjson-bad-pdf-version1.out b/qpdf/qtest/qpdf/qjson-bad-pdf-version1.out
|
||||
index f364f1a6..476128e7 100644
|
||||
--- a/qpdf/qtest/qpdf/qjson-bad-pdf-version1.out
|
||||
+++ b/qpdf/qtest/qpdf/qjson-bad-pdf-version1.out
|
||||
@@ -1,3 +1,3 @@
|
||||
-WARNING: qjson-bad-pdf-version1.json (offset 41): invalid JSON version (must be 2)
|
||||
-WARNING: qjson-bad-pdf-version1.json (offset 70): invalid PDF version (must be x.y)
|
||||
+WARNING: qjson-bad-pdf-version1.json (offset 41): invalid JSON version (must be numeric value 2)
|
||||
+WARNING: qjson-bad-pdf-version1.json (offset 70): invalid PDF version (must be "x.y")
|
||||
qpdf: qjson-bad-pdf-version1.json: errors found in JSON
|
||||
diff --git a/qpdf/qtest/qpdf/qjson-bad-pdf-version2.out b/qpdf/qtest/qpdf/qjson-bad-pdf-version2.out
|
||||
index 9bc88ff4..cb914414 100644
|
||||
--- a/qpdf/qtest/qpdf/qjson-bad-pdf-version2.out
|
||||
+++ b/qpdf/qtest/qpdf/qjson-bad-pdf-version2.out
|
||||
@@ -1,5 +1,5 @@
|
||||
-WARNING: qjson-bad-pdf-version2.json (offset 41): invalid JSON version (must be 2)
|
||||
-WARNING: qjson-bad-pdf-version2.json (offset 66): invalid PDF version (must be x.y)
|
||||
+WARNING: qjson-bad-pdf-version2.json (offset 41): invalid JSON version (must be numeric value 2)
|
||||
+WARNING: qjson-bad-pdf-version2.json (offset 66): invalid PDF version (must be "x.y")
|
||||
WARNING: qjson-bad-pdf-version2.json (offset 97): calledgetallpages must be a boolean
|
||||
WARNING: qjson-bad-pdf-version2.json (offset 138): pushedinheritedpageresources must be a boolean
|
||||
qpdf: qjson-bad-pdf-version2.json: errors found in JSON
|
||||
diff --git a/qpdf/qtest/qpdf/qjson-obj-key-errors.out b/qpdf/qtest/qpdf/qjson-obj-key-errors.out
|
||||
index 0263f294..f1f0a369 100644
|
||||
--- a/qpdf/qtest/qpdf/qjson-obj-key-errors.out
|
||||
+++ b/qpdf/qtest/qpdf/qjson-obj-key-errors.out
|
||||
@@ -1,7 +1,7 @@
|
||||
WARNING: qjson-obj-key-errors.json (obj:2 0 R, offset 244): object must have exactly one of "value" or "stream"
|
||||
WARNING: qjson-obj-key-errors.json (obj:3 0 R, offset 542): object must have exactly one of "value" or "stream"
|
||||
-WARNING: qjson-obj-key-errors.json (obj:4 0 R, offset 710): "stream" is missing "dict"
|
||||
-WARNING: qjson-obj-key-errors.json (obj:4 0 R, offset 710): new "stream" must have exactly one of "data" or "datafile"
|
||||
-WARNING: qjson-obj-key-errors.json (obj:5 0 R, offset 800): new "stream" must have exactly one of "data" or "datafile"
|
||||
+WARNING: qjson-obj-key-errors.json (obj:4 0 R, offset 690): "stream" is missing "dict"
|
||||
+WARNING: qjson-obj-key-errors.json (obj:4 0 R, offset 690): new "stream" must have exactly one of "data" or "datafile"
|
||||
+WARNING: qjson-obj-key-errors.json (obj:5 0 R, offset 780): new "stream" must have exactly one of "data" or "datafile"
|
||||
WARNING: qjson-obj-key-errors.json (trailer, offset 1178): "trailer" is missing "value"
|
||||
qpdf: qjson-obj-key-errors.json: errors found in JSON
|
||||
diff --git a/qpdf/qtest/qpdf/qjson-stream-dict-not-dict.out b/qpdf/qtest/qpdf/qjson-stream-dict-not-dict.out
|
||||
index a264839f..04df1518 100644
|
||||
--- a/qpdf/qtest/qpdf/qjson-stream-dict-not-dict.out
|
||||
+++ b/qpdf/qtest/qpdf/qjson-stream-dict-not-dict.out
|
||||
@@ -1,5 +1,4 @@
|
||||
WARNING: qjson-stream-dict-not-dict.json (obj:1 0 R, offset 142): "stream.dict" must be a dictionary
|
||||
-WARNING: qjson-stream-dict-not-dict.json (obj:1 0 R, offset 142): unrecognized string value
|
||||
-WARNING: qjson-stream-dict-not-dict.json (obj:1 0 R, offset 122): new "stream" must have exactly one of "data" or "datafile"
|
||||
+WARNING: qjson-stream-dict-not-dict.json (obj:1 0 R, offset 102): new "stream" must have exactly one of "data" or "datafile"
|
||||
WARNING: qjson-stream-dict-not-dict.json: "qpdf[1].trailer" was not seen
|
||||
qpdf: qjson-stream-dict-not-dict.json: errors found in JSON
|
||||
diff --git a/qpdf/qtest/qpdf/qjson-stream-not-dict.out b/qpdf/qtest/qpdf/qjson-stream-not-dict.out
|
||||
index fbd953c6..db775b59 100644
|
||||
--- a/qpdf/qtest/qpdf/qjson-stream-not-dict.out
|
||||
+++ b/qpdf/qtest/qpdf/qjson-stream-not-dict.out
|
||||
@@ -1,3 +1,4 @@
|
||||
WARNING: qjson-stream-not-dict.json (obj:1 0 R, offset 122): "stream" must be a dictionary
|
||||
+WARNING: qjson-stream-not-dict.json (obj:1 0 R, offset 102): "stream" is missing "dict"
|
||||
WARNING: qjson-stream-not-dict.json: "qpdf[1].trailer" was not seen
|
||||
qpdf: qjson-stream-not-dict.json: errors found in JSON
|
||||
diff --git a/qpdf/qtest/qpdf/qjson-trailer-stream.out b/qpdf/qtest/qpdf/qjson-trailer-stream.out
|
||||
index a625cd6d..fccb2a39 100644
|
||||
--- a/qpdf/qtest/qpdf/qjson-trailer-stream.out
|
||||
+++ b/qpdf/qtest/qpdf/qjson-trailer-stream.out
|
||||
@@ -1,2 +1,3 @@
|
||||
WARNING: qjson-trailer-stream.json (trailer, offset 1269): the trailer may not be a stream
|
||||
+WARNING: qjson-trailer-stream.json (trailer, offset 1249): "trailer" is missing "value"
|
||||
qpdf: qjson-trailer-stream.json: errors found in JSON
|
||||
diff --git a/qpdf/qtest/qpdf/update-from-json-errors.out b/qpdf/qtest/qpdf/update-from-json-errors.out
|
||||
index 530d707d..5e136c55 100644
|
||||
--- a/qpdf/qtest/qpdf/update-from-json-errors.out
|
||||
+++ b/qpdf/qtest/qpdf/update-from-json-errors.out
|
||||
@@ -1,4 +1,4 @@
|
||||
-WARNING: good13.pdf (obj:4 0 R from qpdf-json-update-errors.json, offset 95): existing "stream" may at most one of "data" or "datafile"
|
||||
+WARNING: good13.pdf (obj:4 0 R from qpdf-json-update-errors.json, offset 75): existing "stream" may at most one of "data" or "datafile"
|
||||
WARNING: good13.pdf (obj:20 0 R from qpdf-json-update-errors.json, offset 335): unrecognized string value
|
||||
-WARNING: good13.pdf (obj:20 0 R from qpdf-json-update-errors.json, offset 293): new "stream" must have exactly one of "data" or "datafile"
|
||||
+WARNING: good13.pdf (obj:20 0 R from qpdf-json-update-errors.json, offset 273): new "stream" must have exactly one of "data" or "datafile"
|
||||
qpdf: qpdf-json-update-errors.json: errors found in JSON
|
||||
@@ -11,6 +11,10 @@ stdenv.mkDerivation rec {
|
||||
hash = "sha256-QXRzvSMi6gKISJo44KIjTYENNqxh1yDhUUhEZa8uz6Q=";
|
||||
};
|
||||
|
||||
patches = [
|
||||
./11.6.1-CVE-2024-24246.patch
|
||||
];
|
||||
|
||||
nativeBuildInputs = [ cmake perl ];
|
||||
|
||||
buildInputs = [ zlib libjpeg ];
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
Based on upstream 1c335944d6a8b1298baf179b7c0b3069f10c514b with a couple
|
||||
of type hints removed from the added tests because they refer to type
|
||||
aliases that don't exist in 3.8.6
|
||||
|
||||
diff --git a/CHANGES/8079.bugfix.rst b/CHANGES/8079.bugfix.rst
|
||||
new file mode 100644
|
||||
index 00000000..57bc8bfe
|
||||
--- /dev/null
|
||||
+++ b/CHANGES/8079.bugfix.rst
|
||||
@@ -0,0 +1 @@
|
||||
+Improved validation of paths for static resources -- by :user:`bdraco`.
|
||||
diff --git a/aiohttp/web_urldispatcher.py b/aiohttp/web_urldispatcher.py
|
||||
index 5942e355..e8a8023e 100644
|
||||
--- a/aiohttp/web_urldispatcher.py
|
||||
+++ b/aiohttp/web_urldispatcher.py
|
||||
@@ -593,9 +593,14 @@ class StaticResource(PrefixResource):
|
||||
url = url / filename
|
||||
|
||||
if append_version:
|
||||
+ unresolved_path = self._directory.joinpath(filename)
|
||||
try:
|
||||
- filepath = self._directory.joinpath(filename).resolve()
|
||||
- if not self._follow_symlinks:
|
||||
+ if self._follow_symlinks:
|
||||
+ normalized_path = Path(os.path.normpath(unresolved_path))
|
||||
+ normalized_path.relative_to(self._directory)
|
||||
+ filepath = normalized_path.resolve()
|
||||
+ else:
|
||||
+ filepath = unresolved_path.resolve()
|
||||
filepath.relative_to(self._directory)
|
||||
except (ValueError, FileNotFoundError):
|
||||
# ValueError for case when path point to symlink
|
||||
@@ -660,8 +665,13 @@ class StaticResource(PrefixResource):
|
||||
# /static/\\machine_name\c$ or /static/D:\path
|
||||
# where the static dir is totally different
|
||||
raise HTTPForbidden()
|
||||
- filepath = self._directory.joinpath(filename).resolve()
|
||||
- if not self._follow_symlinks:
|
||||
+ unresolved_path = self._directory.joinpath(filename)
|
||||
+ if self._follow_symlinks:
|
||||
+ normalized_path = Path(os.path.normpath(unresolved_path))
|
||||
+ normalized_path.relative_to(self._directory)
|
||||
+ filepath = normalized_path.resolve()
|
||||
+ else:
|
||||
+ filepath = unresolved_path.resolve()
|
||||
filepath.relative_to(self._directory)
|
||||
except (ValueError, FileNotFoundError) as error:
|
||||
# relatively safe
|
||||
diff --git a/docs/web_advanced.rst b/docs/web_advanced.rst
|
||||
index 3a98b78a..51293970 100644
|
||||
--- a/docs/web_advanced.rst
|
||||
+++ b/docs/web_advanced.rst
|
||||
@@ -136,12 +136,22 @@ instead could be enabled with ``show_index`` parameter set to ``True``::
|
||||
|
||||
web.static('/prefix', path_to_static_folder, show_index=True)
|
||||
|
||||
-When a symlink from the static directory is accessed, the server responses to
|
||||
-client with ``HTTP/404 Not Found`` by default. To allow the server to follow
|
||||
-symlinks, parameter ``follow_symlinks`` should be set to ``True``::
|
||||
+When a symlink that leads outside the static directory is accessed, the server
|
||||
+responds to the client with ``HTTP/404 Not Found`` by default. To allow the server to
|
||||
+follow symlinks that lead outside the static root, the parameter ``follow_symlinks``
|
||||
+should be set to ``True``::
|
||||
|
||||
web.static('/prefix', path_to_static_folder, follow_symlinks=True)
|
||||
|
||||
+.. caution::
|
||||
+
|
||||
+ Enabling ``follow_symlinks`` can be a security risk, and may lead to
|
||||
+ a directory transversal attack. You do NOT need this option to follow symlinks
|
||||
+ which point to somewhere else within the static directory, this option is only
|
||||
+ used to break out of the security sandbox. Enabling this option is highly
|
||||
+ discouraged, and only expected to be used for edge cases in a local
|
||||
+ development setting where remote users do not have access to the server.
|
||||
+
|
||||
When you want to enable cache busting,
|
||||
parameter ``append_version`` can be set to ``True``
|
||||
|
||||
diff --git a/docs/web_reference.rst b/docs/web_reference.rst
|
||||
index a156f47d..b1006764 100644
|
||||
--- a/docs/web_reference.rst
|
||||
+++ b/docs/web_reference.rst
|
||||
@@ -1836,9 +1836,15 @@ Router is any object that implements :class:`~aiohttp.abc.AbstractRouter` interf
|
||||
by default it's not allowed and HTTP/403 will
|
||||
be returned on directory access.
|
||||
|
||||
- :param bool follow_symlinks: flag for allowing to follow symlinks from
|
||||
- a directory, by default it's not allowed and
|
||||
- HTTP/404 will be returned on access.
|
||||
+ :param bool follow_symlinks: flag for allowing to follow symlinks that lead
|
||||
+ outside the static root directory, by default it's not allowed and
|
||||
+ HTTP/404 will be returned on access. Enabling ``follow_symlinks``
|
||||
+ can be a security risk, and may lead to a directory transversal attack.
|
||||
+ You do NOT need this option to follow symlinks which point to somewhere
|
||||
+ else within the static directory, this option is only used to break out
|
||||
+ of the security sandbox. Enabling this option is highly discouraged,
|
||||
+ and only expected to be used for edge cases in a local development
|
||||
+ setting where remote users do not have access to the server.
|
||||
|
||||
:param bool append_version: flag for adding file version (hash)
|
||||
to the url query string, this value will
|
||||
diff --git a/tests/test_web_urldispatcher.py b/tests/test_web_urldispatcher.py
|
||||
index f24f451e..6b8381c0 100644
|
||||
--- a/tests/test_web_urldispatcher.py
|
||||
+++ b/tests/test_web_urldispatcher.py
|
||||
@@ -123,6 +123,97 @@ async def test_follow_symlink(tmp_dir_path, aiohttp_client) -> None:
|
||||
assert (await r.text()) == data
|
||||
|
||||
|
||||
+async def test_follow_symlink_directory_traversal(
|
||||
+ tmp_path: pathlib.Path, aiohttp_client
|
||||
+) -> None:
|
||||
+ # Tests that follow_symlinks does not allow directory transversal
|
||||
+ data = "private"
|
||||
+
|
||||
+ private_file = tmp_path / "private_file"
|
||||
+ private_file.write_text(data)
|
||||
+
|
||||
+ safe_path = tmp_path / "safe_dir"
|
||||
+ safe_path.mkdir()
|
||||
+
|
||||
+ app = web.Application()
|
||||
+
|
||||
+ # Register global static route:
|
||||
+ app.router.add_static("/", str(safe_path), follow_symlinks=True)
|
||||
+ client = await aiohttp_client(app)
|
||||
+
|
||||
+ await client.start_server()
|
||||
+ # We need to use a raw socket to test this, as the client will normalize
|
||||
+ # the path before sending it to the server.
|
||||
+ reader, writer = await asyncio.open_connection(client.host, client.port)
|
||||
+ writer.write(b"GET /../private_file HTTP/1.1\r\n\r\n")
|
||||
+ response = await reader.readuntil(b"\r\n\r\n")
|
||||
+ assert b"404 Not Found" in response
|
||||
+ writer.close()
|
||||
+ await writer.wait_closed()
|
||||
+ await client.close()
|
||||
+
|
||||
+
|
||||
+async def test_follow_symlink_directory_traversal_after_normalization(
|
||||
+ tmp_path: pathlib.Path, aiohttp_client
|
||||
+) -> None:
|
||||
+ # Tests that follow_symlinks does not allow directory transversal
|
||||
+ # after normalization
|
||||
+ #
|
||||
+ # Directory structure
|
||||
+ # |-- secret_dir
|
||||
+ # | |-- private_file (should never be accessible)
|
||||
+ # | |-- symlink_target_dir
|
||||
+ # | |-- symlink_target_file (should be accessible via the my_symlink symlink)
|
||||
+ # | |-- sandbox_dir
|
||||
+ # | |-- my_symlink -> symlink_target_dir
|
||||
+ #
|
||||
+ secret_path = tmp_path / "secret_dir"
|
||||
+ secret_path.mkdir()
|
||||
+
|
||||
+ # This file is below the symlink target and should not be reachable
|
||||
+ private_file = secret_path / "private_file"
|
||||
+ private_file.write_text("private")
|
||||
+
|
||||
+ symlink_target_path = secret_path / "symlink_target_dir"
|
||||
+ symlink_target_path.mkdir()
|
||||
+
|
||||
+ sandbox_path = symlink_target_path / "sandbox_dir"
|
||||
+ sandbox_path.mkdir()
|
||||
+
|
||||
+ # This file should be reachable via the symlink
|
||||
+ symlink_target_file = symlink_target_path / "symlink_target_file"
|
||||
+ symlink_target_file.write_text("readable")
|
||||
+
|
||||
+ my_symlink_path = sandbox_path / "my_symlink"
|
||||
+ pathlib.Path(str(my_symlink_path)).symlink_to(str(symlink_target_path), True)
|
||||
+
|
||||
+ app = web.Application()
|
||||
+
|
||||
+ # Register global static route:
|
||||
+ app.router.add_static("/", str(sandbox_path), follow_symlinks=True)
|
||||
+ client = await aiohttp_client(app)
|
||||
+
|
||||
+ await client.start_server()
|
||||
+ # We need to use a raw socket to test this, as the client will normalize
|
||||
+ # the path before sending it to the server.
|
||||
+ reader, writer = await asyncio.open_connection(client.host, client.port)
|
||||
+ writer.write(b"GET /my_symlink/../private_file HTTP/1.1\r\n\r\n")
|
||||
+ response = await reader.readuntil(b"\r\n\r\n")
|
||||
+ assert b"404 Not Found" in response
|
||||
+ writer.close()
|
||||
+ await writer.wait_closed()
|
||||
+
|
||||
+ reader, writer = await asyncio.open_connection(client.host, client.port)
|
||||
+ writer.write(b"GET /my_symlink/symlink_target_file HTTP/1.1\r\n\r\n")
|
||||
+ response = await reader.readuntil(b"\r\n\r\n")
|
||||
+ assert b"200 OK" in response
|
||||
+ response = await reader.readuntil(b"readable")
|
||||
+ assert response == b"readable"
|
||||
+ writer.close()
|
||||
+ await writer.wait_closed()
|
||||
+ await client.close()
|
||||
+
|
||||
+
|
||||
@pytest.mark.parametrize(
|
||||
"dir_name,filename,data",
|
||||
[
|
||||
@@ -48,6 +48,7 @@ buildPythonPackage rec {
|
||||
url = "https://github.com/aio-libs/aiohttp/commit/7dcc235cafe0c4521bbbf92f76aecc82fee33e8b.patch";
|
||||
hash = "sha256-ZzhlE50bmA+e2XX2RH1FuWQHZIAa6Dk/hZjxPoX5t4g=";
|
||||
})
|
||||
./3.8.6-CVE-2024-23334.patch
|
||||
];
|
||||
|
||||
postPatch = ''
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
commit 166afaf144d6473464975438353257359dd51708
|
||||
Author: Andreas Wiese <andreas.wiese@kernkonzept.com>
|
||||
Date: Thu Feb 1 11:35:02 2024 +0100
|
||||
|
||||
aa-remove-unknown: fix readability check
|
||||
|
||||
This check is intended for ensuring that the profiles file can actually
|
||||
be opened. The *actual* check is performed by the shell, not the read
|
||||
utility, which won't even be executed if the input redirection (and
|
||||
hence the test) fails.
|
||||
|
||||
If the test succeeds, though, using `read` here might actually
|
||||
jeopardize the test result if there are no profiles loaded and the file
|
||||
is empty.
|
||||
|
||||
This commit fixes that case by simply using `true` instead of `read`.
|
||||
|
||||
diff --git a/utils/aa-remove-unknown b/utils/aa-remove-unknown
|
||||
index 0e00d6a0..3351feef 100755
|
||||
--- a/utils/aa-remove-unknown
|
||||
+++ b/utils/aa-remove-unknown
|
||||
@@ -63,7 +63,7 @@ fi
|
||||
# We have to do this check because error checking awk's getline() below is
|
||||
# tricky and, as is, results in an infinite loop when apparmorfs returns an
|
||||
# error from open().
|
||||
-if ! IFS= read -r _ < "$PROFILES" ; then
|
||||
+if ! true < "$PROFILES" ; then
|
||||
echo "ERROR: Unable to read apparmorfs profiles file" 1>&2
|
||||
exit 1
|
||||
elif [ ! -w "$REMOVE" ] ; then
|
||||
@@ -56,7 +56,9 @@ let
|
||||
--replace "/usr/include/linux/capability.h" "${linuxHeaders}/include/linux/capability.h"
|
||||
'';
|
||||
|
||||
patches = lib.optionals stdenv.hostPlatform.isMusl [
|
||||
patches = [
|
||||
./0001-aa-remove-unknown_empty-ruleset.patch
|
||||
] ++ lib.optionals stdenv.hostPlatform.isMusl [
|
||||
(fetchpatch {
|
||||
url = "https://git.alpinelinux.org/aports/plain/testing/apparmor/0003-Added-missing-typedef-definitions-on-parser.patch?id=74b8427cc21f04e32030d047ae92caa618105b53";
|
||||
name = "0003-Added-missing-typedef-definitions-on-parser.patch";
|
||||
|
||||
@@ -159,7 +159,7 @@ assert !withPasswordQuality;
|
||||
let
|
||||
wantCurl = withRemote || withImportd;
|
||||
wantGcrypt = withResolved || withImportd;
|
||||
version = "254.6";
|
||||
version = "254.10";
|
||||
|
||||
# Bump this variable on every (major) version change. See below (in the meson options list) for why.
|
||||
# command:
|
||||
@@ -176,7 +176,7 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
owner = "systemd";
|
||||
repo = "systemd-stable";
|
||||
rev = "v${version}";
|
||||
hash = "sha256-Ku24ecDeQt0t7A8/adR3Jm47QZ19+wdMPyJRzCxU4uU=";
|
||||
hash = "sha256-+8v1LLvXoK0tMOfB7m9+H+HIHpZuYrIyWwuz7rphbmA=";
|
||||
};
|
||||
|
||||
# On major changes, or when otherwise required, you *must* reformat the patches,
|
||||
|
||||
@@ -815,15 +815,18 @@ fi
|
||||
######################################################################
|
||||
# Textual substitution functions.
|
||||
|
||||
|
||||
substituteStream() {
|
||||
local var=$1
|
||||
local description=$2
|
||||
shift 2
|
||||
|
||||
while (( "$#" )); do
|
||||
local replace_mode="$1"
|
||||
case "$1" in
|
||||
--replace)
|
||||
replace_mode='--replace-warn'
|
||||
;&
|
||||
--replace-quiet|--replace-warn|--replace-fail)
|
||||
pattern="$2"
|
||||
replacement="$3"
|
||||
shift 3
|
||||
@@ -832,7 +835,12 @@ substituteStream() {
|
||||
eval "$var"'=${'"$var"'//"$pattern"/"$replacement"}'
|
||||
if [ "$pattern" != "$replacement" ]; then
|
||||
if [ "${!var}" == "$savedvar" ]; then
|
||||
echo "substituteStream(): WARNING: pattern '$pattern' doesn't match anything in $description" >&2
|
||||
if [ "$replace_mode" == --replace-warn ]; then
|
||||
printf "substituteStream(): WARNING: pattern %q doesn't match anything in %s\n" "$pattern" "$description" >&2
|
||||
elif [ "$replace_mode" == --replace-fail ]; then
|
||||
printf "substituteStream(): ERROR: pattern %q doesn't match anything in %s\n" "$pattern" "$description" >&2
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
|
||||
31
pkgs/tools/misc/coreutils/CVE-2024-0684.patch
Normal file
31
pkgs/tools/misc/coreutils/CVE-2024-0684.patch
Normal file
@@ -0,0 +1,31 @@
|
||||
From c4c5ed8f4e9cd55a12966d4f520e3a13101637d9 Mon Sep 17 00:00:00 2001
|
||||
From: Paul Eggert <eggert@cs.ucla.edu>
|
||||
Date: Tue, 16 Jan 2024 13:48:32 -0800
|
||||
Subject: [PATCH] split: do not shrink hold buffer
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
* src/split.c (line_bytes_split): Do not shrink hold buffer.
|
||||
If it’s large for this batch it’s likely to be large for the next
|
||||
batch, and for ‘split’ it’s not worth the complexity/CPU hassle to
|
||||
shrink it. Do not assume hold_size can be bufsize.
|
||||
---
|
||||
src/split.c | 3 ---
|
||||
1 file changed, 3 deletions(-)
|
||||
|
||||
diff --git a/src/split.c b/src/split.c
|
||||
index 64020c859..037960a59 100644
|
||||
--- a/src/split.c
|
||||
+++ b/src/split.c
|
||||
@@ -809,10 +809,7 @@ line_bytes_split (intmax_t n_bytes, char *buf, idx_t bufsize)
|
||||
{
|
||||
cwrite (n_out == 0, hold, n_hold);
|
||||
n_out += n_hold;
|
||||
- if (n_hold > bufsize)
|
||||
- hold = xirealloc (hold, bufsize);
|
||||
n_hold = 0;
|
||||
- hold_size = bufsize;
|
||||
}
|
||||
|
||||
/* Output to eol if present. */
|
||||
@@ -39,6 +39,11 @@ stdenv.mkDerivation rec {
|
||||
hash = "sha256-rbz8/omSNbceh2jc8HzVMlILf1T5qAZIQ/jRmakEu6o=";
|
||||
};
|
||||
|
||||
patches = [
|
||||
# https://www.openwall.com/lists/oss-security/2024/01/18/2
|
||||
./CVE-2024-0684.patch
|
||||
];
|
||||
|
||||
postPatch = ''
|
||||
# The test tends to fail on btrfs, f2fs and maybe other unusual filesystems.
|
||||
sed '2i echo Skipping dd sparse test && exit 77' -i ./tests/dd/sparse.sh
|
||||
|
||||
94
pkgs/tools/networking/curl/0003-CVE-2024-2398.patch
Normal file
94
pkgs/tools/networking/curl/0003-CVE-2024-2398.patch
Normal file
@@ -0,0 +1,94 @@
|
||||
From b1b7ab02e055249c02eac8c2a80295701f2530a2 Mon Sep 17 00:00:00 2001
|
||||
From: Stefan Eissing <stefan@eissing.org>
|
||||
Date: Wed, 6 Mar 2024 09:36:08 +0100
|
||||
Subject: [PATCH 3/4] http2: push headers better cleanup
|
||||
|
||||
- provide common cleanup method for push headers
|
||||
|
||||
Closes #13054
|
||||
|
||||
(cherry picked from commit deca8039991886a559b67bcd6701db800a5cf764)
|
||||
---
|
||||
lib/http2.c | 34 +++++++++++++++-------------------
|
||||
1 file changed, 15 insertions(+), 19 deletions(-)
|
||||
|
||||
diff --git a/lib/http2.c b/lib/http2.c
|
||||
index c8b059498..8c422d156 100644
|
||||
--- a/lib/http2.c
|
||||
+++ b/lib/http2.c
|
||||
@@ -271,6 +271,15 @@ static CURLcode http2_data_setup(struct Curl_cfilter *cf,
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
+static void free_push_headers(struct stream_ctx *stream)
|
||||
+{
|
||||
+ size_t i;
|
||||
+ for(i = 0; i<stream->push_headers_used; i++)
|
||||
+ free(stream->push_headers[i]);
|
||||
+ Curl_safefree(stream->push_headers);
|
||||
+ stream->push_headers_used = 0;
|
||||
+}
|
||||
+
|
||||
static void http2_data_done(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data, bool premature)
|
||||
{
|
||||
@@ -318,15 +327,7 @@ static void http2_data_done(struct Curl_cfilter *cf,
|
||||
Curl_bufq_free(&stream->recvbuf);
|
||||
Curl_h1_req_parse_free(&stream->h1);
|
||||
Curl_dynhds_free(&stream->resp_trailers);
|
||||
- if(stream->push_headers) {
|
||||
- /* if they weren't used and then freed before */
|
||||
- for(; stream->push_headers_used > 0; --stream->push_headers_used) {
|
||||
- free(stream->push_headers[stream->push_headers_used - 1]);
|
||||
- }
|
||||
- free(stream->push_headers);
|
||||
- stream->push_headers = NULL;
|
||||
- }
|
||||
-
|
||||
+ free_push_headers(stream);
|
||||
free(stream);
|
||||
H2_STREAM_LCTX(data) = NULL;
|
||||
}
|
||||
@@ -865,7 +866,6 @@ static int push_promise(struct Curl_cfilter *cf,
|
||||
struct curl_pushheaders heads;
|
||||
CURLMcode rc;
|
||||
CURLcode result;
|
||||
- size_t i;
|
||||
/* clone the parent */
|
||||
struct Curl_easy *newhandle = h2_duphandle(cf, data);
|
||||
if(!newhandle) {
|
||||
@@ -910,11 +910,7 @@ static int push_promise(struct Curl_cfilter *cf,
|
||||
Curl_set_in_callback(data, false);
|
||||
|
||||
/* free the headers again */
|
||||
- for(i = 0; i<stream->push_headers_used; i++)
|
||||
- free(stream->push_headers[i]);
|
||||
- free(stream->push_headers);
|
||||
- stream->push_headers = NULL;
|
||||
- stream->push_headers_used = 0;
|
||||
+ free_push_headers(stream);
|
||||
|
||||
if(rv) {
|
||||
DEBUGASSERT((rv > CURL_PUSH_OK) && (rv <= CURL_PUSH_ERROROUT));
|
||||
@@ -1455,14 +1451,14 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
if(stream->push_headers_alloc > 1000) {
|
||||
/* this is beyond crazy many headers, bail out */
|
||||
failf(data_s, "Too many PUSH_PROMISE headers");
|
||||
- Curl_safefree(stream->push_headers);
|
||||
+ free_push_headers(stream);
|
||||
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
}
|
||||
stream->push_headers_alloc *= 2;
|
||||
- headp = Curl_saferealloc(stream->push_headers,
|
||||
- stream->push_headers_alloc * sizeof(char *));
|
||||
+ headp = realloc(stream->push_headers,
|
||||
+ stream->push_headers_alloc * sizeof(char *));
|
||||
if(!headp) {
|
||||
- stream->push_headers = NULL;
|
||||
+ free_push_headers(stream);
|
||||
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
}
|
||||
stream->push_headers = headp;
|
||||
--
|
||||
2.44.0
|
||||
|
||||
137
pkgs/tools/networking/curl/0004-CVE-2024-2004.patch
Normal file
137
pkgs/tools/networking/curl/0004-CVE-2024-2004.patch
Normal file
@@ -0,0 +1,137 @@
|
||||
From b091564d9fd187c6dc6410e3badf4621df8f4e0a Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Gustafsson <daniel@yesql.se>
|
||||
Date: Tue, 27 Feb 2024 15:43:56 +0100
|
||||
Subject: [PATCH] setopt: Fix disabling all protocols
|
||||
|
||||
When disabling all protocols without enabling any, the resulting
|
||||
set of allowed protocols remained the default set. Clearing the
|
||||
allowed set before inspecting the passed value from --proto make
|
||||
the set empty even in the errorpath of no protocols enabled.
|
||||
|
||||
Co-authored-by: Dan Fandrich <dan@telarity.com>
|
||||
Reported-by: Dan Fandrich <dan@telarity.com>
|
||||
Reviewed-by: Daniel Stenberg <daniel@haxx.se>
|
||||
Closes: #13004
|
||||
(cherry picked from commit 17d302e56221f5040092db77d4f85086e8a20e0e)
|
||||
---
|
||||
lib/setopt.c | 16 ++++++++--------
|
||||
tests/data/Makefile.inc | 2 +-
|
||||
tests/data/test1475 | 42 +++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 51 insertions(+), 9 deletions(-)
|
||||
create mode 100644 tests/data/test1475
|
||||
|
||||
diff --git a/lib/setopt.c b/lib/setopt.c
|
||||
index 0d399adfe..e022096f6 100644
|
||||
--- a/lib/setopt.c
|
||||
+++ b/lib/setopt.c
|
||||
@@ -154,6 +154,12 @@ static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp)
|
||||
|
||||
static CURLcode protocol2num(const char *str, curl_prot_t *val)
|
||||
{
|
||||
+ /*
|
||||
+ * We are asked to cherry-pick protocols, so play it safe and disallow all
|
||||
+ * protocols to start with, and re-add the wanted ones back in.
|
||||
+ */
|
||||
+ *val = 0;
|
||||
+
|
||||
if(!str)
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
|
||||
@@ -162,8 +168,6 @@ static CURLcode protocol2num(const char *str, curl_prot_t *val)
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
- *val = 0;
|
||||
-
|
||||
do {
|
||||
const char *token = str;
|
||||
size_t tlen;
|
||||
@@ -2690,22 +2694,18 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
|
||||
break;
|
||||
|
||||
case CURLOPT_PROTOCOLS_STR: {
|
||||
- curl_prot_t prot;
|
||||
argptr = va_arg(param, char *);
|
||||
- result = protocol2num(argptr, &prot);
|
||||
+ result = protocol2num(argptr, &data->set.allowed_protocols);
|
||||
if(result)
|
||||
return result;
|
||||
- data->set.allowed_protocols = prot;
|
||||
break;
|
||||
}
|
||||
|
||||
case CURLOPT_REDIR_PROTOCOLS_STR: {
|
||||
- curl_prot_t prot;
|
||||
argptr = va_arg(param, char *);
|
||||
- result = protocol2num(argptr, &prot);
|
||||
+ result = protocol2num(argptr, &data->set.redir_protocols);
|
||||
if(result)
|
||||
return result;
|
||||
- data->set.redir_protocols = prot;
|
||||
break;
|
||||
}
|
||||
|
||||
diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc
|
||||
index 1472b1954..bdb2ef742 100644
|
||||
--- a/tests/data/Makefile.inc
|
||||
+++ b/tests/data/Makefile.inc
|
||||
@@ -185,7 +185,7 @@ test1439 test1440 test1441 test1442 test1443 test1444 test1445 test1446 \
|
||||
test1447 test1448 test1449 test1450 test1451 test1452 test1453 test1454 \
|
||||
test1455 test1456 test1457 test1458 test1459 test1460 test1461 test1462 \
|
||||
test1463 test1464 test1465 test1466 test1467 test1468 test1469 test1470 \
|
||||
-test1471 test1472 test1473 test1474 \
|
||||
+test1471 test1472 test1473 test1474 test1475 \
|
||||
\
|
||||
test1500 test1501 test1502 test1503 test1504 test1505 test1506 test1507 \
|
||||
test1508 test1509 test1510 test1511 test1512 test1513 test1514 test1515 \
|
||||
diff --git a/tests/data/test1475 b/tests/data/test1475
|
||||
new file mode 100644
|
||||
index 000000000..c66fa2810
|
||||
--- /dev/null
|
||||
+++ b/tests/data/test1475
|
||||
@@ -0,0 +1,42 @@
|
||||
+<testcase>
|
||||
+<info>
|
||||
+<keywords>
|
||||
+HTTP
|
||||
+HTTP GET
|
||||
+--proto
|
||||
+</keywords>
|
||||
+</info>
|
||||
+
|
||||
+#
|
||||
+# Server-side
|
||||
+<reply>
|
||||
+<data>
|
||||
+</data>
|
||||
+</reply>
|
||||
+
|
||||
+#
|
||||
+# Client-side
|
||||
+<client>
|
||||
+<server>
|
||||
+none
|
||||
+</server>
|
||||
+<features>
|
||||
+http
|
||||
+</features>
|
||||
+<name>
|
||||
+--proto -all disables all protocols
|
||||
+</name>
|
||||
+<command>
|
||||
+--proto -all http://%HOSTIP:%NOLISTENPORT/%TESTNUMBER
|
||||
+</command>
|
||||
+</client>
|
||||
+
|
||||
+#
|
||||
+# Verify data after the test has been "shot"
|
||||
+<verify>
|
||||
+# 1 - Protocol "http" disabled
|
||||
+<errorcode>
|
||||
+1
|
||||
+</errorcode>
|
||||
+</verify>
|
||||
+</testcase>
|
||||
--
|
||||
2.44.0
|
||||
|
||||
@@ -65,6 +65,10 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
./0001-CVE-2023-42619.patch
|
||||
# https://curl.se/docs/CVE-2023-46218.html
|
||||
./0002-CVE-2023-42618.patch
|
||||
# https://curl.se/docs/CVE-2024-2398.html
|
||||
./0003-CVE-2024-2398.patch
|
||||
# https://curl.se/docs/CVE-2024-2004.html
|
||||
./0004-CVE-2024-2004.patch
|
||||
];
|
||||
|
||||
outputs = [ "bin" "dev" "out" "man" "devdoc" ];
|
||||
|
||||
@@ -57,11 +57,11 @@ let
|
||||
in
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "networkmanager";
|
||||
version = "1.44.2";
|
||||
version = "1.44.4";
|
||||
|
||||
src = fetchurl {
|
||||
url = "mirror://gnome/sources/NetworkManager/${lib.versions.majorMinor version}/NetworkManager-${version}.tar.xz";
|
||||
sha256 = "sha256-S1i/OsV+LO+1ZS79CUXrC0vDamPZKmGrRx2LssmkIOE=";
|
||||
hash = "sha256-Aq+4X1qKPT1w0LahLIttst4uSWt3evW1cYLmC4CgNIk=";
|
||||
};
|
||||
|
||||
outputs = [ "out" "dev" "devdoc" "man" "doc" ];
|
||||
|
||||
@@ -49,11 +49,11 @@
|
||||
|
||||
stdenv.mkDerivation (finalAttrs: {
|
||||
pname = "unbound";
|
||||
version = "1.19.1";
|
||||
version = "1.19.2";
|
||||
|
||||
src = fetchurl {
|
||||
url = "https://nlnetlabs.nl/downloads/unbound/unbound-${finalAttrs.version}.tar.gz";
|
||||
hash = "sha256-vB1Xbz3YRqBzmtxB/6pwJATGdn0rYILeufL5fLsko6k=";
|
||||
hash = "sha256-zFYNNFc0ImwbOecadpeX5/3eImXLt3685UJwS7pInlU=";
|
||||
};
|
||||
|
||||
outputs = [ "out" "lib" "man" ]; # "dev" would only split ~20 kB
|
||||
|
||||
Reference in New Issue
Block a user