Skip to content

Commit 3d5ce83

Browse files
committed
Merge remote-tracking branch 'origin/main' into lsda
2 parents ab6dc42 + f46d641 commit 3d5ce83

File tree

1,221 files changed

+250868
-53930
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,221 files changed

+250868
-53930
lines changed

.ci/metrics/metrics.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,13 @@ def github_get_metrics(
282282
queued_count = collections.Counter()
283283
running_count = collections.Counter()
284284

285+
# Initialize all the counters to 0 so we report 0 when no job is queued
286+
# or running.
287+
for wf_name, wf_metric_name in GITHUB_WORKFLOW_TO_TRACK.items():
288+
for job_name, job_metric_name in GITHUB_JOB_TO_TRACK[wf_metric_name].items():
289+
queued_count[wf_metric_name + "_" + job_metric_name] = 0
290+
running_count[wf_metric_name + "_" + job_metric_name] = 0
291+
285292
# The list of workflows this iteration will process.
286293
# MaxSize = GITHUB_WORKFLOWS_MAX_PROCESS_COUNT
287294
workflow_seen_as_completed = set()

.github/new-prs-labeler.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,12 @@ backend:DirectX:
660660
- '**/*dxil*/**'
661661
- '**/*DXContainer*'
662662
- '**/*DXContainer*/**'
663+
- clang/lib/Sema/SemaDirectX.cpp
664+
- clang/include/clang/Sema/SemaDirectX.h
665+
- clang/include/clang/Basic/BuiltinsDirectX.td
666+
- clang/lib/CodeGen/TargetBuiltins/DirectX.cpp
667+
- clang/test/CodeGenDirectX/**
668+
- clang/test/SemaDirectX/**
663669

664670
backend:SPIR-V:
665671
- clang/lib/Driver/ToolChains/SPIRV.*

bolt/include/bolt/Core/MCPlusBuilder.h

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -577,16 +577,51 @@ class MCPlusBuilder {
577577
return getNoRegister();
578578
}
579579

580-
/// Returns the register used as call destination, or no-register, if not
581-
/// an indirect call. Sets IsAuthenticatedInternally if the instruction
582-
/// accepts a signed pointer as its operand and authenticates it internally.
580+
/// Returns the register used as the destination of an indirect branch or call
581+
/// instruction. Sets IsAuthenticatedInternally if the instruction accepts
582+
/// a signed pointer as its operand and authenticates it internally.
583583
virtual MCPhysReg
584-
getRegUsedAsCallDest(const MCInst &Inst,
585-
bool &IsAuthenticatedInternally) const {
584+
getRegUsedAsIndirectBranchDest(const MCInst &Inst,
585+
bool &IsAuthenticatedInternally) const {
586586
llvm_unreachable("not implemented");
587587
return getNoRegister();
588588
}
589589

590+
/// Returns the register containing an address safely materialized by `Inst`
591+
/// under the Pointer Authentication threat model.
592+
///
593+
/// Returns the register `Inst` writes to if:
594+
/// 1. the register is a materialized address, and
595+
/// 2. the register has been materialized safely, i.e. cannot be attacker-
596+
/// controlled, under the Pointer Authentication threat model.
597+
///
598+
/// If the instruction does not write to any register satisfying the above
599+
/// two conditions, NoRegister is returned.
600+
///
601+
/// The Pointer Authentication threat model assumes an attacker is able to
602+
/// modify any writable memory, but not executable code (due to W^X).
603+
virtual MCPhysReg
604+
getMaterializedAddressRegForPtrAuth(const MCInst &Inst) const {
605+
llvm_unreachable("not implemented");
606+
return getNoRegister();
607+
}
608+
609+
/// Analyzes if this instruction can safely perform address arithmetics
610+
/// under Pointer Authentication threat model.
611+
///
612+
/// If an (OutReg, InReg) pair is returned, then after Inst is executed,
613+
/// OutReg is as trusted as InReg is.
614+
///
615+
/// The arithmetic instruction is considered safe if OutReg is not attacker-
616+
/// controlled, provided InReg and executable code are not. Please note that
617+
/// registers other than InReg as well as the contents of memory which is
618+
/// writable by the process should be considered attacker-controlled.
619+
virtual std::optional<std::pair<MCPhysReg, MCPhysReg>>
620+
analyzeAddressArithmeticsForPtrAuth(const MCInst &Inst) const {
621+
llvm_unreachable("not implemented");
622+
return std::make_pair(getNoRegister(), getNoRegister());
623+
}
624+
590625
virtual bool isTerminator(const MCInst &Inst) const;
591626

592627
virtual bool isNoop(const MCInst &Inst) const {

bolt/include/bolt/Passes/DataflowAnalysis.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -292,14 +292,17 @@ class DataflowAnalysis {
292292
/// Relies on a ptr map to fetch the previous instruction and then retrieve
293293
/// state. WARNING: Watch out for invalidated pointers. Do not use this
294294
/// function if you invalidated pointers after the analysis has been completed
295-
ErrorOr<const StateTy &> getStateBefore(const MCInst &Point) {
296-
return getStateAt(PrevPoint[&Point]);
295+
ErrorOr<const StateTy &> getStateBefore(const MCInst &Point) const {
296+
auto It = PrevPoint.find(&Point);
297+
if (It == PrevPoint.end())
298+
return make_error_code(std::errc::result_out_of_range);
299+
return getStateAt(It->getSecond());
297300
}
298301

299-
ErrorOr<const StateTy &> getStateBefore(ProgramPoint Point) {
302+
ErrorOr<const StateTy &> getStateBefore(ProgramPoint Point) const {
300303
if (Point.isBB())
301304
return getStateAt(*Point.getBB());
302-
return getStateAt(PrevPoint[Point.getInst()]);
305+
return getStateBefore(*Point.getInst());
303306
}
304307

305308
/// Remove any state annotations left by this analysis

bolt/lib/Passes/PAuthGadgetScanner.cpp

Lines changed: 70 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,49 @@ class PacRetAnalysis
335335
});
336336
}
337337

338+
BitVector getClobberedRegs(const MCInst &Point) const {
339+
BitVector Clobbered(NumRegs, false);
340+
// Assume a call can clobber all registers, including callee-saved
341+
// registers. There's a good chance that callee-saved registers will be
342+
// saved on the stack at some point during execution of the callee.
343+
// Therefore they should also be considered as potentially modified by an
344+
// attacker/written to.
345+
// Also, not all functions may respect the AAPCS ABI rules about
346+
// caller/callee-saved registers.
347+
if (BC.MIB->isCall(Point))
348+
Clobbered.set();
349+
else
350+
BC.MIB->getClobberedRegs(Point, Clobbered);
351+
return Clobbered;
352+
}
353+
354+
// Returns all registers that can be treated as if they are written by an
355+
// authentication instruction.
356+
SmallVector<MCPhysReg> getRegsMadeSafeToDeref(const MCInst &Point,
357+
const State &Cur) const {
358+
SmallVector<MCPhysReg> Regs;
359+
const MCPhysReg NoReg = BC.MIB->getNoRegister();
360+
361+
// A signed pointer can be authenticated, or
362+
ErrorOr<MCPhysReg> AutReg = BC.MIB->getAuthenticatedReg(Point);
363+
if (AutReg && *AutReg != NoReg)
364+
Regs.push_back(*AutReg);
365+
366+
// ... a safe address can be materialized, or
367+
MCPhysReg NewAddrReg = BC.MIB->getMaterializedAddressRegForPtrAuth(Point);
368+
if (NewAddrReg != NoReg)
369+
Regs.push_back(NewAddrReg);
370+
371+
// ... an address can be updated in a safe manner, producing the result
372+
// which is as trusted as the input address.
373+
if (auto DstAndSrc = BC.MIB->analyzeAddressArithmeticsForPtrAuth(Point)) {
374+
if (Cur.SafeToDerefRegs[DstAndSrc->second])
375+
Regs.push_back(DstAndSrc->first);
376+
}
377+
378+
return Regs;
379+
}
380+
338381
State computeNext(const MCInst &Point, const State &Cur) {
339382
PacStatePrinter P(BC);
340383
LLVM_DEBUG({
@@ -355,37 +398,35 @@ class PacRetAnalysis
355398
return State();
356399
}
357400

401+
// First, compute various properties of the instruction, taking the state
402+
// before its execution into account, if necessary.
403+
404+
BitVector Clobbered = getClobberedRegs(Point);
405+
SmallVector<MCPhysReg> NewSafeToDerefRegs =
406+
getRegsMadeSafeToDeref(Point, Cur);
407+
408+
// Then, compute the state after this instruction is executed.
358409
State Next = Cur;
359-
BitVector Clobbered(NumRegs, false);
360-
// Assume a call can clobber all registers, including callee-saved
361-
// registers. There's a good chance that callee-saved registers will be
362-
// saved on the stack at some point during execution of the callee.
363-
// Therefore they should also be considered as potentially modified by an
364-
// attacker/written to.
365-
// Also, not all functions may respect the AAPCS ABI rules about
366-
// caller/callee-saved registers.
367-
if (BC.MIB->isCall(Point))
368-
Clobbered.set();
369-
else
370-
BC.MIB->getClobberedRegs(Point, Clobbered);
410+
371411
Next.SafeToDerefRegs.reset(Clobbered);
372412
// Keep track of this instruction if it writes to any of the registers we
373413
// need to track that for:
374414
for (MCPhysReg Reg : RegsToTrackInstsFor.getRegisters())
375415
if (Clobbered[Reg])
376416
lastWritingInsts(Next, Reg) = {&Point};
377417

378-
ErrorOr<MCPhysReg> AutReg = BC.MIB->getAuthenticatedReg(Point);
379-
if (AutReg && *AutReg != BC.MIB->getNoRegister()) {
380-
// The sub-registers of *AutReg are also trusted now, but not its
381-
// super-registers (as they retain untrusted register units).
382-
BitVector AuthenticatedSubregs =
383-
BC.MIB->getAliases(*AutReg, /*OnlySmaller=*/true);
384-
for (MCPhysReg Reg : AuthenticatedSubregs.set_bits()) {
385-
Next.SafeToDerefRegs.set(Reg);
386-
if (RegsToTrackInstsFor.isTracked(Reg))
387-
lastWritingInsts(Next, Reg).clear();
388-
}
418+
// After accounting for clobbered registers in general, override the state
419+
// according to authentication and other *special cases* of clobbering.
420+
421+
// The sub-registers are also safe-to-dereference now, but not their
422+
// super-registers (as they retain untrusted register units).
423+
BitVector NewSafeSubregs(NumRegs);
424+
for (MCPhysReg SafeReg : NewSafeToDerefRegs)
425+
NewSafeSubregs |= BC.MIB->getAliases(SafeReg, /*OnlySmaller=*/true);
426+
for (MCPhysReg Reg : NewSafeSubregs.set_bits()) {
427+
Next.SafeToDerefRegs.set(Reg);
428+
if (RegsToTrackInstsFor.isTracked(Reg))
429+
lastWritingInsts(Next, Reg).clear();
389430
}
390431

391432
LLVM_DEBUG({
@@ -402,7 +443,7 @@ class PacRetAnalysis
402443
public:
403444
std::vector<MCInstReference>
404445
getLastClobberingInsts(const MCInst &Inst, BinaryFunction &BF,
405-
const ArrayRef<MCPhysReg> UsedDirtyRegs) {
446+
const ArrayRef<MCPhysReg> UsedDirtyRegs) const {
406447
if (RegsToTrackInstsFor.empty())
407448
return {};
408449
auto MaybeState = getStateBefore(Inst);
@@ -457,14 +498,16 @@ static std::shared_ptr<Report>
457498
shouldReportCallGadget(const BinaryContext &BC, const MCInstReference &Inst,
458499
const State &S) {
459500
static const GadgetKind CallKind("non-protected call found");
460-
if (!BC.MIB->isCall(Inst) && !BC.MIB->isBranch(Inst))
501+
if (!BC.MIB->isIndirectCall(Inst) && !BC.MIB->isIndirectBranch(Inst))
461502
return nullptr;
462503

463504
bool IsAuthenticated = false;
464-
MCPhysReg DestReg = BC.MIB->getRegUsedAsCallDest(Inst, IsAuthenticated);
465-
if (IsAuthenticated || DestReg == BC.MIB->getNoRegister())
505+
MCPhysReg DestReg =
506+
BC.MIB->getRegUsedAsIndirectBranchDest(Inst, IsAuthenticated);
507+
if (IsAuthenticated)
466508
return nullptr;
467509

510+
assert(DestReg != BC.MIB->getNoRegister());
468511
LLVM_DEBUG({
469512
traceInst(BC, "Found call inst", Inst);
470513
traceReg(BC, "Call destination reg", DestReg);

bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
#include "AArch64InstrInfo.h"
1314
#include "AArch64MCSymbolizer.h"
1415
#include "MCTargetDesc/AArch64AddressingModes.h"
1516
#include "MCTargetDesc/AArch64FixupKinds.h"
@@ -277,15 +278,14 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
277278
}
278279
}
279280

280-
MCPhysReg
281-
getRegUsedAsCallDest(const MCInst &Inst,
282-
bool &IsAuthenticatedInternally) const override {
283-
assert(isCall(Inst) || isBranch(Inst));
284-
IsAuthenticatedInternally = false;
281+
MCPhysReg getRegUsedAsIndirectBranchDest(
282+
const MCInst &Inst, bool &IsAuthenticatedInternally) const override {
283+
assert(isIndirectCall(Inst) || isIndirectBranch(Inst));
285284

286285
switch (Inst.getOpcode()) {
287286
case AArch64::BR:
288287
case AArch64::BLR:
288+
IsAuthenticatedInternally = false;
289289
return Inst.getOperand(0).getReg();
290290
case AArch64::BRAA:
291291
case AArch64::BRAB:
@@ -298,12 +298,47 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
298298
IsAuthenticatedInternally = true;
299299
return Inst.getOperand(0).getReg();
300300
default:
301-
if (isIndirectCall(Inst) || isIndirectBranch(Inst))
302-
llvm_unreachable("Unhandled indirect branch");
301+
llvm_unreachable("Unhandled indirect branch or call");
302+
}
303+
}
304+
305+
MCPhysReg
306+
getMaterializedAddressRegForPtrAuth(const MCInst &Inst) const override {
307+
switch (Inst.getOpcode()) {
308+
case AArch64::ADR:
309+
case AArch64::ADRP:
310+
// These instructions produce an address value based on the information
311+
// encoded into the instruction itself (which should reside in a read-only
312+
// code memory) and the value of PC register (that is, the location of
313+
// this instruction), so the produced value is not attacker-controlled.
314+
return Inst.getOperand(0).getReg();
315+
default:
303316
return getNoRegister();
304317
}
305318
}
306319

320+
std::optional<std::pair<MCPhysReg, MCPhysReg>>
321+
analyzeAddressArithmeticsForPtrAuth(const MCInst &Inst) const override {
322+
switch (Inst.getOpcode()) {
323+
default:
324+
return std::nullopt;
325+
case AArch64::ADDXri:
326+
case AArch64::SUBXri:
327+
// The immediate addend is encoded into the instruction itself, so it is
328+
// not attacker-controlled under Pointer Authentication threat model.
329+
return std::make_pair(Inst.getOperand(0).getReg(),
330+
Inst.getOperand(1).getReg());
331+
case AArch64::ORRXrs:
332+
// "mov Xd, Xm" is equivalent to "orr Xd, XZR, Xm, lsl #0"
333+
if (Inst.getOperand(1).getReg() != AArch64::XZR ||
334+
Inst.getOperand(3).getImm() != 0)
335+
return std::nullopt;
336+
337+
return std::make_pair(Inst.getOperand(0).getReg(),
338+
Inst.getOperand(2).getReg());
339+
}
340+
}
341+
307342
bool isADRP(const MCInst &Inst) const override {
308343
return Inst.getOpcode() == AArch64::ADRP;
309344
}
@@ -662,7 +697,7 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
662697
}
663698

664699
bool isIndirectCall(const MCInst &Inst) const override {
665-
return Inst.getOpcode() == AArch64::BLR;
700+
return isIndirectCallOpcode(Inst.getOpcode());
666701
}
667702

668703
MCPhysReg getSpRegister(int Size) const {

bolt/test/binary-analysis/AArch64/gs-pacret-autiasp.s

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -141,24 +141,9 @@ f_nonx30_ret_ok:
141141
stp x29, x30, [sp, #-16]!
142142
mov x29, sp
143143
bl g
144-
add x0, x0, #3
145144
ldp x29, x30, [sp], #16
146-
// FIXME: Should the scanner understand that an authenticated register (below x30,
147-
// after the autiasp instruction), is OK to be moved to another register
148-
// and then that register being used to return?
149-
// This respects that pac-ret hardening intent, but the scanner currently
150-
// will produce a false positive for this.
151-
// Is it worthwhile to make the scanner more complex for this case?
152-
// So far, scanning many millions of instructions across a linux distro,
153-
// I haven't encountered such an example.
154-
// The ".if 0" block below tests this case and currently fails.
155-
.if 0
156145
autiasp
157146
mov x16, x30
158-
.else
159-
mov x16, x30
160-
autia x16, sp
161-
.endif
162147
// CHECK-NOT: function f_nonx30_ret_ok
163148
ret x16
164149
.size f_nonx30_ret_ok, .-f_nonx30_ret_ok

0 commit comments

Comments
 (0)