aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Target
diff options
context:
space:
mode:
authorLucas Duarte Prates <lucas.prates@arm.com>2024-06-20 10:22:01 +0100
committerGitHub <noreply@github.com>2024-06-20 10:22:01 +0100
commit78ff617d3f573fb3a9b2fef180fa0fd43d5584ea (patch)
treebf866de2bf99817d9b7441dd90cb439c9f044c5b /llvm/lib/Target
parentd594d9f7f4dc6eb748b3261917db689fdc348b96 (diff)
downloadllvm-78ff617d3f573fb3a9b2fef180fa0fd43d5584ea.zip
llvm-78ff617d3f573fb3a9b2fef180fa0fd43d5584ea.tar.gz
llvm-78ff617d3f573fb3a9b2fef180fa0fd43d5584ea.tar.bz2
[ARM] CMSE security mitigation on function arguments and returned values (#89944)
The ABI mandates two things related to function calls: - Function arguments must be sign- or zero-extended to the register size by the caller. - Return values must be sign- or zero-extended to the register size by the callee. As consequence, callees can assume that function arguments have been extended and so can callers with regards to return values. Here lies the problem: Nonsecure code might deliberately ignore this mandate with the intent of attempting an exploit. It might try to pass values that lie outside the expected type's value range in order to trigger undefined behaviour, e.g. out of bounds access. With the mitigation implemented, Secure code always performs extension of values passed by Nonsecure code. This addresses the vulnerability described in CVE-2024-0151. Patches by Victor Campos. --------- Co-authored-by: Victor Campos <victor.campos@arm.com>
Diffstat (limited to 'llvm/lib/Target')
-rw-r--r--llvm/lib/Target/ARM/ARMISelLowering.cpp46
-rw-r--r--llvm/lib/Target/ARM/ARMISelLowering.h2
2 files changed, 33 insertions, 15 deletions
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index bfe137b..5490c3c 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -156,6 +156,17 @@ static const MCPhysReg GPRArgRegs[] = {
ARM::R0, ARM::R1, ARM::R2, ARM::R3
};
+static SDValue handleCMSEValue(const SDValue &Value, const ISD::InputArg &Arg,
+ SelectionDAG &DAG, const SDLoc &DL) {
+ assert(Arg.ArgVT.isScalarInteger());
+ assert(Arg.ArgVT.bitsLT(MVT::i32));
+ SDValue Trunc = DAG.getNode(ISD::TRUNCATE, DL, Arg.ArgVT, Value);
+ SDValue Ext =
+ DAG.getNode(Arg.Flags.isSExt() ? ISD::SIGN_EXTEND : ISD::ZERO_EXTEND, DL,
+ MVT::i32, Trunc);
+ return Ext;
+}
+
void ARMTargetLowering::addTypeForNEON(MVT VT, MVT PromotedLdStVT) {
if (VT != PromotedLdStVT) {
setOperationAction(ISD::LOAD, VT, Promote);
@@ -2193,7 +2204,7 @@ SDValue ARMTargetLowering::LowerCallResult(
SDValue Chain, SDValue InGlue, CallingConv::ID CallConv, bool isVarArg,
const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl,
SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals, bool isThisReturn,
- SDValue ThisVal) const {
+ SDValue ThisVal, bool isCmseNSCall) const {
// Assign locations to each value returned by this call.
SmallVector<CCValAssign, 16> RVLocs;
CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), RVLocs,
@@ -2271,6 +2282,15 @@ SDValue ARMTargetLowering::LowerCallResult(
(VA.getValVT() == MVT::f16 || VA.getValVT() == MVT::bf16))
Val = MoveToHPR(dl, DAG, VA.getLocVT(), VA.getValVT(), Val);
+ // On CMSE Non-secure Calls, call results (returned values) whose bitwidth
+ // is less than 32 bits must be sign- or zero-extended after the call for
+ // security reasons. Although the ABI mandates an extension done by the
+ // callee, the latter cannot be trusted to follow the rules of the ABI.
+ const ISD::InputArg &Arg = Ins[VA.getValNo()];
+ if (isCmseNSCall && Arg.ArgVT.isScalarInteger() &&
+ VA.getLocVT().isScalarInteger() && Arg.ArgVT.bitsLT(MVT::i32))
+ Val = handleCMSEValue(Val, Arg, DAG, dl);
+
InVals.push_back(Val);
}
@@ -2882,7 +2902,7 @@ ARMTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
// return.
return LowerCallResult(Chain, InGlue, CallConv, isVarArg, Ins, dl, DAG,
InVals, isThisReturn,
- isThisReturn ? OutVals[0] : SDValue());
+ isThisReturn ? OutVals[0] : SDValue(), isCmseNSCall);
}
/// HandleByVal - Every parameter *after* a byval parameter is passed
@@ -4485,8 +4505,6 @@ SDValue ARMTargetLowering::LowerFormalArguments(
*DAG.getContext());
CCInfo.AnalyzeFormalArguments(Ins, CCAssignFnForCall(CallConv, isVarArg));
- SmallVector<SDValue, 16> ArgValues;
- SDValue ArgValue;
Function::const_arg_iterator CurOrigArg = MF.getFunction().arg_begin();
unsigned CurArgIdx = 0;
@@ -4541,6 +4559,7 @@ SDValue ARMTargetLowering::LowerFormalArguments(
// Arguments stored in registers.
if (VA.isRegLoc()) {
EVT RegVT = VA.getLocVT();
+ SDValue ArgValue;
if (VA.needsCustom() && VA.getLocVT() == MVT::v2f64) {
// f64 and vector types are split up into multiple registers or
@@ -4604,16 +4623,6 @@ SDValue ARMTargetLowering::LowerFormalArguments(
case CCValAssign::BCvt:
ArgValue = DAG.getNode(ISD::BITCAST, dl, VA.getValVT(), ArgValue);
break;
- case CCValAssign::SExt:
- ArgValue = DAG.getNode(ISD::AssertSext, dl, RegVT, ArgValue,
- DAG.getValueType(VA.getValVT()));
- ArgValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), ArgValue);
- break;
- case CCValAssign::ZExt:
- ArgValue = DAG.getNode(ISD::AssertZext, dl, RegVT, ArgValue,
- DAG.getValueType(VA.getValVT()));
- ArgValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), ArgValue);
- break;
}
// f16 arguments have their size extended to 4 bytes and passed as if they
@@ -4623,6 +4632,15 @@ SDValue ARMTargetLowering::LowerFormalArguments(
(VA.getValVT() == MVT::f16 || VA.getValVT() == MVT::bf16))
ArgValue = MoveToHPR(dl, DAG, VA.getLocVT(), VA.getValVT(), ArgValue);
+ // On CMSE Entry Functions, formal integer arguments whose bitwidth is
+ // less than 32 bits must be sign- or zero-extended in the callee for
+ // security reasons. Although the ABI mandates an extension done by the
+ // caller, the latter cannot be trusted to follow the rules of the ABI.
+ const ISD::InputArg &Arg = Ins[VA.getValNo()];
+ if (AFI->isCmseNSEntryFunction() && Arg.ArgVT.isScalarInteger() &&
+ RegVT.isScalarInteger() && Arg.ArgVT.bitsLT(MVT::i32))
+ ArgValue = handleCMSEValue(ArgValue, Arg, DAG, dl);
+
InVals.push_back(ArgValue);
} else { // VA.isRegLoc()
// Only arguments passed on the stack should make it here.
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.h b/llvm/lib/Target/ARM/ARMISelLowering.h
index 62a52bd..a255e9b 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.h
+++ b/llvm/lib/Target/ARM/ARMISelLowering.h
@@ -894,7 +894,7 @@ class VectorType;
const SmallVectorImpl<ISD::InputArg> &Ins,
const SDLoc &dl, SelectionDAG &DAG,
SmallVectorImpl<SDValue> &InVals, bool isThisReturn,
- SDValue ThisVal) const;
+ SDValue ThisVal, bool isCmseNSCall) const;
bool supportSplitCSR(MachineFunction *MF) const override {
return MF->getFunction().getCallingConv() == CallingConv::CXX_FAST_TLS &&