Fix crash on API queries with Fedora 28 hardening and GCC 8

The actual fix is to handle nullptr references differently
for an empty filter expression. The other changes include
oob checks not necesarily involved.

fixes #6533
This commit is contained in:
Michael Friedrich 2018-09-05 20:42:55 +02:00
parent 1c2a59bf63
commit 1f4f6282c7
1 changed files with 24 additions and 19 deletions

View File

@ -127,7 +127,7 @@ static void FilteredAddTarget(ScriptFrame& permissionFrame, Expression *permissi
ScriptFrame& frame, Expression *ufilter, std::vector<Value>& result, const String& variableName, const Object::Ptr& target) ScriptFrame& frame, Expression *ufilter, std::vector<Value>& result, const String& variableName, const Object::Ptr& target)
{ {
if (FilterUtility::EvaluateFilter(permissionFrame, permissionFilter, target, variableName) && FilterUtility::EvaluateFilter(frame, ufilter, target, variableName)) if (FilterUtility::EvaluateFilter(permissionFrame, permissionFilter, target, variableName) && FilterUtility::EvaluateFilter(frame, ufilter, target, variableName))
result.emplace_back(target); result.emplace_back(std::move(target));
} }
void FilterUtility::CheckPermission(const ApiUser::Ptr& user, const String& permission, Expression **permissionFilter) void FilterUtility::CheckPermission(const ApiUser::Ptr& user, const String& permission, Expression **permissionFilter)
@ -206,7 +206,7 @@ std::vector<Value> FilterUtility::GetFilterTargets(const QueryDescription& qd, c
if (attr == "type") if (attr == "type")
attr = "name"; attr = "name";
if (query->Contains(attr)) { if (query && query->Contains(attr)) {
String name = HttpUtility::GetLastParameter(query, attr); String name = HttpUtility::GetLastParameter(query, attr);
Object::Ptr target = provider->GetTargetByName(type, name); Object::Ptr target = provider->GetTargetByName(type, name);
@ -219,7 +219,7 @@ std::vector<Value> FilterUtility::GetFilterTargets(const QueryDescription& qd, c
attr = provider->GetPluralName(type); attr = provider->GetPluralName(type);
boost::algorithm::to_lower(attr); boost::algorithm::to_lower(attr);
if (query->Contains(attr)) { if (query && query->Contains(attr)) {
Array::Ptr names = query->Get(attr); Array::Ptr names = query->Get(attr);
if (names) { if (names) {
ObjectLock olock(names); ObjectLock olock(names);
@ -235,7 +235,7 @@ std::vector<Value> FilterUtility::GetFilterTargets(const QueryDescription& qd, c
} }
} }
if (query->Contains("filter") || result.empty()) { if ((query && query->Contains("filter")) || result.empty()) {
if (!query->Contains("type")) if (!query->Contains("type"))
BOOST_THROW_EXCEPTION(std::invalid_argument("Type must be specified when using a filter.")); BOOST_THROW_EXCEPTION(std::invalid_argument("Type must be specified when using a filter."));
@ -251,26 +251,31 @@ std::vector<Value> FilterUtility::GetFilterTargets(const QueryDescription& qd, c
frame.Sandboxed = true; frame.Sandboxed = true;
Dictionary::Ptr uvars = new Dictionary(); Dictionary::Ptr uvars = new Dictionary();
std::unique_ptr<Expression> ufilter;
if (query->Contains("filter")) { if (query->Contains("filter")) {
String filter = HttpUtility::GetLastParameter(query, "filter"); String filter = HttpUtility::GetLastParameter(query, "filter");
ufilter = ConfigCompiler::CompileText("<API query>", filter); std::unique_ptr<Expression> ufilter = ConfigCompiler::CompileText("<API query>", filter);
}
Dictionary::Ptr filter_vars = query->Get("filter_vars"); Dictionary::Ptr filter_vars = query->Get("filter_vars");
if (filter_vars) { if (filter_vars) {
ObjectLock olock(filter_vars); ObjectLock olock(filter_vars);
for (const Dictionary::Pair& kv : filter_vars) { for (const Dictionary::Pair& kv : filter_vars) {
uvars->Set(kv.first, kv.second); uvars->Set(kv.first, kv.second);
}
} }
frame.Self = uvars;
provider->FindTargets(type, std::bind(&FilteredAddTarget,
std::ref(permissionFrame), permissionFilter,
std::ref(frame), &*ufilter, std::ref(result), variableName, _1));
} else {
/* Ensure to pass a nullptr as filter expression.
* GCC 8.1.1 on F28 causes problems, see GH #6533.
*/
provider->FindTargets(type, std::bind(&FilteredAddTarget,
std::ref(permissionFrame), permissionFilter,
std::ref(frame), nullptr, std::ref(result), variableName, _1));
} }
frame.Self = uvars;
provider->FindTargets(type, std::bind(&FilteredAddTarget,
std::ref(permissionFrame), permissionFilter,
std::ref(frame), &*ufilter, std::ref(result), variableName, _1));
} }
return result; return result;