2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-08-30 22:05:27 +00:00

parser: Add support for DBus rules

This patch implements the parsing of DBus rules.

It attempts to catch all corner cases, such as specifying a bind
permission with an interface conditional or specifying a subject name
conditional and a peer name conditional in the same rule.

It introduces the concept of conditional lists to the lexer and parser
in order to handle 'peer=(label=/usr/bin/foo name=com.foo.bar)', since
the existing list support in the lexer only supports a list of values.

The DBus rules are encoded as follows:

bus,name<bind_perm>,peer_label,path,interface,member<rw_perms>

Bind rules stop matching at name<bind_perm>. Note that name is used for
the subject name in bind rules and the peer name in rw rules. The
function new_dbus_entry() is what does the proper sanitization to make
sure that if a name conditional is specified, that it is the subject
name in the case of a bind rule or that it is the peer name in the case
of a rw rule.

Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
This commit is contained in:
Tyler Hicks
2013-07-31 09:05:51 -07:00
parent 1aba3394a3
commit ab84444d3a
10 changed files with 732 additions and 11 deletions

View File

@@ -38,6 +38,7 @@
#include "parser.h"
#include "parser_yacc.h"
#include "mount.h"
#include "dbus.h"
/* #define DEBUG */
#ifdef DEBUG
@@ -85,6 +86,14 @@ static struct keyword_table keyword_table[] = {
{"unmount", TOK_UMOUNT},
{"pivot_root", TOK_PIVOTROOT},
{"in", TOK_IN},
{"dbus", TOK_DBUS},
{"send", TOK_SEND},
{"receive", TOK_RECEIVE},
{"bind", TOK_BIND},
{"read", TOK_READ},
{"write", TOK_WRITE},
{"peer", TOK_PEER},
/* terminate */
{NULL, 0}
};
@@ -724,6 +733,81 @@ int parse_mode(const char *str_mode)
return mode;
}
static int parse_dbus_sub_mode(const char *str_mode, int *result, int fail, const char *mode_desc __unused)
{
int mode = 0;
const char *p;
PDEBUG("Parsing DBus mode: %s\n", str_mode);
if (!str_mode)
return 0;
p = str_mode;
while (*p) {
char this = *p;
char lower;
reeval:
switch (this) {
case COD_READ_CHAR:
PDEBUG("Parsing DBus mode: found %s READ\n", mode_desc);
mode |= AA_DBUS_RECEIVE;
break;
case COD_WRITE_CHAR:
PDEBUG("Parsing DBus mode: found %s WRITE\n",
mode_desc);
mode |= AA_DBUS_SEND;
break;
/* error cases */
default:
lower = tolower(this);
switch (lower) {
case COD_READ_CHAR:
case COD_WRITE_CHAR:
PDEBUG("Parsing DBus mode: found invalid upper case char %c\n",
this);
warn_uppercase();
this = lower;
goto reeval;
break;
default:
if (fail)
yyerror(_("Internal: unexpected DBus mode character '%c' in input"),
this);
else
return 0;
break;
}
break;
}
p++;
}
PDEBUG("Parsed DBus mode: %s 0x%x\n", str_mode, mode);
*result = mode;
return 1;
}
int parse_dbus_mode(const char *str_mode, int *mode, int fail)
{
*mode = 0;
if (!parse_dbus_sub_mode(str_mode, mode, fail, ""))
return 0;
if (*mode & ~AA_VALID_DBUS_PERMS) {
if (fail)
yyerror(_("Internal error generated invalid DBus perm 0x%x\n"),
mode);
else
return 0;
}
return 1;
}
struct cod_entry *new_entry(char *namespace, char *id, int mode, char *link_id)
{
struct cod_entry *entry = NULL;
@@ -803,6 +887,16 @@ void free_mnt_entries(struct mnt_entry *list)
free(list);
}
void free_dbus_entries(struct dbus_entry *list)
{
if (!list)
return;
if (list->next)
free_dbus_entries(list->next);
free_dbus_entry(list);
}
static void debug_base_perm_mask(int mask)
{
if (HAS_MAY_READ(mask))
@@ -1148,6 +1242,15 @@ void free_cond_entry(struct cond_entry *ent)
}
}
void free_cond_list(struct cond_entry *ents)
{
struct cond_entry *entry, *tmp;
list_for_each_safe(ents, entry, tmp) {
free_cond_entry(entry);
}
}
void print_cond_entry(struct cond_entry *ent)
{
if (ent) {