diff --git a/SOURCES/glibc-rh1924919.patch b/SOURCES/glibc-rh1924919.patch
new file mode 100644
index 0000000..72c211a
--- /dev/null
+++ b/SOURCES/glibc-rh1924919.patch
@@ -0,0 +1,287 @@
+commit 7d88c6142c6efc160c0ee5e4f85cde382c072888
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Wed Jan 27 13:36:12 2021 +0100
+
+    gconv: Fix assertion failure in ISO-2022-JP-3 module (bug 27256)
+    
+    The conversion loop to the internal encoding does not follow
+    the interface contract that __GCONV_FULL_OUTPUT is only returned
+    after the internal wchar_t buffer has been filled completely.  This
+    is enforced by the first of the two asserts in iconv/skeleton.c:
+    
+                  /* We must run out of output buffer space in this
+                     rerun.  */
+                  assert (outbuf == outerr);
+                  assert (nstatus == __GCONV_FULL_OUTPUT);
+    
+    This commit solves this issue by queuing a second wide character
+    which cannot be written immediately in the state variable, like
+    other converters already do (e.g., BIG5-HKSCS or TSCII).
+    
+    Reported-by: Tavis Ormandy <taviso@gmail.com>
+
+Conflicts:
+	iconvdata/Makefile
+	  (Usual differences in backported tests.)
+
+diff --git a/iconvdata/Makefile b/iconvdata/Makefile
+index a47a4c07cd2e3d1b..32656ad31d9b434b 100644
+--- a/iconvdata/Makefile
++++ b/iconvdata/Makefile
+@@ -73,7 +73,7 @@ modules.so := $(addsuffix .so, $(modules))
+ ifeq (yes,$(build-shared))
+ tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \
+ 	tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9 \
+-	bug-iconv10 bug-iconv11 bug-iconv12 bug-iconv13
++	bug-iconv10 bug-iconv11 bug-iconv12 bug-iconv13 bug-iconv14
+ ifeq ($(have-thread-library),yes)
+ tests += bug-iconv3
+ endif
+@@ -316,6 +316,8 @@ $(objpfx)bug-iconv10.out: $(objpfx)gconv-modules \
+ 			  $(addprefix $(objpfx),$(modules.so))
+ $(objpfx)bug-iconv12.out: $(objpfx)gconv-modules \
+ 			  $(addprefix $(objpfx),$(modules.so))
++$(objpfx)bug-iconv14.out: $(objpfx)gconv-modules \
++			  $(addprefix $(objpfx),$(modules.so))
+ 
+ $(objpfx)iconv-test.out: run-iconv-test.sh $(objpfx)gconv-modules \
+ 			 $(addprefix $(objpfx),$(modules.so)) \
+diff --git a/iconvdata/bug-iconv14.c b/iconvdata/bug-iconv14.c
+new file mode 100644
+index 0000000000000000..902f140fa949cbac
+--- /dev/null
++++ b/iconvdata/bug-iconv14.c
+@@ -0,0 +1,127 @@
++/* Assertion in ISO-2022-JP-3 due to two-character sequence (bug 27256).
++   Copyright (C) 2021 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <https://www.gnu.org/licenses/>.  */
++
++#include <iconv.h>
++#include <string.h>
++#include <errno.h>
++#include <support/check.h>
++
++/* Use an escape sequence to return to the initial state.  */
++static void
++with_escape_sequence (void)
++{
++  iconv_t c = iconv_open ("UTF-8", "ISO-2022-JP-3");
++  TEST_VERIFY_EXIT (c != (iconv_t) -1);
++
++  char in[] = "\e$(O+D\e(B";
++  char *inbuf = in;
++  size_t inleft = strlen (in);
++  char out[3];                  /* Space for one output character.  */
++  char *outbuf;
++  size_t outleft;
++
++  outbuf = out;
++  outleft = sizeof (out);
++  TEST_COMPARE (iconv (c, &inbuf, &inleft, &outbuf, &outleft), (size_t) -1);
++  TEST_COMPARE (errno, E2BIG);
++  TEST_COMPARE (inleft, 3);
++  TEST_COMPARE (inbuf - in, strlen (in) - 3);
++  TEST_COMPARE (outleft, sizeof (out) - 2);
++  TEST_COMPARE (outbuf - out, 2);
++  TEST_COMPARE (out[0] & 0xff, 0xc3);
++  TEST_COMPARE (out[1] & 0xff, 0xa6);
++
++  /* Return to the initial shift state, producing the pending
++     character.  */
++  outbuf = out;
++  outleft = sizeof (out);
++  TEST_COMPARE (iconv (c, &inbuf, &inleft, &outbuf, &outleft), 0);
++  TEST_COMPARE (inleft, 0);
++  TEST_COMPARE (inbuf - in, strlen (in));
++  TEST_COMPARE (outleft, sizeof (out) - 2);
++  TEST_COMPARE (outbuf - out, 2);
++  TEST_COMPARE (out[0] & 0xff, 0xcc);
++  TEST_COMPARE (out[1] & 0xff, 0x80);
++
++  /* Nothing should be flushed the second time.  */
++  outbuf = out;
++  outleft = sizeof (out);
++  TEST_COMPARE (iconv (c, NULL, 0, &outbuf, &outleft), 0);
++  TEST_COMPARE (outleft, sizeof (out));
++  TEST_COMPARE (outbuf - out, 0);
++  TEST_COMPARE (out[0] & 0xff, 0xcc);
++  TEST_COMPARE (out[1] & 0xff, 0x80);
++
++  TEST_COMPARE (iconv_close (c), 0);
++}
++
++/* Use an explicit flush to return to the initial state.  */
++static void
++with_flush (void)
++{
++  iconv_t c = iconv_open ("UTF-8", "ISO-2022-JP-3");
++  TEST_VERIFY_EXIT (c != (iconv_t) -1);
++
++  char in[] = "\e$(O+D";
++  char *inbuf = in;
++  size_t inleft = strlen (in);
++  char out[3];                  /* Space for one output character.  */
++  char *outbuf;
++  size_t outleft;
++
++  outbuf = out;
++  outleft = sizeof (out);
++  TEST_COMPARE (iconv (c, &inbuf, &inleft, &outbuf, &outleft), (size_t) -1);
++  TEST_COMPARE (errno, E2BIG);
++  TEST_COMPARE (inleft, 0);
++  TEST_COMPARE (inbuf - in, strlen (in));
++  TEST_COMPARE (outleft, sizeof (out) - 2);
++  TEST_COMPARE (outbuf - out, 2);
++  TEST_COMPARE (out[0] & 0xff, 0xc3);
++  TEST_COMPARE (out[1] & 0xff, 0xa6);
++
++  /* Flush the pending character.  */
++  outbuf = out;
++  outleft = sizeof (out);
++  TEST_COMPARE (iconv (c, NULL, 0, &outbuf, &outleft), 0);
++  TEST_COMPARE (outleft, sizeof (out) - 2);
++  TEST_COMPARE (outbuf - out, 2);
++  TEST_COMPARE (out[0] & 0xff, 0xcc);
++  TEST_COMPARE (out[1] & 0xff, 0x80);
++
++  /* Nothing should be flushed the second time.  */
++  outbuf = out;
++  outleft = sizeof (out);
++  TEST_COMPARE (iconv (c, NULL, 0, &outbuf, &outleft), 0);
++  TEST_COMPARE (outleft, sizeof (out));
++  TEST_COMPARE (outbuf - out, 0);
++  TEST_COMPARE (out[0] & 0xff, 0xcc);
++  TEST_COMPARE (out[1] & 0xff, 0x80);
++
++  TEST_COMPARE (iconv_close (c), 0);
++}
++
++static int
++do_test (void)
++{
++  with_escape_sequence ();
++  with_flush ();
++  return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/iconvdata/iso-2022-jp-3.c b/iconvdata/iso-2022-jp-3.c
+index de259580c3f378bb..047fab8e8dfbde7e 100644
+--- a/iconvdata/iso-2022-jp-3.c
++++ b/iconvdata/iso-2022-jp-3.c
+@@ -67,23 +67,34 @@ enum
+   CURRENT_SEL_MASK = 7 << 3
+ };
+ 
+-/* During UCS-4 to ISO-2022-JP-3 conversion, the COUNT element of the state
+-   also contains the last two bytes to be output, shifted by 6 bits, and a
+-   one-bit indicator whether they must be preceded by the shift sequence,
+-   in bit 22.  */
++/* During UCS-4 to ISO-2022-JP-3 conversion, the COUNT element of the
++   state also contains the last two bytes to be output, shifted by 6
++   bits, and a one-bit indicator whether they must be preceded by the
++   shift sequence, in bit 22.  During ISO-2022-JP-3 to UCS-4
++   conversion, COUNT may also contain a non-zero pending wide
++   character, shifted by six bits.  This happens for certain inputs in
++   JISX0213_1_2004_set and JISX0213_2_set if the second wide character
++   in a combining sequence cannot be written because the buffer is
++   full.  */
+ 
+ /* Since this is a stateful encoding we have to provide code which resets
+    the output state to the initial state.  This has to be done during the
+    flushing.  */
+ #define EMIT_SHIFT_TO_INIT \
+-  if ((data->__statep->__count & ~7) != ASCII_set)			      \
++  if (data->__statep->__count != ASCII_set)			      \
+     {									      \
+       if (FROM_DIRECTION)						      \
+ 	{								      \
+-	  /* It's easy, we don't have to emit anything, we just reset the     \
+-	     state for the input.  */					      \
+-	  data->__statep->__count &= 7;					      \
+-	  data->__statep->__count |= ASCII_set;				      \
++	  if (__glibc_likely (outbuf + 4 <= outend))			      \
++	    {								      \
++	      /* Write out the last character.  */			      \
++	      *((uint32_t *) outbuf) = data->__statep->__count >> 6;	      \
++	      outbuf += sizeof (uint32_t);				      \
++	      data->__statep->__count = ASCII_set;			\
++	    }								      \
++	  else								      \
++	    /* We don't have enough room in the output buffer.  */	      \
++	    status = __GCONV_FULL_OUTPUT;				      \
+ 	}								      \
+       else								      \
+ 	{								      \
+@@ -151,7 +162,21 @@ enum
+ #define LOOPFCT			FROM_LOOP
+ #define BODY \
+   {									      \
+-    uint32_t ch = *inptr;						      \
++    uint32_t ch;							      \
++									      \
++    /* Output any pending character.  */				      \
++    ch = set >> 6;							      \
++    if (__glibc_unlikely (ch != 0))					      \
++      {									      \
++	put32 (outptr, ch);						      \
++	outptr += 4;							      \
++	/* Remove the pending character, but preserve state bits.  */	      \
++	set &= (1 << 6) - 1;						      \
++	continue;							      \
++      }									      \
++									      \
++    /* Otherwise read the next input byte.  */				      \
++    ch = *inptr;							      \
+ 									      \
+     /* Recognize escape sequences.  */					      \
+     if (__glibc_unlikely (ch == ESC))					      \
+@@ -297,21 +322,25 @@ enum
+ 	    uint32_t u1 = __jisx0213_to_ucs_combining[ch - 1][0];	      \
+ 	    uint32_t u2 = __jisx0213_to_ucs_combining[ch - 1][1];	      \
+ 									      \
++	    inptr += 2;							      \
++									      \
++	    put32 (outptr, u1);						      \
++	    outptr += 4;						      \
++									      \
+ 	    /* See whether we have room for two characters.  */		      \
+-	    if (outptr + 8 <= outend)					      \
++	    if (outptr + 4 <= outend)					      \
+ 	      {								      \
+-		inptr += 2;						      \
+-		put32 (outptr, u1);					      \
+-		outptr += 4;						      \
+ 		put32 (outptr, u2);					      \
+ 		outptr += 4;						      \
+ 		continue;						      \
+ 	      }								      \
+-	    else							      \
+-	      {								      \
+-		result = __GCONV_FULL_OUTPUT;				      \
+-		break;							      \
+-	      }								      \
++									      \
++	    /* Otherwise store only the first character now, and	      \
++	       put the second one into the queue.  */			      \
++	    set |= u2 << 6;						      \
++	    /* Tell the caller why we terminate the loop.  */		      \
++	    result = __GCONV_FULL_OUTPUT;				      \
++	    break;							      \
+ 	  }								      \
+ 									      \
+ 	inptr += 2;							      \
diff --git a/SPECS/glibc.spec b/SPECS/glibc.spec
index 24421a5..b8f63c3 100644
--- a/SPECS/glibc.spec
+++ b/SPECS/glibc.spec
@@ -1,6 +1,6 @@
 %define glibcsrcdir glibc-2.28
 %define glibcversion 2.28
-%define glibcrelease 147%{?dist}
+%define glibcrelease 148%{?dist}
 # Pre-release tarballs are pulled in from git using a command that is
 # effectively:
 #
@@ -679,6 +679,7 @@ Patch542: glibc-rh1882466-3.patch
 Patch543: glibc-rh1817513-133.patch
 Patch544: glibc-rh1912544.patch
 Patch545: glibc-rh1918115.patch
+Patch546: glibc-rh1924919.patch
 
 ##############################################################################
 # Continued list of core "glibc" package information:
@@ -2590,6 +2591,9 @@ fi
 %files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared
 
 %changelog
+* Fri Feb  5 2021 Florian Weimer <fweimer@redhat.com> - 2.28-148
+- CVE-2021-3326: iconv assertion failure in ISO-2022-JP-3 decoding (#1924919)
+
 * Wed Jan 20 2021 Florian Weimer <fweimer@redhat.com> - 2.28-147
 - x86-64: Fix FMA4 math routine selection after bug 1817513 (#1918115)