diff --git a/SOURCES/glibc-rh1966472-1.patch b/SOURCES/glibc-rh1966472-1.patch
new file mode 100644
index 0000000..ecccfeb
--- /dev/null
+++ b/SOURCES/glibc-rh1966472-1.patch
@@ -0,0 +1,159 @@
+nptl: Add __pthread_attr_copy for copying pthread_attr_t objects
+
+Also add the private type union pthread_attr_transparent, to reduce
+the amount of casting that is required.
+
+Reviewed-by: Carlos O'Donell <carlos@redhat.com>
+Tested-by: Carlos O'Donell <carlos@redhat.com>
+(cherry picked from commit 331c6e8a184167dd21a9f0b3fc165aeefea6eeca)
+
+Difference from upstream:
+Unlike upstream, __pthread_attr_copy is in libpthread.so.
+
+# Conflicts:
+#	nptl/Makefile
+#	nptl/Versions
+
+diff --git a/nptl/Makefile b/nptl/Makefile
+index d6b37b6efd3b7d78..b14de3ffb330c10b 100644
+--- a/nptl/Makefile
++++ b/nptl/Makefile
+@@ -54,7 +54,8 @@ libpthread-routines = nptl-init nptlfreeres vars events version pt-interp \
+ 		      pthread_getconcurrency pthread_setconcurrency \
+ 		      pthread_getschedparam pthread_setschedparam \
+ 		      pthread_setschedprio \
+-		      pthread_attr_init pthread_attr_destroy \
++		      pthread_attr_init pthread_attr_copy \
++		      pthread_attr_destroy \
+ 		      pthread_attr_getdetachstate pthread_attr_setdetachstate \
+ 		      pthread_attr_getguardsize pthread_attr_setguardsize \
+ 		      pthread_attr_getschedparam pthread_attr_setschedparam \
+diff --git a/nptl/Versions b/nptl/Versions
+index 6007fd03e7ed117c..e38272aa187fbe78 100644
+--- a/nptl/Versions
++++ b/nptl/Versions
+@@ -283,5 +283,6 @@ libpthread {
+     __pthread_barrier_init; __pthread_barrier_wait;
+     __shm_directory;
+     __libpthread_freeres;
++    __pthread_attr_copy;
+   }
+ }
+diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h
+index 00be8f92793e8710..a2d48b2015cd385c 100644
+--- a/nptl/pthreadP.h
++++ b/nptl/pthreadP.h
+@@ -464,6 +464,9 @@ extern int __pthread_attr_getstack (const pthread_attr_t *__restrict __attr,
+ 				    size_t *__restrict __stacksize);
+ extern int __pthread_attr_setstack (pthread_attr_t *__attr, void *__stackaddr,
+ 				    size_t __stacksize);
++extern int __pthread_attr_setaffinity_np (pthread_attr_t *attr,
++					  size_t cpusetsize,
++					  const cpu_set_t *cpuset);
+ extern int __pthread_rwlock_init (pthread_rwlock_t *__restrict __rwlock,
+ 				  const pthread_rwlockattr_t *__restrict
+ 				  __attr);
+@@ -605,6 +608,11 @@ extern void __wait_lookup_done (void) attribute_hidden;
+ # define PTHREAD_STATIC_FN_REQUIRE(name) __asm (".globl " #name);
+ #endif
+ 
++/* Make a deep copy of the attribute *SOURCE in *TARGET.  *TARGET is
++   not assumed to have been initialized.  Returns 0 on success, or a
++   positive error code otherwise.  */
++int __pthread_attr_copy (pthread_attr_t *target, const pthread_attr_t *source);
++
+ /* Returns 0 if POL is a valid scheduling policy.  */
+ static inline int
+ check_sched_policy_attr (int pol)
+diff --git a/nptl/pthread_attr_copy.c b/nptl/pthread_attr_copy.c
+new file mode 100644
+index 0000000000000000..67f272acf297100c
+--- /dev/null
++++ b/nptl/pthread_attr_copy.c
+@@ -0,0 +1,56 @@
++/* Deep copy of a pthread_attr_t object.
++   Copyright (C) 2020 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 <errno.h>
++#include <pthreadP.h>
++#include <stdlib.h>
++
++int
++__pthread_attr_copy (pthread_attr_t *target, const pthread_attr_t *source)
++{
++  /* Avoid overwriting *TARGET until all allocations have
++     succeeded.  */
++  union pthread_attr_transparent temp;
++  temp.external = *source;
++
++  /* Force new allocation.  This function has full ownership of temp.  */
++  temp.internal.cpuset = NULL;
++  temp.internal.cpusetsize = 0;
++
++  int ret = 0;
++
++  struct pthread_attr *isource = (struct pthread_attr *) source;
++
++  /* Propagate affinity mask information.  */
++  if (isource->cpusetsize > 0)
++    ret = __pthread_attr_setaffinity_np (&temp.external,
++					 isource->cpusetsize,
++					 isource->cpuset);
++
++  if (ret != 0)
++    {
++      /* Deallocate because we have ownership.  */
++      __pthread_attr_destroy (&temp.external);
++      return ret;
++    }
++
++  /* Transfer ownership.  *target is not assumed to have been
++     initialized.  */
++  *target = temp.external;
++  return 0;
++}
+diff --git a/nptl/pthread_attr_setaffinity.c b/nptl/pthread_attr_setaffinity.c
+index 545b72c91e290216..914ebf6f9cbfd5ff 100644
+--- a/nptl/pthread_attr_setaffinity.c
++++ b/nptl/pthread_attr_setaffinity.c
+@@ -55,6 +55,7 @@ __pthread_attr_setaffinity_new (pthread_attr_t *attr, size_t cpusetsize,
+ 
+   return 0;
+ }
++strong_alias (__pthread_attr_setaffinity_new, __pthread_attr_setaffinity_np)
+ versioned_symbol (libpthread, __pthread_attr_setaffinity_new,
+ 		  pthread_attr_setaffinity_np, GLIBC_2_3_4);
+ 
+diff --git a/sysdeps/nptl/internaltypes.h b/sysdeps/nptl/internaltypes.h
+index b78ad99a888b4e3b..d3dce1278de989e2 100644
+--- a/sysdeps/nptl/internaltypes.h
++++ b/sysdeps/nptl/internaltypes.h
+@@ -49,6 +49,13 @@ struct pthread_attr
+ #define ATTR_FLAG_SCHED_SET		0x0020
+ #define ATTR_FLAG_POLICY_SET		0x0040
+ 
++/* Used to allocate a pthread_attr_t object which is also accessed
++   internally.  */
++union pthread_attr_transparent
++{
++  pthread_attr_t external;
++  struct pthread_attr internal;
++};
+ 
+ /* Mutex attribute data structure.  */
+ struct pthread_mutexattr
diff --git a/SOURCES/glibc-rh1966472-2.patch b/SOURCES/glibc-rh1966472-2.patch
new file mode 100644
index 0000000..014f62a
--- /dev/null
+++ b/SOURCES/glibc-rh1966472-2.patch
@@ -0,0 +1,50 @@
+Use __pthread_attr_copy in mq_notify (bug 27896)
+
+Make a deep copy of the pthread attribute object to remove a potential
+use-after-free issue.
+
+(cherry picked from commit 42d359350510506b87101cf77202fefcbfc790cb)
+
+# Conflicts:
+#	NEWS
+
+diff --git a/sysdeps/unix/sysv/linux/mq_notify.c b/sysdeps/unix/sysv/linux/mq_notify.c
+index 3563e82cd4f4b552..c4091169306ffde8 100644
+--- a/sysdeps/unix/sysv/linux/mq_notify.c
++++ b/sysdeps/unix/sysv/linux/mq_notify.c
+@@ -135,8 +135,11 @@ helper_thread (void *arg)
+ 	    (void) __pthread_barrier_wait (&notify_barrier);
+ 	}
+       else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED)
+-	/* The only state we keep is the copy of the thread attributes.  */
+-	free (data.attr);
++	{
++	  /* The only state we keep is the copy of the thread attributes.  */
++	  pthread_attr_destroy (data.attr);
++	  free (data.attr);
++	}
+     }
+   return NULL;
+ }
+@@ -257,8 +260,7 @@ mq_notify (mqd_t mqdes, const struct sigevent *notification)
+       if (data.attr == NULL)
+ 	return -1;
+ 
+-      memcpy (data.attr, notification->sigev_notify_attributes,
+-	      sizeof (pthread_attr_t));
++      __pthread_attr_copy (data.attr, notification->sigev_notify_attributes);
+     }
+ 
+   /* Construct the new request.  */
+@@ -272,7 +274,10 @@ mq_notify (mqd_t mqdes, const struct sigevent *notification)
+ 
+   /* If it failed, free the allocated memory.  */
+   if (__glibc_unlikely (retval != 0))
+-    free (data.attr);
++    {
++      pthread_attr_destroy (data.attr);
++      free (data.attr);
++    }
+ 
+   return retval;
+ }
diff --git a/SOURCES/glibc-rh1966472-3.patch b/SOURCES/glibc-rh1966472-3.patch
new file mode 100644
index 0000000..23d704f
--- /dev/null
+++ b/SOURCES/glibc-rh1966472-3.patch
@@ -0,0 +1,44 @@
+Fix use of __pthread_attr_copy in mq_notify (bug 27896)
+
+__pthread_attr_copy can fail and does not initialize the attribute
+structure in that case.
+
+If __pthread_attr_copy is never called and there is no allocated
+attribute, pthread_attr_destroy should not be called, otherwise
+there is a null pointer dereference in rt/tst-mqueue6.
+
+Fixes commit 42d359350510506b87101cf77202fefcbfc790cb
+("Use __pthread_attr_copy in mq_notify (bug 27896)").
+
+Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
+(cherry picked from commit 217b6dc298156bdb0d6aea9ea93e7e394a5ff091)
+
+diff --git a/sysdeps/unix/sysv/linux/mq_notify.c b/sysdeps/unix/sysv/linux/mq_notify.c
+index c4091169306ffde8..45449571d14c379f 100644
+--- a/sysdeps/unix/sysv/linux/mq_notify.c
++++ b/sysdeps/unix/sysv/linux/mq_notify.c
+@@ -260,7 +260,14 @@ mq_notify (mqd_t mqdes, const struct sigevent *notification)
+       if (data.attr == NULL)
+ 	return -1;
+ 
+-      __pthread_attr_copy (data.attr, notification->sigev_notify_attributes);
++      int ret = __pthread_attr_copy (data.attr,
++				     notification->sigev_notify_attributes);
++      if (ret != 0)
++	{
++	  free (data.attr);
++	  __set_errno (ret);
++	  return -1;
++	}
+     }
+ 
+   /* Construct the new request.  */
+@@ -273,7 +280,7 @@ mq_notify (mqd_t mqdes, const struct sigevent *notification)
+   int retval = INLINE_SYSCALL (mq_notify, 2, mqdes, &se);
+ 
+   /* If it failed, free the allocated memory.  */
+-  if (__glibc_unlikely (retval != 0))
++  if (retval != 0 && data.attr != NULL)
+     {
+       pthread_attr_destroy (data.attr);
+       free (data.attr);
diff --git a/SOURCES/glibc-rh1966472-4.patch b/SOURCES/glibc-rh1966472-4.patch
new file mode 100644
index 0000000..47a01ff
--- /dev/null
+++ b/SOURCES/glibc-rh1966472-4.patch
@@ -0,0 +1,34 @@
+commit b805aebd42364fe696e417808a700fdb9800c9e8
+Author: Nikita Popov <npv1310@gmail.com>
+Date:   Mon Aug 9 20:17:34 2021 +0530
+
+    librt: fix NULL pointer dereference (bug 28213)
+    
+    Helper thread frees copied attribute on NOTIFY_REMOVED message
+    received from the OS kernel.  Unfortunately, it fails to check whether
+    copied attribute actually exists (data.attr != NULL).  This worked
+    earlier because free() checks passed pointer before actually
+    attempting to release corresponding memory.  But
+    __pthread_attr_destroy assumes pointer is not NULL.
+    
+    So passing NULL pointer to __pthread_attr_destroy will result in
+    segmentation fault.  This scenario is possible if
+    notification->sigev_notify_attributes == NULL (which means default
+    thread attributes should be used).
+    
+    Signed-off-by: Nikita Popov <npv1310@gmail.com>
+    Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
+
+diff --git a/sysdeps/unix/sysv/linux/mq_notify.c b/sysdeps/unix/sysv/linux/mq_notify.c
+index 45449571d14c379f..581959d621135fb0 100644
+--- a/sysdeps/unix/sysv/linux/mq_notify.c
++++ b/sysdeps/unix/sysv/linux/mq_notify.c
+@@ -134,7 +134,7 @@ helper_thread (void *arg)
+ 	       to wait until it is done with it.  */
+ 	    (void) __pthread_barrier_wait (&notify_barrier);
+ 	}
+-      else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED)
++      else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED && data.attr != NULL)
+ 	{
+ 	  /* The only state we keep is the copy of the thread attributes.  */
+ 	  pthread_attr_destroy (data.attr);
diff --git a/SPECS/glibc.spec b/SPECS/glibc.spec
index 2aa98e9..fbc88ac 100644
--- a/SPECS/glibc.spec
+++ b/SPECS/glibc.spec
@@ -1,6 +1,6 @@
 %define glibcsrcdir glibc-2.28
 %define glibcversion 2.28
-%define glibcrelease 162%{?dist}
+%define glibcrelease 164%{?dist}
 # Pre-release tarballs are pulled in from git using a command that is
 # effectively:
 #
@@ -715,6 +715,10 @@ Patch578: glibc-rh1956357-6.patch
 Patch579: glibc-rh1956357-7.patch
 Patch580: glibc-rh1956357-8.patch
 Patch581: glibc-rh1979127.patch
+Patch582: glibc-rh1966472-1.patch
+Patch583: glibc-rh1966472-2.patch
+Patch584: glibc-rh1966472-3.patch
+Patch585: glibc-rh1966472-4.patch
 
 ##############################################################################
 # Continued list of core "glibc" package information:
@@ -2627,6 +2631,12 @@ fi
 %files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared
 
 %changelog
+* Mon Aug  9 2021 Siddhesh Poyarekar <siddhesh@redhat.com> - 2.28-164
+- librt: fix NULL pointer dereference (#1966472).
+
+* Mon Aug  9 2021 Siddhesh Poyarekar <siddhesh@redhat.com> - 2.28-163
+- CVE-2021-33574: Deep copy pthread attribute in mq_notify (#1966472)
+
 * Thu Jul  8 2021 Siddhesh Poyarekar <siddhesh@redhat.com> - 2.28-162
 - CVE-2021-35942: wordexp: handle overflow in positional parameter number
   (#1979127)