Compare commits
No commits in common. "c8" and "c8-beta" have entirely different histories.
@ -1,52 +0,0 @@
|
|||||||
From d4ec4ab3aaf1fa736a6195c2d1317450dc1f2c4b Mon Sep 17 00:00:00 2001
|
|
||||||
From: =?UTF-8?q?Tina=20M=C3=BCller?= <cpan2@tinita.de>
|
|
||||||
Date: Tue, 2 Oct 2018 22:56:00 +0200
|
|
||||||
Subject: [PATCH] Fix memory corruption error
|
|
||||||
|
|
||||||
Currently the following examples abort the program:
|
|
||||||
|
|
||||||
"- &anchor1 &anchor2 x"
|
|
||||||
double free or corruption (fasttop)
|
|
||||||
|
|
||||||
"- &anchor1 &anchor2 x"
|
|
||||||
double free or corruption (fasttop)
|
|
||||||
|
|
||||||
"x: &anchor1 &anchor2 x"
|
|
||||||
malloc(): memory corruption (fast)
|
|
||||||
|
|
||||||
"key1: &a value1
|
|
||||||
&b *a : value2"
|
|
||||||
double free or corruption (fasttop)
|
|
||||||
|
|
||||||
This fix will prevent the abort and falsely accept invalid YAML.
|
|
||||||
Instead the code should return an error/throw an exception, but I don't
|
|
||||||
know how to do this here.
|
|
||||||
So this is just the less optimal solution, avoiding a program abort.
|
|
||||||
---
|
|
||||||
handler.c | 10 ++++++++++
|
|
||||||
1 file changed, 10 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/handler.c b/handler.c
|
|
||||||
index d9cf8ec..5de4359 100644
|
|
||||||
--- a/handler.c
|
|
||||||
+++ b/handler.c
|
|
||||||
@@ -32,6 +32,16 @@ syck_hdlr_add_anchor( SyckParser *p, char *a, SyckNode *n )
|
|
||||||
{
|
|
||||||
SyckNode *ntmp = NULL;
|
|
||||||
|
|
||||||
+ if (n->anchor != NULL) {
|
|
||||||
+ /*
|
|
||||||
+ * Note: An error should be returned here. But this is better than
|
|
||||||
+ * not checking at all because it will abort the program with a
|
|
||||||
+ * memory corruption error.
|
|
||||||
+ * Happens if you have two anchors after each other or an anchor
|
|
||||||
+ * before an alias
|
|
||||||
+ * */
|
|
||||||
+ return n;
|
|
||||||
+ }
|
|
||||||
n->anchor = a;
|
|
||||||
if ( p->bad_anchors != NULL )
|
|
||||||
{
|
|
||||||
--
|
|
||||||
2.53.0
|
|
||||||
|
|
||||||
@ -1,268 +0,0 @@
|
|||||||
From e8844a31c8cf0052914b198fc784ed4e6b8ae69e Mon Sep 17 00:00:00 2001
|
|
||||||
From: Toddr Bot <toddbot@rinaldo.us>
|
|
||||||
Date: Sat, 14 Mar 2026 07:18:00 +0000
|
|
||||||
Subject: [PATCH] fix: address all 4 C-layer audit findings from issue #67
|
|
||||||
|
|
||||||
- HIGH: Fix heap buffer overflow in emitter tag buffer. The 512-byte
|
|
||||||
fixed allocation overflowed via strcat(tag, ref) with long class names.
|
|
||||||
Now tracks buffer size and grows dynamically with Renew() when needed.
|
|
||||||
|
|
||||||
- MEDIUM: Fix base64 decoder reading past buffer end on trailing
|
|
||||||
newlines. Added s < send guard to the inner whitespace-skip loop.
|
|
||||||
|
|
||||||
- MEDIUM: Replace strtok(id, "/:") with savepv copy + strtok at all 6
|
|
||||||
call sites in the parser handler. strtok mutated n->type_id in place,
|
|
||||||
corrupting shared node data. Each site now operates on a local copy
|
|
||||||
that is freed after use.
|
|
||||||
|
|
||||||
- LOW: Fix memory leak in syck_hdlr_add_anchor when a node already has
|
|
||||||
an anchor. The incoming anchor string 'a' was leaked on early return.
|
|
||||||
|
|
||||||
Closes #67
|
|
||||||
|
|
||||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
|
||||||
---
|
|
||||||
emitter.c | 3 ++-
|
|
||||||
handler.c | 1 +
|
|
||||||
perl_common.h | 1 +
|
|
||||||
perl_syck.h | 36 +++++++++++++++++++++++++++++-------
|
|
||||||
t/tag-overflow.t | 44 ++++++++++++++++++++++++++++++++++++++++++++
|
|
||||||
5 files changed, 77 insertions(+), 8 deletions(-)
|
|
||||||
create mode 100644 t/tag-overflow.t
|
|
||||||
|
|
||||||
diff --git a/emitter.c b/emitter.c
|
|
||||||
index cd8150b..da3c91b 100644
|
|
||||||
--- a/emitter.c
|
|
||||||
+++ b/emitter.c
|
|
||||||
@@ -80,7 +80,8 @@ syck_base64dec( char *s, long len, long *out_len )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (s < send) {
|
|
||||||
- while (s[0] == '\r' || s[0] == '\n') { s++; }
|
|
||||||
+ while (s < send && (s[0] == '\r' || s[0] == '\n')) { s++; }
|
|
||||||
+ if (s >= send) break;
|
|
||||||
if ((a = b64_xtable[(int)s[0]]) == -1) break;
|
|
||||||
if ((b = b64_xtable[(int)s[1]]) == -1) break;
|
|
||||||
if ((c = b64_xtable[(int)s[2]]) == -1) break;
|
|
||||||
diff --git a/handler.c b/handler.c
|
|
||||||
index 5de4359..48341a9 100644
|
|
||||||
--- a/handler.c
|
|
||||||
+++ b/handler.c
|
|
||||||
@@ -40,6 +40,7 @@ syck_hdlr_add_anchor( SyckParser *p, char *a, SyckNode *n )
|
|
||||||
* Happens if you have two anchors after each other or an anchor
|
|
||||||
* before an alias
|
|
||||||
* */
|
|
||||||
+ S_FREE(a);
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
n->anchor = a;
|
|
||||||
diff --git a/perl_common.h b/perl_common.h
|
|
||||||
index 4512237..bc9924b 100644
|
|
||||||
--- a/perl_common.h
|
|
||||||
+++ b/perl_common.h
|
|
||||||
@@ -37,6 +37,7 @@ struct emitter_xtra {
|
|
||||||
PerlIO* outio;
|
|
||||||
} out;
|
|
||||||
char* tag;
|
|
||||||
+ STRLEN tag_len;
|
|
||||||
char dump_code;
|
|
||||||
bool implicit_binary;
|
|
||||||
int ioerror;
|
|
||||||
diff --git a/perl_syck.h b/perl_syck.h
|
|
||||||
index 14cd311..1b00bd6 100644
|
|
||||||
--- a/perl_syck.h
|
|
||||||
+++ b/perl_syck.h
|
|
||||||
@@ -332,7 +332,8 @@ yaml_syck_parser_handler
|
|
||||||
|
|
||||||
} else if (strnEQ( n->data.str->ptr, REF_LITERAL, 1+REF_LITERAL_LENGTH)) {
|
|
||||||
/* type tag in a scalar ref */
|
|
||||||
- char *lang = strtok(id, "/:");
|
|
||||||
+ char *id_copy = savepv(id);
|
|
||||||
+ char *lang = strtok(id_copy, "/:");
|
|
||||||
char *type = strtok(NULL, "");
|
|
||||||
|
|
||||||
if (lang == NULL || (strEQ(lang, "perl"))) {
|
|
||||||
@@ -341,6 +342,7 @@ yaml_syck_parser_handler
|
|
||||||
else {
|
|
||||||
sv = newSVpv(form((type == NULL) ? "%s" : "%s::%s", lang, type), 0);
|
|
||||||
}
|
|
||||||
+ Safefree(id_copy);
|
|
||||||
} else if ( strEQ( id, "perl/scalar" ) || strnEQ( id, "perl/scalar:", 12 ) ) {
|
|
||||||
char *pkg = id + 12;
|
|
||||||
|
|
||||||
@@ -362,7 +364,8 @@ yaml_syck_parser_handler
|
|
||||||
} else if ( (strEQ(id, "perl/regexp") || strnEQ( id, "perl/regexp:", 12 ) ) ) {
|
|
||||||
dSP;
|
|
||||||
SV *val = newSVpvn(n->data.str->ptr, n->data.str->len);
|
|
||||||
- char *lang = strtok(id, "/:");
|
|
||||||
+ char *id_copy = savepv(id);
|
|
||||||
+ char *lang = strtok(id_copy, "/:");
|
|
||||||
char *type = strtok(NULL, "");
|
|
||||||
|
|
||||||
ENTER;
|
|
||||||
@@ -396,6 +399,7 @@ yaml_syck_parser_handler
|
|
||||||
sv_bless(sv, gv_stashpv(form((type == NULL) ? "%s" : "%s::%s", lang, type), TRUE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+ Safefree(id_copy);
|
|
||||||
#endif /* PERL_LOADMOD_NOIMPORT */
|
|
||||||
#endif /* !YAML_IS_JSON */
|
|
||||||
} else {
|
|
||||||
@@ -427,7 +431,8 @@ yaml_syck_parser_handler
|
|
||||||
|
|
||||||
if (id) {
|
|
||||||
/* bless it if necessary */
|
|
||||||
- char *lang = strtok(id, "/:");
|
|
||||||
+ char *id_copy = savepv(id);
|
|
||||||
+ char *lang = strtok(id_copy, "/:");
|
|
||||||
char *type = strtok(NULL, "");
|
|
||||||
|
|
||||||
if ( type != NULL ) {
|
|
||||||
@@ -435,7 +440,7 @@ yaml_syck_parser_handler
|
|
||||||
/* !perl/array:Foo::Bar blesses into Foo::Bar */
|
|
||||||
type += 6;
|
|
||||||
}
|
|
||||||
-
|
|
||||||
+
|
|
||||||
/* FIXME deprecated - here compatibility with @Foo::Bar style blessing */
|
|
||||||
while ( *type == '@' ) { type++; }
|
|
||||||
}
|
|
||||||
@@ -451,6 +456,7 @@ yaml_syck_parser_handler
|
|
||||||
sv_bless(sv, gv_stashpv(form((type == NULL) ? "%s" : "%s::%s", lang, type), TRUE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+ Safefree(id_copy);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
@@ -480,7 +486,8 @@ yaml_syck_parser_handler
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* bless it if necessary */
|
|
||||||
- char *lang = strtok(id, "/:");
|
|
||||||
+ char *id_copy = savepv(id);
|
|
||||||
+ char *lang = strtok(id_copy, "/:");
|
|
||||||
char *type = strtok(NULL, "");
|
|
||||||
|
|
||||||
if ( type != NULL && strnEQ(type, "ref:", 4)) {
|
|
||||||
@@ -496,6 +503,7 @@ yaml_syck_parser_handler
|
|
||||||
else {
|
|
||||||
sv_bless(sv, gv_stashpv(form((type == NULL) ? "%s" : "%s::%s", lang, type), TRUE));
|
|
||||||
}
|
|
||||||
+ Safefree(id_copy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -527,7 +535,8 @@ yaml_syck_parser_handler
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* bless it if necessary */
|
|
||||||
- char *lang = strtok(id, "/:");
|
|
||||||
+ char *id_copy = savepv(id);
|
|
||||||
+ char *lang = strtok(id_copy, "/:");
|
|
||||||
char *type = strtok(NULL, "");
|
|
||||||
|
|
||||||
if ( type != NULL && strnEQ(type, "regexp:", 7)) {
|
|
||||||
@@ -544,6 +553,7 @@ yaml_syck_parser_handler
|
|
||||||
else {
|
|
||||||
sv_bless(sv, gv_stashpv(form((type == NULL) ? "%s" : "%s::%s", lang, type), TRUE));
|
|
||||||
}
|
|
||||||
+ Safefree(id_copy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -579,7 +589,8 @@ yaml_syck_parser_handler
|
|
||||||
#ifndef YAML_IS_JSON
|
|
||||||
if (id) {
|
|
||||||
/* bless it if necessary */
|
|
||||||
- char *lang = strtok(id, "/:");
|
|
||||||
+ char *id_copy = savepv(id);
|
|
||||||
+ char *lang = strtok(id_copy, "/:");
|
|
||||||
char *type = strtok(NULL, "");
|
|
||||||
|
|
||||||
if ( type != NULL ) {
|
|
||||||
@@ -602,6 +613,7 @@ yaml_syck_parser_handler
|
|
||||||
sv_bless(sv, gv_stashpv(form((type == NULL) ? "%s" : "%s::%s", lang, type), TRUE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+ Safefree(id_copy);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
@@ -960,6 +972,15 @@ yaml_syck_emitter_handler
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+ {
|
|
||||||
+ /* Grow tag buffer if ref won't fit (prevents heap overflow) */
|
|
||||||
+ STRLEN need = strlen(tag) + strlen(ref) + 1;
|
|
||||||
+ if (need > bonus->tag_len) {
|
|
||||||
+ Renew(bonus->tag, need, char);
|
|
||||||
+ bonus->tag_len = need;
|
|
||||||
+ tag = bonus->tag;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
strcat(tag, ref);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -1284,6 +1305,7 @@ DumpYAMLImpl
|
|
||||||
emitter->anchor_format = "%d";
|
|
||||||
|
|
||||||
New(801, bonus->tag, 512, char);
|
|
||||||
+ bonus->tag_len = 512;
|
|
||||||
*(bonus->tag) = '\0';
|
|
||||||
bonus->dump_code = SvTRUE(use_code) || SvTRUE(dump_code);
|
|
||||||
bonus->implicit_binary = SvTRUE(implicit_binary);
|
|
||||||
diff --git a/t/tag-overflow.t b/t/tag-overflow.t
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..8570f13
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/t/tag-overflow.t
|
|
||||||
@@ -0,0 +1,44 @@
|
|
||||||
+use FindBin;
|
|
||||||
+BEGIN { push @INC, $FindBin::Bin }
|
|
||||||
+
|
|
||||||
+use TestYAML tests => 6;
|
|
||||||
+
|
|
||||||
+$YAML::Syck::LoadBlessed = 1;
|
|
||||||
+
|
|
||||||
+# Test that Dump handles objects with very long class names without crashing.
|
|
||||||
+# This exercises the dynamic tag buffer growth added to prevent a heap overflow
|
|
||||||
+# when class names exceed the initial 512-byte allocation.
|
|
||||||
+
|
|
||||||
+my $short_class = 'A' x 100;
|
|
||||||
+my $long_class = 'B' x 600; # exceeds initial 512-byte tag buffer
|
|
||||||
+my $huge_class = 'C' x 2000;
|
|
||||||
+
|
|
||||||
+# Short class name (fits in initial buffer)
|
|
||||||
+{
|
|
||||||
+ my $obj = bless {}, $short_class;
|
|
||||||
+ my $yaml = Dump($obj);
|
|
||||||
+ like($yaml, qr/!!perl\/hash:\Q$short_class\E/, "dump short class name ($short_class)");
|
|
||||||
+
|
|
||||||
+ my $rt = Load($yaml);
|
|
||||||
+ is(ref($rt), $short_class, "roundtrip short class name");
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+# Long class name (exceeds 512-byte buffer)
|
|
||||||
+{
|
|
||||||
+ my $obj = bless {}, $long_class;
|
|
||||||
+ my $yaml = Dump($obj);
|
|
||||||
+ like($yaml, qr/!!perl\/hash:\Q$long_class\E/, "dump long class name (600 chars)");
|
|
||||||
+
|
|
||||||
+ my $rt = Load($yaml);
|
|
||||||
+ is(ref($rt), $long_class, "roundtrip long class name");
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+# Huge class name
|
|
||||||
+{
|
|
||||||
+ my $obj = bless {}, $huge_class;
|
|
||||||
+ my $yaml = Dump($obj);
|
|
||||||
+ like($yaml, qr/!!perl\/hash:\Q$huge_class\E/, "dump huge class name (2000 chars)");
|
|
||||||
+
|
|
||||||
+ my $rt = Load($yaml);
|
|
||||||
+ is(ref($rt), $huge_class, "roundtrip huge class name");
|
|
||||||
+}
|
|
||||||
--
|
|
||||||
2.53.0
|
|
||||||
|
|
||||||
@ -7,15 +7,11 @@
|
|||||||
|
|
||||||
Name: perl-YAML-Syck
|
Name: perl-YAML-Syck
|
||||||
Version: 1.30
|
Version: 1.30
|
||||||
Release: 6%{?dist}
|
Release: 5%{?dist}
|
||||||
Summary: Fast, lightweight YAML loader and dumper
|
Summary: Fast, lightweight YAML loader and dumper
|
||||||
License: BSD and MIT
|
License: BSD and MIT
|
||||||
URL: http://search.cpan.org/dist/YAML-Syck/
|
URL: http://search.cpan.org/dist/YAML-Syck/
|
||||||
Source0: http://www.cpan.org/authors/id/T/TO/TODDR/YAML-Syck-%{version}.tar.gz
|
Source0: http://www.cpan.org/authors/id/T/TO/TODDR/YAML-Syck-%{version}.tar.gz
|
||||||
# Fix memory corruption error
|
|
||||||
Patch0: YAML-Syck-1.33-Fix-memory-corruption-error.patch
|
|
||||||
# Fix heap buffer overflow in the YAML emitter - CVE-2026-4177
|
|
||||||
Patch1: YAML-Syck-1.37-Fix-CVE-2026-4177.patch
|
|
||||||
BuildRequires: coreutils
|
BuildRequires: coreutils
|
||||||
BuildRequires: findutils
|
BuildRequires: findutils
|
||||||
BuildRequires: gcc
|
BuildRequires: gcc
|
||||||
@ -62,8 +58,6 @@ structures to YAML strings, and the other way around.
|
|||||||
|
|
||||||
%prep
|
%prep
|
||||||
%setup -q -n YAML-Syck-%{version}
|
%setup -q -n YAML-Syck-%{version}
|
||||||
%patch -P0 -p1
|
|
||||||
%patch -P1 -p1
|
|
||||||
|
|
||||||
# Unbundle core and unused modules
|
# Unbundle core and unused modules
|
||||||
rm -rvf inc/{parent.pm,PerlIO.pm,Scalar/,Test/}
|
rm -rvf inc/{parent.pm,PerlIO.pm,Scalar/,Test/}
|
||||||
@ -91,10 +85,6 @@ make test
|
|||||||
%{_mandir}/man3/YAML::Syck.3*
|
%{_mandir}/man3/YAML::Syck.3*
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
* Wed Mar 25 2026 Jitka Plesnikova <jplesnik@redhat.com> - 1.30-6
|
|
||||||
- Resolves: RHEL-156475
|
|
||||||
- Fix CVE-2026-4177
|
|
||||||
|
|
||||||
* Fri Feb 09 2018 Fedora Release Engineering <releng@fedoraproject.org> - 1.30-5
|
* Fri Feb 09 2018 Fedora Release Engineering <releng@fedoraproject.org> - 1.30-5
|
||||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user