29enum SetPrivilegeFunctionKind {
Irrelevant, Setuid, Setgid };
31class SetgidSetuidOrderChecker :
public Checker<check::PostCall, eval::Assume> {
32 const BugType BT{
this,
"Possible wrong order of privilege revocation"};
41 {CDM::CLibrary, {
"seteuid"}, 1}, {CDM::CLibrary, {
"setegid"}, 1},
42 {CDM::CLibrary, {
"setreuid"}, 2}, {CDM::CLibrary, {
"setregid"}, 2},
43 {CDM::CLibrary, {
"setresuid"}, 3}, {CDM::CLibrary, {
"setresgid"}, 3}};
48 bool Assumption)
const;
78void SetgidSetuidOrderChecker::checkPostCall(
const CallEvent &
Call,
81 if (SetuidDesc.matches(
Call)) {
82 processSetuid(State,
Call,
C);
83 }
else if (SetgidDesc.matches(
Call)) {
84 processSetgid(State,
Call,
C);
85 }
else if (OtherSetPrivilegeDesc.contains(
Call)) {
86 processOther(State,
Call,
C);
92 bool Assumption)
const {
93 SValBuilder &SVB = State->getStateManager().getSValBuilder();
94 SymbolRef LastSetuidSym = State->get<LastSetuidCallSVal>();
103 auto FailComparison =
107 .getAs<DefinedOrUnknownSVal>();
110 if (
auto IsFailBranch = State->assume(*FailComparison);
111 IsFailBranch.first && !IsFailBranch.second) {
114 State = State->set<LastSetPrivilegeCall>(
Irrelevant);
115 State = State->set<LastSetuidCallSVal>(
SymbolRef{});
123 bool IsSetuidWithGetuid = isFunctionCalledInArg(GetuidDesc,
Call);
124 if (State->get<LastSetPrivilegeCall>() != Setgid && IsSetuidWithGetuid) {
126 State = State->set<LastSetPrivilegeCall>(Setuid);
127 State = State->set<LastSetuidCallSVal>(RetSym);
132 return "Call to 'setuid' found here that removes superuser privileges";
134 C.addTransition(State,
Note);
137 State = State->set<LastSetPrivilegeCall>(
Irrelevant);
138 State = State->set<LastSetuidCallSVal>(
SymbolRef{});
139 C.addTransition(State);
145 bool IsSetgidWithGetgid = isFunctionCalledInArg(GetgidDesc,
Call);
146 if (State->get<LastSetPrivilegeCall>() == Setuid) {
147 if (IsSetgidWithGetgid) {
148 State = State->set<LastSetPrivilegeCall>(
Irrelevant);
149 emitReport(State,
C);
152 State = State->set<LastSetPrivilegeCall>(
Irrelevant);
154 State = State->set<LastSetPrivilegeCall>(IsSetgidWithGetgid ? Setgid
157 State = State->set<LastSetuidCallSVal>(
SymbolRef{});
158 C.addTransition(State);
164 State = State->set<LastSetuidCallSVal>(
SymbolRef{});
165 State = State->set<LastSetPrivilegeCall>(
Irrelevant);
166 C.addTransition(State);
169bool SetgidSetuidOrderChecker::isFunctionCalledInArg(
171 if (
const auto *CallInArg0 =
172 dyn_cast<CallExpr>(
Call.getArgExpr(0)->IgnoreParenImpCasts()))
180 llvm::StringLiteral Msg =
181 "A 'setgid(getgid())' call following a 'setuid(getuid())' "
182 "call is likely to fail; probably the order of these "
183 "statements is wrong";
184 auto Report = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
185 Report->markInteresting(State->get<LastSetuidCallSVal>());
186 C.emitReport(std::move(Report));
194bool ento::shouldRegisterSetgidSetuidOrderChecker(
const CheckerManager &mgr) {
#define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type)
Declares a program state trait for type Type called Name, and introduce a type named NameTy.
const BugType & getBugType() const
An immutable set of CallDescriptions.
A CallDescription is a pattern that can be used to match calls based on the qualified name and the ar...
bool matchesAsWritten(const CallExpr &CE) const
Returns true if the CallExpr is a call to a function that matches the CallDescription.
Represents an abstract call to a function or method along a particular path.
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
The tag upon which the TagVisitor reacts.
bool isInteresting(SymbolRef sym) const
nonloc::ConcreteInt makeIntVal(const IntegerLiteral *integer)
virtual SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs, QualType resultTy)=0
Create a new value which represents a binary expression with two non- location operands.
QualType getConditionType() const
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
Represents symbolic expression that isn't a location.
@ Irrelevant
We do not know anything about 'errno'.
The JSON file list parser is used to communicate input to InstallAPI.