From c8421200e9accf5a10a52768bb3dca2f555bd092 Mon Sep 17 00:00:00 2001
From: Changqing Li <changqing.li@windriver.com>
Date: Tue, 5 Aug 2025 15:05:07 +0800
Subject: [PATCH] Fix unsinking of IR_FSTORE for NULL metatable.

Reported by pwnhacker0x18. #1147

CVE: CVE-2024-25177
Upstream-Status: Backport [https://github.com/openresty/luajit2/commit/85b4fed0b0353dd78c8c875c2f562d522a2b310f]

Signed-off-by: Changqing Li <changqing.li@windriver.com>
---
 src/lj_snap.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/lj_snap.c b/src/lj_snap.c
index 4140fdb7..d7027875 100644
--- a/src/lj_snap.c
+++ b/src/lj_snap.c
@@ -453,6 +453,7 @@ static TRef snap_replay_const(jit_State *J, IRIns *ir)
   case IR_KNUM: case IR_KINT64:
     return lj_ir_k64(J, (IROp)ir->o, ir_k64(ir)->u64);
   case IR_KPTR: return lj_ir_kptr(J, ir_kptr(ir));  /* Continuation. */
+  case IR_KNULL: return lj_ir_knull(J, irt_type(ir->t));
   default: lj_assertJ(0, "bad IR constant op %d", ir->o); return TREF_NIL;
   }
 }
@@ -882,9 +883,13 @@ static void snap_unsink(jit_State *J, GCtrace *T, ExitState *ex,
 	if (irk->o == IR_FREF) {
 	  lj_assertJ(irk->op2 == IRFL_TAB_META,
 		     "sunk store with bad field %d", irk->op2);
+	if (T->ir[irs->op2].o == IR_KNULL) {
+	  setgcrefnull(t->metatable);
+	} else {
 	  snap_restoreval(J, T, ex, snapno, rfilt, irs->op2, &tmp);
 	  /* NOBARRIER: The table is new (marked white). */
 	  setgcref(t->metatable, obj2gco(tabV(&tmp)));
+	}
 	} else {
 	  irk = &T->ir[irk->op2];
 	  if (irk->o == IR_KSLOT) irk = &T->ir[irk->op1];
-- 
2.34.1

