diff --git a/valgrind-3.18.1-arm64-atomic-align.patch b/valgrind-3.18.1-arm64-atomic-align.patch
new file mode 100644
index 0000000..8cce35f
--- /dev/null
+++ b/valgrind-3.18.1-arm64-atomic-align.patch
@@ -0,0 +1,163 @@
+commit 2be719921e700a9ac9b85f470ed87cb8adf8151b
+Author: Julian Seward <jseward@acm.org>
+Date:   Sat Nov 13 09:27:01 2021 +0100
+
+    Bug 445415 - arm64 front end: alignment checks missing for atomic instructions.
+    
+    For the arm64 front end, none of the atomic instructions have address
+    alignment checks included in their IR.  They all should.  The effect of
+    missing alignment checks in the IR is that, since this IR will in most cases
+    be translated back to atomic instructions in the back end, we will get
+    alignment traps (SIGBUS) on the host side and not on the guest side, which is
+    (very) incorrect behaviour of the simulation.
+
+ 
+diff --git a/VEX/priv/guest_arm64_toIR.c b/VEX/priv/guest_arm64_toIR.c
+index ee018c6a9..16a7e075f 100644
+--- a/VEX/priv/guest_arm64_toIR.c
++++ b/VEX/priv/guest_arm64_toIR.c
+@@ -4833,6 +4833,34 @@ static IRTemp gen_zwidening_load ( UInt szB, IRTemp addr )
+ }
+ 
+ 
++/* Generate a SIGBUS followed by a restart of the current instruction if
++   `effective_addr` is `align`-aligned.  This is required behaviour for atomic
++   instructions.  This assumes that guest_RIP_curr_instr is set correctly!
++
++   This is hardwired to generate SIGBUS because so far the only supported arm64
++   (arm64-linux) does that.  Should we need to later extend it to generate some
++   other signal, use the same scheme as with gen_SIGNAL_if_not_XX_aligned in
++   guest_amd64_toIR.c. */
++static
++void gen_SIGBUS_if_not_XX_aligned ( IRTemp effective_addr, ULong align )
++{
++   if (align == 1) {
++      return;
++   }
++   vassert(align == 16 || align == 8 || align == 4 || align == 2);
++   stmt(
++      IRStmt_Exit(
++         binop(Iop_CmpNE64,
++               binop(Iop_And64,mkexpr(effective_addr),mkU64(align-1)),
++               mkU64(0)),
++         Ijk_SigBUS,
++         IRConst_U64(guest_PC_curr_instr),
++         OFFB_PC
++      )
++   );
++}
++
++
+ /* Generate a "standard 7" name, from bitQ and size.  But also
+    allow ".1d" since that's occasionally useful. */
+ static
+@@ -6670,7 +6698,7 @@ Bool dis_ARM64_load_store(/*MB_OUT*/DisResult* dres, UInt insn,
+ 
+       IRTemp ea = newTemp(Ity_I64);
+       assign(ea, getIReg64orSP(nn));
+-      /* FIXME generate check that ea is szB-aligned */
++      gen_SIGBUS_if_not_XX_aligned(ea, szB);
+ 
+       if (isLD && ss == BITS5(1,1,1,1,1)) {
+          IRTemp res = newTemp(ty);
+@@ -6803,7 +6831,7 @@ Bool dis_ARM64_load_store(/*MB_OUT*/DisResult* dres, UInt insn,
+ 
+       IRTemp ea = newTemp(Ity_I64);
+       assign(ea, getIReg64orSP(nn));
+-      /* FIXME generate check that ea is 2*elemSzB-aligned */
++      gen_SIGBUS_if_not_XX_aligned(ea, fullSzB);
+ 
+       if (isLD && ss == BITS5(1,1,1,1,1)) {
+          if (abiinfo->guest__use_fallback_LLSC) {
+@@ -7044,7 +7072,7 @@ Bool dis_ARM64_load_store(/*MB_OUT*/DisResult* dres, UInt insn,
+ 
+       IRTemp ea = newTemp(Ity_I64);
+       assign(ea, getIReg64orSP(nn));
+-      /* FIXME generate check that ea is szB-aligned */
++      gen_SIGBUS_if_not_XX_aligned(ea, szB);
+ 
+       if (isLD) {
+          IRTemp res = newTemp(ty);
+@@ -7159,6 +7187,7 @@ Bool dis_ARM64_load_store(/*MB_OUT*/DisResult* dres, UInt insn,
+ 
+       IRTemp ea = newTemp(Ity_I64);
+       assign(ea, getIReg64orSP(nn));
++      gen_SIGBUS_if_not_XX_aligned(ea, szB);
+ 
+       // Insert barrier before loading for acquire and acquire-release variants:
+       // A and AL.
+@@ -7266,6 +7295,10 @@ Bool dis_ARM64_load_store(/*MB_OUT*/DisResult* dres, UInt insn,
+       IRType ty = integerIRTypeOfSize(szB);
+       Bool is64 = szB == 8;
+ 
++      IRTemp ea = newTemp(Ity_I64);
++      assign(ea, getIReg64orSP(nn));
++      gen_SIGBUS_if_not_XX_aligned(ea, szB);
++
+       IRExpr *exp = narrowFrom64(ty, getIReg64orZR(ss));
+       IRExpr *new = narrowFrom64(ty, getIReg64orZR(tt));
+ 
+@@ -7275,7 +7308,7 @@ Bool dis_ARM64_load_store(/*MB_OUT*/DisResult* dres, UInt insn,
+       // Store the result back if LHS remains unchanged in memory.
+       IRTemp old = newTemp(ty);
+       stmt( IRStmt_CAS(mkIRCAS(/*oldHi*/IRTemp_INVALID, old,
+-                               Iend_LE, getIReg64orSP(nn),
++                               Iend_LE, mkexpr(ea),
+                                /*expdHi*/NULL, exp,
+                                /*dataHi*/NULL, new)) );
+ 
+@@ -7307,6 +7340,10 @@ Bool dis_ARM64_load_store(/*MB_OUT*/DisResult* dres, UInt insn,
+       if ((ss & 0x1) || (tt & 0x1)) {
+          /* undefined; fall through */
+       } else {
++         IRTemp ea = newTemp(Ity_I64);
++         assign(ea, getIReg64orSP(nn));
++         gen_SIGBUS_if_not_XX_aligned(ea, is64 ? 16 : 8);
++
+          IRExpr *expLo = getIRegOrZR(is64, ss);
+          IRExpr *expHi = getIRegOrZR(is64, ss + 1);
+          IRExpr *newLo = getIRegOrZR(is64, tt);
+@@ -7318,7 +7355,7 @@ Bool dis_ARM64_load_store(/*MB_OUT*/DisResult* dres, UInt insn,
+             stmt(IRStmt_MBE(Imbe_Fence));
+ 
+          stmt( IRStmt_CAS(mkIRCAS(oldHi, oldLo,
+-                                  Iend_LE, getIReg64orSP(nn),
++                                  Iend_LE, mkexpr(ea),
+                                   expHi, expLo,
+                                   newHi, newLo)) );
+ 
+diff --git a/VEX/priv/host_arm64_defs.c b/VEX/priv/host_arm64_defs.c
+index b65e27db4..39c6aaa46 100644
+--- a/VEX/priv/host_arm64_defs.c
++++ b/VEX/priv/host_arm64_defs.c
+@@ -4033,6 +4033,7 @@ Int emit_ARM64Instr ( /*MB_MOD*/Bool* is_profInc,
+             case Ijk_FlushDCache: trcval = VEX_TRC_JMP_FLUSHDCACHE; break;
+             case Ijk_NoRedir:     trcval = VEX_TRC_JMP_NOREDIR;     break;
+             case Ijk_SigTRAP:     trcval = VEX_TRC_JMP_SIGTRAP;     break;
++            case Ijk_SigBUS:      trcval = VEX_TRC_JMP_SIGBUS;      break;
+             //case Ijk_SigSEGV:     trcval = VEX_TRC_JMP_SIGSEGV;     break;
+             case Ijk_Boring:      trcval = VEX_TRC_JMP_BORING;      break;
+             /* We don't expect to see the following being assisted. */
+diff --git a/VEX/priv/host_arm64_isel.c b/VEX/priv/host_arm64_isel.c
+index 094e7e74b..82cb2d78c 100644
+--- a/VEX/priv/host_arm64_isel.c
++++ b/VEX/priv/host_arm64_isel.c
+@@ -4483,6 +4483,7 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt )
+          case Ijk_InvalICache:
+          case Ijk_FlushDCache:
+          case Ijk_SigTRAP:
++         case Ijk_SigBUS:
+          case Ijk_Yield: {
+             HReg r = iselIntExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst));
+             addInstr(env, ARM64Instr_XAssisted(r, amPC, cc,
+@@ -4576,8 +4577,8 @@ static void iselNext ( ISelEnv* env,
+       case Ijk_InvalICache:
+       case Ijk_FlushDCache:
+       case Ijk_SigTRAP:
+-      case Ijk_Yield:
+-      {
++      case Ijk_SigBUS:
++      case Ijk_Yield: {
+          HReg        r    = iselIntExpr_R(env, next);
+          ARM64AMode* amPC = mk_baseblock_64bit_access_amode(offsIP);
+          addInstr(env, ARM64Instr_XAssisted(r, amPC, ARM64cc_AL, jk));
diff --git a/valgrind.spec b/valgrind.spec
index 01ecfe8..e2a97c2 100644
--- a/valgrind.spec
+++ b/valgrind.spec
@@ -114,6 +114,9 @@ Patch13: valgrind-3.18.1-arm64-doubleword-cas.patch
 # KDE#444399 arm64: unhandled instruction LD{,A}XP and ST{,L}XP
 Patch14: valgrind-3.18.1-arm64-ldaxp-stlxp.patch
 
+# KDE#445415 arm64 front end: alignment checks missing for atomic instructions.
+Patch15: valgrind-3.18.1-arm64-atomic-align.patch
+
 BuildRequires: make
 BuildRequires: glibc-devel
 
@@ -260,6 +263,7 @@ Valgrind User Manual for details.
 %patch12 -p1
 %patch13 -p1
 %patch14 -p1
+%patch15 -p1
 
 %build
 # LTO triggers undefined symbols in valgrind.  Valgrind has a --enable-lto
@@ -496,6 +500,7 @@ fi
 - Add valgrind-3.18.1-rust-v0-demangle.patch
 - Add valgrind-3.18.1-arm64-doubleword-cas.patch
 - Add valgrind-3.18.1-arm64-ldaxp-stlxp.patch
+- Add valgrind-3.18.1-arm64-atomic-align.patch
 
 * Mon Nov  1 2021 Mark Wielaard <mjw@fedoraproject.org> - 3.18.1-2
 - Add valgrind-3.18.1-dhat-tests-copy.patch