mgr: validate that profile caps are actually valid

Signed-off-by: Jason Dillaman <dillaman@redhat.com>
This commit is contained in:
Jason Dillaman 2019-10-17 09:37:13 -04:00
parent b0d73aed19
commit 9193d87623
3 changed files with 39 additions and 14 deletions

View File

@ -131,7 +131,7 @@ void MgrCapGrant::parse_network() {
&network_prefix);
}
void MgrCapGrant::expand_profile() const {
void MgrCapGrant::expand_profile(std::ostream *err) const {
// only generate this list once
if (!profile_grants.empty()) {
return;
@ -160,6 +160,12 @@ void MgrCapGrant::expand_profile() const {
for (auto& [key, constraint] : arguments) {
if (key == "pool" || key == "namespace") {
filtered_arguments[key] = std::move(constraint);
} else {
if (err != nullptr) {
*err << "profile '" << profile << "' does not recognize key '" << key
<< "'";
}
return;
}
}
@ -174,6 +180,10 @@ void MgrCapGrant::expand_profile() const {
std::move(filtered_arguments), perms});
return;
}
if (err != nullptr) {
*err << "unrecognized profile '" << profile << "'";
}
}
bool MgrCapGrant::validate_arguments(
@ -218,7 +228,7 @@ mgr_rwxa_t MgrCapGrant::get_allowed(
const std::string& m, const std::string& c,
const std::map<std::string, std::string>& args) const {
if (!profile.empty()) {
expand_profile();
expand_profile(nullptr);
mgr_rwxa_t a;
for (auto& grant : profile_grants) {
a = a | grant.get_allowed(cct, name, s, m, c, args);
@ -523,8 +533,22 @@ bool MgrCap::parse(const std::string& str, ostream *err) {
bool r = qi::parse(iter, end, exp, *this);
if (r && iter == end) {
text = str;
std::stringstream profile_err;
for (auto& g : grants) {
g.parse_network();
if (!g.profile.empty()) {
g.expand_profile(&profile_err);
}
}
if (!profile_err.str().empty()) {
if (err != nullptr) {
*err << "mgr capability parse failed during profile evaluation: "
<< profile_err.str();
}
return false;
}
return true;
}

View File

@ -104,7 +104,7 @@ struct MgrCapGrant {
// needed by expand_profile() (via is_match()) and cached here.
mutable std::list<MgrCapGrant> profile_grants;
void expand_profile() const;
void expand_profile(std::ostream *err=nullptr) const;
MgrCapGrant() : allow(0) {}
MgrCapGrant(std::string&& service,

View File

@ -33,9 +33,9 @@ const char *parse_good[] = {
"\tallow\nrwx\t",
"allow service=foo x",
"allow service=\"froo\" x",
"allow profile osd",
"allow profile osd-bootstrap",
"allow profile \"mds-bootstrap\", allow *",
"allow profile read-only",
"allow profile read-write",
"allow profile \"rbd-read-only\", allow *",
"allow command \"a b c\"",
"allow command abc",
"allow command abc with arg=foo",
@ -63,16 +63,16 @@ const char *parse_good[] = {
"allow command \"foo bar\" with arg=\"baz\"",
"allow command \"foo bar\" with arg=\"baz.xx\"",
"allow command \"foo bar\" with arg = \"baz.xx\"",
"profile osd",
"profile crash",
"profile rbd pool=ABC namespace=NS",
"profile \"mds-bootstrap\", profile foo",
"profile \"rbd-read-only\", profile crash",
"allow * network 1.2.3.4/24",
"allow * network ::1/128",
"allow * network [aa:bb::1]/128",
"allow service=foo x network 1.2.3.4/16",
"allow command abc network 1.2.3.4/8",
"profile osd network 1.2.3.4/32",
"allow profile mon network 1.2.3.4/32",
"profile crash network 1.2.3.4/32",
"allow profile crash network 1.2.3.4/32",
0
};
@ -93,10 +93,8 @@ const char *parse_identity[] = {
"allow r",
"allow rwx",
"allow service foo x",
"profile osd",
"profile osd-bootstrap",
"profile mds-bootstrap, allow *",
"profile \"foo bar\", allow *",
"profile crash",
"profile rbd-read-only, allow *",
"profile rbd namespace=NS pool=ABC",
"allow command abc",
"allow command \"a b c\"",
@ -267,6 +265,9 @@ TEST(MgrCap, Profile) {
MgrCap cap;
ASSERT_FALSE(cap.is_allow_all());
ASSERT_FALSE(cap.parse("profile unknown"));
ASSERT_FALSE(cap.parse("profile rbd invalid-key=value"));
ASSERT_TRUE(cap.parse("profile rbd", nullptr));
ASSERT_FALSE(cap.is_capable(nullptr, {}, "", "abc", "", {}, true, false,
false, {}));