From 2ee902bc3a015cc4515363c78f584391aa491884 Mon Sep 17 00:00:00 2001 From: Thomas Deutschmann Date: Mon, 31 May 2021 23:16:25 +0200 Subject: sys-devel/gettext: fix CVE-2020-12825 Bug: https://bugs.gentoo.org/769998 Package-Manager: Portage-3.0.19, Repoman-3.0.3 Signed-off-by: Thomas Deutschmann --- .../files/gettext-0.21-CVE-2020-12825.patch | 335 +++++++++++++++++++++ sys-devel/gettext/gettext-0.21-r1.ebuild | 157 ++++++++++ 2 files changed, 492 insertions(+) create mode 100644 sys-devel/gettext/files/gettext-0.21-CVE-2020-12825.patch create mode 100644 sys-devel/gettext/gettext-0.21-r1.ebuild diff --git a/sys-devel/gettext/files/gettext-0.21-CVE-2020-12825.patch b/sys-devel/gettext/files/gettext-0.21-CVE-2020-12825.patch new file mode 100644 index 000000000000..6b4c463b4118 --- /dev/null +++ b/sys-devel/gettext/files/gettext-0.21-CVE-2020-12825.patch @@ -0,0 +1,335 @@ +https://gitlab.gnome.org/GNOME/gnome-shell/-/commit/44cbd1e718d6a08e59b9300280c340218a84e089 + +--- a/libtextstyle/gnulib-local/lib/libcroco/cr-parser.c ++++ b/libtextstyle/gnulib-local/lib/libcroco/cr-parser.c +@@ -146,6 +146,8 @@ struct _CRParserPriv { + + #define CHARS_TAB_SIZE 12 + ++#define RECURSIVE_CALLERS_LIMIT 100 ++ + /** + * IS_NUM: + *@a_char: the char to test. +@@ -354,9 +356,11 @@ static enum CRStatus cr_parser_parse_selector_core (CRParser * a_this); + + static enum CRStatus cr_parser_parse_declaration_core (CRParser * a_this); + +-static enum CRStatus cr_parser_parse_any_core (CRParser * a_this); ++static enum CRStatus cr_parser_parse_any_core (CRParser * a_this, ++ guint n_calls); + +-static enum CRStatus cr_parser_parse_block_core (CRParser * a_this); ++static enum CRStatus cr_parser_parse_block_core (CRParser * a_this, ++ guint n_calls); + + static enum CRStatus cr_parser_parse_value_core (CRParser * a_this); + +@@ -794,7 +798,7 @@ cr_parser_parse_atrule_core (CRParser * a_this) + cr_parser_try_to_skip_spaces_and_comments (a_this); + + do { +- status = cr_parser_parse_any_core (a_this); ++ status = cr_parser_parse_any_core (a_this, 0); + } while (status == CR_OK); + + status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, +@@ -805,7 +809,7 @@ cr_parser_parse_atrule_core (CRParser * a_this) + cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, + token); + token = NULL; +- status = cr_parser_parse_block_core (a_this); ++ status = cr_parser_parse_block_core (a_this, 0); + CHECK_PARSING_STATUS (status, + FALSE); + goto done; +@@ -940,11 +944,11 @@ cr_parser_parse_selector_core (CRParser * a_this) + + RECORD_INITIAL_POS (a_this, &init_pos); + +- status = cr_parser_parse_any_core (a_this); ++ status = cr_parser_parse_any_core (a_this, 0); + CHECK_PARSING_STATUS (status, FALSE); + + do { +- status = cr_parser_parse_any_core (a_this); ++ status = cr_parser_parse_any_core (a_this, 0); + + } while (status == CR_OK); + +@@ -966,10 +970,12 @@ cr_parser_parse_selector_core (CRParser * a_this) + *in chapter 4.1 of the css2 spec. + *block ::= '{' S* [ any | block | ATKEYWORD S* | ';' ]* '}' S*; + *@param a_this the current instance of #CRParser. ++ *@param n_calls used to limit recursion depth + *FIXME: code this function. + */ + static enum CRStatus +-cr_parser_parse_block_core (CRParser * a_this) ++cr_parser_parse_block_core (CRParser * a_this, ++ guint n_calls) + { + CRToken *token = NULL; + CRInputPos init_pos; +@@ -977,6 +983,9 @@ cr_parser_parse_block_core (CRParser * a_this) + + g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); + ++ if (n_calls > RECURSIVE_CALLERS_LIMIT) ++ return CR_ERROR; ++ + RECORD_INITIAL_POS (a_this, &init_pos); + + status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); +@@ -1006,13 +1015,13 @@ cr_parser_parse_block_core (CRParser * a_this) + } else if (token->type == CBO_TK) { + cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); + token = NULL; +- status = cr_parser_parse_block_core (a_this); ++ status = cr_parser_parse_block_core (a_this, n_calls + 1); + CHECK_PARSING_STATUS (status, FALSE); + goto parse_block_content; + } else { + cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); + token = NULL; +- status = cr_parser_parse_any_core (a_this); ++ status = cr_parser_parse_any_core (a_this, n_calls + 1); + CHECK_PARSING_STATUS (status, FALSE); + goto parse_block_content; + } +@@ -1119,7 +1128,7 @@ cr_parser_parse_value_core (CRParser * a_this) + status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, + token); + token = NULL; +- status = cr_parser_parse_block_core (a_this); ++ status = cr_parser_parse_block_core (a_this, 0); + CHECK_PARSING_STATUS (status, FALSE); + ref++; + goto continue_parsing; +@@ -1133,7 +1142,7 @@ cr_parser_parse_value_core (CRParser * a_this) + status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, + token); + token = NULL; +- status = cr_parser_parse_any_core (a_this); ++ status = cr_parser_parse_any_core (a_this, 0); + if (status == CR_OK) { + ref++; + goto continue_parsing; +@@ -1172,10 +1181,12 @@ cr_parser_parse_value_core (CRParser * a_this) + * | FUNCTION | DASHMATCH | '(' any* ')' | '[' any* ']' ] S*; + * + *@param a_this the current instance of #CRParser. ++ *@param n_calls used to limit recursion depth + *@return CR_OK upon successfull completion, an error code otherwise. + */ + static enum CRStatus +-cr_parser_parse_any_core (CRParser * a_this) ++cr_parser_parse_any_core (CRParser * a_this, ++ guint n_calls) + { + CRToken *token1 = NULL, + *token2 = NULL; +@@ -1184,6 +1195,9 @@ cr_parser_parse_any_core (CRParser * a_this) + + g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); + ++ if (n_calls > RECURSIVE_CALLERS_LIMIT) ++ return CR_ERROR; ++ + RECORD_INITIAL_POS (a_this, &init_pos); + + status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token1); +@@ -1222,7 +1236,7 @@ cr_parser_parse_any_core (CRParser * a_this) + *We consider parameter as being an "any*" production. + */ + do { +- status = cr_parser_parse_any_core (a_this); ++ status = cr_parser_parse_any_core (a_this, n_calls + 1); + } while (status == CR_OK); + + ENSURE_PARSING_COND (status == CR_PARSING_ERROR); +@@ -1247,7 +1261,7 @@ cr_parser_parse_any_core (CRParser * a_this) + } + + do { +- status = cr_parser_parse_any_core (a_this); ++ status = cr_parser_parse_any_core (a_this, n_calls + 1); + } while (status == CR_OK); + + ENSURE_PARSING_COND (status == CR_PARSING_ERROR); +@@ -1275,7 +1289,7 @@ cr_parser_parse_any_core (CRParser * a_this) + } + + do { +- status = cr_parser_parse_any_core (a_this); ++ status = cr_parser_parse_any_core (a_this, n_calls + 1); + } while (status == CR_OK); + + ENSURE_PARSING_COND (status == CR_PARSING_ERROR); +--- a/libtextstyle/lib/libcroco/cr-parser.c ++++ b/libtextstyle/lib/libcroco/cr-parser.c +@@ -146,6 +146,8 @@ struct _CRParserPriv { + + #define CHARS_TAB_SIZE 12 + ++#define RECURSIVE_CALLERS_LIMIT 100 ++ + /** + * IS_NUM: + *@a_char: the char to test. +@@ -354,9 +356,11 @@ static enum CRStatus cr_parser_parse_selector_core (CRParser * a_this); + + static enum CRStatus cr_parser_parse_declaration_core (CRParser * a_this); + +-static enum CRStatus cr_parser_parse_any_core (CRParser * a_this); ++static enum CRStatus cr_parser_parse_any_core (CRParser * a_this, ++ guint n_calls); + +-static enum CRStatus cr_parser_parse_block_core (CRParser * a_this); ++static enum CRStatus cr_parser_parse_block_core (CRParser * a_this, ++ guint n_calls); + + static enum CRStatus cr_parser_parse_value_core (CRParser * a_this); + +@@ -794,7 +798,7 @@ cr_parser_parse_atrule_core (CRParser * a_this) + cr_parser_try_to_skip_spaces_and_comments (a_this); + + do { +- status = cr_parser_parse_any_core (a_this); ++ status = cr_parser_parse_any_core (a_this, 0); + } while (status == CR_OK); + + status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, +@@ -805,7 +809,7 @@ cr_parser_parse_atrule_core (CRParser * a_this) + cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, + token); + token = NULL; +- status = cr_parser_parse_block_core (a_this); ++ status = cr_parser_parse_block_core (a_this, 0); + CHECK_PARSING_STATUS (status, + FALSE); + goto done; +@@ -940,11 +944,11 @@ cr_parser_parse_selector_core (CRParser * a_this) + + RECORD_INITIAL_POS (a_this, &init_pos); + +- status = cr_parser_parse_any_core (a_this); ++ status = cr_parser_parse_any_core (a_this, 0); + CHECK_PARSING_STATUS (status, FALSE); + + do { +- status = cr_parser_parse_any_core (a_this); ++ status = cr_parser_parse_any_core (a_this, 0); + + } while (status == CR_OK); + +@@ -966,10 +970,12 @@ cr_parser_parse_selector_core (CRParser * a_this) + *in chapter 4.1 of the css2 spec. + *block ::= '{' S* [ any | block | ATKEYWORD S* | ';' ]* '}' S*; + *@param a_this the current instance of #CRParser. ++ *@param n_calls used to limit recursion depth + *FIXME: code this function. + */ + static enum CRStatus +-cr_parser_parse_block_core (CRParser * a_this) ++cr_parser_parse_block_core (CRParser * a_this, ++ guint n_calls) + { + CRToken *token = NULL; + CRInputPos init_pos; +@@ -977,6 +983,9 @@ cr_parser_parse_block_core (CRParser * a_this) + + g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); + ++ if (n_calls > RECURSIVE_CALLERS_LIMIT) ++ return CR_ERROR; ++ + RECORD_INITIAL_POS (a_this, &init_pos); + + status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); +@@ -1006,13 +1015,13 @@ cr_parser_parse_block_core (CRParser * a_this) + } else if (token->type == CBO_TK) { + cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); + token = NULL; +- status = cr_parser_parse_block_core (a_this); ++ status = cr_parser_parse_block_core (a_this, n_calls + 1); + CHECK_PARSING_STATUS (status, FALSE); + goto parse_block_content; + } else { + cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); + token = NULL; +- status = cr_parser_parse_any_core (a_this); ++ status = cr_parser_parse_any_core (a_this, n_calls + 1); + CHECK_PARSING_STATUS (status, FALSE); + goto parse_block_content; + } +@@ -1119,7 +1128,7 @@ cr_parser_parse_value_core (CRParser * a_this) + status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, + token); + token = NULL; +- status = cr_parser_parse_block_core (a_this); ++ status = cr_parser_parse_block_core (a_this, 0); + CHECK_PARSING_STATUS (status, FALSE); + ref++; + goto continue_parsing; +@@ -1133,7 +1142,7 @@ cr_parser_parse_value_core (CRParser * a_this) + status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, + token); + token = NULL; +- status = cr_parser_parse_any_core (a_this); ++ status = cr_parser_parse_any_core (a_this, 0); + if (status == CR_OK) { + ref++; + goto continue_parsing; +@@ -1172,10 +1181,12 @@ cr_parser_parse_value_core (CRParser * a_this) + * | FUNCTION | DASHMATCH | '(' any* ')' | '[' any* ']' ] S*; + * + *@param a_this the current instance of #CRParser. ++ *@param n_calls used to limit recursion depth + *@return CR_OK upon successfull completion, an error code otherwise. + */ + static enum CRStatus +-cr_parser_parse_any_core (CRParser * a_this) ++cr_parser_parse_any_core (CRParser * a_this, ++ guint n_calls) + { + CRToken *token1 = NULL, + *token2 = NULL; +@@ -1184,6 +1195,9 @@ cr_parser_parse_any_core (CRParser * a_this) + + g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); + ++ if (n_calls > RECURSIVE_CALLERS_LIMIT) ++ return CR_ERROR; ++ + RECORD_INITIAL_POS (a_this, &init_pos); + + status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token1); +@@ -1222,7 +1236,7 @@ cr_parser_parse_any_core (CRParser * a_this) + *We consider parameter as being an "any*" production. + */ + do { +- status = cr_parser_parse_any_core (a_this); ++ status = cr_parser_parse_any_core (a_this, n_calls + 1); + } while (status == CR_OK); + + ENSURE_PARSING_COND (status == CR_PARSING_ERROR); +@@ -1247,7 +1261,7 @@ cr_parser_parse_any_core (CRParser * a_this) + } + + do { +- status = cr_parser_parse_any_core (a_this); ++ status = cr_parser_parse_any_core (a_this, n_calls + 1); + } while (status == CR_OK); + + ENSURE_PARSING_COND (status == CR_PARSING_ERROR); +@@ -1275,7 +1289,7 @@ cr_parser_parse_any_core (CRParser * a_this) + } + + do { +- status = cr_parser_parse_any_core (a_this); ++ status = cr_parser_parse_any_core (a_this, n_calls + 1); + } while (status == CR_OK); + + ENSURE_PARSING_COND (status == CR_PARSING_ERROR); + diff --git a/sys-devel/gettext/gettext-0.21-r1.ebuild b/sys-devel/gettext/gettext-0.21-r1.ebuild new file mode 100644 index 000000000000..f6ce7c38d3ed --- /dev/null +++ b/sys-devel/gettext/gettext-0.21-r1.ebuild @@ -0,0 +1,157 @@ +# Copyright 1999-2021 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +# Note: Keep version bumps in sync with dev-libs/libintl. + +EAPI=7 + +inherit mono-env libtool java-pkg-opt-2 multilib-minimal + +DESCRIPTION="GNU locale utilities" +HOMEPAGE="https://www.gnu.org/software/gettext/" +if [[ "${PV}" == *_rc* ]] ; then + SRC_URI="https://alpha.gnu.org/gnu/${PN}/${P/_/-}.tar.bz2" + S="${WORKDIR}/${P/_/-}" +else + SRC_URI="mirror://gnu/${PN}/${P}.tar.gz" + KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~m68k ~mips ~ppc ~ppc64 ~riscv ~s390 ~sparc ~x86 ~x64-cygwin ~amd64-linux ~x86-linux ~ppc-macos ~x64-macos ~sparc-solaris ~sparc64-solaris ~x64-solaris ~x86-solaris ~x86-winnt" +fi +# Only libasprintf is under the LGPL (and libintl is in a sep package), +# so put that license behind USE=cxx. +LICENSE="GPL-3+ cxx? ( LGPL-2.1+ )" +SLOT="0" +IUSE="acl -cvs +cxx doc emacs git java ncurses nls openmp static-libs" + +# only runtime goes multilib +# Note: The version of libxml2 corresponds to the version bundled via gnulib. +# If the build detects too old of a system version, it will end up falling back +# to the bundled copy. #596918 +# Note: expat lacks a subslot because it is dynamically loaded at runtime. We +# would depend on older subslots if they were available (based on the ABIs that +# are explicitly handled), but expat doesn't currently use subslots. +DEPEND=">=virtual/libiconv-0-r1[${MULTILIB_USEDEP}] + >=virtual/libintl-0-r2[${MULTILIB_USEDEP}] + >=dev-libs/libxml2-2.9.3:= + dev-libs/expat + acl? ( virtual/acl ) + ncurses? ( sys-libs/ncurses:0= ) + java? ( >=virtual/jdk-1.4:= )" +RDEPEND="${DEPEND} + !git? ( cvs? ( dev-vcs/cvs ) ) + git? ( dev-vcs/git ) + java? ( >=virtual/jre-1.4 )" +BDEPEND=" + git? ( dev-vcs/git ) +" +PDEPEND="emacs? ( app-emacs/po-mode )" + +MULTILIB_WRAPPED_HEADERS=( + # only installed for native ABI + /usr/include/gettext-po.h + + /usr/include/autosprintf.h + /usr/include/textstyle.h + /usr/include/textstyle/stdbool.h + /usr/include/textstyle/version.h + /usr/include/textstyle/woe32dll.h +) + +PATCHES=( + "${FILESDIR}"/${PN}-0.19.7-disable-libintl.patch #564168 + "${FILESDIR}"/${PN}-0.20-parallel_install.patch #685530 + "${FILESDIR}"/${PN}-0.21_rc1-avoid_eautomake.patch + "${FILESDIR}"/${PN}-0.21-CVE-2020-12825.patch +) + +QA_SONAME_NO_SYMLINK=".*/preloadable_libintl.so" + +pkg_setup() { + mono-env_pkg_setup + java-pkg-opt-2_pkg_setup +} + +src_prepare() { + java-pkg-opt-2_src_prepare + + default + + elibtoolize +} + +multilib_src_configure() { + local myconf=( + # switches common to runtime and top-level + --cache-file="${BUILD_DIR}"/config.cache + #--docdir="\$(datarootdir)/doc/${PF}" + + # Emacs support is now in a separate package + --without-emacs + --without-lispdir + # glib depends on us so avoid circular deps + --with-included-glib + # libcroco depends on glib which ... ^^^ + --with-included-libcroco + # this will _disable_ libunistring (since it is not bundled), + # see bug #326477 + --with-included-libunistring + # Never build libintl since it's in dev-libs/libintl now. + --without-included-gettext + # Never build bundled copy of libxml2. + --without-included-libxml + + $(use_enable acl) + $(use_enable cxx c++) + $(use_enable cxx libasprintf) + $(use_with git) + $(usex git --without-cvs $(use_with cvs)) + $(use_enable java) + $(use_enable ncurses curses) + $(use_enable nls) + $(use_enable openmp) + $(use_enable static-libs static) + ) + + local ECONF_SOURCE="${S}" + if ! multilib_is_native_abi ; then + # for non-native ABIs, we build runtime only + ECONF_SOURCE+=/gettext-runtime + fi + + econf "${myconf[@]}" +} + +multilib_src_install() { + emake DESTDIR="${D}" install + + if multilib_is_native_abi ; then + dosym msgfmt /usr/bin/gmsgfmt #43435 + dobin gettext-tools/misc/gettextize + fi +} + +multilib_src_install_all() { + find "${ED}" -type f -name "*.la" -delete || die + + if use java ; then + java-pkg_dojar "${ED}"/usr/share/${PN}/*.jar + rm "${ED}"/usr/share/${PN}/*.jar || die + rm "${ED}"/usr/share/${PN}/*.class || die + if use doc ; then + java-pkg_dojavadoc "${ED}"/usr/share/doc/${PF}/html/javadoc2 + fi + fi + + dodoc AUTHORS ChangeLog NEWS README THANKS + + if use doc ; then + docinto html + dodoc "${ED}"/usr/share/doc/${PF}/*.html + else + rm -rf "${ED}"/usr/share/doc/${PF}/{csharpdoc,examples,javadoc2,javadoc1} + fi + rm "${ED}"/usr/share/doc/${PF}/*.html || die +} + +pkg_preinst() { + java-pkg-opt-2_pkg_preinst +} -- cgit v1.2.3-65-gdbad