apparmor/parser/dbus.cc

306 lines
7.9 KiB
C++
Raw Normal View History

/*
* Copyright (c) 2013
* Canonical, Ltd. (All rights reserved)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, contact Novell, Inc. or Canonical
* Ltd.
*/
#include <stdlib.h>
#include <string.h>
parser: Add make variable to build against local or system libapparmor [v3] By default, statically link against the in-tree libapparmor. If the in-tree libapparmor is not yet built, print a helpful error message. To build against the system libapparmor, the USE_SYSTEM make variable can be set on the command line like so: $ make USE_SYSTEM=1 This patch also fixes issues around the inclusion of the apparmor.h header. Previously, the in-tree apparmor.h was always being included even if the parser was being linked against the system libapparmor. It modifies the apparmor.h include path based on the previous patch separating them out in the libapparmor source. This was needed because header file name collisions were already occurring. For source files needing to include apparmor.h, the make targets were also updated to depend on the local apparmor.h when building against the in-tree libapparmor. When building against the system libapparmor, the variable used in the dependency list is empty. Likewise, a libapparmor.a dependency is added to the apparmor_parser target when building against the in-tree apparmor. Patch history: v1: from Tyler Hicks <tyhicks@canonical.com> - initial version v2: revert to altering the include search path rather than including the apparmor.h header directly via cpp arguments, alter the include statements to <sys/apparmor.h> which will work against either in-tree or (default) system paths. v3: convert controlling variable to USE_SYSTEM from SYSTEM_LIBAPPARMOR to unify between the parser and the regression tests. Signed-off-by: Tyler Hicks <tyhicks@canonical.com> Signed-off-by: Steve Beattie <steve@nxnw.org>
2014-01-06 14:46:10 -08:00
#include <sys/apparmor.h>
#include <iomanip>
#include <string>
#include <sstream>
#include "parser.h"
#include "profile.h"
#include "parser_yacc.h"
#include "dbus.h"
int parse_dbus_mode(const char *str_mode, int *mode, int fail)
{
return parse_X_mode("DBus", AA_VALID_DBUS_PERMS, str_mode, mode, fail);
}
void dbus_rule::move_conditionals(struct cond_entry *conds)
{
struct cond_entry *cond_ent;
list_for_each(conds, cond_ent) {
/* for now disallow keyword 'in' (list) */
if (!cond_ent->eq)
yyerror("keyword \"in\" is not allowed in dbus rules\n");
if (list_len(cond_ent->vals) > 1)
yyerror("dbus conditional \"%s\" only supports a single value\n",
cond_ent->name);
if (strcmp(cond_ent->name, "bus") == 0) {
move_conditional_value("dbus", &bus, cond_ent);
} else if (strcmp(cond_ent->name, "name") == 0) {
move_conditional_value("dbus", &name, cond_ent);
} else if (strcmp(cond_ent->name, "label") == 0) {
move_conditional_value("dbus", &peer_label, cond_ent);
} else if (strcmp(cond_ent->name, "path") == 0) {
move_conditional_value("dbus", &path, cond_ent);
} else if (strcmp(cond_ent->name, "interface") == 0) {
move_conditional_value("dbus", &interface, cond_ent);
} else if (strcmp(cond_ent->name, "member") == 0) {
move_conditional_value("dbus", &member, cond_ent);
} else {
yyerror("invalid dbus conditional \"%s\"\n",
cond_ent->name);
}
}
}
dbus_rule::dbus_rule(int mode_p, struct cond_entry *conds,
struct cond_entry *peer_conds):
bus(NULL), name(NULL), peer_label(NULL), path(NULL), interface(NULL), member(NULL),
mode(0), audit(0), deny(0)
{
int name_is_subject_cond = 0, message_rule = 0, service_rule = 0;
/* Move the global/subject conditionals over & check the results */
move_conditionals(conds);
if (name)
name_is_subject_cond = 1;
if (peer_label)
yyerror("dbus \"label\" conditional can only be used inside of the \"peer=()\" grouping\n");
/* Move the peer conditionals */
move_conditionals(peer_conds);
if (path || interface || member || peer_label ||
(name && !name_is_subject_cond))
message_rule = 1;
if (name && name_is_subject_cond)
service_rule = 1;
if (message_rule && service_rule)
yyerror("dbus rule contains message conditionals and service conditionals\n");
/* Copy mode. If no mode was specified, assign an implied mode. */
if (mode_p) {
mode = mode_p;
if (mode & ~AA_VALID_DBUS_PERMS)
2015-05-01 10:25:57 +02:00
yyerror("mode contains unknown dbus access\n");
else if (message_rule && (mode & AA_DBUS_BIND))
yyerror("dbus \"bind\" access cannot be used with message rule conditionals\n");
else if (service_rule && (mode & (AA_DBUS_SEND | AA_DBUS_RECEIVE)))
yyerror("dbus \"send\" and/or \"receive\" accesses cannot be used with service rule conditionals\n");
else if (mode & AA_DBUS_EAVESDROP &&
(path || interface || member ||
peer_label || name)) {
yyerror("dbus \"eavesdrop\" access can only contain a bus conditional\n");
}
} else {
if (message_rule)
mode = (AA_DBUS_SEND | AA_DBUS_RECEIVE);
else if (service_rule)
mode = (AA_DBUS_BIND);
else
mode = AA_VALID_DBUS_PERMS;
}
free_cond_list(conds);
free_cond_list(peer_conds);
}
ostream &dbus_rule::dump(ostream &os)
{
if (audit)
os << "audit ";
if (deny)
os << "deny ";
os << "dbus ( ";
if (mode & AA_DBUS_SEND)
os << "send ";
if (mode & AA_DBUS_RECEIVE)
os << "receive ";
if (mode & AA_DBUS_BIND)
os << "bind ";
if (mode & AA_DBUS_EAVESDROP)
os << "eavesdrop ";
os << ")";
if (bus)
os << " bus=\"" << bus << "\"";
if ((mode & AA_DBUS_BIND) && name)
os << " name=\"" << name << "\"";
if (path)
os << " path=\"" << path << "\"";
if (interface)
os << " interface=\"" << interface << "\"";
if (member)
os << " member=\"" << member << "\"";
if (!(mode & AA_DBUS_BIND) && (peer_label || name)) {
os << " peer=( ";
if (peer_label)
os << "label=\"" << peer_label << "\" ";
if (name)
os << "name=\"" << name << "\" ";
os << ")";
}
os << ",\n";
return os;
}
int dbus_rule::expand_variables(void)
{
int error = expand_entry_variables(&bus);
if (error)
return error;
error = expand_entry_variables(&name);
if (error)
return error;
error = expand_entry_variables(&peer_label);
if (error)
return error;
error = expand_entry_variables(&path);
if (error)
return error;
filter_slashes(path);
error = expand_entry_variables(&interface);
if (error)
return error;
error = expand_entry_variables(&member);
if (error)
return error;
return 0;
}
void dbus_rule::warn_once(const char *name)
{
rule_t::warn_once(name, "dbus rules not enforced");
}
int dbus_rule::gen_policy_re(Profile &prof)
{
std::string busbuf;
std::string namebuf;
std::string peer_labelbuf;
std::string pathbuf;
std::string ifacebuf;
std::string memberbuf;
std::ostringstream buffer;
const char *vec[6];
pattern_t ptype;
int pos;
if (!features_supports_dbus) {
warn_once(prof.name);
return RULE_NOT_SUPPORTED;
}
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_DBUS;
busbuf.append(buffer.str());
if (bus) {
ptype = convert_aaregex_to_pcre(bus, 0, glob_default, busbuf, &pos);
if (ptype == ePatternInvalid)
goto fail;
} else {
/* match any char except \000 0 or more times */
busbuf.append(default_match_pattern);
}
vec[0] = busbuf.c_str();
if (name) {
ptype = convert_aaregex_to_pcre(name, 0, glob_default, namebuf, &pos);
if (ptype == ePatternInvalid)
goto fail;
vec[1] = namebuf.c_str();
} else {
/* match any char except \000 0 or more times */
vec[1] = default_match_pattern;
}
if (peer_label) {
ptype = convert_aaregex_to_pcre(peer_label, 0, glob_default,
peer_labelbuf, &pos);
if (ptype == ePatternInvalid)
goto fail;
vec[2] = peer_labelbuf.c_str();
} else {
/* match any char except \000 0 or more times */
vec[2] = default_match_pattern;
}
if (path) {
ptype = convert_aaregex_to_pcre(path, 0, glob_default, pathbuf, &pos);
if (ptype == ePatternInvalid)
goto fail;
vec[3] = pathbuf.c_str();
} else {
/* match any char except \000 0 or more times */
vec[3] = default_match_pattern;
}
if (interface) {
ptype = convert_aaregex_to_pcre(interface, 0, glob_default, ifacebuf, &pos);
if (ptype == ePatternInvalid)
goto fail;
vec[4] = ifacebuf.c_str();
} else {
/* match any char except \000 0 or more times */
vec[4] = default_match_pattern;
}
if (member) {
ptype = convert_aaregex_to_pcre(member, 0, glob_default, memberbuf, &pos);
if (ptype == ePatternInvalid)
goto fail;
vec[5] = memberbuf.c_str();
} else {
/* match any char except \000 0 or more times */
vec[5] = default_match_pattern;
}
if (mode & AA_DBUS_BIND) {
if (!prof.policy.rules->add_rule_vec(deny, mode & AA_DBUS_BIND,
audit & AA_DBUS_BIND,
add ability to use out of band transitions Currently the NULL character is used as an out of band transition for string/path elements. This works for them as the NULL character is not valid for this data. However this does not work for binary data that can contain a NULL character. So far we have only dealt with fixed length fields of binary data making the NULL separator either unnecessary. However binary data like in the xattr match and mount data field are variable length and can contain NULL characters. To deal with this add the ability to specify out of band transitions, that can only be triggered by code not input data. The out of band transition can be used to separate variable length data fields just as the NULL transition has been used to separate variable length strings. In the compressed hfa out of band transitions are expressed as a negative offset from the states base. This leaves us room to expand the character match range in the future if desired and on average makes the range between the out of band transition and the input transitions smaller than would be had if the out of band transition had been stored after the valid input transitions. Out of band transitions in the dfa will not break old kernels that don't know about them, but they won't be able to trigger the out of band transition match. So they should not be used unless the kernel indicates that it supports them. It should be noted that this patch only adds support for a single out of band transition. If multiple out of band transitions are required. It is trivial to extend. - Add a tag indicating support in the kernel - add a oob max range field to the dfa header so the kernel knows what the max range that needs verifying is. - extend oob generation fns to generate oob based on value instead of a fixed -1. Signed-off-by: John Johansen <john.johansen@canonical.com>
2019-08-11 06:18:27 -07:00
2, vec, dfaflags, false))
goto fail;
}
if (mode & (AA_DBUS_SEND | AA_DBUS_RECEIVE)) {
if (!prof.policy.rules->add_rule_vec(deny,
mode & (AA_DBUS_SEND | AA_DBUS_RECEIVE),
audit & (AA_DBUS_SEND | AA_DBUS_RECEIVE),
add ability to use out of band transitions Currently the NULL character is used as an out of band transition for string/path elements. This works for them as the NULL character is not valid for this data. However this does not work for binary data that can contain a NULL character. So far we have only dealt with fixed length fields of binary data making the NULL separator either unnecessary. However binary data like in the xattr match and mount data field are variable length and can contain NULL characters. To deal with this add the ability to specify out of band transitions, that can only be triggered by code not input data. The out of band transition can be used to separate variable length data fields just as the NULL transition has been used to separate variable length strings. In the compressed hfa out of band transitions are expressed as a negative offset from the states base. This leaves us room to expand the character match range in the future if desired and on average makes the range between the out of band transition and the input transitions smaller than would be had if the out of band transition had been stored after the valid input transitions. Out of band transitions in the dfa will not break old kernels that don't know about them, but they won't be able to trigger the out of band transition match. So they should not be used unless the kernel indicates that it supports them. It should be noted that this patch only adds support for a single out of band transition. If multiple out of band transitions are required. It is trivial to extend. - Add a tag indicating support in the kernel - add a oob max range field to the dfa header so the kernel knows what the max range that needs verifying is. - extend oob generation fns to generate oob based on value instead of a fixed -1. Signed-off-by: John Johansen <john.johansen@canonical.com>
2019-08-11 06:18:27 -07:00
6, vec, dfaflags, false))
goto fail;
}
if (mode & AA_DBUS_EAVESDROP) {
if (!prof.policy.rules->add_rule_vec(deny,
mode & AA_DBUS_EAVESDROP,
audit & AA_DBUS_EAVESDROP,
add ability to use out of band transitions Currently the NULL character is used as an out of band transition for string/path elements. This works for them as the NULL character is not valid for this data. However this does not work for binary data that can contain a NULL character. So far we have only dealt with fixed length fields of binary data making the NULL separator either unnecessary. However binary data like in the xattr match and mount data field are variable length and can contain NULL characters. To deal with this add the ability to specify out of band transitions, that can only be triggered by code not input data. The out of band transition can be used to separate variable length data fields just as the NULL transition has been used to separate variable length strings. In the compressed hfa out of band transitions are expressed as a negative offset from the states base. This leaves us room to expand the character match range in the future if desired and on average makes the range between the out of band transition and the input transitions smaller than would be had if the out of band transition had been stored after the valid input transitions. Out of band transitions in the dfa will not break old kernels that don't know about them, but they won't be able to trigger the out of band transition match. So they should not be used unless the kernel indicates that it supports them. It should be noted that this patch only adds support for a single out of band transition. If multiple out of band transitions are required. It is trivial to extend. - Add a tag indicating support in the kernel - add a oob max range field to the dfa header so the kernel knows what the max range that needs verifying is. - extend oob generation fns to generate oob based on value instead of a fixed -1. Signed-off-by: John Johansen <john.johansen@canonical.com>
2019-08-11 06:18:27 -07:00
1, vec, dfaflags, false))
goto fail;
}
return RULE_OK;
fail:
return RULE_ERROR;
}