mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-09-02 15:25:27 +00:00
Compare commits
170 Commits
v4.0.0-alp
...
v4.0.0-bet
Author | SHA1 | Date | |
---|---|---|---|
|
b264bb62c9 | ||
|
35287c8e1c | ||
|
119e3f38f9 | ||
|
dd0d145a19 | ||
|
f6ad1cbe1e | ||
|
8a5e7227db | ||
|
79ee3eb180 | ||
|
052dd987b3 | ||
|
7e25be7b0b | ||
|
ddefe11a40 | ||
|
b83cf90b82 | ||
|
e3cb9e1669 | ||
|
924b335dfc | ||
|
a2da64304f | ||
|
bb53886211 | ||
|
746f76d3e1 | ||
|
35f25a251b | ||
|
c09f58a364 | ||
|
909e330fd0 | ||
|
88907253e4 | ||
|
124e73ec93 | ||
|
4b1bc85022 | ||
|
c4f649da92 | ||
|
108f489f2b | ||
|
4d2172e82e | ||
|
95d9ba8d8b | ||
|
420d3395fc | ||
|
4608d32628 | ||
|
2394ca82c5 | ||
|
105b50502b | ||
|
105bdfdeb9 | ||
|
f9d38c9b2c | ||
|
3ea050eb30 | ||
|
b49822a48d | ||
|
32bba24468 | ||
|
fd25954c56 | ||
|
ca3afe1691 | ||
|
2577fbf077 | ||
|
2b8cf1be80 | ||
|
89a9f76733 | ||
|
4621af8ead | ||
|
668f5af436 | ||
|
48d475036a | ||
|
0e378f52a8 | ||
|
15337db4af | ||
|
ce3c97df0f | ||
|
789cda2f08 | ||
|
6add80d83f | ||
|
3e28d0a254 | ||
|
e63c1e3a76 | ||
|
b03abbd75f | ||
|
6e81104bbf | ||
|
6cc3a3642d | ||
|
166ebdb3bc | ||
|
253eace573 | ||
|
c2487f017f | ||
|
dc73f0fc0b | ||
|
3578b07aeb | ||
|
28e67c7ba8 | ||
|
c8a2dc34d9 | ||
|
350f9cf3dd | ||
|
f889f9f434 | ||
|
5ca2ea3621 | ||
|
2c5bc5a09b | ||
|
dc821ef762 | ||
|
31c9cf6845 | ||
|
66484687e8 | ||
|
dfb6f90aee | ||
|
fcd46063fd | ||
|
f10e106a08 | ||
|
d778fbef57 | ||
|
70809fc716 | ||
|
15d8e21945 | ||
|
3ee47af402 | ||
|
eb6fa02251 | ||
|
923cbcf3be | ||
|
78a2c9f5f3 | ||
|
81bc26c934 | ||
|
71e28e9357 | ||
|
7c684f9d22 | ||
|
6c01b90c13 | ||
|
832bb8f417 | ||
|
e0bc90f5cf | ||
|
6a96067938 | ||
|
dcad01ccc3 | ||
|
2594d936ad | ||
|
9bba464d93 | ||
|
96b1aa549b | ||
|
dcc719c69c | ||
|
6304d372bf | ||
|
54915dabc4 | ||
|
d55a1e6d5d | ||
|
6580331625 | ||
|
1e7f63415a | ||
|
d4dff5ce4e | ||
|
86c05357cf | ||
|
f17bd59904 | ||
|
d38c7b22ce | ||
|
942202da17 | ||
|
5c34655f4a | ||
|
57ba373213 | ||
|
5d9d4483fb | ||
|
8b95030665 | ||
|
58a89284d5 | ||
|
28f336cb91 | ||
|
61fc6805a9 | ||
|
f2f24884c3 | ||
|
5d8347bc26 | ||
|
0c595ac801 | ||
|
1d5f90efcd | ||
|
4f51c93f9d | ||
|
4d1c17b426 | ||
|
918a15e244 | ||
|
fc8c7722a1 | ||
|
7eff621fc7 | ||
|
659a187687 | ||
|
cee501349e | ||
|
27de7ea0c2 | ||
|
bfd72c93be | ||
|
6ac0e0236b | ||
|
151bf26bb9 | ||
|
26903320fd | ||
|
884adcc58f | ||
|
f5be84acdc | ||
|
5d940b2a47 | ||
|
583d116871 | ||
|
e361644d5a | ||
|
4e758a838d | ||
|
197d00d21a | ||
|
a9c5388f69 | ||
|
75ca0e7919 | ||
|
fb5f59024c | ||
|
a71ac76e6d | ||
|
2be9c431ca | ||
|
05de4b82e7 | ||
|
820f1fb5f2 | ||
|
65905b0c55 | ||
|
1945ecbf19 | ||
|
11976c42e3 | ||
|
327588f019 | ||
|
84e22b4cca | ||
|
248625ae00 | ||
|
9ab72ffc7c | ||
|
9be09aa909 | ||
|
2bf35277a0 | ||
|
9db134223c | ||
|
ef56e60e06 | ||
|
96965c3da2 | ||
|
a9494f5523 | ||
|
57985480ca | ||
|
f10467556c | ||
|
30707be87f | ||
|
f61fd42061 | ||
|
847ab59e1c | ||
|
427b58a4b6 | ||
|
aa20721be1 | ||
|
5957aa49f5 | ||
|
e133a9fc68 | ||
|
32307601a0 | ||
|
5b139521aa | ||
|
2d7bd40606 | ||
|
24806f6f61 | ||
|
fbe68f0078 | ||
|
74265e8ded | ||
|
41df2ca366 | ||
|
adf19138d5 | ||
|
1758b66c9d | ||
|
dd9b7b358f | ||
|
b45c10d4de | ||
|
c175e414c8 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -29,6 +29,7 @@ parser/parser_yacc.h
|
|||||||
parser/pod2htm*.tmp
|
parser/pod2htm*.tmp
|
||||||
parser/af_rule.o
|
parser/af_rule.o
|
||||||
parser/af_unix.o
|
parser/af_unix.o
|
||||||
|
parser/all_rule.o
|
||||||
parser/common_optarg.o
|
parser/common_optarg.o
|
||||||
parser/dbus.o
|
parser/dbus.o
|
||||||
parser/default_features.o
|
parser/default_features.o
|
||||||
@@ -263,7 +264,10 @@ tests/regression/apparmor/link_subset
|
|||||||
tests/regression/apparmor/mkdir
|
tests/regression/apparmor/mkdir
|
||||||
tests/regression/apparmor/mmap
|
tests/regression/apparmor/mmap
|
||||||
tests/regression/apparmor/mount
|
tests/regression/apparmor/mount
|
||||||
|
tests/regression/apparmor/move_mount
|
||||||
tests/regression/apparmor/named_pipe
|
tests/regression/apparmor/named_pipe
|
||||||
|
tests/regression/apparmor/net_finegrained_rcv
|
||||||
|
tests/regression/apparmor/net_finegrained_snd
|
||||||
tests/regression/apparmor/net_raw
|
tests/regression/apparmor/net_raw
|
||||||
tests/regression/apparmor/open
|
tests/regression/apparmor/open
|
||||||
tests/regression/apparmor/openat
|
tests/regression/apparmor/openat
|
||||||
|
@@ -17,7 +17,7 @@ stages:
|
|||||||
- uname -a
|
- uname -a
|
||||||
|
|
||||||
.install-c-build-deps: &install-c-build-deps
|
.install-c-build-deps: &install-c-build-deps
|
||||||
- apt-get install --no-install-recommends -y build-essential apache2-dev autoconf automake bison dejagnu flex libpam-dev libtool pkg-config python3-all-dev python3-setuptools ruby-dev swig zlib1g-dev
|
- apt-get install --no-install-recommends -y build-essential apache2-dev autoconf autoconf-archive automake bison dejagnu flex libpam-dev libtool pkg-config python3-all-dev python3-setuptools ruby-dev swig zlib1g-dev
|
||||||
|
|
||||||
build-all:
|
build-all:
|
||||||
stage: build
|
stage: build
|
||||||
|
@@ -181,6 +181,9 @@ $ make check # depends on the parser having been built first
|
|||||||
$ make install
|
$ make install
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note that the empty local/* profile sniplets no longer get created by default.
|
||||||
|
If you want them, run `make local` before running `make check`.
|
||||||
|
|
||||||
[Note that for the parser, binutils, and utils, if you only wish to build/use
|
[Note that for the parser, binutils, and utils, if you only wish to build/use
|
||||||
some of the locale languages, you can override the default by passing
|
some of the locale languages, you can override the default by passing
|
||||||
the LANGS arguments to make; e.g. make all install "LANGS=en_US fr".]
|
the LANGS arguments to make; e.g. make all install "LANGS=en_US fr".]
|
||||||
|
@@ -115,6 +115,7 @@ static void free_processes(struct process *processes, size_t n) {
|
|||||||
#define SHOW_PROCESSES 2
|
#define SHOW_PROCESSES 2
|
||||||
|
|
||||||
static int verbose = 1;
|
static int verbose = 1;
|
||||||
|
static bool quiet = false;
|
||||||
int opt_show = SHOW_PROFILES | SHOW_PROCESSES;
|
int opt_show = SHOW_PROFILES | SHOW_PROCESSES;
|
||||||
bool opt_json = false;
|
bool opt_json = false;
|
||||||
bool opt_pretty = false;
|
bool opt_pretty = false;
|
||||||
@@ -127,15 +128,21 @@ const char *opt_exe = ".*";
|
|||||||
const char *profile_statuses[] = {"enforce", "complain", "prompt", "kill", "unconfined"};
|
const char *profile_statuses[] = {"enforce", "complain", "prompt", "kill", "unconfined"};
|
||||||
const char *process_statuses[] = {"enforce", "complain", "prompt", "kill", "unconfined", "mixed"};
|
const char *process_statuses[] = {"enforce", "complain", "prompt", "kill", "unconfined", "mixed"};
|
||||||
|
|
||||||
|
#define eprintf(...) \
|
||||||
|
do { \
|
||||||
|
if (!quiet) \
|
||||||
|
fprintf(stderr, __VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define dprintf(...) \
|
#define dprintf(...) \
|
||||||
do { \
|
do { \
|
||||||
if (verbose) \
|
if (verbose && !opt_json) \
|
||||||
printf(__VA_ARGS__); \
|
printf(__VA_ARGS__); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define dfprintf(...) \
|
#define dfprintf(...) \
|
||||||
do { \
|
do { \
|
||||||
if (verbose) \
|
if (verbose && !opt_json) \
|
||||||
fprintf(__VA_ARGS__); \
|
fprintf(__VA_ARGS__); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
@@ -149,14 +156,14 @@ static int open_profiles(FILE **fp)
|
|||||||
|
|
||||||
ret = stat("/sys/module/apparmor", &st);
|
ret = stat("/sys/module/apparmor", &st);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
dfprintf(stderr, "apparmor not present.\n");
|
eprintf("apparmor not present.\n");
|
||||||
return AA_EXIT_DISABLED;
|
return AA_EXIT_DISABLED;
|
||||||
}
|
}
|
||||||
dprintf("apparmor module is loaded.\n");
|
dprintf("apparmor module is loaded.\n");
|
||||||
|
|
||||||
ret = aa_find_mountpoint(&apparmorfs);
|
ret = aa_find_mountpoint(&apparmorfs);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
dfprintf(stderr, "apparmor filesystem is not mounted.\n");
|
eprintf("apparmor filesystem is not mounted.\n");
|
||||||
return AA_EXIT_NO_CONTROL;
|
return AA_EXIT_NO_CONTROL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,9 +176,9 @@ static int open_profiles(FILE **fp)
|
|||||||
*fp = fopen(apparmor_profiles, "r");
|
*fp = fopen(apparmor_profiles, "r");
|
||||||
if (*fp == NULL) {
|
if (*fp == NULL) {
|
||||||
if (errno == EACCES) {
|
if (errno == EACCES) {
|
||||||
dfprintf(stderr, "You do not have enough privilege to read the profile set.\n");
|
eprintf("You do not have enough privilege to read the profile set.\n");
|
||||||
} else {
|
} else {
|
||||||
dfprintf(stderr, "Could not open %s: %s", apparmor_profiles, strerror(errno));
|
eprintf("Could not open %s: %s", apparmor_profiles, strerror(errno));
|
||||||
}
|
}
|
||||||
return AA_EXIT_NO_PERM;
|
return AA_EXIT_NO_PERM;
|
||||||
}
|
}
|
||||||
@@ -201,7 +208,7 @@ static int get_profiles(FILE *fp, struct profile **profiles, size_t *n) {
|
|||||||
char *tmpname = aa_splitcon(line, &status);
|
char *tmpname = aa_splitcon(line, &status);
|
||||||
|
|
||||||
if (!tmpname) {
|
if (!tmpname) {
|
||||||
dfprintf(stderr, "Error: failed profile name split of '%s'.\n", line);
|
eprintf("Error: failed profile name split of '%s'.\n", line);
|
||||||
// skip this entry and keep processing
|
// skip this entry and keep processing
|
||||||
// else would be AA_EXIT_INTERNAL_ERROR;
|
// else would be AA_EXIT_INTERNAL_ERROR;
|
||||||
continue;
|
continue;
|
||||||
@@ -344,7 +351,7 @@ static int get_processes(struct profile *profiles,
|
|||||||
continue;
|
continue;
|
||||||
} else if (rc == -1 ||
|
} else if (rc == -1 ||
|
||||||
asprintf(&exe, "/proc/%s/exe", entry->d_name) == -1) {
|
asprintf(&exe, "/proc/%s/exe", entry->d_name) == -1) {
|
||||||
fprintf(stderr, "ERROR: Failed to allocate memory\n");
|
eprintf("ERROR: Failed to allocate memory\n");
|
||||||
ret = AA_EXIT_INTERNAL_ERROR;
|
ret = AA_EXIT_INTERNAL_ERROR;
|
||||||
goto exit;
|
goto exit;
|
||||||
} else if (mode) {
|
} else if (mode) {
|
||||||
@@ -367,7 +374,7 @@ static int get_processes(struct profile *profiles,
|
|||||||
// ensure enough space for NUL terminator
|
// ensure enough space for NUL terminator
|
||||||
real_exe = calloc(PATH_MAX + 1, sizeof(char));
|
real_exe = calloc(PATH_MAX + 1, sizeof(char));
|
||||||
if (real_exe == NULL) {
|
if (real_exe == NULL) {
|
||||||
fprintf(stderr, "ERROR: Failed to allocate memory\n");
|
eprintf("ERROR: Failed to allocate memory\n");
|
||||||
ret = AA_EXIT_INTERNAL_ERROR;
|
ret = AA_EXIT_INTERNAL_ERROR;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
@@ -575,7 +582,7 @@ static int detailed_profiles(FILE *outf, filters_t *filters, bool json,
|
|||||||
*/
|
*/
|
||||||
subfilters.mode = &mode_filter;
|
subfilters.mode = &mode_filter;
|
||||||
if (regcomp(&mode_filter, profile_statuses[i], REG_NOSUB) != 0) {
|
if (regcomp(&mode_filter, profile_statuses[i], REG_NOSUB) != 0) {
|
||||||
dfprintf(stderr, "Error: failed to compile sub filter '%s'\n",
|
eprintf("Error: failed to compile sub filter '%s'\n",
|
||||||
profile_statuses[i]);
|
profile_statuses[i]);
|
||||||
return AA_EXIT_INTERNAL_ERROR;
|
return AA_EXIT_INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
@@ -641,7 +648,7 @@ static int detailed_processes(FILE *outf, filters_t *filters, bool json,
|
|||||||
*/
|
*/
|
||||||
subfilters.mode = &mode_filter;
|
subfilters.mode = &mode_filter;
|
||||||
if (regcomp(&mode_filter, process_statuses[i], REG_NOSUB) != 0) {
|
if (regcomp(&mode_filter, process_statuses[i], REG_NOSUB) != 0) {
|
||||||
dfprintf(stderr, "Error: failed to compile sub filter '%s'\n",
|
eprintf("Error: failed to compile sub filter '%s'\n",
|
||||||
profile_statuses[i]);
|
profile_statuses[i]);
|
||||||
return AA_EXIT_INTERNAL_ERROR;
|
return AA_EXIT_INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
@@ -765,8 +772,9 @@ static int print_usage(const char *command, bool error)
|
|||||||
" --json displays multiple data points in machine-readable JSON format\n"
|
" --json displays multiple data points in machine-readable JSON format\n"
|
||||||
" --pretty-json same data as --json, formatted for human consumption as well\n"
|
" --pretty-json same data as --json, formatted for human consumption as well\n"
|
||||||
" --verbose (default) displays data points about loaded policy set\n"
|
" --verbose (default) displays data points about loaded policy set\n"
|
||||||
" -h [(legacy|filter)] this message, or info on the specified option\n"
|
" --quiet don't output error messages\n"
|
||||||
" --help[=(legacy|filter)] this message, or info on the specified option\n",
|
" -h[(legacy|filters)] this message, or info on the specified option\n"
|
||||||
|
" --help[=(legacy|filters)] this message, or info on the specified option\n",
|
||||||
command);
|
command);
|
||||||
|
|
||||||
exit(status);
|
exit(status);
|
||||||
@@ -792,6 +800,7 @@ static int print_usage(const char *command, bool error)
|
|||||||
#define ARG_EXE 143
|
#define ARG_EXE 143
|
||||||
#define ARG_PROMPT 144
|
#define ARG_PROMPT 144
|
||||||
#define ARG_VERBOSE 'v'
|
#define ARG_VERBOSE 'v'
|
||||||
|
#define ARG_QUIET 'q'
|
||||||
#define ARG_HELP 'h'
|
#define ARG_HELP 'h'
|
||||||
|
|
||||||
static int parse_args(int argc, char **argv)
|
static int parse_args(int argc, char **argv)
|
||||||
@@ -809,6 +818,7 @@ static int parse_args(int argc, char **argv)
|
|||||||
{"json", no_argument, 0, ARG_JSON},
|
{"json", no_argument, 0, ARG_JSON},
|
||||||
{"pretty-json", no_argument, 0, ARG_PRETTY},
|
{"pretty-json", no_argument, 0, ARG_PRETTY},
|
||||||
{"verbose", no_argument, 0, ARG_VERBOSE},
|
{"verbose", no_argument, 0, ARG_VERBOSE},
|
||||||
|
{"quiet", no_argument, 0, ARG_QUIET},
|
||||||
{"help", 2, 0, ARG_HELP},
|
{"help", 2, 0, ARG_HELP},
|
||||||
{"count", no_argument, 0, ARG_COUNT},
|
{"count", no_argument, 0, ARG_COUNT},
|
||||||
{"show", 1, 0, ARG_SHOW},
|
{"show", 1, 0, ARG_SHOW},
|
||||||
@@ -820,7 +830,7 @@ static int parse_args(int argc, char **argv)
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Using exit here is temporary
|
// Using exit here is temporary
|
||||||
while ((opt = getopt_long(argc, argv, "+vh", long_opts, NULL)) != -1) {
|
while ((opt = getopt_long(argc, argv, "+vh::", long_opts, NULL)) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case ARG_ENABLED:
|
case ARG_ENABLED:
|
||||||
exit(aa_is_enabled() == 1 ? 0 : AA_EXIT_DISABLED);
|
exit(aa_is_enabled() == 1 ? 0 : AA_EXIT_DISABLED);
|
||||||
@@ -830,6 +840,9 @@ static int parse_args(int argc, char **argv)
|
|||||||
/* default opt_mode */
|
/* default opt_mode */
|
||||||
/* default opt_show */
|
/* default opt_show */
|
||||||
break;
|
break;
|
||||||
|
case ARG_QUIET:
|
||||||
|
quiet = true;
|
||||||
|
break;
|
||||||
case ARG_HELP:
|
case ARG_HELP:
|
||||||
if (!optarg) {
|
if (!optarg) {
|
||||||
print_usage(argv[0], false);
|
print_usage(argv[0], false);
|
||||||
@@ -838,7 +851,7 @@ static int parse_args(int argc, char **argv)
|
|||||||
} else if (strcmp(optarg, "filters") == 0) {
|
} else if (strcmp(optarg, "filters") == 0) {
|
||||||
usage_filters();
|
usage_filters();
|
||||||
} else {
|
} else {
|
||||||
dfprintf(stderr, "Error: Invalid --help option '%s'.\n", optarg);
|
eprintf("Error: Invalid --help option '%s'.\n", optarg);
|
||||||
print_usage(argv[0], true);
|
print_usage(argv[0], true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -906,7 +919,7 @@ static int parse_args(int argc, char **argv)
|
|||||||
} else if (strcmp(optarg, "processes") == 0) {
|
} else if (strcmp(optarg, "processes") == 0) {
|
||||||
opt_show = SHOW_PROCESSES;
|
opt_show = SHOW_PROCESSES;
|
||||||
} else {
|
} else {
|
||||||
dfprintf(stderr, "Error: Invalid --show option '%s'.\n", optarg);
|
eprintf("Error: Invalid --show option '%s'.\n", optarg);
|
||||||
print_usage(argv[0], true);
|
print_usage(argv[0], true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -928,7 +941,7 @@ static int parse_args(int argc, char **argv)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
dfprintf(stderr, "Error: Invalid command.\n");
|
eprintf("Error: Invalid command.\n");
|
||||||
print_usage(argv[0], true);
|
print_usage(argv[0], true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -953,7 +966,7 @@ int main(int argc, char **argv)
|
|||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
int pos = parse_args(argc, argv);
|
int pos = parse_args(argc, argv);
|
||||||
if (pos < argc) {
|
if (pos < argc) {
|
||||||
dfprintf(stderr, "Error: Unknown options.\n");
|
eprintf("Error: Unknown options.\n");
|
||||||
print_usage(progname, true);
|
print_usage(progname, true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -965,24 +978,24 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
init_filters(&filters, &filter_set);
|
init_filters(&filters, &filter_set);
|
||||||
if (regcomp(filters.mode, opt_mode, REG_NOSUB) != 0) {
|
if (regcomp(filters.mode, opt_mode, REG_NOSUB) != 0) {
|
||||||
dfprintf(stderr, "Error: failed to compile mode filter '%s'\n",
|
eprintf("Error: failed to compile mode filter '%s'\n",
|
||||||
opt_mode);
|
opt_mode);
|
||||||
return AA_EXIT_INTERNAL_ERROR;
|
return AA_EXIT_INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
if (regcomp(filters.profile, opt_profiles, REG_NOSUB) != 0) {
|
if (regcomp(filters.profile, opt_profiles, REG_NOSUB) != 0) {
|
||||||
dfprintf(stderr, "Error: failed to compile profiles filter '%s'\n",
|
eprintf("Error: failed to compile profiles filter '%s'\n",
|
||||||
opt_profiles);
|
opt_profiles);
|
||||||
ret = AA_EXIT_INTERNAL_ERROR;
|
ret = AA_EXIT_INTERNAL_ERROR;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (regcomp(filters.pid, opt_pid, REG_NOSUB) != 0) {
|
if (regcomp(filters.pid, opt_pid, REG_NOSUB) != 0) {
|
||||||
dfprintf(stderr, "Error: failed to compile ps filter '%s'\n",
|
eprintf("Error: failed to compile ps filter '%s'\n",
|
||||||
opt_pid);
|
opt_pid);
|
||||||
ret = AA_EXIT_INTERNAL_ERROR;
|
ret = AA_EXIT_INTERNAL_ERROR;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (regcomp(filters.exe, opt_exe, REG_NOSUB) != 0) {
|
if (regcomp(filters.exe, opt_exe, REG_NOSUB) != 0) {
|
||||||
dfprintf(stderr, "Error: failed to compile exe filter '%s'\n",
|
eprintf("Error: failed to compile exe filter '%s'\n",
|
||||||
opt_exe);
|
opt_exe);
|
||||||
ret = AA_EXIT_INTERNAL_ERROR;
|
ret = AA_EXIT_INTERNAL_ERROR;
|
||||||
goto out;
|
goto out;
|
||||||
@@ -997,7 +1010,7 @@ int main(int argc, char **argv)
|
|||||||
outf_save = outf;
|
outf_save = outf;
|
||||||
outf = open_memstream(&buffer, &buffer_size);
|
outf = open_memstream(&buffer, &buffer_size);
|
||||||
if (!outf) {
|
if (!outf) {
|
||||||
dfprintf(stderr, "Failed to open memstream: %m\n");
|
eprintf("Failed to open memstream: %m\n");
|
||||||
return AA_EXIT_INTERNAL_ERROR;
|
return AA_EXIT_INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1008,7 +1021,7 @@ int main(int argc, char **argv)
|
|||||||
*/
|
*/
|
||||||
ret = get_profiles(fp, &profiles, &nprofiles);
|
ret = get_profiles(fp, &profiles, &nprofiles);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
dfprintf(stderr, "Failed to get profiles: %d....\n", ret);
|
eprintf("Failed to get profiles: %d....\n", ret);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1032,7 +1045,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
ret = get_processes(profiles, nprofiles, &processes, &nprocesses);
|
ret = get_processes(profiles, nprofiles, &processes, &nprocesses);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
dfprintf(stderr, "Failed to get processes: %d....\n", ret);
|
eprintf("Failed to get processes: %d....\n", ret);
|
||||||
} else if (opt_count) {
|
} else if (opt_count) {
|
||||||
ret = simple_filtered_process_count(outf, &filters,
|
ret = simple_filtered_process_count(outf, &filters,
|
||||||
processes, nprocesses);
|
processes, nprocesses);
|
||||||
@@ -1058,14 +1071,14 @@ int main(int argc, char **argv)
|
|||||||
outf = outf_save;
|
outf = outf_save;
|
||||||
json = cJSON_Parse(buffer);
|
json = cJSON_Parse(buffer);
|
||||||
if (!json) {
|
if (!json) {
|
||||||
dfprintf(stderr, "Failed to parse json output");
|
eprintf("Failed to parse json output");
|
||||||
ret = AA_EXIT_INTERNAL_ERROR;
|
ret = AA_EXIT_INTERNAL_ERROR;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
pretty = cJSON_Print(json);
|
pretty = cJSON_Print(json);
|
||||||
if (!pretty) {
|
if (!pretty) {
|
||||||
dfprintf(stderr, "Failed to print pretty json");
|
eprintf("Failed to print pretty json");
|
||||||
ret = AA_EXIT_INTERNAL_ERROR;
|
ret = AA_EXIT_INTERNAL_ERROR;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@@ -1 +1 @@
|
|||||||
4.0.0~alpha2
|
4.0.0~beta1
|
||||||
|
@@ -92,6 +92,13 @@ if test "$ac_cv_prog_cc_c99" = "no"; then
|
|||||||
AC_MSG_ERROR([C99 mode is required to build libapparmor])
|
AC_MSG_ERROR([C99 mode is required to build libapparmor])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
EXTRA_CFLAGS="-Wall $(EXTRA_WARNINGS) -fPIC"
|
||||||
|
AX_CHECK_COMPILE_FLAG([-flto-partition=none], , , [-Werror])
|
||||||
|
AS_VAR_IF([ax_cv_check_cflags__Werror__flto_partition_none], [yes],
|
||||||
|
[EXTRA_CFLAGS="$EXTRA_CFLAGS -flto-partition=none"]
|
||||||
|
,)
|
||||||
|
AC_SUBST([AM_CFLAGS], ["$EXTRA_CFLAGS"])
|
||||||
|
|
||||||
AC_OUTPUT(
|
AC_OUTPUT(
|
||||||
Makefile
|
Makefile
|
||||||
doc/Makefile
|
doc/Makefile
|
||||||
|
@@ -116,6 +116,14 @@ The specified I<file/task> does not exist or is not visible.
|
|||||||
|
|
||||||
The confinement data is too large to fit in the supplied buffer.
|
The confinement data is too large to fit in the supplied buffer.
|
||||||
|
|
||||||
|
=item B<ENOPROTOOPT>
|
||||||
|
|
||||||
|
The kernel doesn't support the SO_PEERLABEL option in sockets. This happens
|
||||||
|
mainly when the kernel lacks 'fine grained unix mediation' support. It also
|
||||||
|
can happen on LSM stacking kernels where another LSM has claimed this
|
||||||
|
interface and decides to return this error, although this is really a
|
||||||
|
corner case.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
=head1 NOTES
|
=head1 NOTES
|
||||||
|
@@ -109,12 +109,12 @@ To immediately stack a profile named "profile_a", as performed with
|
|||||||
aa_stack_profile("profile_a"), the equivalent of this shell command can be
|
aa_stack_profile("profile_a"), the equivalent of this shell command can be
|
||||||
used:
|
used:
|
||||||
|
|
||||||
$ echo -n "stackprofile profile_a" > /proc/self/attr/current
|
$ echo -n "stack profile_a" > /proc/self/attr/current
|
||||||
|
|
||||||
To stack a profile named "profile_a" at the next exec, as performed with
|
To stack a profile named "profile_a" at the next exec, as performed with
|
||||||
aa_stack_onexec("profile_a"), the equivalent of this shell command can be used:
|
aa_stack_onexec("profile_a"), the equivalent of this shell command can be used:
|
||||||
|
|
||||||
$ echo -n "stackexec profile_a" > /proc/self/attr/exec
|
$ echo -n "stack profile_a" > /proc/self/attr/exec
|
||||||
|
|
||||||
These raw AppArmor filesystem operations must only be used when using
|
These raw AppArmor filesystem operations must only be used when using
|
||||||
libapparmor is not a viable option.
|
libapparmor is not a viable option.
|
||||||
@@ -184,6 +184,7 @@ with apparmor_parser(8):
|
|||||||
/etc/passwd r,
|
/etc/passwd r,
|
||||||
|
|
||||||
# Needed for aa_stack_profile()
|
# Needed for aa_stack_profile()
|
||||||
|
change-profile -> &i_cant_be_trusted_anymore,
|
||||||
/usr/lib/libapparmor*.so* mr,
|
/usr/lib/libapparmor*.so* mr,
|
||||||
/proc/[0-9]*/attr/current w,
|
/proc/[0-9]*/attr/current w,
|
||||||
}
|
}
|
||||||
|
@@ -33,9 +33,9 @@ INCLUDES = $(all_includes)
|
|||||||
# After changing the AA_LIB_* variables, also update EXPECTED_SO_NAME.
|
# After changing the AA_LIB_* variables, also update EXPECTED_SO_NAME.
|
||||||
|
|
||||||
AA_LIB_CURRENT = 18
|
AA_LIB_CURRENT = 18
|
||||||
AA_LIB_REVISION = 0
|
AA_LIB_REVISION = 1
|
||||||
AA_LIB_AGE = 17
|
AA_LIB_AGE = 17
|
||||||
EXPECTED_SO_NAME = libapparmor.so.1.17.0
|
EXPECTED_SO_NAME = libapparmor.so.1.17.1
|
||||||
|
|
||||||
SUFFIXES = .pc.in .pc
|
SUFFIXES = .pc.in .pc
|
||||||
|
|
||||||
@@ -45,7 +45,6 @@ include $(COMMONDIR)/Make.rules
|
|||||||
BUILT_SOURCES = grammar.h scanner.h af_protos.h
|
BUILT_SOURCES = grammar.h scanner.h af_protos.h
|
||||||
AM_LFLAGS = -v
|
AM_LFLAGS = -v
|
||||||
AM_YFLAGS = -d -p aalogparse_
|
AM_YFLAGS = -d -p aalogparse_
|
||||||
AM_CFLAGS = -Wall $(EXTRA_WARNINGS) -fPIC -flto-partition=none
|
|
||||||
AM_CPPFLAGS = -D_GNU_SOURCE -I$(top_srcdir)/include/
|
AM_CPPFLAGS = -D_GNU_SOURCE -I$(top_srcdir)/include/
|
||||||
scanner.h: scanner.l
|
scanner.h: scanner.l
|
||||||
$(LEX) -v $<
|
$(LEX) -v $<
|
||||||
|
@@ -0,0 +1 @@
|
|||||||
|
type=AVC msg=audit(1709108389.303:12383): apparmor="DENIED" operation="mount" class="mount" info="failed mntpnt match" error=-13 profile="/home/user/test/testmount" name="/tmp/foo/" pid=14155 comm="testmount" flags="ro, remount"
|
@@ -0,0 +1,15 @@
|
|||||||
|
START
|
||||||
|
File: testcase_remount_01.in
|
||||||
|
Event type: AA_RECORD_DENIED
|
||||||
|
Audit ID: 1709108389.303:12383
|
||||||
|
Operation: mount
|
||||||
|
Profile: /home/user/test/testmount
|
||||||
|
Name: /tmp/foo/
|
||||||
|
Command: testmount
|
||||||
|
Info: failed mntpnt match
|
||||||
|
ErrorCode: 13
|
||||||
|
PID: 14155
|
||||||
|
Flags: ro, remount
|
||||||
|
Class: mount
|
||||||
|
Epoch: 1709108389
|
||||||
|
Audit subid: 12383
|
@@ -0,0 +1,4 @@
|
|||||||
|
/home/user/test/testmount {
|
||||||
|
mount options=(remount, ro) -> /tmp/foo/,
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1 @@
|
|||||||
|
type=AVC msg=audit(1709025786.045:43147): apparmor="DENIED" operation="umount" class="mount" profile="/home/user/test/testmount" name="/mnt/a/" pid=26697 comm="testmount"
|
@@ -0,0 +1,12 @@
|
|||||||
|
START
|
||||||
|
File: testcase_umount_01.in
|
||||||
|
Event type: AA_RECORD_DENIED
|
||||||
|
Audit ID: 1709025786.045:43147
|
||||||
|
Operation: umount
|
||||||
|
Profile: /home/user/test/testmount
|
||||||
|
Name: /mnt/a/
|
||||||
|
Command: testmount
|
||||||
|
PID: 26697
|
||||||
|
Class: mount
|
||||||
|
Epoch: 1709025786
|
||||||
|
Audit subid: 43147
|
@@ -0,0 +1,4 @@
|
|||||||
|
/home/user/test/testmount {
|
||||||
|
umount /mnt/a/,
|
||||||
|
|
||||||
|
}
|
@@ -70,7 +70,10 @@ CFLAGS = -g -pg -fprofile-arcs -ftest-coverage
|
|||||||
endif
|
endif
|
||||||
endif #CFLAGS
|
endif #CFLAGS
|
||||||
|
|
||||||
CFLAGS += -flto-partition=none
|
HAVE_FLTO_PARTITION_NONE:=$(shell ${CC} -E -flto-partition=none /dev/null 1>/dev/null 2>&1 && echo true)
|
||||||
|
ifeq ($(HAVE_FLTO_PARTITION_NONE),true)
|
||||||
|
CFLAGS += -flto-partition=none
|
||||||
|
endif
|
||||||
|
|
||||||
EXTRA_CXXFLAGS = ${CFLAGS} ${CPPFLAGS} ${CXX_WARNINGS} -std=gnu++0x
|
EXTRA_CXXFLAGS = ${CFLAGS} ${CPPFLAGS} ${CXX_WARNINGS} -std=gnu++0x
|
||||||
EXTRA_CFLAGS = ${EXTRA_CXXFLAGS} ${CPP_WARNINGS}
|
EXTRA_CFLAGS = ${EXTRA_CXXFLAGS} ${CPP_WARNINGS}
|
||||||
@@ -99,15 +102,15 @@ EXTRA_CFLAGS+=-DPACKAGE=\"${NAME}\" -DLOCALEDIR=\"${LOCALEDIR}\"
|
|||||||
SRCS = parser_common.c parser_include.c parser_interface.c parser_lex.c \
|
SRCS = parser_common.c parser_include.c parser_interface.c parser_lex.c \
|
||||||
parser_main.c parser_misc.c parser_merge.c parser_symtab.c \
|
parser_main.c parser_misc.c parser_merge.c parser_symtab.c \
|
||||||
parser_yacc.c parser_regex.c parser_variable.c parser_policy.c \
|
parser_yacc.c parser_regex.c parser_variable.c parser_policy.c \
|
||||||
parser_alias.c common_optarg.c lib.c network.c \
|
parser_alias.c common_optarg.c lib.c network.cc \
|
||||||
mount.cc dbus.cc profile.cc rule.cc signal.cc ptrace.cc \
|
mount.cc dbus.cc profile.cc rule.cc signal.cc ptrace.cc \
|
||||||
af_rule.cc af_unix.cc policy_cache.c default_features.c userns.cc \
|
af_rule.cc af_unix.cc policy_cache.c default_features.c userns.cc \
|
||||||
mqueue.cc io_uring.cc
|
mqueue.cc io_uring.cc all_rule.cc
|
||||||
STATIC_HDRS = af_rule.h af_unix.h capability.h common_optarg.h dbus.h \
|
STATIC_HDRS = af_rule.h af_unix.h capability.h common_optarg.h dbus.h \
|
||||||
file_cache.h immunix.h lib.h mount.h network.h parser.h \
|
file_cache.h immunix.h lib.h mount.h network.h parser.h \
|
||||||
parser_include.h parser_version.h policy_cache.h policydb.h \
|
parser_include.h parser_version.h policy_cache.h policydb.h \
|
||||||
profile.h ptrace.h rule.h signal.h userns.h mqueue.h io_uring.h \
|
profile.h ptrace.h rule.h signal.h userns.h mqueue.h io_uring.h \
|
||||||
common_flags.h
|
common_flags.h bignum.h all_rule.h
|
||||||
|
|
||||||
SPECIAL_HDRS = parser_yacc.h unit_test.h base_cap_names.h
|
SPECIAL_HDRS = parser_yacc.h unit_test.h base_cap_names.h
|
||||||
GENERATED_HDRS = af_names.h generated_af_names.h \
|
GENERATED_HDRS = af_names.h generated_af_names.h \
|
||||||
@@ -295,7 +298,7 @@ signal.o: signal.cc $(HDRS)
|
|||||||
ptrace.o: ptrace.cc $(HDRS)
|
ptrace.o: ptrace.cc $(HDRS)
|
||||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
network.o: network.c $(HDRS)
|
network.o: network.cc $(HDRS)
|
||||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
default_features.o: default_features.c $(HDRS)
|
default_features.o: default_features.c $(HDRS)
|
||||||
@@ -322,6 +325,9 @@ mqueue.o: mqueue.cc $(HDRS)
|
|||||||
io_uring.o: io_uring.cc $(HDRS)
|
io_uring.o: io_uring.cc $(HDRS)
|
||||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
all_rule.o: all_rule.cc $(HDRS)
|
||||||
|
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
parser_version.h: Makefile
|
parser_version.h: Makefile
|
||||||
@echo \#define PARSER_VERSION \"$(VERSION)\" > .ver
|
@echo \#define PARSER_VERSION \"$(VERSION)\" > .ver
|
||||||
@mv -f .ver $@
|
@mv -f .ver $@
|
||||||
@@ -373,13 +379,8 @@ tests: apparmor_parser ${TESTS}
|
|||||||
$(AAREOBJECT): FORCE
|
$(AAREOBJECT): FORCE
|
||||||
$(MAKE) -C $(AAREDIR) CFLAGS="$(EXTRA_CXXFLAGS)"
|
$(MAKE) -C $(AAREDIR) CFLAGS="$(EXTRA_CXXFLAGS)"
|
||||||
|
|
||||||
.PHONY: install-rhel4
|
|
||||||
install-rhel4: install-redhat
|
|
||||||
|
|
||||||
.PHONY: install-redhat
|
.PHONY: install-redhat
|
||||||
install-redhat:
|
install-redhat: install-systemd
|
||||||
install -m 755 -d $(DESTDIR)/etc/init.d
|
|
||||||
install -m 755 rc.apparmor.$(subst install-,,$@) $(DESTDIR)/etc/init.d/apparmor
|
|
||||||
|
|
||||||
.PHONY: install-suse
|
.PHONY: install-suse
|
||||||
install-suse: install-systemd
|
install-suse: install-systemd
|
||||||
@@ -410,9 +411,9 @@ DISTRO=$(shell if [ -f /etc/slackware-version ] ; then \
|
|||||||
if [ "$$(rpm --eval '0%{?suse_version}')" != "0" ] ; then \
|
if [ "$$(rpm --eval '0%{?suse_version}')" != "0" ] ; then \
|
||||||
echo suse ;\
|
echo suse ;\
|
||||||
elif [ "$$(rpm --eval '%{_host_vendor}')" = redhat ] ; then \
|
elif [ "$$(rpm --eval '%{_host_vendor}')" = redhat ] ; then \
|
||||||
echo rhel4 ;\
|
echo redhat ;\
|
||||||
elif [ "$$(rpm --eval '0%{?fedora}')" != "0" ] ; then \
|
elif [ "$$(rpm --eval '0%{?fedora}')" != "0" ] ; then \
|
||||||
echo rhel4 ;\
|
echo redhat ;\
|
||||||
else \
|
else \
|
||||||
echo unknown ;\
|
echo unknown ;\
|
||||||
fi ;\
|
fi ;\
|
||||||
|
@@ -108,6 +108,9 @@ unix_rule::unix_rule(unsigned int type_p, audit_t audit_p, rule_mode_t rule_mode
|
|||||||
perms = AA_VALID_NET_PERMS;
|
perms = AA_VALID_NET_PERMS;
|
||||||
audit = audit_p;
|
audit = audit_p;
|
||||||
rule_mode = rule_mode_p;
|
rule_mode = rule_mode_p;
|
||||||
|
/* if this constructor is used, then there's already a
|
||||||
|
* downgraded network_rule in profile */
|
||||||
|
downgrade = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
unix_rule::unix_rule(perms_t perms_p, struct cond_entry *conds,
|
unix_rule::unix_rule(perms_t perms_p, struct cond_entry *conds,
|
||||||
@@ -190,7 +193,7 @@ static void writeu16(std::ostringstream &o, int v)
|
|||||||
void unix_rule::downgrade_rule(Profile &prof) {
|
void unix_rule::downgrade_rule(Profile &prof) {
|
||||||
perms_t mask = (perms_t) -1;
|
perms_t mask = (perms_t) -1;
|
||||||
|
|
||||||
if (!prof.net.allow && !prof.alloc_net_table())
|
if (!prof.net.allow && !prof.net.alloc_net_table())
|
||||||
yyerror(_("Memory allocation error."));
|
yyerror(_("Memory allocation error."));
|
||||||
if (sock_type_n != -1)
|
if (sock_type_n != -1)
|
||||||
mask = 1 << sock_type_n;
|
mask = 1 << sock_type_n;
|
||||||
@@ -198,6 +201,11 @@ void unix_rule::downgrade_rule(Profile &prof) {
|
|||||||
prof.net.allow[AF_UNIX] |= mask;
|
prof.net.allow[AF_UNIX] |= mask;
|
||||||
if (audit == AUDIT_FORCE)
|
if (audit == AUDIT_FORCE)
|
||||||
prof.net.audit[AF_UNIX] |= mask;
|
prof.net.audit[AF_UNIX] |= mask;
|
||||||
|
const char *error;
|
||||||
|
network_rule *netv8 = new network_rule(perms, AF_UNIX, sock_type_n);
|
||||||
|
if(!netv8->add_prefix({audit, rule_mode, owner}, error))
|
||||||
|
yyerror(error);
|
||||||
|
prof.rule_ents.push_back(netv8);
|
||||||
} else {
|
} else {
|
||||||
/* deny rules have to be dropped because the downgrade makes
|
/* deny rules have to be dropped because the downgrade makes
|
||||||
* the rule less specific meaning it will make the profile more
|
* the rule less specific meaning it will make the profile more
|
||||||
@@ -317,6 +325,7 @@ int unix_rule::gen_policy_re(Profile &prof)
|
|||||||
* older kernels and be enforced to the best of the old network
|
* older kernels and be enforced to the best of the old network
|
||||||
* rules ability
|
* rules ability
|
||||||
*/
|
*/
|
||||||
|
if (downgrade)
|
||||||
downgrade_rule(prof);
|
downgrade_rule(prof);
|
||||||
if (!features_supports_unix) {
|
if (!features_supports_unix) {
|
||||||
if (features_supports_network || features_supports_networkv8) {
|
if (features_supports_network || features_supports_networkv8) {
|
||||||
|
@@ -36,6 +36,7 @@ class unix_rule: public af_rule {
|
|||||||
public:
|
public:
|
||||||
char *addr;
|
char *addr;
|
||||||
char *peer_addr;
|
char *peer_addr;
|
||||||
|
bool downgrade = true;
|
||||||
|
|
||||||
unix_rule(unsigned int type_p, audit_t audit_p, rule_mode_t rule_mode_p);
|
unix_rule(unsigned int type_p, audit_t audit_p, rule_mode_t rule_mode_p);
|
||||||
unix_rule(perms_t perms, struct cond_entry *conds,
|
unix_rule(perms_t perms, struct cond_entry *conds,
|
||||||
|
130
parser/all_rule.cc
Normal file
130
parser/all_rule.cc
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023
|
||||||
|
* 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 Canonical Ltd.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "profile.h"
|
||||||
|
#include "all_rule.h"
|
||||||
|
#include "af_unix.h"
|
||||||
|
#include "dbus.h"
|
||||||
|
#include "io_uring.h"
|
||||||
|
#include "mqueue.h"
|
||||||
|
#include "ptrace.h"
|
||||||
|
#include "signal.h"
|
||||||
|
#include "userns.h"
|
||||||
|
#include "mount.h"
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
#include <iomanip>
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void all_rule::add_implied_rules(Profile &prof)
|
||||||
|
{
|
||||||
|
prefix_rule_t *rule;
|
||||||
|
const prefixes *prefix = this;
|
||||||
|
|
||||||
|
rule = new unix_rule(0, audit, rule_mode);
|
||||||
|
(void) rule->add_prefix(*prefix);
|
||||||
|
prof.rule_ents.push_back(rule);
|
||||||
|
|
||||||
|
rule = new dbus_rule(0, NULL, NULL);
|
||||||
|
(void) rule->add_prefix(*prefix);
|
||||||
|
prof.rule_ents.push_back(rule);
|
||||||
|
|
||||||
|
rule = new io_uring_rule(0, NULL, NULL);
|
||||||
|
(void) rule->add_prefix(*prefix);
|
||||||
|
prof.rule_ents.push_back(rule);
|
||||||
|
|
||||||
|
rule = new mqueue_rule(0, NULL);
|
||||||
|
(void) rule->add_prefix(*prefix);
|
||||||
|
prof.rule_ents.push_back(rule);
|
||||||
|
|
||||||
|
rule = new ptrace_rule(0, NULL);
|
||||||
|
(void) rule->add_prefix(*prefix);
|
||||||
|
prof.rule_ents.push_back(rule);
|
||||||
|
|
||||||
|
rule = new signal_rule(0, NULL);
|
||||||
|
(void) rule->add_prefix(*prefix);
|
||||||
|
prof.rule_ents.push_back(rule);
|
||||||
|
|
||||||
|
rule = new userns_rule(0, NULL);
|
||||||
|
(void) rule->add_prefix(*prefix);
|
||||||
|
prof.rule_ents.push_back(rule);
|
||||||
|
|
||||||
|
rule = new mnt_rule(NULL, NULL, NULL, NULL, 0);
|
||||||
|
(void) rule->add_prefix(*prefix);
|
||||||
|
prof.rule_ents.push_back(rule);
|
||||||
|
|
||||||
|
rule = new mnt_rule(NULL, NULL, NULL, NULL, AA_DUMMY_REMOUNT);
|
||||||
|
(void) rule->add_prefix(*prefix);
|
||||||
|
prof.rule_ents.push_back(rule);
|
||||||
|
|
||||||
|
rule = new mnt_rule(NULL, NULL, NULL, NULL, AA_MAY_UMOUNT);
|
||||||
|
(void) rule->add_prefix(*prefix);
|
||||||
|
prof.rule_ents.push_back(rule);
|
||||||
|
|
||||||
|
rule = new mnt_rule(NULL, NULL, NULL, NULL, AA_MAY_PIVOTROOT);
|
||||||
|
(void) rule->add_prefix(*prefix);
|
||||||
|
prof.rule_ents.push_back(rule);
|
||||||
|
|
||||||
|
rule = new network_rule(0, (struct cond_entry *)NULL, (struct cond_entry *)NULL);
|
||||||
|
(void) rule->add_prefix(*prefix);
|
||||||
|
prof.rule_ents.push_back(rule);
|
||||||
|
|
||||||
|
/* rules that have not been converted to use rule.h */
|
||||||
|
|
||||||
|
//file
|
||||||
|
{
|
||||||
|
const char *error;
|
||||||
|
struct cod_entry *entry;
|
||||||
|
char *path = strdup("/{**,}");
|
||||||
|
int perms = ((AA_BASE_PERMS & ~AA_EXEC_TYPE) |
|
||||||
|
(AA_MAY_EXEC));
|
||||||
|
if (rule_mode != RULE_DENY)
|
||||||
|
perms |= AA_EXEC_INHERIT;
|
||||||
|
/* duplicate to other permission set */
|
||||||
|
perms |= perms << AA_OTHER_SHIFT;
|
||||||
|
if (!path)
|
||||||
|
yyerror(_("Memory allocation error."));
|
||||||
|
entry = new_entry(path, perms, NULL);
|
||||||
|
if (!entry_add_prefix(entry, *prefix, error)) {
|
||||||
|
yyerror(_("%s"), error);
|
||||||
|
}
|
||||||
|
add_entry_to_policy(&prof, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
// caps
|
||||||
|
{
|
||||||
|
if (prefix->owner)
|
||||||
|
yyerror(_("owner prefix not allowed on capability rules"));
|
||||||
|
|
||||||
|
if (rule_mode == RULE_DENY && audit == AUDIT_FORCE) {
|
||||||
|
prof.caps.deny |= 0xffffffffffffffff;
|
||||||
|
} else if (rule_mode == RULE_DENY) {
|
||||||
|
prof.caps.deny |= 0xffffffffffffffff;
|
||||||
|
prof.caps.quiet |= 0xffffffffffffffff;
|
||||||
|
} else {
|
||||||
|
prof.caps.allow |= 0xffffffffffffffff;
|
||||||
|
if (audit != AUDIT_UNSPECIFIED)
|
||||||
|
prof.caps.audit |= 0xffffffffffffffff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: rlimit
|
||||||
|
}
|
70
parser/all_rule.h
Normal file
70
parser/all_rule.h
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023
|
||||||
|
* 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 Canonical Ltd.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __AA_ALL_H
|
||||||
|
#define __AA_ALL_H
|
||||||
|
|
||||||
|
#include "rule.h"
|
||||||
|
|
||||||
|
#define AA_IO_URING_OVERRIDE_CREDS AA_MAY_APPEND
|
||||||
|
#define AA_IO_URING_SQPOLL AA_MAY_CREATE
|
||||||
|
|
||||||
|
#define AA_VALID_IO_URING_PERMS (AA_IO_URING_OVERRIDE_CREDS | \
|
||||||
|
AA_IO_URING_SQPOLL)
|
||||||
|
|
||||||
|
class all_rule: public prefix_rule_t {
|
||||||
|
void move_conditionals(struct cond_entry *conds);
|
||||||
|
public:
|
||||||
|
char *label;
|
||||||
|
|
||||||
|
all_rule(void): prefix_rule_t(RULE_TYPE_ALL) { }
|
||||||
|
|
||||||
|
virtual bool valid_prefix(const prefixes &p, const char *&error) {
|
||||||
|
if (p.owner) {
|
||||||
|
error = _("owner prefix not allowed on all rules");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
int expand_variables(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
virtual ostream &dump(ostream &os) {
|
||||||
|
prefix_rule_t::dump(os);
|
||||||
|
|
||||||
|
os << "all";
|
||||||
|
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
virtual bool is_mergeable(void) { return true; }
|
||||||
|
virtual int cmp(rule_t const &rhs) const
|
||||||
|
{
|
||||||
|
return prefix_rule_t::cmp(rhs);
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual void add_implied_rules(Profile &prof);
|
||||||
|
|
||||||
|
virtual int gen_policy_re(Profile &prof unused) { return RULE_OK; };
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void warn_once(const char *name unused, const char *msg unused) { };
|
||||||
|
virtual void warn_once(const char *name unused) { };
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __AA_ALL_H */
|
@@ -115,9 +115,9 @@ B<PROFILE FLAG CONDS> = [ 'flags=' ] '(' comma or white space separated list of
|
|||||||
|
|
||||||
B<PROFILE FLAGS> = I<PROFILE MODE> | I<AUDIT_MODE> | 'mediate_deleted'
|
B<PROFILE FLAGS> = I<PROFILE MODE> | I<AUDIT_MODE> | 'mediate_deleted'
|
||||||
| 'attach_disconnected' | 'attach_disconneced.path='I<ABS PATH> | 'chroot_relative'
|
| 'attach_disconnected' | 'attach_disconneced.path='I<ABS PATH> | 'chroot_relative'
|
||||||
| 'debug'
|
| 'debug' | 'interruptible' | 'kill.signal='I<SIGNAL>
|
||||||
|
|
||||||
B<PROFILE MODE> = 'enforce' | 'complain' | 'kill' | 'unconfined' | 'prompt'
|
B<PROFILE MODE> = 'enforce' | 'complain' | 'kill' | 'default_allow' | 'unconfined' | 'prompt'
|
||||||
|
|
||||||
B<AUDIT MODE> = 'audit'
|
B<AUDIT MODE> = 'audit'
|
||||||
|
|
||||||
@@ -125,7 +125,7 @@ B<RULES> = [ ( I<LINE RULES> | I<COMMA RULES> ',' | I<BLOCK RULES> )
|
|||||||
|
|
||||||
B<LINE RULES> = ( I<COMMENT> | I<INCLUDE> ) [ '\r' ] '\n'
|
B<LINE RULES> = ( I<COMMENT> | I<INCLUDE> ) [ '\r' ] '\n'
|
||||||
|
|
||||||
B<COMMA RULES> = ( I<CAPABILITY RULE> | I<NETWORK RULE> | I<MOUNT RULE> | I<PIVOT ROOT RULE> | I<UNIX RULE> | I<FILE RULE> | I<LINK RULE> | I<CHANGE_PROFILE RULE> | I<RLIMIT RULE> | I<DBUS RULE> | I<MQUEUE RULE> )
|
B<COMMA RULES> = ( I<CAPABILITY RULE> | I<NETWORK RULE> | I<MOUNT RULE> | I<PIVOT ROOT RULE> | I<UNIX RULE> | I<FILE RULE> | I<LINK RULE> | I<CHANGE_PROFILE RULE> | I<RLIMIT RULE> | I<DBUS RULE> | I<MQUEUE RULE> | I<IO_URING RULE> | I<USERNS RULE> | I<ALL RULE>)
|
||||||
|
|
||||||
B<BLOCK RULES> = ( I<SUBPROFILE> | I<HAT> | I<QUALIFIER BLOCK> )
|
B<BLOCK RULES> = ( I<SUBPROFILE> | I<HAT> | I<QUALIFIER BLOCK> )
|
||||||
|
|
||||||
@@ -192,6 +192,16 @@ B<MQUEUE LABEL> = 'label' '=' '(' '"' I<AARE> '"' | I<AARE> ')'
|
|||||||
|
|
||||||
B<MQUEUE NAME> = I<AARE>
|
B<MQUEUE NAME> = I<AARE>
|
||||||
|
|
||||||
|
B<USERNS RULE> = [ I<QUALIFIERS> ] 'userns' [ I<USERNS ACCESS PERMISSIONS> ]
|
||||||
|
|
||||||
|
B<USERNS ACCESS PERMISSIONS> = ( 'create' )
|
||||||
|
|
||||||
|
B<IO_URING RULE> = [ I<QUALIFIERS> ] 'io_uring' [ I<IO_URING ACCESS PERMISSIONS> [ I<IO_URING LABEL> ]
|
||||||
|
|
||||||
|
B<IO_URING ACCESS PERMISSIONS> = ( 'sqpoll' | 'override_creds' )
|
||||||
|
|
||||||
|
B<IO_URING LABEL> = 'label' '=' '(' '"' I<AARE> '"' | I<AARE> ')'
|
||||||
|
|
||||||
B<PIVOT ROOT RULE> = [ I<QUALIFIERS> ] pivot_root [ oldroot=I<OLD PUT FILEGLOB> ] [ I<NEW ROOT FILEGLOB> ] [ '-E<gt>' I<PROFILE NAME> ]
|
B<PIVOT ROOT RULE> = [ I<QUALIFIERS> ] pivot_root [ oldroot=I<OLD PUT FILEGLOB> ] [ I<NEW ROOT FILEGLOB> ] [ '-E<gt>' I<PROFILE NAME> ]
|
||||||
|
|
||||||
B<SOURCE FILEGLOB> = I<FILEGLOB>
|
B<SOURCE FILEGLOB> = I<FILEGLOB>
|
||||||
@@ -220,9 +230,9 @@ B<SIGNAL ACCESS> = ( 'r' | 'w' | 'rw' | 'read' | 'write' | 'send' | 'receive' )
|
|||||||
|
|
||||||
B<SIGNAL SET> = 'set' '=' '(' I<SIGNAL LIST> ')'
|
B<SIGNAL SET> = 'set' '=' '(' I<SIGNAL LIST> ')'
|
||||||
|
|
||||||
B<SIGNAL LIST> = Comma or space separated list of I<SIGNALS>
|
B<SIGNAL LIST> = Comma or space separated list of I<SIGNAL>s
|
||||||
|
|
||||||
B<SIGNALS> = ( 'hup' | 'int' | 'quit' | 'ill' | 'trap' | 'abrt' | 'bus' | 'fpe' | 'kill' | 'usr1' | 'segv' | 'usr2' | 'pipe' | 'alrm' | 'term' | 'stkflt' | 'chld' | 'cont' | 'stop' | 'stp' | 'ttin' | 'ttou' | 'urg' | 'xcpu' | 'xfsz' | 'vtalrm' | 'prof' | 'winch' | 'io' | 'pwr' | 'sys' | 'emt' | 'exists' | 'rtmin+0' ... 'rtmin+32' )
|
B<SIGNAL> = ( 'hup' | 'int' | 'quit' | 'ill' | 'trap' | 'abrt' | 'bus' | 'fpe' | 'kill' | 'usr1' | 'segv' | 'usr2' | 'pipe' | 'alrm' | 'term' | 'stkflt' | 'chld' | 'cont' | 'stop' | 'stp' | 'ttin' | 'ttou' | 'urg' | 'xcpu' | 'xfsz' | 'vtalrm' | 'prof' | 'winch' | 'io' | 'pwr' | 'sys' | 'emt' | 'exists' | 'rtmin+0' ... 'rtmin+32' )
|
||||||
|
|
||||||
B<SIGNAL PEER> = 'peer' '=' I<AARE>
|
B<SIGNAL PEER> = 'peer' '=' I<AARE>
|
||||||
|
|
||||||
@@ -336,6 +346,8 @@ B<EXEC_MODE> = ( 'safe' | 'unsafe' )
|
|||||||
|
|
||||||
B<EXEC COND> = I<FILEGLOB>
|
B<EXEC COND> = I<FILEGLOB>
|
||||||
|
|
||||||
|
B<ALL RULE> = 'all'
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
All resources and programs need a full path. There may be any number of
|
All resources and programs need a full path. There may be any number of
|
||||||
@@ -454,12 +466,36 @@ a signal to kill it.
|
|||||||
permission the action will be allowed, but the violation will be logged
|
permission the action will be allowed, but the violation will be logged
|
||||||
with a tag of the access being B<ALLOWED>.
|
with a tag of the access being B<ALLOWED>.
|
||||||
|
|
||||||
|
=item B<default_allow> This mode changes the default behavior of
|
||||||
|
apparmor from default deny to default allow. When default_allow is
|
||||||
|
specified the resulting profile will allow operations that the profile
|
||||||
|
does not have a rule for. This mode is similar to I<unconfined> but
|
||||||
|
allows for allow and deny rules, specifying audit, and domain
|
||||||
|
transitions. Profiles in this mode may be be reported as being in
|
||||||
|
I<enforce> mode or I<allow> mode when introspected from the kernel.
|
||||||
|
|
||||||
|
Note: default_allow is similar and for many profiles will be equivalent
|
||||||
|
to specifying an I<allow all,> rule in the profile. The default_allow
|
||||||
|
flag does not provide all the same option that the I<allow all,> rule
|
||||||
|
provides.
|
||||||
|
|
||||||
=item B<unconfined> This mode allows a task confined by the profile to
|
=item B<unconfined> This mode allows a task confined by the profile to
|
||||||
behave as though they are I<unconfined>. This mode allow for an
|
behave as though it is I<unconfined>. The unconfined behavior can be
|
||||||
unconfined behavior that can be later changed to confinement by using
|
later changed to confinement by using profile replacement. This mode
|
||||||
profile replacement. This mode is should not be used under regular
|
should not be used under regular deployment but can be useful during
|
||||||
deployment but can be useful during debugging and some system
|
debugging and some system initialization scenarios.
|
||||||
initialization scenarios.
|
|
||||||
|
This mode is similar to default_allow and may be emulated by
|
||||||
|
default_allow in kernels that no longer support a true unconfined
|
||||||
|
mode. It does not generally allow for specifying deny rules, or allow
|
||||||
|
rules that override the default behavior, except in a few custom
|
||||||
|
kernels where unconfined restricts a few operations. It relies on
|
||||||
|
special customized behavior of the unconfined profile in the kernel
|
||||||
|
and as such should only be used for debugging.
|
||||||
|
|
||||||
|
Note: true unconfined is being phased out, with unconfined becoming a
|
||||||
|
replaceable profile. As such unconfined mode will be emulated by a
|
||||||
|
special profile compiled with the default_allow flag in newer kernels.
|
||||||
|
|
||||||
=item B<prompt> This mode allows task mediation to send an up call to
|
=item B<prompt> This mode allows task mediation to send an up call to
|
||||||
userspace to ask for a decision when there isn't a rule covering the
|
userspace to ask for a decision when there isn't a rule covering the
|
||||||
@@ -506,6 +542,11 @@ flags to control what messages will be output. Its effect is kernel
|
|||||||
dependent, and it should never appear in policy except when trying
|
dependent, and it should never appear in policy except when trying
|
||||||
to debug kernel or policy problems.
|
to debug kernel or policy problems.
|
||||||
|
|
||||||
|
=item B<interruptible> Enables interrupts for prompt upcall to userspace.
|
||||||
|
|
||||||
|
=item B<kill.signal>=I<SIGNAL> This changes the signal that will be
|
||||||
|
sent by AppArmor when in kill mode or a kill rule has been violated.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
=head2 Access Modes
|
=head2 Access Modes
|
||||||
@@ -1133,6 +1174,89 @@ Example AppArmor Message Queue rules:
|
|||||||
# Allow create permission for a SYSV queue of label foo
|
# Allow create permission for a SYSV queue of label foo
|
||||||
mqueue create label=foo 123,
|
mqueue create label=foo 123,
|
||||||
|
|
||||||
|
=head2 User Namespace Rules
|
||||||
|
|
||||||
|
User namespaces are part of many sandboxing and containerization
|
||||||
|
solutions. They provide a way for a non-system root process to be
|
||||||
|
root within the container. Unfortunately this opens up attack surface
|
||||||
|
in the kernel and has been part of several exploit chains. As such
|
||||||
|
AppArmor can be used to restrict the creation of user namespaces to
|
||||||
|
select processes.
|
||||||
|
|
||||||
|
User namespace permission are implied when a rule does not explicitly
|
||||||
|
state an access list. The rule becomes more restrictive as further
|
||||||
|
information is specified.
|
||||||
|
|
||||||
|
Note: user namespace creation may be restricted so that it is not
|
||||||
|
available to unprivieged unconfined processes. If this is the case any
|
||||||
|
process trying to create user namespaces will require a profile that
|
||||||
|
allows the necessary permissions.
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item B<create>
|
||||||
|
|
||||||
|
Allow creation of user namespaces.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
Example userns rules:
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
# Allow all userns perms
|
||||||
|
userns,
|
||||||
|
|
||||||
|
# Allow creation of a userns
|
||||||
|
userns create,
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head2 IO_URing Rules
|
||||||
|
|
||||||
|
AppArmor supports mediation of the new Linux high speed IO interface.
|
||||||
|
There is limited mediation at this time to just a few permissions at
|
||||||
|
the moment.
|
||||||
|
|
||||||
|
IO Uring permission are implied when a rule does not explicitly state
|
||||||
|
an access list. The rule becomes more restrictive as further
|
||||||
|
information is specified.
|
||||||
|
|
||||||
|
Note: io_uring access may be restricted so that it is not available to
|
||||||
|
unprivileged unconfined processes. If this is the case any process
|
||||||
|
trying to use io_uring will require a profile that allows the
|
||||||
|
necessary io_uring permissions.
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item B<sqpoll>
|
||||||
|
|
||||||
|
All the task confined by the profile to spawn a io_uring polling
|
||||||
|
thread.
|
||||||
|
|
||||||
|
=item B<override_creds>
|
||||||
|
|
||||||
|
Grants the task confined by the profile to override (change) its
|
||||||
|
credentials to the specified label, when executing an io_uring
|
||||||
|
operation.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
Example IO_URING rules:
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
# Allow io_uring operations
|
||||||
|
io_ring,
|
||||||
|
|
||||||
|
# Allow creation of a polling thread
|
||||||
|
io_uring sqpoll,
|
||||||
|
|
||||||
|
# Allow task to override credentials during io_uring operation
|
||||||
|
io_uring override_creds label=new_creds,
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
=head2 Pivot Root Rules
|
=head2 Pivot Root Rules
|
||||||
|
|
||||||
AppArmor mediates changing of the root filesystem through the pivot_root(2)
|
AppArmor mediates changing of the root filesystem through the pivot_root(2)
|
||||||
@@ -1506,6 +1630,26 @@ Not all kernels support B<safe> mode and the parser will downgrade rules to
|
|||||||
B<unsafe> mode in that situation. If no exec mode is specified, the default is
|
B<unsafe> mode in that situation. If no exec mode is specified, the default is
|
||||||
B<safe> mode in kernels that support it.
|
B<safe> mode in kernels that support it.
|
||||||
|
|
||||||
|
=head2 all rule
|
||||||
|
|
||||||
|
The all rule is used to add a generic rule for all supported rule types.
|
||||||
|
This is useful when policy wants to define a black list instead of
|
||||||
|
white list, but can also be useful to add an access qualifier to all
|
||||||
|
rules.
|
||||||
|
|
||||||
|
Eg. Black list
|
||||||
|
|
||||||
|
allow all,
|
||||||
|
# begin blacklist
|
||||||
|
deny file,
|
||||||
|
deny unix,
|
||||||
|
|
||||||
|
|
||||||
|
Eg. Adding audit qualifier
|
||||||
|
|
||||||
|
audit access all,
|
||||||
|
|
||||||
|
|
||||||
=head2 rlimit rules
|
=head2 rlimit rules
|
||||||
|
|
||||||
AppArmor can set and control the resource limits associated with a
|
AppArmor can set and control the resource limits associated with a
|
||||||
|
@@ -6,6 +6,8 @@ After=systemd-journald-audit.socket
|
|||||||
# profile cache: /var/cache/apparmor/ and /usr/share/apparmor/cache/
|
# profile cache: /var/cache/apparmor/ and /usr/share/apparmor/cache/
|
||||||
After=var.mount var-cache.mount usr.mount usr-share.mount
|
After=var.mount var-cache.mount usr.mount usr-share.mount
|
||||||
ConditionSecurity=apparmor
|
ConditionSecurity=apparmor
|
||||||
|
Documentation=man:apparmor(7)
|
||||||
|
Documentation=https://gitlab.com/apparmor/apparmor/wikis/home/
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=oneshot
|
Type=oneshot
|
||||||
|
@@ -299,11 +299,11 @@ Enable various warnings during policy compilation. A single warn flag
|
|||||||
can be specified per --warn option, but the --warn flag can be passed
|
can be specified per --warn option, but the --warn flag can be passed
|
||||||
multiple times.
|
multiple times.
|
||||||
|
|
||||||
apparmor_parser --warn=rules-not-enforced ...
|
apparmor_parser --warn=rule-not-enforced ...
|
||||||
|
|
||||||
A specific warning can be disabled by prepending I<no>- to the flag
|
A specific warning can be disabled by prepending I<no>- to the flag
|
||||||
|
|
||||||
apparmor_parser --warn=no-rules-not-enforced ...
|
apparmor_parser --warn=no-rule-not-enforced ...
|
||||||
|
|
||||||
Use --help=warn to see a full list of which warn flags are supported.
|
Use --help=warn to see a full list of which warn flags are supported.
|
||||||
|
|
||||||
|
233
parser/bignum.h
Normal file
233
parser/bignum.h
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023
|
||||||
|
* 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 Canonical Ltd.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __AA_BIGNUM_H
|
||||||
|
#define __AA_BIGNUM_H
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <sstream>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class bignum
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::vector<uint8_t> data;
|
||||||
|
uint8_t base;
|
||||||
|
bool negative = false;
|
||||||
|
bignum () : base(0) {}
|
||||||
|
|
||||||
|
bignum (unsigned long val) {
|
||||||
|
if (val == 0)
|
||||||
|
data.push_back(val);
|
||||||
|
else {
|
||||||
|
while(val > 0) {
|
||||||
|
data.push_back(val % 10);
|
||||||
|
val /= 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
base = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
bignum (const char *val) {
|
||||||
|
while (*val) {
|
||||||
|
data.push_back(*val - 48);
|
||||||
|
val++;
|
||||||
|
}
|
||||||
|
std::reverse(data.begin(), data.end());
|
||||||
|
base = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
bignum (const uint8_t val[16]) {
|
||||||
|
size_t i;
|
||||||
|
bool flag = true;
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
if (flag && (val[i] & 0xF0) >> 4 != 0)
|
||||||
|
flag = false;
|
||||||
|
if (!flag)
|
||||||
|
data.push_back((val[i] & 0xF0) >> 4);
|
||||||
|
if (flag && (val[i] & 0x0F) != 0)
|
||||||
|
flag = false;
|
||||||
|
if (!flag)
|
||||||
|
data.push_back(val[i] & 0x0F);
|
||||||
|
}
|
||||||
|
std::reverse(data.begin(), data.end());
|
||||||
|
base = 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
bignum operator+(const bignum &brhs) const {
|
||||||
|
bignum b1 = this->size() < brhs.size() ? *this : brhs;
|
||||||
|
bignum b2 = this->size() < brhs.size() ? brhs : *this;
|
||||||
|
bignum result;
|
||||||
|
result.base = this->base;
|
||||||
|
uint8_t carryover = 0;
|
||||||
|
uint8_t sum;
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < b1.size(); i++) {
|
||||||
|
sum = b1[i] + b2[i] + carryover;
|
||||||
|
if (sum > base - 1)
|
||||||
|
carryover = 1;
|
||||||
|
else
|
||||||
|
carryover = 0;
|
||||||
|
result.data.push_back(sum % base);
|
||||||
|
}
|
||||||
|
for (; i < b2.size(); i++) {
|
||||||
|
sum = b2[i] + carryover;
|
||||||
|
if (sum > base - 1)
|
||||||
|
carryover = 1;
|
||||||
|
else
|
||||||
|
carryover = 0;
|
||||||
|
result.data.push_back(sum % base);
|
||||||
|
}
|
||||||
|
if (carryover != 0)
|
||||||
|
result.data.push_back(carryover);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bignum operator-(const bignum &brhs) const {
|
||||||
|
bignum b1 = this->size() < brhs.size() ? *this : brhs;
|
||||||
|
bignum b2 = this->size() < brhs.size() ? brhs : *this;
|
||||||
|
bignum result;
|
||||||
|
result.negative = *this < brhs;
|
||||||
|
result.base = this->base;
|
||||||
|
int8_t borrow = 0;
|
||||||
|
int8_t sub;
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < b1.size(); i++) {
|
||||||
|
sub = b2[i] - b1[i] - borrow;
|
||||||
|
if (sub < 0) {
|
||||||
|
sub += base;
|
||||||
|
borrow = 1;
|
||||||
|
} else
|
||||||
|
borrow = 0;
|
||||||
|
result.data.push_back(sub);
|
||||||
|
}
|
||||||
|
for (; i < b2.size(); i++) {
|
||||||
|
sub = b2[i] - borrow;
|
||||||
|
if (sub < 0) {
|
||||||
|
sub += base;
|
||||||
|
borrow = 1;
|
||||||
|
} else
|
||||||
|
borrow = 0;
|
||||||
|
result.data.push_back(sub);
|
||||||
|
}
|
||||||
|
if (borrow) {
|
||||||
|
int8_t tmp = result.data[result.size() - 1] -= base;
|
||||||
|
tmp *= -1;
|
||||||
|
result.data[result.size() - 1] = tmp;
|
||||||
|
}
|
||||||
|
while (result.size() > 1 && result.data[result.size() - 1] == 0)
|
||||||
|
result.data.pop_back();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
bool operator>=(const bignum &rhs) const {
|
||||||
|
return cmp_bignum(this->data, rhs.data) >= 0;
|
||||||
|
}
|
||||||
|
bool operator<=(const bignum &rhs) const {
|
||||||
|
return cmp_bignum(this->data, rhs.data) <= 0;
|
||||||
|
}
|
||||||
|
bool operator>(const bignum &rhs) const {
|
||||||
|
return cmp_bignum(this->data, rhs.data) > 0;
|
||||||
|
}
|
||||||
|
bool operator<(const bignum &rhs) const {
|
||||||
|
return cmp_bignum(this->data, rhs.data) < 0;
|
||||||
|
}
|
||||||
|
int operator[](int index) const {
|
||||||
|
return this->data[index];
|
||||||
|
}
|
||||||
|
friend std::ostream &operator<<(std::ostream &os, bignum &bn);
|
||||||
|
size_t size() const {
|
||||||
|
return data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
returns:
|
||||||
|
- 0, if the lhs and rhs are equal;
|
||||||
|
- a negative value if lhs is less than rhs;
|
||||||
|
- a positive value if lhs is greater than rhs.
|
||||||
|
*/
|
||||||
|
int cmp_bignum(std::vector<uint8_t> lhs, std::vector<uint8_t> rhs) const
|
||||||
|
{
|
||||||
|
if (lhs.size() > rhs.size())
|
||||||
|
return 1;
|
||||||
|
else if (lhs.size() < rhs.size())
|
||||||
|
return -1;
|
||||||
|
else {
|
||||||
|
/* assumes the digits are stored in reverse order */
|
||||||
|
std::reverse(lhs.begin(), lhs.end());
|
||||||
|
std::reverse(rhs.begin(), rhs.end());
|
||||||
|
for (size_t i = 0; i < lhs.size(); i++) {
|
||||||
|
if (lhs[i] > rhs[i])
|
||||||
|
return 1;
|
||||||
|
if (lhs[i] < rhs[i])
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bignum lower_bound_regex(bignum val)
|
||||||
|
{
|
||||||
|
/* single digit numbers reduce to 0 */
|
||||||
|
if (val.size() == 1) {
|
||||||
|
val.data[0] = 0;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& j : val.data) {
|
||||||
|
uint8_t tmp = j;
|
||||||
|
j = 0;
|
||||||
|
if (tmp != val.base - 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (&j == &val.data[val.size()-2]) {
|
||||||
|
val.data[val.size()-1] = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static bignum upper_bound_regex(bignum val)
|
||||||
|
{
|
||||||
|
for (auto& j : val.data) {
|
||||||
|
uint8_t tmp = j;
|
||||||
|
j = val.base - 1;
|
||||||
|
if (tmp != 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
inline std::ostream &operator<<(std::ostream &os, bignum &bn)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
bignum tmp = bn;
|
||||||
|
std::reverse(tmp.data.begin(), tmp.data.end());
|
||||||
|
for (auto i : tmp.data)
|
||||||
|
ss << std::hex << (int) i;
|
||||||
|
os << ss.str();
|
||||||
|
return os;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __AA_BIGNUM_H */
|
@@ -12,7 +12,7 @@
|
|||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, contact or Canonical Ltd.
|
* along with this program; if not, contact Canonical Ltd.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "common_optarg.h"
|
#include "common_optarg.h"
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, contact or Canonical Ltd.
|
* along with this program; if not, contact Canonical Ltd.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __AA_IO_URING_H
|
#ifndef __AA_IO_URING_H
|
||||||
|
@@ -72,6 +72,7 @@ static inline Chars* insert_char_range(Chars* cset, transchar a, transchar b)
|
|||||||
* parsing succeeds!
|
* parsing succeeds!
|
||||||
*/
|
*/
|
||||||
%destructor { $$->release(); } expr terms0 terms qterm term
|
%destructor { $$->release(); } expr terms0 terms qterm term
|
||||||
|
%destructor { delete $$; } charset cset_chars
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
|
396
parser/network.c
396
parser/network.c
@@ -1,396 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014
|
|
||||||
* 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>
|
|
||||||
#include <sys/apparmor.h>
|
|
||||||
|
|
||||||
#include <iomanip>
|
|
||||||
#include <string>
|
|
||||||
#include <sstream>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include "lib.h"
|
|
||||||
#include "parser.h"
|
|
||||||
#include "profile.h"
|
|
||||||
#include "parser_yacc.h"
|
|
||||||
#include "network.h"
|
|
||||||
|
|
||||||
|
|
||||||
int parse_net_perms(const char *str_mode, perms_t *mode, int fail)
|
|
||||||
{
|
|
||||||
return parse_X_perms("net", AA_VALID_NET_PERMS, str_mode, mode, fail);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Bleah C++ doesn't have non-trivial designated initializers so we just
|
|
||||||
* have to make sure these are in order. This means we are more brittle
|
|
||||||
* but there isn't much we can do.
|
|
||||||
*/
|
|
||||||
struct sock_type_map {
|
|
||||||
const char *name;
|
|
||||||
int value;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sock_type_map sock_types[] = {
|
|
||||||
{ "none", 0 },
|
|
||||||
{ "stream", SOCK_STREAM },
|
|
||||||
{ "dgram", SOCK_DGRAM },
|
|
||||||
{ "raw", SOCK_RAW },
|
|
||||||
{ "rdm", SOCK_RDM },
|
|
||||||
{ "seqpacket", SOCK_SEQPACKET },
|
|
||||||
{ "dccp", SOCK_DCCP },
|
|
||||||
{ "invalid", -1 },
|
|
||||||
{ "invalid", -1 },
|
|
||||||
{ "invalid", -1 },
|
|
||||||
{ "packet", SOCK_PACKET },
|
|
||||||
{ NULL, -1 },
|
|
||||||
/*
|
|
||||||
* See comment above
|
|
||||||
*/
|
|
||||||
};
|
|
||||||
|
|
||||||
int net_find_type_val(const char *type)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0; sock_types[i].name; i++) {
|
|
||||||
if (strcmp(sock_types[i].name, type) == 0)
|
|
||||||
return sock_types[i].value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *net_find_type_name(int type)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0; sock_types[i].name; i++) {
|
|
||||||
if (sock_types[i].value == type)
|
|
||||||
return sock_types[i].name;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* FIXME: currently just treating as a bit mask this will have to change
|
|
||||||
* set up a table of mappings, there can be several mappings for a
|
|
||||||
* given match.
|
|
||||||
* currently the mapping does not set the protocol for stream/dgram to
|
|
||||||
* anything other than 0.
|
|
||||||
* network inet tcp -> network inet stream 0 instead of
|
|
||||||
* network inet raw tcp.
|
|
||||||
* some entries are just provided for completeness at this time
|
|
||||||
*/
|
|
||||||
/* values stolen from /etc/protocols - needs to change */
|
|
||||||
#define RAW_TCP 6
|
|
||||||
#define RAW_UDP 17
|
|
||||||
#define RAW_ICMP 1
|
|
||||||
#define RAW_ICMPv6 58
|
|
||||||
|
|
||||||
/* used by af_name.h to auto generate table entries for "name", AF_NAME
|
|
||||||
* pair */
|
|
||||||
#define AA_GEN_NET_ENT(name, AF) \
|
|
||||||
{name, AF, "stream", SOCK_STREAM, "", 0xffffff}, \
|
|
||||||
{name, AF, "dgram", SOCK_DGRAM, "", 0xffffff}, \
|
|
||||||
{name, AF, "seqpacket", SOCK_SEQPACKET, "", 0xffffff}, \
|
|
||||||
{name, AF, "rdm", SOCK_RDM, "", 0xffffff}, \
|
|
||||||
{name, AF, "raw", SOCK_RAW, "", 0xffffff}, \
|
|
||||||
{name, AF, "packet", SOCK_PACKET, "", 0xffffff},
|
|
||||||
/*FIXME: missing {name, AF, "dccp", SOCK_DCCP, "", 0xfffffff}, */
|
|
||||||
|
|
||||||
static struct network_tuple network_mappings[] = {
|
|
||||||
/* basic types */
|
|
||||||
#include "af_names.h"
|
|
||||||
/* FIXME: af_names.h is missing AF_LLC, AF_TIPC */
|
|
||||||
/* mapped types */
|
|
||||||
{"inet", AF_INET, "raw", SOCK_RAW,
|
|
||||||
"tcp", 1 << RAW_TCP},
|
|
||||||
{"inet", AF_INET, "raw", SOCK_RAW,
|
|
||||||
"udp", 1 << RAW_UDP},
|
|
||||||
{"inet", AF_INET, "raw", SOCK_RAW,
|
|
||||||
"icmp", 1 << RAW_ICMP},
|
|
||||||
{"inet", AF_INET, "tcp", SOCK_STREAM,
|
|
||||||
"", 0xffffffff}, /* should we give raw tcp too? */
|
|
||||||
{"inet", AF_INET, "udp", SOCK_DGRAM,
|
|
||||||
"", 0xffffffff}, /* should these be open masks? */
|
|
||||||
{"inet", AF_INET, "icmp", SOCK_RAW,
|
|
||||||
"", 1 << RAW_ICMP},
|
|
||||||
{"inet6", AF_INET6, "tcp", SOCK_STREAM,
|
|
||||||
"", 0xffffffff},
|
|
||||||
{"inet6", AF_INET6, "udp", SOCK_DGRAM,
|
|
||||||
"", 0xffffffff},
|
|
||||||
/* what do we do with icmp on inet6?
|
|
||||||
{"inet6", AF_INET, "icmp", SOCK_RAW, 0},
|
|
||||||
{"inet6", AF_INET, "icmpv6", SOCK_RAW, 0},
|
|
||||||
*/
|
|
||||||
/* terminate */
|
|
||||||
{NULL, 0, NULL, 0, NULL, 0}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* The apparmor kernel patches up until 2.6.38 didn't handle networking
|
|
||||||
* tables with sizes > AF_MAX correctly. This could happen when the
|
|
||||||
* parser was built against newer kernel headers and then used to load
|
|
||||||
* policy on an older kernel. This could happen during upgrades or
|
|
||||||
* in multi-kernel boot systems.
|
|
||||||
*
|
|
||||||
* Try to detect the running kernel version and use that to determine
|
|
||||||
* AF_MAX
|
|
||||||
*/
|
|
||||||
#define PROC_VERSION "/proc/sys/kernel/osrelease"
|
|
||||||
static size_t kernel_af_max(void) {
|
|
||||||
char buffer[32];
|
|
||||||
int major;
|
|
||||||
autoclose int fd = -1;
|
|
||||||
int res;
|
|
||||||
|
|
||||||
if (!net_af_max_override) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/* the override parameter is specifying the max value */
|
|
||||||
if (net_af_max_override > 0)
|
|
||||||
return net_af_max_override;
|
|
||||||
|
|
||||||
fd = open(PROC_VERSION, O_RDONLY);
|
|
||||||
if (fd == -1)
|
|
||||||
/* fall back to default provided during build */
|
|
||||||
return 0;
|
|
||||||
res = read(fd, &buffer, sizeof(buffer) - 1);
|
|
||||||
if (res <= 0)
|
|
||||||
return 0;
|
|
||||||
buffer[res] = '\0';
|
|
||||||
res = sscanf(buffer, "2.6.%d", &major);
|
|
||||||
if (res != 1)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
switch(major) {
|
|
||||||
case 24:
|
|
||||||
case 25:
|
|
||||||
case 26:
|
|
||||||
return 34;
|
|
||||||
case 27:
|
|
||||||
return 35;
|
|
||||||
case 28:
|
|
||||||
case 29:
|
|
||||||
case 30:
|
|
||||||
return 36;
|
|
||||||
case 31:
|
|
||||||
case 32:
|
|
||||||
case 33:
|
|
||||||
case 34:
|
|
||||||
case 35:
|
|
||||||
return 37;
|
|
||||||
case 36:
|
|
||||||
case 37:
|
|
||||||
return 38;
|
|
||||||
/* kernels .38 and later should handle this correctly so no
|
|
||||||
* static mapping needed
|
|
||||||
*/
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Yuck. We grab AF_* values to define above from linux/socket.h because
|
|
||||||
* they are more accurate than sys/socket.h for what the kernel actually
|
|
||||||
* supports. However, we can't just include linux/socket.h directly,
|
|
||||||
* because the AF_* definitions are protected with an ifdef KERNEL
|
|
||||||
* wrapper, but we don't want to define that because that can cause
|
|
||||||
* other redefinitions from glibc. However, because the kernel may have
|
|
||||||
* more definitions than glibc, we need make sure AF_MAX reflects this,
|
|
||||||
* hence the wrapping function.
|
|
||||||
*/
|
|
||||||
size_t get_af_max() {
|
|
||||||
size_t af_max;
|
|
||||||
/* HACK: declare that version without "create" had a static AF_MAX */
|
|
||||||
if (!perms_create && !net_af_max_override)
|
|
||||||
net_af_max_override = -1;
|
|
||||||
|
|
||||||
#if AA_AF_MAX > AF_MAX
|
|
||||||
af_max = AA_AF_MAX;
|
|
||||||
#else
|
|
||||||
af_max = AF_MAX;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* HACK: some kernels didn't handle network tables from parsers
|
|
||||||
* compiled against newer kernel headers as they are larger than
|
|
||||||
* the running kernel expected. If net_override is defined check
|
|
||||||
* to see if there is a static max specified for that kernel
|
|
||||||
*/
|
|
||||||
if (net_af_max_override) {
|
|
||||||
size_t max = kernel_af_max();
|
|
||||||
if (max && max < af_max)
|
|
||||||
return max;
|
|
||||||
}
|
|
||||||
|
|
||||||
return af_max;
|
|
||||||
}
|
|
||||||
struct aa_network_entry *new_network_ent(unsigned int family,
|
|
||||||
unsigned int type,
|
|
||||||
unsigned int protocol)
|
|
||||||
{
|
|
||||||
struct aa_network_entry *new_entry;
|
|
||||||
new_entry = (struct aa_network_entry *) calloc(1, sizeof(struct aa_network_entry));
|
|
||||||
if (new_entry) {
|
|
||||||
new_entry->family = family;
|
|
||||||
new_entry->type = type;
|
|
||||||
new_entry->protocol = protocol;
|
|
||||||
new_entry->next = NULL;
|
|
||||||
}
|
|
||||||
return new_entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const struct network_tuple *net_find_mapping(const struct network_tuple *map,
|
|
||||||
const char *family,
|
|
||||||
const char *type,
|
|
||||||
const char *protocol)
|
|
||||||
{
|
|
||||||
if (!map)
|
|
||||||
map = network_mappings;
|
|
||||||
else
|
|
||||||
/* assumes it points to last entry returned */
|
|
||||||
map++;
|
|
||||||
|
|
||||||
for (; map->family_name; map++) {
|
|
||||||
if (family) {
|
|
||||||
PDEBUG("Checking family %s\n", map->family_name);
|
|
||||||
if (strcmp(family, map->family_name) != 0)
|
|
||||||
continue;
|
|
||||||
PDEBUG("Found family %s\n", family);
|
|
||||||
}
|
|
||||||
if (type) {
|
|
||||||
PDEBUG("Checking type %s\n", map->type_name);
|
|
||||||
if (strcmp(type, map->type_name) != 0)
|
|
||||||
continue;
|
|
||||||
PDEBUG("Found type %s\n", type);
|
|
||||||
}
|
|
||||||
if (protocol) {
|
|
||||||
/* allows the proto to be the "type", ie. tcp implies
|
|
||||||
* stream */
|
|
||||||
if (!type) {
|
|
||||||
PDEBUG("Checking protocol type %s\n", map->type_name);
|
|
||||||
if (strcmp(protocol, map->type_name) == 0)
|
|
||||||
goto match;
|
|
||||||
}
|
|
||||||
PDEBUG("Checking type %s protocol %s\n", map->type_name, map->protocol_name);
|
|
||||||
if (strcmp(protocol, map->protocol_name) != 0)
|
|
||||||
continue;
|
|
||||||
/* fixme should we allow specifying protocol by #
|
|
||||||
* without needing the protocol mapping? */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if we get this far we have a match */
|
|
||||||
match:
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct aa_network_entry *network_entry(const char *family, const char *type,
|
|
||||||
const char *protocol)
|
|
||||||
{
|
|
||||||
struct aa_network_entry *new_entry, *entry = NULL;
|
|
||||||
const struct network_tuple *mapping = NULL;
|
|
||||||
|
|
||||||
while ((mapping = net_find_mapping(mapping, family, type, protocol))) {
|
|
||||||
new_entry = new_network_ent(mapping->family, mapping->type,
|
|
||||||
mapping->protocol);
|
|
||||||
if (!new_entry)
|
|
||||||
yyerror(_("Memory allocation error."));
|
|
||||||
new_entry->next = entry;
|
|
||||||
entry = new_entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
return entry;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define ALL_TYPES 0x43e
|
|
||||||
|
|
||||||
const char *net_find_af_name(unsigned int af)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
if (af < 0 || af > get_af_max())
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
for (i = 0; i < sizeof(network_mappings) / sizeof(*network_mappings); i++) {
|
|
||||||
if (network_mappings[i].family == af)
|
|
||||||
return network_mappings[i].family_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void __debug_network(unsigned int *array, const char *name)
|
|
||||||
{
|
|
||||||
unsigned int count = sizeof(sock_types)/sizeof(sock_types[0]);
|
|
||||||
unsigned int mask = ~((1 << count) -1);
|
|
||||||
unsigned int i, j;
|
|
||||||
int none = 1;
|
|
||||||
size_t af_max = get_af_max();
|
|
||||||
|
|
||||||
for (i = AF_UNSPEC; i < af_max; i++)
|
|
||||||
if (array[i]) {
|
|
||||||
none = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (none)
|
|
||||||
return;
|
|
||||||
|
|
||||||
printf("%s: ", name);
|
|
||||||
|
|
||||||
/* This can only be set by an unqualified network rule */
|
|
||||||
if (array[AF_UNSPEC]) {
|
|
||||||
printf("<all>\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < af_max; i++) {
|
|
||||||
if (array[i]) {
|
|
||||||
const char *fam = net_find_af_name(i);
|
|
||||||
if (fam)
|
|
||||||
printf("%s ", fam);
|
|
||||||
else
|
|
||||||
printf("#%u ", i);
|
|
||||||
|
|
||||||
/* All types/protocols */
|
|
||||||
if (array[i] == 0xffffffff || array[i] == ALL_TYPES)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
printf("{ ");
|
|
||||||
|
|
||||||
for (j = 0; j < count; j++) {
|
|
||||||
const char *type;
|
|
||||||
if (array[i] & (1 << j)) {
|
|
||||||
type = sock_types[j].name;
|
|
||||||
if (type)
|
|
||||||
printf("%s ", type);
|
|
||||||
else
|
|
||||||
printf("#%u ", j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (array[i] & mask)
|
|
||||||
printf("#%x ", array[i] & mask);
|
|
||||||
|
|
||||||
printf("} ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
783
parser/network.cc
Normal file
783
parser/network.cc
Normal file
@@ -0,0 +1,783 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014
|
||||||
|
* 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 <iomanip>
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include <map>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
|
#include "parser.h"
|
||||||
|
#include "profile.h"
|
||||||
|
#include "network.h"
|
||||||
|
|
||||||
|
#define ALL_TYPES 0x43e
|
||||||
|
|
||||||
|
int parse_net_perms(const char *str_mode, perms_t *mode, int fail)
|
||||||
|
{
|
||||||
|
return parse_X_perms("net", AA_VALID_NET_PERMS, str_mode, mode, fail);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bleah C++ doesn't have non-trivial designated initializers so we just
|
||||||
|
* have to make sure these are in order. This means we are more brittle
|
||||||
|
* but there isn't much we can do.
|
||||||
|
*/
|
||||||
|
struct sock_type_map {
|
||||||
|
const char *name;
|
||||||
|
int value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sock_type_map sock_types[] = {
|
||||||
|
{ "none", 0 },
|
||||||
|
{ "stream", SOCK_STREAM },
|
||||||
|
{ "dgram", SOCK_DGRAM },
|
||||||
|
{ "raw", SOCK_RAW },
|
||||||
|
{ "rdm", SOCK_RDM },
|
||||||
|
{ "seqpacket", SOCK_SEQPACKET },
|
||||||
|
{ "dccp", SOCK_DCCP },
|
||||||
|
{ "invalid", -1 },
|
||||||
|
{ "invalid", -1 },
|
||||||
|
{ "invalid", -1 },
|
||||||
|
{ "packet", SOCK_PACKET },
|
||||||
|
{ NULL, -1 },
|
||||||
|
/*
|
||||||
|
* See comment above
|
||||||
|
*/
|
||||||
|
};
|
||||||
|
|
||||||
|
int net_find_type_val(const char *type)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; sock_types[i].name; i++) {
|
||||||
|
if (strcmp(sock_types[i].name, type) == 0)
|
||||||
|
return sock_types[i].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *net_find_type_name(int type)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; sock_types[i].name; i++) {
|
||||||
|
if (sock_types[i].value == type)
|
||||||
|
return sock_types[i].name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* FIXME: currently just treating as a bit mask this will have to change
|
||||||
|
* set up a table of mappings, there can be several mappings for a
|
||||||
|
* given match.
|
||||||
|
* currently the mapping does not set the protocol for stream/dgram to
|
||||||
|
* anything other than 0.
|
||||||
|
* network inet tcp -> network inet stream 0 instead of
|
||||||
|
* network inet raw tcp.
|
||||||
|
* some entries are just provided for completeness at this time
|
||||||
|
*/
|
||||||
|
/* values stolen from /etc/protocols - needs to change */
|
||||||
|
#define RAW_TCP 6
|
||||||
|
#define RAW_UDP 17
|
||||||
|
#define RAW_ICMP 1
|
||||||
|
#define RAW_ICMPv6 58
|
||||||
|
|
||||||
|
/* used by af_name.h to auto generate table entries for "name", AF_NAME
|
||||||
|
* pair */
|
||||||
|
#define AA_GEN_NET_ENT(name, AF) \
|
||||||
|
{name, AF, "stream", SOCK_STREAM, "", 0xffffff}, \
|
||||||
|
{name, AF, "dgram", SOCK_DGRAM, "", 0xffffff}, \
|
||||||
|
{name, AF, "seqpacket", SOCK_SEQPACKET, "", 0xffffff}, \
|
||||||
|
{name, AF, "rdm", SOCK_RDM, "", 0xffffff}, \
|
||||||
|
{name, AF, "raw", SOCK_RAW, "", 0xffffff}, \
|
||||||
|
{name, AF, "packet", SOCK_PACKET, "", 0xffffff},
|
||||||
|
/*FIXME: missing {name, AF, "dccp", SOCK_DCCP, "", 0xfffffff}, */
|
||||||
|
|
||||||
|
static struct network_tuple network_mappings[] = {
|
||||||
|
/* basic types */
|
||||||
|
#include "af_names.h"
|
||||||
|
/* FIXME: af_names.h is missing AF_LLC, AF_TIPC */
|
||||||
|
/* mapped types */
|
||||||
|
{"inet", AF_INET, "raw", SOCK_RAW,
|
||||||
|
"tcp", 1 << RAW_TCP},
|
||||||
|
{"inet", AF_INET, "raw", SOCK_RAW,
|
||||||
|
"udp", 1 << RAW_UDP},
|
||||||
|
{"inet", AF_INET, "raw", SOCK_RAW,
|
||||||
|
"icmp", 1 << RAW_ICMP},
|
||||||
|
{"inet", AF_INET, "tcp", SOCK_STREAM,
|
||||||
|
"", 0xffffffff}, /* should we give raw tcp too? */
|
||||||
|
{"inet", AF_INET, "udp", SOCK_DGRAM,
|
||||||
|
"", 0xffffffff}, /* should these be open masks? */
|
||||||
|
{"inet", AF_INET, "icmp", SOCK_RAW,
|
||||||
|
"", 1 << RAW_ICMP},
|
||||||
|
{"inet6", AF_INET6, "tcp", SOCK_STREAM,
|
||||||
|
"", 0xffffffff},
|
||||||
|
{"inet6", AF_INET6, "udp", SOCK_DGRAM,
|
||||||
|
"", 0xffffffff},
|
||||||
|
/* what do we do with icmp on inet6?
|
||||||
|
{"inet6", AF_INET, "icmp", SOCK_RAW, 0},
|
||||||
|
{"inet6", AF_INET, "icmpv6", SOCK_RAW, 0},
|
||||||
|
*/
|
||||||
|
/* terminate */
|
||||||
|
{NULL, 0, NULL, 0, NULL, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The apparmor kernel patches up until 2.6.38 didn't handle networking
|
||||||
|
* tables with sizes > AF_MAX correctly. This could happen when the
|
||||||
|
* parser was built against newer kernel headers and then used to load
|
||||||
|
* policy on an older kernel. This could happen during upgrades or
|
||||||
|
* in multi-kernel boot systems.
|
||||||
|
*
|
||||||
|
* Try to detect the running kernel version and use that to determine
|
||||||
|
* AF_MAX
|
||||||
|
*/
|
||||||
|
#define PROC_VERSION "/proc/sys/kernel/osrelease"
|
||||||
|
static size_t kernel_af_max(void) {
|
||||||
|
char buffer[32];
|
||||||
|
int major;
|
||||||
|
autoclose int fd = -1;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (!net_af_max_override) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* the override parameter is specifying the max value */
|
||||||
|
if (net_af_max_override > 0)
|
||||||
|
return net_af_max_override;
|
||||||
|
|
||||||
|
fd = open(PROC_VERSION, O_RDONLY);
|
||||||
|
if (fd == -1)
|
||||||
|
/* fall back to default provided during build */
|
||||||
|
return 0;
|
||||||
|
res = read(fd, &buffer, sizeof(buffer) - 1);
|
||||||
|
if (res <= 0)
|
||||||
|
return 0;
|
||||||
|
buffer[res] = '\0';
|
||||||
|
res = sscanf(buffer, "2.6.%d", &major);
|
||||||
|
if (res != 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
switch(major) {
|
||||||
|
case 24:
|
||||||
|
case 25:
|
||||||
|
case 26:
|
||||||
|
return 34;
|
||||||
|
case 27:
|
||||||
|
return 35;
|
||||||
|
case 28:
|
||||||
|
case 29:
|
||||||
|
case 30:
|
||||||
|
return 36;
|
||||||
|
case 31:
|
||||||
|
case 32:
|
||||||
|
case 33:
|
||||||
|
case 34:
|
||||||
|
case 35:
|
||||||
|
return 37;
|
||||||
|
case 36:
|
||||||
|
case 37:
|
||||||
|
return 38;
|
||||||
|
/* kernels .38 and later should handle this correctly so no
|
||||||
|
* static mapping needed
|
||||||
|
*/
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Yuck. We grab AF_* values to define above from linux/socket.h because
|
||||||
|
* they are more accurate than sys/socket.h for what the kernel actually
|
||||||
|
* supports. However, we can't just include linux/socket.h directly,
|
||||||
|
* because the AF_* definitions are protected with an ifdef KERNEL
|
||||||
|
* wrapper, but we don't want to define that because that can cause
|
||||||
|
* other redefinitions from glibc. However, because the kernel may have
|
||||||
|
* more definitions than glibc, we need make sure AF_MAX reflects this,
|
||||||
|
* hence the wrapping function.
|
||||||
|
*/
|
||||||
|
size_t get_af_max() {
|
||||||
|
size_t af_max;
|
||||||
|
/* HACK: declare that version without "create" had a static AF_MAX */
|
||||||
|
if (!perms_create && !net_af_max_override)
|
||||||
|
net_af_max_override = -1;
|
||||||
|
|
||||||
|
#if AA_AF_MAX > AF_MAX
|
||||||
|
af_max = AA_AF_MAX;
|
||||||
|
#else
|
||||||
|
af_max = AF_MAX;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* HACK: some kernels didn't handle network tables from parsers
|
||||||
|
* compiled against newer kernel headers as they are larger than
|
||||||
|
* the running kernel expected. If net_override is defined check
|
||||||
|
* to see if there is a static max specified for that kernel
|
||||||
|
*/
|
||||||
|
if (net_af_max_override) {
|
||||||
|
size_t max = kernel_af_max();
|
||||||
|
if (max && max < af_max)
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
return af_max;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *net_find_af_name(unsigned int af)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (af < 0 || af > get_af_max())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(network_mappings) / sizeof(*network_mappings); i++) {
|
||||||
|
if (network_mappings[i].family == af)
|
||||||
|
return network_mappings[i].family_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct network_tuple *net_find_mapping(const struct network_tuple *map,
|
||||||
|
const char *family,
|
||||||
|
const char *type,
|
||||||
|
const char *protocol)
|
||||||
|
{
|
||||||
|
if (!map)
|
||||||
|
map = network_mappings;
|
||||||
|
else
|
||||||
|
/* assumes it points to last entry returned */
|
||||||
|
map++;
|
||||||
|
|
||||||
|
for (; map->family_name; map++) {
|
||||||
|
if (family) {
|
||||||
|
PDEBUG("Checking family %s\n", map->family_name);
|
||||||
|
if (strcmp(family, map->family_name) != 0)
|
||||||
|
continue;
|
||||||
|
PDEBUG("Found family %s\n", family);
|
||||||
|
}
|
||||||
|
if (type) {
|
||||||
|
PDEBUG("Checking type %s\n", map->type_name);
|
||||||
|
if (strcmp(type, map->type_name) != 0)
|
||||||
|
continue;
|
||||||
|
PDEBUG("Found type %s\n", type);
|
||||||
|
}
|
||||||
|
if (protocol) {
|
||||||
|
/* allows the proto to be the "type", ie. tcp implies
|
||||||
|
* stream */
|
||||||
|
if (!type) {
|
||||||
|
PDEBUG("Checking protocol type %s\n", map->type_name);
|
||||||
|
if (strcmp(protocol, map->type_name) == 0)
|
||||||
|
goto match;
|
||||||
|
}
|
||||||
|
PDEBUG("Checking type %s protocol %s\n", map->type_name, map->protocol_name);
|
||||||
|
if (strcmp(protocol, map->protocol_name) != 0)
|
||||||
|
continue;
|
||||||
|
/* fixme should we allow specifying protocol by #
|
||||||
|
* without needing the protocol mapping? */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if we get this far we have a match */
|
||||||
|
match:
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parse_ipv4_address(const char *input, struct ip_address *result)
|
||||||
|
{
|
||||||
|
struct in_addr addr;
|
||||||
|
if (inet_pton(AF_INET, input, &addr) == 1) {
|
||||||
|
result->family = AF_INET;
|
||||||
|
result->address.address_v4 = addr.s_addr;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parse_ipv6_address(const char *input, struct ip_address *result)
|
||||||
|
{
|
||||||
|
struct in6_addr addr;
|
||||||
|
if (inet_pton(AF_INET6, input, &addr) == 1) {
|
||||||
|
result->family = AF_INET6;
|
||||||
|
memcpy(result->address.address_v6, addr.s6_addr, 16);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parse_ip(const char *ip, struct ip_address *result)
|
||||||
|
{
|
||||||
|
return parse_ipv6_address(ip, result) ||
|
||||||
|
parse_ipv4_address(ip, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parse_port_number(const char *port_entry, uint16_t *port) {
|
||||||
|
char *eptr;
|
||||||
|
unsigned long port_tmp = strtoul(port_entry, &eptr, 10);
|
||||||
|
|
||||||
|
if (port_tmp >= 0 && port_entry != eptr &&
|
||||||
|
*eptr == '\0' && port_tmp <= UINT16_MAX) {
|
||||||
|
*port = port_tmp;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool network_rule::parse_port(ip_conds &entry)
|
||||||
|
{
|
||||||
|
entry.is_port = true;
|
||||||
|
return parse_port_number(entry.sport, &entry.port);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool network_rule::parse_address(ip_conds &entry)
|
||||||
|
{
|
||||||
|
entry.is_ip = true;
|
||||||
|
return parse_ip(entry.sip, &entry.ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
void network_rule::move_conditionals(struct cond_entry *conds, ip_conds &ip_cond)
|
||||||
|
{
|
||||||
|
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 network rules\n");
|
||||||
|
if (strcmp(cond_ent->name, "ip") == 0) {
|
||||||
|
move_conditional_value("network", &ip_cond.sip, cond_ent);
|
||||||
|
if (!parse_address(ip_cond))
|
||||||
|
yyerror("network invalid ip='%s'\n", ip_cond.sip);
|
||||||
|
} else if (strcmp(cond_ent->name, "port") == 0) {
|
||||||
|
move_conditional_value("network", &ip_cond.sport, cond_ent);
|
||||||
|
if (!parse_port(ip_cond))
|
||||||
|
yyerror("network invalid port='%s'\n", ip_cond.sport);
|
||||||
|
} else {
|
||||||
|
yyerror("invalid network rule conditional \"%s\"\n",
|
||||||
|
cond_ent->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void network_rule::set_netperm(unsigned int family, unsigned int type)
|
||||||
|
{
|
||||||
|
if (type > SOCK_PACKET) {
|
||||||
|
/* setting mask instead of a bit */
|
||||||
|
network_perms[family] |= type;
|
||||||
|
} else
|
||||||
|
network_perms[family] |= 1 << type;
|
||||||
|
}
|
||||||
|
|
||||||
|
network_rule::network_rule(perms_t perms_p, struct cond_entry *conds,
|
||||||
|
struct cond_entry *peer_conds):
|
||||||
|
dedup_perms_rule_t(AA_CLASS_NETV8)
|
||||||
|
{
|
||||||
|
size_t family_index;
|
||||||
|
for (family_index = AF_UNSPEC; family_index < get_af_max(); family_index++) {
|
||||||
|
network_map[family_index].push_back({ family_index, 0xFFFFFFFF, 0xFFFFFFFF });
|
||||||
|
set_netperm(family_index, 0xFFFFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
move_conditionals(conds, local);
|
||||||
|
move_conditionals(peer_conds, peer);
|
||||||
|
free_cond_list(conds);
|
||||||
|
free_cond_list(peer_conds);
|
||||||
|
|
||||||
|
if (perms_p) {
|
||||||
|
perms = perms_p;
|
||||||
|
if (perms & ~AA_VALID_NET_PERMS)
|
||||||
|
yyerror("perms contains invalid permissions for network rules\n");
|
||||||
|
else if ((perms & ~AA_PEER_NET_PERMS) && has_peer_conds())
|
||||||
|
yyerror("network 'create', 'shutdown', 'setattr', 'getattr', 'bind', 'listen', 'setopt', and/or 'getopt' accesses cannot be used with peer socket conditionals\n");
|
||||||
|
} else {
|
||||||
|
perms = AA_VALID_NET_PERMS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
network_rule::network_rule(perms_t perms_p, const char *family, const char *type,
|
||||||
|
const char *protocol, struct cond_entry *conds,
|
||||||
|
struct cond_entry *peer_conds):
|
||||||
|
dedup_perms_rule_t(AA_CLASS_NETV8)
|
||||||
|
{
|
||||||
|
const struct network_tuple *mapping = NULL;
|
||||||
|
while ((mapping = net_find_mapping(mapping, family, type, protocol))) {
|
||||||
|
network_map[mapping->family].push_back({ mapping->family, mapping->type, mapping->protocol });
|
||||||
|
set_netperm(mapping->family, mapping->type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == NULL && network_map.empty()) {
|
||||||
|
while ((mapping = net_find_mapping(mapping, type, family, protocol))) {
|
||||||
|
network_map[mapping->family].push_back({ mapping->family, mapping->type, mapping->protocol });
|
||||||
|
set_netperm(mapping->family, mapping->type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (network_map.empty())
|
||||||
|
yyerror(_("Invalid network entry."));
|
||||||
|
|
||||||
|
move_conditionals(conds, local);
|
||||||
|
move_conditionals(peer_conds, peer);
|
||||||
|
free_cond_list(conds);
|
||||||
|
free_cond_list(peer_conds);
|
||||||
|
|
||||||
|
if (perms_p) {
|
||||||
|
perms = perms_p;
|
||||||
|
if (perms & ~AA_VALID_NET_PERMS)
|
||||||
|
yyerror("perms contains invalid permissions for network rules\n");
|
||||||
|
else if ((perms & ~AA_PEER_NET_PERMS) && has_peer_conds())
|
||||||
|
yyerror("network 'create', 'shutdown', 'setattr', 'getattr', 'bind', 'listen', 'setopt', and/or 'getopt' accesses cannot be used with peer socket conditionals\n");
|
||||||
|
} else {
|
||||||
|
perms = AA_VALID_NET_PERMS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
network_rule::network_rule(perms_t perms_p, unsigned int family, unsigned int type):
|
||||||
|
dedup_perms_rule_t(AA_CLASS_NETV8)
|
||||||
|
{
|
||||||
|
network_map[family].push_back({ family, type, 0xFFFFFFFF });
|
||||||
|
set_netperm(family, type);
|
||||||
|
|
||||||
|
if (perms_p) {
|
||||||
|
perms = perms_p;
|
||||||
|
if (perms & ~AA_VALID_NET_PERMS)
|
||||||
|
yyerror("perms contains invalid permissions for network rules\n");
|
||||||
|
else if ((perms & ~AA_PEER_NET_PERMS) && has_peer_conds())
|
||||||
|
yyerror("network 'create', 'shutdown', 'setattr', 'getattr', 'bind', 'listen', 'setopt', and/or 'getopt' accesses cannot be used with peer socket conditionals\n");
|
||||||
|
} else {
|
||||||
|
perms = AA_VALID_NET_PERMS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ostream &network_rule::dump(ostream &os)
|
||||||
|
{
|
||||||
|
class_rule_t::dump(os);
|
||||||
|
|
||||||
|
unsigned int count = sizeof(sock_types)/sizeof(sock_types[0]);
|
||||||
|
unsigned int mask = ~((1 << count) -1);
|
||||||
|
unsigned int j;
|
||||||
|
|
||||||
|
/* This can only be set by an unqualified network rule */
|
||||||
|
if (network_map.find(AF_UNSPEC) != network_map.end()) {
|
||||||
|
os << ",\n";
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& perm : network_perms) {
|
||||||
|
unsigned int family = perm.first;
|
||||||
|
unsigned int type = perm.second;
|
||||||
|
|
||||||
|
const char *family_name = net_find_af_name(family);
|
||||||
|
if (family_name)
|
||||||
|
os << " " << family_name;
|
||||||
|
else
|
||||||
|
os << " #" << family;
|
||||||
|
|
||||||
|
/* All types/protocols */
|
||||||
|
if (type == 0xffffffff || type == ALL_TYPES)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
printf(" {");
|
||||||
|
|
||||||
|
for (j = 0; j < count; j++) {
|
||||||
|
const char *type_name;
|
||||||
|
if (type & (1 << j)) {
|
||||||
|
type_name = sock_types[j].name;
|
||||||
|
if (type_name)
|
||||||
|
os << " " << type_name;
|
||||||
|
else
|
||||||
|
os << " #" << j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (type & mask)
|
||||||
|
os << " #" << std::hex << (type & mask);
|
||||||
|
|
||||||
|
printf(" }");
|
||||||
|
}
|
||||||
|
|
||||||
|
os << ",\n";
|
||||||
|
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int network_rule::expand_variables(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void network_rule::warn_once(const char *name)
|
||||||
|
{
|
||||||
|
rule_t::warn_once(name, "network rules not enforced");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string gen_ip_cond(const struct ip_address ip)
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
int i;
|
||||||
|
if (ip.family == AF_INET) {
|
||||||
|
/* add a byte containing the size of the following ip */
|
||||||
|
oss << "\\x04";
|
||||||
|
|
||||||
|
u8 *byte = (u8 *) &ip.address.address_v4; /* in network byte order */
|
||||||
|
for (i = 0; i < 4; i++)
|
||||||
|
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << static_cast<unsigned int>(byte[i]);
|
||||||
|
} else {
|
||||||
|
/* add a byte containing the size of the following ip */
|
||||||
|
oss << "\\x10";
|
||||||
|
for (i = 0; i < 16; ++i)
|
||||||
|
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << static_cast<unsigned int>(ip.address.address_v6[i]);
|
||||||
|
}
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string gen_port_cond(uint16_t port)
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
if (port > 0) {
|
||||||
|
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << ((port & 0xff00) >> 8);
|
||||||
|
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << (port & 0xff);
|
||||||
|
} else {
|
||||||
|
oss << "..";
|
||||||
|
}
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void network_rule::gen_ip_conds(std::ostringstream &oss, ip_conds entry, bool is_peer, bool is_cmd)
|
||||||
|
{
|
||||||
|
/* encode protocol */
|
||||||
|
if (!is_cmd) {
|
||||||
|
if (entry.is_ip) {
|
||||||
|
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << ((entry.ip.family & 0xff00) >> 8);
|
||||||
|
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << (entry.ip.family & 0xff);
|
||||||
|
} else {
|
||||||
|
oss << "..";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.is_port) {
|
||||||
|
/* encode port type (privileged - 1, remote - 2, unprivileged - 0) */
|
||||||
|
if (!is_peer && perms & AA_NET_BIND && entry.port < IPPORT_RESERVED)
|
||||||
|
oss << "\\x01";
|
||||||
|
else if (is_peer)
|
||||||
|
oss << "\\x02";
|
||||||
|
else
|
||||||
|
oss << "\\x00";
|
||||||
|
|
||||||
|
oss << gen_port_cond(entry.port);
|
||||||
|
} else {
|
||||||
|
/* port type + port number */
|
||||||
|
if (!is_cmd)
|
||||||
|
oss << ".";
|
||||||
|
oss << "..";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.is_ip) {
|
||||||
|
oss << gen_ip_cond(entry.ip);
|
||||||
|
} else {
|
||||||
|
/* encode 0 to indicate there's no ip (ip size) */
|
||||||
|
oss << "\\x00";
|
||||||
|
}
|
||||||
|
|
||||||
|
oss << "\\-x01"; /* oob separator */
|
||||||
|
oss << default_match_pattern; /* label - not used for now */
|
||||||
|
oss << "\\x00"; /* null transition */
|
||||||
|
}
|
||||||
|
|
||||||
|
bool network_rule::gen_net_rule(Profile &prof, u16 family, unsigned int type_mask) {
|
||||||
|
std::ostringstream buffer;
|
||||||
|
std::string buf;
|
||||||
|
|
||||||
|
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_NETV8;
|
||||||
|
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << ((family & 0xff00) >> 8);
|
||||||
|
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << (family & 0xff);
|
||||||
|
if (type_mask > 0xffff) {
|
||||||
|
buffer << "..";
|
||||||
|
} else {
|
||||||
|
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << ((type_mask & 0xff00) >> 8);
|
||||||
|
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << (type_mask & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!features_supports_inet) {
|
||||||
|
buf = buffer.str();
|
||||||
|
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(AA_VALID_NET_PERMS),
|
||||||
|
dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(AA_VALID_NET_PERMS) : 0,
|
||||||
|
parseopts))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (perms & AA_PEER_NET_PERMS) {
|
||||||
|
gen_ip_conds(buffer, peer, true, false);
|
||||||
|
|
||||||
|
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << CMD_ADDR;
|
||||||
|
|
||||||
|
gen_ip_conds(buffer, local, false, true);
|
||||||
|
|
||||||
|
buf = buffer.str();
|
||||||
|
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(perms),
|
||||||
|
dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0,
|
||||||
|
parseopts))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((perms & AA_NET_LISTEN) || (perms & AA_NET_OPT)) {
|
||||||
|
gen_ip_conds(buffer, local, false, false);
|
||||||
|
|
||||||
|
if (perms & AA_NET_LISTEN) {
|
||||||
|
std::ostringstream cmd_buffer;
|
||||||
|
cmd_buffer << buffer.str();
|
||||||
|
cmd_buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << CMD_LISTEN;
|
||||||
|
/* length of queue allowed - not used for now */
|
||||||
|
cmd_buffer << "..";
|
||||||
|
buf = cmd_buffer.str();
|
||||||
|
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(perms),
|
||||||
|
dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0,
|
||||||
|
parseopts))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (perms & AA_NET_OPT) {
|
||||||
|
std::ostringstream cmd_buffer;
|
||||||
|
cmd_buffer << buffer.str();
|
||||||
|
cmd_buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << CMD_OPT;
|
||||||
|
/* level - not used for now */
|
||||||
|
cmd_buffer << "..";
|
||||||
|
/* socket mapping - not used for now */
|
||||||
|
cmd_buffer << "..";
|
||||||
|
buf = cmd_buffer.str();
|
||||||
|
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(perms),
|
||||||
|
dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0,
|
||||||
|
parseopts))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int network_rule::gen_policy_re(Profile &prof)
|
||||||
|
{
|
||||||
|
std::ostringstream buffer;
|
||||||
|
std::string buf;
|
||||||
|
|
||||||
|
if (!features_supports_networkv8) {
|
||||||
|
warn_once(prof.name);
|
||||||
|
return RULE_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& perm : network_perms) {
|
||||||
|
unsigned int family = perm.first;
|
||||||
|
unsigned int type = perm.second;
|
||||||
|
|
||||||
|
if (type > 0xffff) {
|
||||||
|
if (!gen_net_rule(prof, family, type))
|
||||||
|
goto fail;
|
||||||
|
} else {
|
||||||
|
int t;
|
||||||
|
/* generate rules for types that are set */
|
||||||
|
for (t = 0; t < 16; t++) {
|
||||||
|
if (type & (1 << t)) {
|
||||||
|
if (!gen_net_rule(prof, family, t))
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return RULE_OK;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return RULE_ERROR;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* initialize static members */
|
||||||
|
unsigned int *network_rule::allow = NULL;
|
||||||
|
unsigned int *network_rule::audit = NULL;
|
||||||
|
unsigned int *network_rule::deny = NULL;
|
||||||
|
unsigned int *network_rule::quiet = NULL;
|
||||||
|
|
||||||
|
bool network_rule::alloc_net_table()
|
||||||
|
{
|
||||||
|
if (allow)
|
||||||
|
return true;
|
||||||
|
allow = (unsigned int *) calloc(get_af_max(), sizeof(unsigned int));
|
||||||
|
audit = (unsigned int *) calloc(get_af_max(), sizeof(unsigned int));
|
||||||
|
deny = (unsigned int *) calloc(get_af_max(), sizeof(unsigned int));
|
||||||
|
quiet = (unsigned int *) calloc(get_af_max(), sizeof(unsigned int));
|
||||||
|
if (!allow || !audit || !deny || !quiet)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update is required because at the point of the creation of the
|
||||||
|
* network_rule object, we don't have owner, rule_mode, or audit
|
||||||
|
* set.
|
||||||
|
*/
|
||||||
|
void network_rule::update_compat_net(void)
|
||||||
|
{
|
||||||
|
if (!alloc_net_table())
|
||||||
|
yyerror(_("Memory allocation error."));
|
||||||
|
|
||||||
|
for (auto& nm: network_map) {
|
||||||
|
for (auto& entry : nm.second) {
|
||||||
|
if (entry.type > SOCK_PACKET) {
|
||||||
|
/* setting mask instead of a bit */
|
||||||
|
if (rule_mode == RULE_DENY) {
|
||||||
|
deny[entry.family] |= entry.type;
|
||||||
|
if (dedup_perms_rule_t::audit != AUDIT_FORCE)
|
||||||
|
quiet[entry.family] |= entry.type;
|
||||||
|
} else {
|
||||||
|
allow[entry.family] |= entry.type;
|
||||||
|
if (dedup_perms_rule_t::audit == AUDIT_FORCE)
|
||||||
|
audit[entry.family] |= entry.type;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (rule_mode == RULE_DENY) {
|
||||||
|
deny[entry.family] |= 1 << entry.type;
|
||||||
|
if (dedup_perms_rule_t::audit != AUDIT_FORCE)
|
||||||
|
quiet[entry.family] |= 1 << entry.type;
|
||||||
|
} else {
|
||||||
|
allow[entry.family] |= 1 << entry.type;
|
||||||
|
if (dedup_perms_rule_t::audit == AUDIT_FORCE)
|
||||||
|
audit[entry.family] |= 1 << entry.type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmp_network_map(std::unordered_map<unsigned int, perms_t> lhs,
|
||||||
|
std::unordered_map<unsigned int, perms_t> rhs)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
size_t family_index;
|
||||||
|
for (family_index = AF_UNSPEC; family_index < get_af_max(); family_index++) {
|
||||||
|
res = lhs[family_index] - rhs[family_index];
|
||||||
|
if (res)
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int network_rule::cmp(rule_t const &rhs) const
|
||||||
|
{
|
||||||
|
int res = dedup_perms_rule_t::cmp(rhs);
|
||||||
|
if (res)
|
||||||
|
return res;
|
||||||
|
network_rule const &nrhs = rule_cast<network_rule const &>(rhs);
|
||||||
|
return cmp_network_map(network_perms, nrhs.network_perms);
|
||||||
|
};
|
152
parser/network.h
152
parser/network.h
@@ -29,6 +29,8 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
#include "rule.h"
|
#include "rule.h"
|
||||||
@@ -73,6 +75,10 @@
|
|||||||
#define AA_PEER_NET_PERMS (AA_VALID_NET_PERMS & (~AA_LOCAL_NET_PERMS | \
|
#define AA_PEER_NET_PERMS (AA_VALID_NET_PERMS & (~AA_LOCAL_NET_PERMS | \
|
||||||
AA_NET_ACCEPT))
|
AA_NET_ACCEPT))
|
||||||
|
|
||||||
|
#define CMD_ADDR 1
|
||||||
|
#define CMD_LISTEN 2
|
||||||
|
#define CMD_OPT 4
|
||||||
|
|
||||||
struct network_tuple {
|
struct network_tuple {
|
||||||
const char *family_name;
|
const char *family_name;
|
||||||
unsigned int family;
|
unsigned int family;
|
||||||
@@ -82,13 +88,10 @@ struct network_tuple {
|
|||||||
unsigned int protocol;
|
unsigned int protocol;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* supported AF protocols */
|
|
||||||
struct aa_network_entry {
|
struct aa_network_entry {
|
||||||
unsigned int family;
|
long unsigned int family;
|
||||||
unsigned int type;
|
unsigned int type;
|
||||||
unsigned int protocol;
|
unsigned int protocol;
|
||||||
|
|
||||||
struct aa_network_entry *next;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline uint32_t map_perms(uint32_t mask)
|
static inline uint32_t map_perms(uint32_t mask)
|
||||||
@@ -99,45 +102,114 @@ static inline uint32_t map_perms(uint32_t mask)
|
|||||||
((mask & (AA_NET_SETOPT | AA_NET_GETOPT)) >> 5); /* 5 + (AA_OTHER_SHIFT - 24) */
|
((mask & (AA_NET_SETOPT | AA_NET_GETOPT)) >> 5); /* 5 + (AA_OTHER_SHIFT - 24) */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
int parse_net_perms(const char *str_mode, perms_t *perms, int fail);
|
int parse_net_perms(const char *str_mode, perms_t *perms, int fail);
|
||||||
extern struct aa_network_entry *new_network_ent(unsigned int family,
|
size_t get_af_max();
|
||||||
unsigned int type,
|
|
||||||
unsigned int protocol);
|
|
||||||
extern struct aa_network_entry *network_entry(const char *family,
|
|
||||||
const char *type,
|
|
||||||
const char *protocol);
|
|
||||||
extern size_t get_af_max(void);
|
|
||||||
|
|
||||||
void __debug_network(unsigned int *array, const char *name);
|
|
||||||
|
|
||||||
struct network {
|
|
||||||
unsigned int *allow; /* array of type masks
|
|
||||||
* indexed by AF_FAMILY */
|
|
||||||
unsigned int *audit;
|
|
||||||
unsigned int *deny;
|
|
||||||
unsigned int *quiet;
|
|
||||||
|
|
||||||
network(void) { allow = audit = deny = quiet = NULL; }
|
|
||||||
|
|
||||||
void dump(void) {
|
|
||||||
if (allow)
|
|
||||||
__debug_network(allow, "Network");
|
|
||||||
if (audit)
|
|
||||||
__debug_network(audit, "Audit Net");
|
|
||||||
if (deny)
|
|
||||||
__debug_network(deny, "Deny Net");
|
|
||||||
if (quiet)
|
|
||||||
__debug_network(quiet, "Quiet Net");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
int net_find_type_val(const char *type);
|
int net_find_type_val(const char *type);
|
||||||
const char *net_find_type_name(int type);
|
const char *net_find_type_name(int type);
|
||||||
const char *net_find_af_name(unsigned int af);
|
const char *net_find_af_name(unsigned int af);
|
||||||
const struct network_tuple *net_find_mapping(const struct network_tuple *map,
|
|
||||||
const char *family,
|
struct ip_address {
|
||||||
const char *type,
|
union {
|
||||||
const char *protocol);
|
uint8_t address_v6[16];
|
||||||
|
uint32_t address_v4;
|
||||||
|
} address;
|
||||||
|
uint16_t family;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ip_conds {
|
||||||
|
public:
|
||||||
|
char *sip = NULL;
|
||||||
|
char *sport = NULL;
|
||||||
|
|
||||||
|
bool is_ip = false;
|
||||||
|
bool is_port = false;
|
||||||
|
|
||||||
|
uint16_t port;
|
||||||
|
struct ip_address ip;
|
||||||
|
|
||||||
|
void free_conds() {
|
||||||
|
if (sip)
|
||||||
|
free(sip);
|
||||||
|
if (sport)
|
||||||
|
free(sport);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class network_rule: public dedup_perms_rule_t {
|
||||||
|
void move_conditionals(struct cond_entry *conds, ip_conds &ip_cond);
|
||||||
|
public:
|
||||||
|
std::unordered_map<unsigned int, std::vector<struct aa_network_entry>> network_map;
|
||||||
|
std::unordered_map<unsigned int, perms_t> network_perms;
|
||||||
|
|
||||||
|
ip_conds peer;
|
||||||
|
ip_conds local;
|
||||||
|
|
||||||
|
bool has_local_conds(void) { return local.sip || local.sport; }
|
||||||
|
bool has_peer_conds(void) { return peer.sip || peer.sport; }
|
||||||
|
/* empty constructor used only for the profile to access
|
||||||
|
* static elements to maintain compatibility with
|
||||||
|
* AA_CLASS_NET */
|
||||||
|
network_rule(): dedup_perms_rule_t(AA_CLASS_NETV8) { }
|
||||||
|
network_rule(perms_t perms_p, struct cond_entry *conds,
|
||||||
|
struct cond_entry *peer_conds);
|
||||||
|
network_rule(perms_t perms_p, const char *family, const char *type,
|
||||||
|
const char *protocol, struct cond_entry *conds,
|
||||||
|
struct cond_entry *peer_conds);
|
||||||
|
network_rule(perms_t perms_p, unsigned int family, unsigned int type);
|
||||||
|
virtual ~network_rule()
|
||||||
|
{
|
||||||
|
peer.free_conds();
|
||||||
|
local.free_conds();
|
||||||
|
if (allow) {
|
||||||
|
free(allow);
|
||||||
|
allow = NULL;
|
||||||
|
}
|
||||||
|
if (audit) {
|
||||||
|
free(audit);
|
||||||
|
audit = NULL;
|
||||||
|
}
|
||||||
|
if (deny) {
|
||||||
|
free(deny);
|
||||||
|
deny = NULL;
|
||||||
|
}
|
||||||
|
if (quiet) {
|
||||||
|
free(quiet);
|
||||||
|
quiet = NULL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void gen_ip_conds(std::ostringstream &oss, ip_conds entry, bool is_peer, bool is_cmd);
|
||||||
|
bool gen_net_rule(Profile &prof, u16 family, unsigned int type_mask);
|
||||||
|
void set_netperm(unsigned int family, unsigned int type);
|
||||||
|
void update_compat_net(void);
|
||||||
|
bool parse_address(ip_conds &entry);
|
||||||
|
bool parse_port(ip_conds &entry);
|
||||||
|
|
||||||
|
virtual bool valid_prefix(const prefixes &p, const char *&error) {
|
||||||
|
if (p.owner) {
|
||||||
|
error = _("owner prefix not allowed on network rules");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
virtual ostream &dump(ostream &os);
|
||||||
|
virtual int expand_variables(void);
|
||||||
|
virtual int gen_policy_re(Profile &prof);
|
||||||
|
|
||||||
|
virtual bool is_mergeable(void) { return true; }
|
||||||
|
virtual int cmp(rule_t const &rhs) const;
|
||||||
|
|
||||||
|
/* array of type masks indexed by AF_FAMILY */
|
||||||
|
/* allow, audit, deny and quiet are used for compatibility with AA_CLASS_NET */
|
||||||
|
static unsigned int *allow;
|
||||||
|
static unsigned int *audit;
|
||||||
|
static unsigned int *deny;
|
||||||
|
static unsigned int *quiet;
|
||||||
|
|
||||||
|
bool alloc_net_table(void);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void warn_once(const char *name) override;
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* __AA_NETWORK_H */
|
#endif /* __AA_NETWORK_H */
|
||||||
|
@@ -37,6 +37,7 @@
|
|||||||
#include "libapparmor_re/apparmor_re.h"
|
#include "libapparmor_re/apparmor_re.h"
|
||||||
#include "libapparmor_re/aare_rules.h"
|
#include "libapparmor_re/aare_rules.h"
|
||||||
#include "rule.h"
|
#include "rule.h"
|
||||||
|
#include "bignum.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@@ -340,6 +341,7 @@ extern int kernel_load;
|
|||||||
extern int kernel_supports_setload;
|
extern int kernel_supports_setload;
|
||||||
extern int features_supports_network;
|
extern int features_supports_network;
|
||||||
extern int features_supports_networkv8;
|
extern int features_supports_networkv8;
|
||||||
|
extern int features_supports_inet;
|
||||||
extern int kernel_supports_policydb;
|
extern int kernel_supports_policydb;
|
||||||
extern int kernel_supports_diff_encode;
|
extern int kernel_supports_diff_encode;
|
||||||
extern int features_supports_mount;
|
extern int features_supports_mount;
|
||||||
@@ -353,6 +355,8 @@ extern int features_supports_userns;
|
|||||||
extern int features_supports_posix_mqueue;
|
extern int features_supports_posix_mqueue;
|
||||||
extern int features_supports_sysv_mqueue;
|
extern int features_supports_sysv_mqueue;
|
||||||
extern int features_supports_io_uring;
|
extern int features_supports_io_uring;
|
||||||
|
extern int features_supports_flag_interruptible;
|
||||||
|
extern int features_supports_flag_signal;
|
||||||
extern int kernel_supports_oob;
|
extern int kernel_supports_oob;
|
||||||
extern int conf_verbose;
|
extern int conf_verbose;
|
||||||
extern int conf_quiet;
|
extern int conf_quiet;
|
||||||
@@ -409,6 +413,7 @@ extern pattern_t convert_aaregex_to_pcre(const char *aare, int anchor, int glob,
|
|||||||
extern int build_list_val_expr(std::string& buffer, struct value_list *list);
|
extern int build_list_val_expr(std::string& buffer, struct value_list *list);
|
||||||
extern int convert_entry(std::string& buffer, char *entry);
|
extern int convert_entry(std::string& buffer, char *entry);
|
||||||
extern int clear_and_convert_entry(std::string& buffer, char *entry);
|
extern int clear_and_convert_entry(std::string& buffer, char *entry);
|
||||||
|
extern int convert_range(std::string& buffer, bignum start, bignum end);
|
||||||
extern int process_regex(Profile *prof);
|
extern int process_regex(Profile *prof);
|
||||||
extern int post_process_entry(struct cod_entry *entry);
|
extern int post_process_entry(struct cod_entry *entry);
|
||||||
|
|
||||||
@@ -457,6 +462,9 @@ extern bool strcomp (const char *lhs, const char *rhs);
|
|||||||
extern struct cod_entry *copy_cod_entry(struct cod_entry *cod);
|
extern struct cod_entry *copy_cod_entry(struct cod_entry *cod);
|
||||||
extern void free_cod_entries(struct cod_entry *list);
|
extern void free_cod_entries(struct cod_entry *list);
|
||||||
void debug_cod_entries(struct cod_entry *list);
|
void debug_cod_entries(struct cod_entry *list);
|
||||||
|
bool check_x_qualifier(struct cod_entry *entry, const char *&error);
|
||||||
|
bool entry_add_prefix(struct cod_entry *entry, const prefixes &p, const char *&error);
|
||||||
|
|
||||||
|
|
||||||
#define SECONDS_P_MS (1000LL * 1000LL)
|
#define SECONDS_P_MS (1000LL * 1000LL)
|
||||||
long long convert_time_units(long long value, long long base, const char *units);
|
long long convert_time_units(long long value, long long base, const char *units);
|
||||||
|
@@ -69,6 +69,7 @@ int kernel_load = 1;
|
|||||||
int kernel_supports_setload = 0; /* kernel supports atomic set loads */
|
int kernel_supports_setload = 0; /* kernel supports atomic set loads */
|
||||||
int features_supports_network = 0; /* kernel supports network rules */
|
int features_supports_network = 0; /* kernel supports network rules */
|
||||||
int features_supports_networkv8 = 0; /* kernel supports 4.17 network rules */
|
int features_supports_networkv8 = 0; /* kernel supports 4.17 network rules */
|
||||||
|
int features_supports_inet = 0; /* kernel supports inet network rules */
|
||||||
int features_supports_unix = 0; /* kernel supports unix socket rules */
|
int features_supports_unix = 0; /* kernel supports unix socket rules */
|
||||||
int kernel_supports_policydb = 0; /* kernel supports new policydb */
|
int kernel_supports_policydb = 0; /* kernel supports new policydb */
|
||||||
int features_supports_mount = 0; /* kernel supports mount rules */
|
int features_supports_mount = 0; /* kernel supports mount rules */
|
||||||
@@ -82,6 +83,8 @@ int features_supports_userns = 0; /* kernel supports user namespace */
|
|||||||
int features_supports_posix_mqueue = 0; /* kernel supports mqueue rules */
|
int features_supports_posix_mqueue = 0; /* kernel supports mqueue rules */
|
||||||
int features_supports_sysv_mqueue = 0; /* kernel supports mqueue rules */
|
int features_supports_sysv_mqueue = 0; /* kernel supports mqueue rules */
|
||||||
int features_supports_io_uring = 0; /* kernel supports io_uring rules */
|
int features_supports_io_uring = 0; /* kernel supports io_uring rules */
|
||||||
|
int features_supports_flag_interruptible = 0;
|
||||||
|
int features_supports_flag_signal = 0;
|
||||||
int kernel_supports_oob = 0; /* out of band transitions */
|
int kernel_supports_oob = 0; /* out of band transitions */
|
||||||
int conf_verbose = 0;
|
int conf_verbose = 0;
|
||||||
int conf_quiet = 0;
|
int conf_quiet = 0;
|
||||||
|
@@ -276,7 +276,7 @@ static inline void sd_write_aligned_blob(std::ostringstream &buf, void *b, int b
|
|||||||
buf.write((const char *) b, b_size);
|
buf.write((const char *) b, b_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sd_write_strn(std::ostringstream &buf, char *b, int size, const char *name)
|
static void sd_write_strn(std::ostringstream &buf, const char *b, int size, const char *name)
|
||||||
{
|
{
|
||||||
sd_write_name(buf, name);
|
sd_write_name(buf, name);
|
||||||
sd_write8(buf, SD_STRING);
|
sd_write8(buf, SD_STRING);
|
||||||
@@ -284,7 +284,7 @@ static void sd_write_strn(std::ostringstream &buf, char *b, int size, const char
|
|||||||
buf.write(b, size);
|
buf.write(b, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void sd_write_string(std::ostringstream &buf, char *b, const char *name)
|
static inline void sd_write_string(std::ostringstream &buf, const char *b, const char *name)
|
||||||
{
|
{
|
||||||
sd_write_strn(buf, b, strlen(b) + 1, name);
|
sd_write_strn(buf, b, strlen(b) + 1, name);
|
||||||
}
|
}
|
||||||
@@ -403,11 +403,7 @@ void sd_serialize_profile(std::ostringstream &buf, Profile *profile,
|
|||||||
sd_write_struct(buf, "profile");
|
sd_write_struct(buf, "profile");
|
||||||
if (flattened) {
|
if (flattened) {
|
||||||
assert(profile->parent);
|
assert(profile->parent);
|
||||||
autofree char *name = (char *) malloc(3 + strlen(profile->name) + strlen(profile->parent->name));
|
sd_write_string(buf, profile->get_name(false).c_str(), NULL);
|
||||||
if (!name)
|
|
||||||
return;
|
|
||||||
sprintf(name, "%s//%s", profile->parent->name, profile->name);
|
|
||||||
sd_write_string(buf, name, NULL);
|
|
||||||
} else {
|
} else {
|
||||||
sd_write_string(buf, profile->name, NULL);
|
sd_write_string(buf, profile->name, NULL);
|
||||||
}
|
}
|
||||||
@@ -426,6 +422,10 @@ void sd_serialize_profile(std::ostringstream &buf, Profile *profile,
|
|||||||
"disconnected");
|
"disconnected");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (profile->flags.signal && features_supports_flag_signal) {
|
||||||
|
sd_write_name(buf, "kill");
|
||||||
|
sd_write_uint32(buf, profile->flags.signal);
|
||||||
|
}
|
||||||
sd_write_struct(buf, "flags");
|
sd_write_struct(buf, "flags");
|
||||||
/* used to be flags.debug, but that's no longer supported */
|
/* used to be flags.debug, but that's no longer supported */
|
||||||
sd_write_uint32(buf, profile->flags.flags);
|
sd_write_uint32(buf, profile->flags.flags);
|
||||||
|
@@ -378,7 +378,7 @@ GT >
|
|||||||
yyterminate();
|
yyterminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
<INITIAL,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,MQUEUE_MODE>{
|
<INITIAL,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,MQUEUE_MODE,NETWORK_MODE>{
|
||||||
(peer|xattrs)/{WS}*={WS}*\( {
|
(peer|xattrs)/{WS}*={WS}*\( {
|
||||||
/* we match to the = in the lexer so that we can switch scanner
|
/* we match to the = in the lexer so that we can switch scanner
|
||||||
* state. By the time the parser see the = it may be too late
|
* state. By the time the parser see the = it may be too late
|
||||||
@@ -517,12 +517,6 @@ GT >
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
<NETWORK_MODE>{
|
|
||||||
{IDS} {
|
|
||||||
yylval.id = strdup(yytext);
|
|
||||||
RETURN_TOKEN(TOK_ID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
<CHANGE_PROFILE_MODE>{
|
<CHANGE_PROFILE_MODE>{
|
||||||
safe { RETURN_TOKEN(TOK_SAFE); }
|
safe { RETURN_TOKEN(TOK_SAFE); }
|
||||||
@@ -558,7 +552,7 @@ GT >
|
|||||||
{LT_EQUAL} { RETURN_TOKEN(TOK_LE); }
|
{LT_EQUAL} { RETURN_TOKEN(TOK_LE); }
|
||||||
}
|
}
|
||||||
|
|
||||||
<UNIX_MODE>{
|
<UNIX_MODE,NETWORK_MODE>{
|
||||||
listen { RETURN_TOKEN(TOK_LISTEN); }
|
listen { RETURN_TOKEN(TOK_LISTEN); }
|
||||||
accept { RETURN_TOKEN(TOK_ACCEPT); }
|
accept { RETURN_TOKEN(TOK_ACCEPT); }
|
||||||
connect { RETURN_TOKEN(TOK_CONNECT); }
|
connect { RETURN_TOKEN(TOK_CONNECT); }
|
||||||
@@ -567,7 +561,7 @@ GT >
|
|||||||
shutdown { RETURN_TOKEN(TOK_SHUTDOWN); }
|
shutdown { RETURN_TOKEN(TOK_SHUTDOWN); }
|
||||||
}
|
}
|
||||||
|
|
||||||
<UNIX_MODE,USERNS_MODE,MQUEUE_MODE>{
|
<UNIX_MODE,USERNS_MODE,MQUEUE_MODE,NETWORK_MODE>{
|
||||||
create { RETURN_TOKEN(TOK_CREATE); }
|
create { RETURN_TOKEN(TOK_CREATE); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -576,12 +570,12 @@ GT >
|
|||||||
delete { RETURN_TOKEN(TOK_DELETE); }
|
delete { RETURN_TOKEN(TOK_DELETE); }
|
||||||
}
|
}
|
||||||
|
|
||||||
<UNIX_MODE,MQUEUE_MODE>{
|
<UNIX_MODE,MQUEUE_MODE,NETWORK_MODE>{
|
||||||
getattr { RETURN_TOKEN(TOK_GETATTR); }
|
getattr { RETURN_TOKEN(TOK_GETATTR); }
|
||||||
setattr { RETURN_TOKEN(TOK_SETATTR); }
|
setattr { RETURN_TOKEN(TOK_SETATTR); }
|
||||||
}
|
}
|
||||||
|
|
||||||
<DBUS_MODE,UNIX_MODE>{
|
<DBUS_MODE,UNIX_MODE,NETWORK_MODE>{
|
||||||
bind { RETURN_TOKEN(TOK_BIND); }
|
bind { RETURN_TOKEN(TOK_BIND); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -589,7 +583,7 @@ GT >
|
|||||||
eavesdrop { RETURN_TOKEN(TOK_EAVESDROP); }
|
eavesdrop { RETURN_TOKEN(TOK_EAVESDROP); }
|
||||||
}
|
}
|
||||||
|
|
||||||
<DBUS_MODE,SIGNAL_MODE,UNIX_MODE>{
|
<DBUS_MODE,SIGNAL_MODE,UNIX_MODE,NETWORK_MODE>{
|
||||||
send { RETURN_TOKEN(TOK_SEND); }
|
send { RETURN_TOKEN(TOK_SEND); }
|
||||||
receive { RETURN_TOKEN(TOK_RECEIVE); }
|
receive { RETURN_TOKEN(TOK_RECEIVE); }
|
||||||
}
|
}
|
||||||
@@ -600,7 +594,7 @@ GT >
|
|||||||
tracedby { RETURN_TOKEN(TOK_TRACEDBY); }
|
tracedby { RETURN_TOKEN(TOK_TRACEDBY); }
|
||||||
}
|
}
|
||||||
|
|
||||||
<DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,MQUEUE_MODE>{
|
<DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,MQUEUE_MODE,NETWORK_MODE>{
|
||||||
read { RETURN_TOKEN(TOK_READ); }
|
read { RETURN_TOKEN(TOK_READ); }
|
||||||
write { RETURN_TOKEN(TOK_WRITE); }
|
write { RETURN_TOKEN(TOK_WRITE); }
|
||||||
{OPEN_PAREN} {
|
{OPEN_PAREN} {
|
||||||
@@ -621,7 +615,7 @@ GT >
|
|||||||
sqpoll { RETURN_TOKEN(TOK_SQPOLL); }
|
sqpoll { RETURN_TOKEN(TOK_SQPOLL); }
|
||||||
}
|
}
|
||||||
|
|
||||||
<MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,MQUEUE_MODE,IOURING_MODE>{
|
<MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,MQUEUE_MODE,IOURING_MODE,NETWORK_MODE>{
|
||||||
({IDS_NOEQ}|{LABEL}|{QUOTED_ID}) {
|
({IDS_NOEQ}|{LABEL}|{QUOTED_ID}) {
|
||||||
yylval.id = processid(yytext, yyleng);
|
yylval.id = processid(yytext, yyleng);
|
||||||
RETURN_TOKEN(TOK_ID);
|
RETURN_TOKEN(TOK_ID);
|
||||||
@@ -658,6 +652,10 @@ include/{WS} {
|
|||||||
yy_push_state(INCLUDE);
|
yy_push_state(INCLUDE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
all/({WS}|[^[:alnum:]_]) {
|
||||||
|
RETURN_TOKEN(TOK_ALL);
|
||||||
|
}
|
||||||
|
|
||||||
#.*\r?\n { /* normal comment */
|
#.*\r?\n { /* normal comment */
|
||||||
DUMP_AND_DEBUG("comment(%d): %s\n", current_lineno, yytext);
|
DUMP_AND_DEBUG("comment(%d): %s\n", current_lineno, yytext);
|
||||||
current_lineno++;
|
current_lineno++;
|
||||||
|
@@ -919,6 +919,9 @@ void set_supported_features()
|
|||||||
features_supports_networkv8 = features_intersect(kernel_features,
|
features_supports_networkv8 = features_intersect(kernel_features,
|
||||||
policy_features,
|
policy_features,
|
||||||
"network_v8");
|
"network_v8");
|
||||||
|
features_supports_inet = features_intersect(kernel_features,
|
||||||
|
policy_features,
|
||||||
|
"network/af_inet");
|
||||||
features_supports_unix = features_intersect(kernel_features,
|
features_supports_unix = features_intersect(kernel_features,
|
||||||
policy_features,
|
policy_features,
|
||||||
"network/af_unix");
|
"network/af_unix");
|
||||||
@@ -951,6 +954,12 @@ void set_supported_features()
|
|||||||
features_supports_io_uring = features_intersect(kernel_features,
|
features_supports_io_uring = features_intersect(kernel_features,
|
||||||
policy_features,
|
policy_features,
|
||||||
"io_uring");
|
"io_uring");
|
||||||
|
features_supports_flag_interruptible = features_intersect(kernel_features,
|
||||||
|
policy_features,
|
||||||
|
"policy/profile/interruptible");
|
||||||
|
features_supports_flag_signal = features_intersect(kernel_features,
|
||||||
|
policy_features,
|
||||||
|
"policy/profile/kill.signal");
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool do_print_cache_dir(aa_features *features, int dirfd, const char *path)
|
static bool do_print_cache_dir(aa_features *features, int dirfd, const char *path)
|
||||||
|
@@ -129,6 +129,7 @@ static struct keyword_table keyword_table[] = {
|
|||||||
{"io_uring", TOK_IO_URING},
|
{"io_uring", TOK_IO_URING},
|
||||||
{"override_creds", TOK_OVERRIDE_CREDS},
|
{"override_creds", TOK_OVERRIDE_CREDS},
|
||||||
{"sqpoll", TOK_SQPOLL},
|
{"sqpoll", TOK_SQPOLL},
|
||||||
|
{"all", TOK_ALL},
|
||||||
|
|
||||||
/* terminate */
|
/* terminate */
|
||||||
{NULL, 0}
|
{NULL, 0}
|
||||||
@@ -1086,6 +1087,47 @@ void debug_cod_entries(struct cod_entry *list)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool check_x_qualifier(struct cod_entry *entry, const char *&error)
|
||||||
|
{
|
||||||
|
if (entry->perms & AA_EXEC_BITS) {
|
||||||
|
if ((entry->rule_mode == RULE_DENY) &&
|
||||||
|
(entry->perms & ALL_AA_EXEC_TYPE)) {
|
||||||
|
error = _("Invalid perms, in deny rules 'x' must not be preceded by exec qualifier 'i', 'p', or 'u'");
|
||||||
|
return false;
|
||||||
|
} else if ((entry->rule_mode != RULE_DENY) &&
|
||||||
|
!(entry->perms & ALL_AA_EXEC_TYPE)) {
|
||||||
|
error = _("Invalid perms, 'x' must be preceded by exec qualifier 'i', 'p', or 'u'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cod_entry version of ->add_prefix here just as file rules aren't converted yet
|
||||||
|
bool entry_add_prefix(struct cod_entry *entry, const prefixes &p, const char *&error)
|
||||||
|
{
|
||||||
|
/* modifiers aren't correctly stored for cod_entries yet so
|
||||||
|
* we can't conflict on them easily. Leave that until conversion
|
||||||
|
* to rule_t
|
||||||
|
*/
|
||||||
|
/* apply rule mode */
|
||||||
|
entry->rule_mode = p.rule_mode;
|
||||||
|
|
||||||
|
/* apply owner/other */
|
||||||
|
if (p.owner == 1)
|
||||||
|
entry->perms &= (AA_USER_PERMS | AA_SHARED_PERMS);
|
||||||
|
else if (p.owner == 2)
|
||||||
|
entry->perms &= (AA_OTHER_PERMS | AA_SHARED_PERMS);
|
||||||
|
|
||||||
|
/* implied audit modifier */
|
||||||
|
if (p.audit == AUDIT_FORCE && (entry->rule_mode != RULE_DENY))
|
||||||
|
entry->audit = AUDIT_FORCE;
|
||||||
|
else if (p.audit != AUDIT_FORCE && (entry->rule_mode == RULE_DENY))
|
||||||
|
entry->audit = AUDIT_FORCE;
|
||||||
|
|
||||||
|
return check_x_qualifier(entry, error);
|
||||||
|
}
|
||||||
|
|
||||||
// these need to move to stl
|
// these need to move to stl
|
||||||
int ordered_cmp_value_list(value_list *lhs, value_list *rhs)
|
int ordered_cmp_value_list(value_list *lhs, value_list *rhs)
|
||||||
{
|
{
|
||||||
|
@@ -33,6 +33,7 @@
|
|||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
#include "profile.h"
|
#include "profile.h"
|
||||||
#include "parser_yacc.h"
|
#include "parser_yacc.h"
|
||||||
|
#include "network.h"
|
||||||
|
|
||||||
/* #define DEBUG */
|
/* #define DEBUG */
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@@ -845,6 +845,116 @@ int clear_and_convert_entry(std::string& buffer, char *entry)
|
|||||||
return convert_entry(buffer, entry);
|
return convert_entry(buffer, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::vector<std::pair<bignum, bignum>> regex_range_generator(bignum start, bignum end)
|
||||||
|
{
|
||||||
|
std::vector<std::pair<bignum, bignum>> forward;
|
||||||
|
std::vector<std::pair<bignum, bignum>> reverse;
|
||||||
|
bignum next, prev;
|
||||||
|
|
||||||
|
while (start <= end) {
|
||||||
|
next = bignum::upper_bound_regex(start);
|
||||||
|
if (next > end)
|
||||||
|
break;
|
||||||
|
|
||||||
|
forward.emplace_back(start, next);
|
||||||
|
start = next + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!end.negative && end >= start) {
|
||||||
|
prev = bignum::lower_bound_regex(end);
|
||||||
|
if (prev < start || prev.negative)
|
||||||
|
break;
|
||||||
|
|
||||||
|
reverse.emplace_back(prev, end);
|
||||||
|
end = prev - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!end.negative && start <= end) {
|
||||||
|
forward.emplace_back(start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
forward.insert(forward.end(), reverse.rbegin(), reverse.rend());
|
||||||
|
return forward;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string generate_regex_range(bignum start, bignum end)
|
||||||
|
{
|
||||||
|
std::ostringstream result;
|
||||||
|
std::vector<std::pair<bignum, bignum>> regex_range;
|
||||||
|
int j;
|
||||||
|
regex_range = regex_range_generator(std::move(start), std::move(end));
|
||||||
|
for (auto &i: regex_range) {
|
||||||
|
bignum sstart = i.first;
|
||||||
|
bignum send = i.second;
|
||||||
|
if (sstart.base == 16) {
|
||||||
|
for (j = (size_t) sstart.size(); j < 32; j++)
|
||||||
|
result << '0';
|
||||||
|
}
|
||||||
|
for (j = sstart.size() - 1; j >= 0; j--) {
|
||||||
|
result << std::nouppercase;
|
||||||
|
if (sstart[j] == send[j]) {
|
||||||
|
if (sstart[j] >= 10)
|
||||||
|
result << '[';
|
||||||
|
result << std::hex << sstart[j];
|
||||||
|
if (sstart[j] >= 10)
|
||||||
|
result << std::uppercase << std::hex << sstart[j] << ']';
|
||||||
|
} else {
|
||||||
|
if (sstart[j] < 10 && send[j] >= 10) {
|
||||||
|
result << '[';
|
||||||
|
result << std::hex << sstart[j];
|
||||||
|
if (sstart[j] < 9) {
|
||||||
|
result << '-';
|
||||||
|
result << '9';
|
||||||
|
}
|
||||||
|
if (send[j] > 10) {
|
||||||
|
result << 'a';
|
||||||
|
result << '-';
|
||||||
|
}
|
||||||
|
result << std::hex << send[j];
|
||||||
|
if (send[j] > 10) {
|
||||||
|
result << 'A';
|
||||||
|
result << '-';
|
||||||
|
}
|
||||||
|
result << std::uppercase << std::hex << send[j];
|
||||||
|
result << ']';
|
||||||
|
} else {
|
||||||
|
result << '[';
|
||||||
|
result << std::hex << sstart[j];
|
||||||
|
result << '-';
|
||||||
|
result << std::hex << send[j];
|
||||||
|
if (sstart[j] >= 10) {
|
||||||
|
result << std::uppercase << std::hex << sstart[j];
|
||||||
|
result << '-';
|
||||||
|
result << std::uppercase << std::hex << send[j];
|
||||||
|
}
|
||||||
|
result << ']';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (&i != ®ex_range.back())
|
||||||
|
result << ",";
|
||||||
|
}
|
||||||
|
return result.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
int convert_range(std::string& buffer, bignum start, bignum end)
|
||||||
|
{
|
||||||
|
pattern_t ptype;
|
||||||
|
int pos;
|
||||||
|
|
||||||
|
std::string regex_range = generate_regex_range(std::move(start), std::move(end));
|
||||||
|
|
||||||
|
if (!regex_range.empty()) {
|
||||||
|
ptype = convert_aaregex_to_pcre(regex_range.c_str(), 0, glob_default, buffer, &pos);
|
||||||
|
if (ptype == ePatternInvalid)
|
||||||
|
return FALSE;
|
||||||
|
} else {
|
||||||
|
buffer.append(default_match_pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
int post_process_policydb_ents(Profile *prof)
|
int post_process_policydb_ents(Profile *prof)
|
||||||
{
|
{
|
||||||
for (RuleList::iterator i = prof->rule_ents.begin(); i != prof->rule_ents.end(); i++) {
|
for (RuleList::iterator i = prof->rule_ents.begin(); i != prof->rule_ents.end(); i++) {
|
||||||
@@ -857,80 +967,6 @@ int post_process_policydb_ents(Profile *prof)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool gen_net_rule(Profile *prof, u16 family, unsigned int type_mask,
|
|
||||||
bool audit, bool deny) {
|
|
||||||
std::ostringstream buffer;
|
|
||||||
std::string buf;
|
|
||||||
|
|
||||||
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_NETV8;
|
|
||||||
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << ((family & 0xff00) >> 8);
|
|
||||||
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << (family & 0xff);
|
|
||||||
if (type_mask > 0xffff) {
|
|
||||||
buffer << "..";
|
|
||||||
} else {
|
|
||||||
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << ((type_mask & 0xff00) >> 8);
|
|
||||||
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << (type_mask & 0xff);
|
|
||||||
}
|
|
||||||
buf = buffer.str();
|
|
||||||
if (!prof->policy.rules->add_rule(buf.c_str(), deny, map_perms(AA_VALID_NET_PERMS),
|
|
||||||
audit ? map_perms(AA_VALID_NET_PERMS) : 0,
|
|
||||||
parseopts))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool gen_af_rules(Profile *prof, u16 family, unsigned int type_mask,
|
|
||||||
unsigned int audit_mask, bool deny)
|
|
||||||
{
|
|
||||||
if (type_mask > 0xffff && audit_mask > 0xffff) {
|
|
||||||
/* instead of generating multiple rules wild card type */
|
|
||||||
return gen_net_rule(prof, family, type_mask, audit_mask, deny);
|
|
||||||
} else {
|
|
||||||
int t;
|
|
||||||
/* generate rules for types that are set */
|
|
||||||
for (t = 0; t < 16; t++) {
|
|
||||||
if (type_mask & (1 << t)) {
|
|
||||||
if (!gen_net_rule(prof, family, t,
|
|
||||||
audit_mask & (1 << t),
|
|
||||||
deny))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool post_process_policydb_net(Profile *prof)
|
|
||||||
{
|
|
||||||
u16 af;
|
|
||||||
|
|
||||||
/* no network rules defined so we don't have generate them */
|
|
||||||
if (!prof->net.allow)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
/* generate rules if the af has something set */
|
|
||||||
for (af = AF_UNSPEC; af < get_af_max(); af++) {
|
|
||||||
if (prof->net.allow[af] ||
|
|
||||||
prof->net.deny[af] ||
|
|
||||||
prof->net.audit[af] ||
|
|
||||||
prof->net.quiet[af]) {
|
|
||||||
if (!gen_af_rules(prof, af, prof->net.allow[af],
|
|
||||||
prof->net.audit[af],
|
|
||||||
false))
|
|
||||||
return false;
|
|
||||||
if (!gen_af_rules(prof, af, prof->net.deny[af],
|
|
||||||
prof->net.quiet[af],
|
|
||||||
true))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MAKE_STR(X) #X
|
#define MAKE_STR(X) #X
|
||||||
#define CLASS_STR(X) "\\d" MAKE_STR(X)
|
#define CLASS_STR(X) "\\d" MAKE_STR(X)
|
||||||
#define MAKE_SUB_STR(X) "\\000" MAKE_STR(X)
|
#define MAKE_SUB_STR(X) "\\000" MAKE_STR(X)
|
||||||
@@ -959,9 +995,6 @@ int process_profile_policydb(Profile *prof)
|
|||||||
|
|
||||||
if (!post_process_policydb_ents(prof))
|
if (!post_process_policydb_ents(prof))
|
||||||
goto out;
|
goto out;
|
||||||
/* TODO: move to network class */
|
|
||||||
if (features_supports_networkv8 && !post_process_policydb_net(prof))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/* insert entries to show indicate what compiler/policy expects
|
/* insert entries to show indicate what compiler/policy expects
|
||||||
* to be supported
|
* to be supported
|
||||||
|
@@ -70,8 +70,6 @@ mnt_rule *do_mnt_rule(struct cond_entry *src_conds, char *src,
|
|||||||
mnt_rule *do_pivot_rule(struct cond_entry *old, char *root,
|
mnt_rule *do_pivot_rule(struct cond_entry *old, char *root,
|
||||||
char *transition);
|
char *transition);
|
||||||
static void abi_features(char *filename, bool search);
|
static void abi_features(char *filename, bool search);
|
||||||
bool add_prefix(struct cod_entry *entry, const prefixes &p, const char *&error);
|
|
||||||
bool check_x_qualifier(struct cod_entry *entry, const char *&errror);
|
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
@@ -149,6 +147,7 @@ bool check_x_qualifier(struct cod_entry *entry, const char *&errror);
|
|||||||
%token TOK_IO_URING
|
%token TOK_IO_URING
|
||||||
%token TOK_OVERRIDE_CREDS
|
%token TOK_OVERRIDE_CREDS
|
||||||
%token TOK_SQPOLL
|
%token TOK_SQPOLL
|
||||||
|
%token TOK_ALL
|
||||||
|
|
||||||
/* rlimits */
|
/* rlimits */
|
||||||
%token TOK_RLIMIT
|
%token TOK_RLIMIT
|
||||||
@@ -187,13 +186,15 @@ bool check_x_qualifier(struct cod_entry *entry, const char *&errror);
|
|||||||
#include "userns.h"
|
#include "userns.h"
|
||||||
#include "mqueue.h"
|
#include "mqueue.h"
|
||||||
#include "io_uring.h"
|
#include "io_uring.h"
|
||||||
|
#include "network.h"
|
||||||
|
#include "all_rule.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
%union {
|
%union {
|
||||||
char *id;
|
char *id;
|
||||||
char *flag_id;
|
char *flag_id;
|
||||||
char *mode;
|
char *mode;
|
||||||
struct aa_network_entry *network_entry;
|
network_rule *network_entry;
|
||||||
Profile *prof;
|
Profile *prof;
|
||||||
struct cod_net_entry *net_entry;
|
struct cod_net_entry *net_entry;
|
||||||
struct cod_entry *user_entry;
|
struct cod_entry *user_entry;
|
||||||
@@ -206,6 +207,7 @@ bool check_x_qualifier(struct cod_entry *entry, const char *&errror);
|
|||||||
userns_rule *userns_entry;
|
userns_rule *userns_entry;
|
||||||
mqueue_rule *mqueue_entry;
|
mqueue_rule *mqueue_entry;
|
||||||
io_uring_rule *io_uring_entry;
|
io_uring_rule *io_uring_entry;
|
||||||
|
all_rule *all_entry;
|
||||||
prefix_rule_t *prefix_entry;
|
prefix_rule_t *prefix_entry;
|
||||||
|
|
||||||
flagvals flags;
|
flagvals flags;
|
||||||
@@ -302,6 +304,7 @@ bool check_x_qualifier(struct cod_entry *entry, const char *&errror);
|
|||||||
%type <fperms> io_uring_perms
|
%type <fperms> io_uring_perms
|
||||||
%type <fperms> opt_io_uring_perm
|
%type <fperms> opt_io_uring_perm
|
||||||
%type <io_uring_entry> io_uring_rule
|
%type <io_uring_entry> io_uring_rule
|
||||||
|
%type <all_entry> all_rule
|
||||||
%%
|
%%
|
||||||
|
|
||||||
|
|
||||||
@@ -575,8 +578,9 @@ valuelist: valuelist TOK_VALUE
|
|||||||
}
|
}
|
||||||
|
|
||||||
flags: { /* nothing */
|
flags: { /* nothing */
|
||||||
flagvals fv = { 0, MODE_UNSPECIFIED, 0, 0, NULL };
|
flagvals fv;
|
||||||
|
|
||||||
|
fv.init();
|
||||||
$$ = fv;
|
$$ = fv;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -596,27 +600,7 @@ flags: opt_flags TOK_OPENPAREN flagvals TOK_CLOSEPAREN
|
|||||||
|
|
||||||
flagvals: flagvals flagval
|
flagvals: flagvals flagval
|
||||||
{
|
{
|
||||||
if (merge_profile_mode($1.mode, $2.mode) == MODE_CONFLICT)
|
$1.merge($2);
|
||||||
yyerror(_("Profile flag '%s' conflicts with '%s'"),
|
|
||||||
profile_mode_table[$1.mode],
|
|
||||||
profile_mode_table[$2.mode]);
|
|
||||||
$1.mode = merge_profile_mode($1.mode, $2.mode);
|
|
||||||
$1.audit = $1.audit || $2.audit;
|
|
||||||
$1.path = $1.path | $2.path;
|
|
||||||
if (($1.path & (PATH_CHROOT_REL | PATH_NS_REL)) ==
|
|
||||||
(PATH_CHROOT_REL | PATH_NS_REL))
|
|
||||||
yyerror(_("Profile flag chroot_relative conflicts with namespace_relative"));
|
|
||||||
|
|
||||||
if (($1.path & (PATH_MEDIATE_DELETED | PATH_DELEGATE_DELETED)) ==
|
|
||||||
(PATH_MEDIATE_DELETED | PATH_DELEGATE_DELETED))
|
|
||||||
yyerror(_("Profile flag mediate_deleted conflicts with delegate_deleted"));
|
|
||||||
if (($1.path & (PATH_ATTACH | PATH_NO_ATTACH)) ==
|
|
||||||
(PATH_ATTACH | PATH_NO_ATTACH))
|
|
||||||
yyerror(_("Profile flag attach_disconnected conflicts with no_attach_disconnected"));
|
|
||||||
if (($1.path & (PATH_CHROOT_NSATTACH | PATH_CHROOT_NO_ATTACH)) ==
|
|
||||||
(PATH_CHROOT_NSATTACH | PATH_CHROOT_NO_ATTACH))
|
|
||||||
yyerror(_("Profile flag chroot_attach conflicts with chroot_no_attach"));
|
|
||||||
|
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -627,39 +611,9 @@ flagvals: flagval
|
|||||||
|
|
||||||
flagval: TOK_VALUE
|
flagval: TOK_VALUE
|
||||||
{
|
{
|
||||||
flagvals fv = { 0, MODE_UNSPECIFIED, 0, 0, NULL };
|
flagvals fv;
|
||||||
enum profile_mode mode;
|
|
||||||
|
|
||||||
if (strcmp($1, "debug") == 0) {
|
fv.init($1);
|
||||||
/* DEBUG2 is left for internal compiler use atm */
|
|
||||||
fv.flags |= FLAG_DEBUG1;
|
|
||||||
} else if ((mode = str_to_mode($1))) {
|
|
||||||
fv.mode = mode;
|
|
||||||
} else if (strcmp($1, "audit") == 0) {
|
|
||||||
fv.audit = 1;
|
|
||||||
} else if (strcmp($1, "chroot_relative") == 0) {
|
|
||||||
fv.path |= PATH_CHROOT_REL;
|
|
||||||
} else if (strcmp($1, "namespace_relative") == 0) {
|
|
||||||
fv.path |= PATH_NS_REL;
|
|
||||||
} else if (strcmp($1, "mediate_deleted") == 0) {
|
|
||||||
fv.path |= PATH_MEDIATE_DELETED;
|
|
||||||
} else if (strcmp($1, "delegate_deleted") == 0) {
|
|
||||||
fv.path |= PATH_DELEGATE_DELETED;
|
|
||||||
} else if (strcmp($1, "attach_disconnected") == 0) {
|
|
||||||
fv.path |= PATH_ATTACH;
|
|
||||||
} else if (strcmp($1, "no_attach_disconnected") == 0) {
|
|
||||||
fv.path |= PATH_NO_ATTACH;
|
|
||||||
} else if (strcmp($1, "chroot_attach") == 0) {
|
|
||||||
fv.path |= PATH_CHROOT_NSATTACH;
|
|
||||||
} else if (strcmp($1, "chroot_no_attach") == 0) {
|
|
||||||
fv.path |= PATH_CHROOT_NO_ATTACH;
|
|
||||||
} else if (strncmp($1, "attach_disconnected.path=", 25) == 0) {
|
|
||||||
/* TODO: make this a proper parse */
|
|
||||||
fv.path |= PATH_ATTACH;
|
|
||||||
fv.disconnected_path = strdup($1 + 25);
|
|
||||||
} else {
|
|
||||||
yyerror(_("Invalid profile flag: %s."), $1);
|
|
||||||
}
|
|
||||||
free($1);
|
free($1);
|
||||||
$$ = fv;
|
$$ = fv;
|
||||||
};
|
};
|
||||||
@@ -704,7 +658,7 @@ rules: rules opt_prefix rule
|
|||||||
PDEBUG("rules rule: (%s)\n", $3->name);
|
PDEBUG("rules rule: (%s)\n", $3->name);
|
||||||
if (!$3)
|
if (!$3)
|
||||||
yyerror(_("Assert: `rule' returned NULL."));
|
yyerror(_("Assert: `rule' returned NULL."));
|
||||||
if (!add_prefix($3, $2, error)) {
|
if (!entry_add_prefix($3, $2, error)) {
|
||||||
yyerror(_("%s"), error);
|
yyerror(_("%s"), error);
|
||||||
}
|
}
|
||||||
add_entry_to_policy($1, $3);
|
add_entry_to_policy($1, $3);
|
||||||
@@ -725,7 +679,7 @@ rules: rules opt_prefix block
|
|||||||
list_for_each_safe($3->entries, entry, tmp) {
|
list_for_each_safe($3->entries, entry, tmp) {
|
||||||
const char *error;
|
const char *error;
|
||||||
entry->next = NULL;
|
entry->next = NULL;
|
||||||
if (!add_prefix(entry, $2, error)) {
|
if (!entry_add_prefix(entry, $2, error)) {
|
||||||
yyerror(_("%s"), error);
|
yyerror(_("%s"), error);
|
||||||
}
|
}
|
||||||
/* transfer rule for now, TODO keep block and just
|
/* transfer rule for now, TODO keep block and just
|
||||||
@@ -742,51 +696,23 @@ rules: rules opt_prefix block
|
|||||||
|
|
||||||
rules: rules opt_prefix network_rule
|
rules: rules opt_prefix network_rule
|
||||||
{
|
{
|
||||||
struct aa_network_entry *entry, *tmp;
|
const char *error;
|
||||||
|
if (!$3->add_prefix($2, error))
|
||||||
|
yyerror(error);
|
||||||
|
/* class members need to be updated after prefix is added */
|
||||||
|
$3->update_compat_net();
|
||||||
|
|
||||||
PDEBUG("Matched: network rule\n");
|
auto nm_af_unix = $3->network_map.find(AF_UNIX);
|
||||||
if ($2.owner)
|
if (nm_af_unix != $3->network_map.end()) {
|
||||||
yyerror(_("owner prefix not allowed"));
|
for (auto& entry : nm_af_unix->second) {
|
||||||
if (!$3)
|
unix_rule *rule = new unix_rule(entry.type,
|
||||||
yyerror(_("Assert: `network_rule' return invalid protocol."));
|
$2.audit, $2.rule_mode);
|
||||||
if (!$1->alloc_net_table())
|
|
||||||
yyerror(_("Memory allocation error."));
|
|
||||||
list_for_each_safe($3, entry, tmp) {
|
|
||||||
|
|
||||||
/* map to extended mediation, let rule backend do
|
|
||||||
* downgrade if needed
|
|
||||||
*/
|
|
||||||
if (entry->family == AF_UNIX) {
|
|
||||||
unix_rule *rule = new unix_rule(entry->type, $2.audit, $2.rule_mode);
|
|
||||||
if (!rule)
|
if (!rule)
|
||||||
yyerror(_("Memory allocation error."));
|
yyerror(_("Memory allocation error."));
|
||||||
$1->rule_ents.push_back(rule);
|
$1->rule_ents.push_back(rule);
|
||||||
}
|
}
|
||||||
if (entry->type > SOCK_PACKET) {
|
|
||||||
/* setting mask instead of a bit */
|
|
||||||
if ($2.rule_mode == RULE_DENY) {
|
|
||||||
$1->net.deny[entry->family] |= entry->type;
|
|
||||||
if ($2.audit != AUDIT_FORCE)
|
|
||||||
$1->net.quiet[entry->family] |= entry->type;
|
|
||||||
} else {
|
|
||||||
$1->net.allow[entry->family] |= entry->type;
|
|
||||||
if ($2.audit == AUDIT_FORCE)
|
|
||||||
$1->net.audit[entry->family] |= entry->type;
|
|
||||||
}
|
}
|
||||||
} else {
|
$1->rule_ents.push_back($3);
|
||||||
if ($2.rule_mode == RULE_DENY) {
|
|
||||||
$1->net.deny[entry->family] |= 1 << entry->type;
|
|
||||||
if ($2.audit != AUDIT_FORCE)
|
|
||||||
$1->net.quiet[entry->family] |= 1 << entry->type;
|
|
||||||
} else {
|
|
||||||
$1->net.allow[entry->family] |= 1 << entry->type;
|
|
||||||
if ($2.audit == AUDIT_FORCE)
|
|
||||||
$1->net.audit[entry->family] |= 1 << entry->type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -798,6 +724,7 @@ prefix_rule : mnt_rule { $$ = $1; }
|
|||||||
| userns_rule { $$ = $1; }
|
| userns_rule { $$ = $1; }
|
||||||
| mqueue_rule { $$ = $1; }
|
| mqueue_rule { $$ = $1; }
|
||||||
| io_uring_rule { $$ = $1; }
|
| io_uring_rule { $$ = $1; }
|
||||||
|
| all_rule { $$ = $1; }
|
||||||
|
|
||||||
rules: rules opt_prefix prefix_rule
|
rules: rules opt_prefix prefix_rule
|
||||||
{
|
{
|
||||||
@@ -1156,45 +1083,48 @@ link_rule: TOK_LINK opt_subset_flag id_or_var TOK_ARROW id_or_var TOK_END_OF_RUL
|
|||||||
$$ = entry;
|
$$ = entry;
|
||||||
};
|
};
|
||||||
|
|
||||||
network_rule: TOK_NETWORK TOK_END_OF_RULE
|
network_rule: TOK_NETWORK opt_net_perm opt_conds opt_cond_list TOK_END_OF_RULE
|
||||||
{
|
{
|
||||||
size_t family;
|
network_rule *entry;
|
||||||
struct aa_network_entry *new_entry, *entry = NULL;
|
|
||||||
for (family = AF_UNSPEC; family < get_af_max(); family++) {
|
if ($4.name) {
|
||||||
new_entry = new_network_ent(family, 0xffffffff,
|
if (strcmp($4.name, "peer") != 0)
|
||||||
0xffffffff);
|
yyerror(_("network rule: invalid conditional group %s=()"), $4.name);
|
||||||
if (!new_entry)
|
free($4.name);
|
||||||
yyerror(_("Memory allocation error."));
|
|
||||||
new_entry->next = entry;
|
|
||||||
entry = new_entry;
|
|
||||||
}
|
}
|
||||||
|
entry = new network_rule($2, $3, $4.list);
|
||||||
$$ = entry;
|
$$ = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
network_rule: TOK_NETWORK TOK_ID TOK_END_OF_RULE
|
network_rule: TOK_NETWORK opt_net_perm TOK_ID opt_conds opt_cond_list TOK_END_OF_RULE
|
||||||
{
|
{
|
||||||
struct aa_network_entry *entry;
|
network_rule *entry;
|
||||||
entry = network_entry($2, NULL, NULL);
|
|
||||||
if (!entry)
|
|
||||||
/* test for short circuiting of family */
|
|
||||||
entry = network_entry(NULL, $2, NULL);
|
|
||||||
if (!entry)
|
|
||||||
yyerror(_("Invalid network entry."));
|
|
||||||
free($2);
|
|
||||||
$$ = entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
network_rule: TOK_NETWORK TOK_ID TOK_ID TOK_END_OF_RULE
|
if ($5.name) {
|
||||||
{
|
if (strcmp($5.name, "peer") != 0)
|
||||||
struct aa_network_entry *entry;
|
yyerror(_("network rule: invalid conditional group %s=()"), $5.name);
|
||||||
entry = network_entry($2, $3, NULL);
|
free($5.name);
|
||||||
if (!entry)
|
}
|
||||||
yyerror(_("Invalid network entry."));
|
entry = new network_rule($2, $3, NULL, NULL, $4, $5.list);
|
||||||
free($2);
|
|
||||||
free($3);
|
free($3);
|
||||||
$$ = entry;
|
$$ = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
network_rule: TOK_NETWORK opt_net_perm TOK_ID TOK_ID opt_conds opt_cond_list TOK_END_OF_RULE
|
||||||
|
{
|
||||||
|
network_rule *entry;
|
||||||
|
|
||||||
|
if ($6.name) {
|
||||||
|
if (strcmp($6.name, "peer") != 0)
|
||||||
|
yyerror(_("network rule: invalid conditional group %s=()"), $6.name);
|
||||||
|
free($6.name);
|
||||||
|
}
|
||||||
|
entry = new network_rule($2, $3, $4, NULL, $5, $6.list);
|
||||||
|
free($3);
|
||||||
|
free($4);
|
||||||
|
$$ = entry;
|
||||||
|
}
|
||||||
|
|
||||||
cond: TOK_CONDID
|
cond: TOK_CONDID
|
||||||
{
|
{
|
||||||
struct cond_entry *ent;
|
struct cond_entry *ent;
|
||||||
@@ -1605,6 +1535,14 @@ io_uring_rule: TOK_IO_URING opt_io_uring_perm opt_conds opt_cond_list TOK_END_OF
|
|||||||
$$ = ent;
|
$$ = ent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
all_rule: TOK_ALL TOK_END_OF_RULE
|
||||||
|
{
|
||||||
|
all_rule *ent = new all_rule();
|
||||||
|
if (!ent)
|
||||||
|
yyerror(_("Memory allocation error."));
|
||||||
|
$$ = ent;
|
||||||
|
}
|
||||||
|
|
||||||
hat_start: TOK_CARET {}
|
hat_start: TOK_CARET {}
|
||||||
| TOK_HAT {}
|
| TOK_HAT {}
|
||||||
|
|
||||||
@@ -1867,43 +1805,3 @@ static void abi_features(char *filename, bool search)
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bool check_x_qualifier(struct cod_entry *entry, const char *&error)
|
|
||||||
{
|
|
||||||
if (entry->perms & AA_EXEC_BITS) {
|
|
||||||
if ((entry->rule_mode == RULE_DENY) &&
|
|
||||||
(entry->perms & ALL_AA_EXEC_TYPE)) {
|
|
||||||
error = _("Invalid perms, in deny rules 'x' must not be preceded by exec qualifier 'i', 'p', or 'u'");
|
|
||||||
return false;
|
|
||||||
} else if ((entry->rule_mode != RULE_DENY) &&
|
|
||||||
!(entry->perms & ALL_AA_EXEC_TYPE)) {
|
|
||||||
error = _("Invalid perms, 'x' must be preceded by exec qualifier 'i', 'p', or 'u'");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// cod_entry version of ->add_prefix here just as file rules aren't converted yet
|
|
||||||
bool add_prefix(struct cod_entry *entry, const prefixes &p, const char *&error)
|
|
||||||
{
|
|
||||||
/* modifiers aren't correctly stored for cod_entries yet so
|
|
||||||
* we can't conflict on them easily. Leave that until conversion
|
|
||||||
* to rule_t
|
|
||||||
*/
|
|
||||||
/* apply rule mode */
|
|
||||||
entry->rule_mode = p.rule_mode;
|
|
||||||
|
|
||||||
/* apply owner/other */
|
|
||||||
if (p.owner == 1)
|
|
||||||
entry->perms &= (AA_USER_PERMS | AA_SHARED_PERMS);
|
|
||||||
else if (p.owner == 2)
|
|
||||||
entry->perms &= (AA_OTHER_PERMS | AA_SHARED_PERMS);
|
|
||||||
|
|
||||||
/* implied audit modifier */
|
|
||||||
if (p.audit == AUDIT_FORCE && (entry->rule_mode != RULE_DENY))
|
|
||||||
entry->audit = AUDIT_FORCE;
|
|
||||||
else if (p.audit != AUDIT_FORCE && (entry->rule_mode == RULE_DENY))
|
|
||||||
entry->audit = AUDIT_FORCE;
|
|
||||||
|
|
||||||
return check_x_qualifier(entry, error);
|
|
||||||
}
|
|
||||||
|
@@ -27,7 +27,9 @@ const char *profile_mode_table[] = {
|
|||||||
"complain",
|
"complain",
|
||||||
"kill",
|
"kill",
|
||||||
"unconfined",
|
"unconfined",
|
||||||
"prompt"
|
"prompt",
|
||||||
|
"default_allow",
|
||||||
|
"conflict" /* should not ever be displayed */
|
||||||
};
|
};
|
||||||
|
|
||||||
bool deref_profileptr_lt::operator()(Profile * const &lhs, Profile * const &rhs) const
|
bool deref_profileptr_lt::operator()(Profile * const &lhs, Profile * const &rhs) const
|
||||||
@@ -71,20 +73,6 @@ void ProfileList::dump_profile_names(bool children)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Profile::alloc_net_table()
|
|
||||||
{
|
|
||||||
if (net.allow)
|
|
||||||
return true;
|
|
||||||
net.allow = (unsigned int *) calloc(get_af_max(), sizeof(unsigned int));
|
|
||||||
net.audit = (unsigned int *) calloc(get_af_max(), sizeof(unsigned int));
|
|
||||||
net.deny = (unsigned int *) calloc(get_af_max(), sizeof(unsigned int));
|
|
||||||
net.quiet = (unsigned int *) calloc(get_af_max(), sizeof(unsigned int));
|
|
||||||
if (!net.allow || !net.audit || !net.deny || !net.quiet)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Profile::~Profile()
|
Profile::~Profile()
|
||||||
{
|
{
|
||||||
hat_table.clear();
|
hat_table.clear();
|
||||||
@@ -114,14 +102,6 @@ Profile::~Profile()
|
|||||||
for (int i = (AA_EXEC_LOCAL >> 10) + 1; i < AA_EXEC_COUNT; i++)
|
for (int i = (AA_EXEC_LOCAL >> 10) + 1; i < AA_EXEC_COUNT; i++)
|
||||||
if (exec_table[i])
|
if (exec_table[i])
|
||||||
free(exec_table[i]);
|
free(exec_table[i]);
|
||||||
if (net.allow)
|
|
||||||
free(net.allow);
|
|
||||||
if (net.audit)
|
|
||||||
free(net.audit);
|
|
||||||
if (net.deny)
|
|
||||||
free(net.deny);
|
|
||||||
if (net.quiet)
|
|
||||||
free(net.quiet);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool comp (rule_t *lhs, rule_t *rhs)
|
static bool comp (rule_t *lhs, rule_t *rhs)
|
||||||
@@ -347,6 +327,19 @@ static int profile_add_hat_rules(Profile *prof)
|
|||||||
|
|
||||||
void Profile::post_parse_profile(void)
|
void Profile::post_parse_profile(void)
|
||||||
{
|
{
|
||||||
|
/* semantic check stuff that can't be done in parse, like flags */
|
||||||
|
if (flags.flags & FLAG_INTERRUPTIBLE) {
|
||||||
|
if (!features_supports_flag_interruptible) {
|
||||||
|
warn_once(name, "flag interruptible not supported. Ignoring");
|
||||||
|
/* TODO: don't clear in parse data, only at encode */
|
||||||
|
flags.flags &= ~FLAG_INTERRUPTIBLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (flags.signal) {
|
||||||
|
if (!features_supports_flag_signal) {
|
||||||
|
warn_once(name, "kill.signal not supported. Ignoring");
|
||||||
|
}
|
||||||
|
}
|
||||||
post_process_file_entries(this);
|
post_process_file_entries(this);
|
||||||
post_process_rule_entries(this);
|
post_process_rule_entries(this);
|
||||||
}
|
}
|
||||||
@@ -355,6 +348,12 @@ void Profile::add_implied_rules(void)
|
|||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
for (RuleList::iterator i = rule_ents.begin(); i != rule_ents.end(); i++) {
|
||||||
|
if ((*i)->skip())
|
||||||
|
continue;
|
||||||
|
(*i)->add_implied_rules(*this);
|
||||||
|
}
|
||||||
|
|
||||||
error = profile_add_hat_rules(this);
|
error = profile_add_hat_rules(this);
|
||||||
if (error) {
|
if (error) {
|
||||||
PERROR(_("ERROR adding hat access rule for profile %s\n"),
|
PERROR(_("ERROR adding hat access rule for profile %s\n"),
|
||||||
@@ -363,3 +362,9 @@ void Profile::add_implied_rules(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* do we want to warn once/profile or just once per compile?? */
|
||||||
|
void Profile::warn_once(const char *name, const char *msg)
|
||||||
|
{
|
||||||
|
common_warn_once(name, msg, &warned_name);
|
||||||
|
}
|
||||||
|
131
parser/profile.h
131
parser/profile.h
@@ -23,6 +23,7 @@
|
|||||||
#include "rule.h"
|
#include "rule.h"
|
||||||
#include "libapparmor_re/aare_rules.h"
|
#include "libapparmor_re/aare_rules.h"
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
|
#include "signal.h"
|
||||||
|
|
||||||
class Profile;
|
class Profile;
|
||||||
|
|
||||||
@@ -63,9 +64,10 @@ enum profile_mode {
|
|||||||
MODE_KILL = 3,
|
MODE_KILL = 3,
|
||||||
MODE_UNCONFINED = 4,
|
MODE_UNCONFINED = 4,
|
||||||
MODE_PROMPT = 5,
|
MODE_PROMPT = 5,
|
||||||
MODE_CONFLICT = 6 /* greater than MODE_LAST */
|
MODE_DEFAULT_ALLOW = 6,
|
||||||
|
MODE_CONFLICT = 7 /* greater than MODE_LAST */
|
||||||
};
|
};
|
||||||
#define MODE_LAST MODE_PROMPT
|
#define MODE_LAST MODE_DEFAULT_ALLOW
|
||||||
|
|
||||||
static inline enum profile_mode operator++(enum profile_mode &mode)
|
static inline enum profile_mode operator++(enum profile_mode &mode)
|
||||||
{
|
{
|
||||||
@@ -84,6 +86,9 @@ static inline enum profile_mode merge_profile_mode(enum profile_mode l, enum pro
|
|||||||
|
|
||||||
static inline uint32_t profile_mode_packed(enum profile_mode mode)
|
static inline uint32_t profile_mode_packed(enum profile_mode mode)
|
||||||
{
|
{
|
||||||
|
/* until dominance is fixed use unconfined mode for default_allow */
|
||||||
|
if (mode == MODE_DEFAULT_ALLOW)
|
||||||
|
mode = MODE_UNCONFINED;
|
||||||
/* kernel doesn't have an unspecified mode everything
|
/* kernel doesn't have an unspecified mode everything
|
||||||
* shifts down by 1
|
* shifts down by 1
|
||||||
*/
|
*/
|
||||||
@@ -114,7 +119,9 @@ static inline enum profile_mode str_to_mode(const char *str)
|
|||||||
#define FLAG_HAT 1
|
#define FLAG_HAT 1
|
||||||
#define FLAG_DEBUG1 2
|
#define FLAG_DEBUG1 2
|
||||||
#define FLAG_DEBUG2 4
|
#define FLAG_DEBUG2 4
|
||||||
|
#define FLAG_INTERRUPTIBLE 8
|
||||||
|
|
||||||
|
/* sigh, used in parse union so needs trivial constructors. */
|
||||||
class flagvals {
|
class flagvals {
|
||||||
public:
|
public:
|
||||||
int flags;
|
int flags;
|
||||||
@@ -122,6 +129,61 @@ public:
|
|||||||
int audit;
|
int audit;
|
||||||
int path;
|
int path;
|
||||||
char *disconnected_path;
|
char *disconnected_path;
|
||||||
|
int signal;
|
||||||
|
|
||||||
|
// stupid not constructor constructors
|
||||||
|
void init(void)
|
||||||
|
{
|
||||||
|
flags = 0;
|
||||||
|
mode = MODE_UNSPECIFIED;
|
||||||
|
audit = 0;
|
||||||
|
path = 0;
|
||||||
|
disconnected_path = NULL;
|
||||||
|
signal = 0;
|
||||||
|
}
|
||||||
|
void init(const char *str)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
enum profile_mode pmode = str_to_mode(str);
|
||||||
|
|
||||||
|
if (strcmp(str, "debug") == 0) {
|
||||||
|
/* DEBUG2 is left for internal compiler use atm */
|
||||||
|
flags |= FLAG_DEBUG1;
|
||||||
|
} else if (pmode) {
|
||||||
|
mode = pmode;
|
||||||
|
} else if (strcmp(str, "audit") == 0) {
|
||||||
|
audit = 1;
|
||||||
|
} else if (strcmp(str, "chroot_relative") == 0) {
|
||||||
|
path |= PATH_CHROOT_REL;
|
||||||
|
} else if (strcmp(str, "namespace_relative") == 0) {
|
||||||
|
path |= PATH_NS_REL;
|
||||||
|
} else if (strcmp(str, "mediate_deleted") == 0) {
|
||||||
|
path |= PATH_MEDIATE_DELETED;
|
||||||
|
} else if (strcmp(str, "delegate_deleted") == 0) {
|
||||||
|
path |= PATH_DELEGATE_DELETED;
|
||||||
|
} else if (strcmp(str, "attach_disconnected") == 0) {
|
||||||
|
path |= PATH_ATTACH;
|
||||||
|
} else if (strcmp(str, "no_attach_disconnected") == 0) {
|
||||||
|
path |= PATH_NO_ATTACH;
|
||||||
|
} else if (strcmp(str, "chroot_attach") == 0) {
|
||||||
|
path |= PATH_CHROOT_NSATTACH;
|
||||||
|
} else if (strcmp(str, "chroot_no_attach") == 0) {
|
||||||
|
path |= PATH_CHROOT_NO_ATTACH;
|
||||||
|
} else if (strncmp(str, "attach_disconnected.path=", 25) == 0) {
|
||||||
|
/* TODO: make this a proper parse */
|
||||||
|
path |= PATH_ATTACH;
|
||||||
|
disconnected_path = strdup(str + 25);
|
||||||
|
} else if (strncmp(str, "kill.signal=", 12) == 0) {
|
||||||
|
/* TODO: make this a proper parse */
|
||||||
|
signal = find_signal_mapping(str + 12);
|
||||||
|
if (signal == -1)
|
||||||
|
yyerror("unknown signal specified for kill.signal=\'%s\'\n", str + 12);
|
||||||
|
} else if (strcmp(str, "interruptible") == 0) {
|
||||||
|
flags |= FLAG_INTERRUPTIBLE;
|
||||||
|
} else {
|
||||||
|
yyerror(_("Invalid profile flag: %s."), str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ostream &dump(ostream &os)
|
ostream &dump(ostream &os)
|
||||||
{
|
{
|
||||||
@@ -135,6 +197,8 @@ public:
|
|||||||
|
|
||||||
if (disconnected_path)
|
if (disconnected_path)
|
||||||
os << ", attach_disconnected.path=" << disconnected_path;
|
os << ", attach_disconnected.path=" << disconnected_path;
|
||||||
|
if (signal)
|
||||||
|
os << ", kill.signal=" << signal;
|
||||||
os << "\n";
|
os << "\n";
|
||||||
|
|
||||||
return os;
|
return os;
|
||||||
@@ -148,6 +212,58 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* warning for now disconnected_path is just passed on (not copied),
|
||||||
|
* or leaked on error. It is not freed here, It is freed when the
|
||||||
|
* profile destroys it self.
|
||||||
|
*/
|
||||||
|
void merge(const flagvals &rhs)
|
||||||
|
{
|
||||||
|
if (merge_profile_mode(mode, rhs.mode) == MODE_CONFLICT)
|
||||||
|
yyerror(_("Profile flag '%s' conflicts with '%s'"),
|
||||||
|
profile_mode_table[mode],
|
||||||
|
profile_mode_table[rhs.mode]);
|
||||||
|
mode = merge_profile_mode(mode, rhs.mode);
|
||||||
|
audit = audit || rhs.audit;
|
||||||
|
path = path | rhs.path;
|
||||||
|
if ((path & (PATH_CHROOT_REL | PATH_NS_REL)) ==
|
||||||
|
(PATH_CHROOT_REL | PATH_NS_REL))
|
||||||
|
yyerror(_("Profile flag chroot_relative conflicts with namespace_relative"));
|
||||||
|
|
||||||
|
if ((path & (PATH_MEDIATE_DELETED | PATH_DELEGATE_DELETED)) ==
|
||||||
|
(PATH_MEDIATE_DELETED | PATH_DELEGATE_DELETED))
|
||||||
|
yyerror(_("Profile flag mediate_deleted conflicts with delegate_deleted"));
|
||||||
|
if ((path & (PATH_ATTACH | PATH_NO_ATTACH)) ==
|
||||||
|
(PATH_ATTACH | PATH_NO_ATTACH))
|
||||||
|
yyerror(_("Profile flag attach_disconnected conflicts with no_attach_disconnected"));
|
||||||
|
if ((path & (PATH_CHROOT_NSATTACH | PATH_CHROOT_NO_ATTACH)) ==
|
||||||
|
(PATH_CHROOT_NSATTACH | PATH_CHROOT_NO_ATTACH))
|
||||||
|
yyerror(_("Profile flag chroot_attach conflicts with chroot_no_attach"));
|
||||||
|
|
||||||
|
if (rhs.disconnected_path) {
|
||||||
|
if (disconnected_path) {
|
||||||
|
if (strcmp(disconnected_path, rhs.disconnected_path) != 0) {
|
||||||
|
yyerror(_("Profile flag attach_disconnected set to conflicting values: '%s' and '%s'"), disconnected_path, rhs.disconnected_path);
|
||||||
|
}
|
||||||
|
// same ignore rhs.disconnect_path
|
||||||
|
} else {
|
||||||
|
disconnected_path = rhs.disconnected_path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rhs.signal) {
|
||||||
|
if (signal) {
|
||||||
|
if (signal != rhs.signal) {
|
||||||
|
yyerror(_("Profile flag kill.signal set to conflicting values: '%d' and '%d'"), signal, rhs.signal);
|
||||||
|
}
|
||||||
|
// same so do nothing
|
||||||
|
} else {
|
||||||
|
signal = rhs.signal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if we move to dupping disconnected_path will need to have
|
||||||
|
* an assignment and copy constructor and a destructor
|
||||||
|
*/
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct capabilities {
|
struct capabilities {
|
||||||
@@ -199,7 +315,7 @@ public:
|
|||||||
|
|
||||||
flagvals flags;
|
flagvals flags;
|
||||||
struct capabilities caps;
|
struct capabilities caps;
|
||||||
struct network net;
|
network_rule net;
|
||||||
|
|
||||||
struct aa_rlimits rlimits;
|
struct aa_rlimits rlimits;
|
||||||
|
|
||||||
@@ -225,7 +341,7 @@ public:
|
|||||||
|
|
||||||
parent = NULL;
|
parent = NULL;
|
||||||
|
|
||||||
flags = { 0, MODE_UNSPECIFIED, 0, 0, NULL };
|
flags.init();
|
||||||
rlimits = {0, {}};
|
rlimits = {0, {}};
|
||||||
|
|
||||||
std::fill(exec_table, exec_table + AA_EXEC_COUNT, (char *)NULL);
|
std::fill(exec_table, exec_table + AA_EXEC_COUNT, (char *)NULL);
|
||||||
@@ -272,7 +388,6 @@ public:
|
|||||||
|
|
||||||
flags.dump(cerr);
|
flags.dump(cerr);
|
||||||
caps.dump();
|
caps.dump();
|
||||||
net.dump();
|
|
||||||
|
|
||||||
if (entries)
|
if (entries)
|
||||||
debug_cod_entries(entries);
|
debug_cod_entries(entries);
|
||||||
@@ -285,8 +400,6 @@ public:
|
|||||||
hat_table.dump();
|
hat_table.dump();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool alloc_net_table();
|
|
||||||
|
|
||||||
std::string hname(void)
|
std::string hname(void)
|
||||||
{
|
{
|
||||||
if (!parent)
|
if (!parent)
|
||||||
@@ -319,6 +432,10 @@ public:
|
|||||||
|
|
||||||
void post_parse_profile(void);
|
void post_parse_profile(void);
|
||||||
void add_implied_rules(void);
|
void add_implied_rules(void);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const char *warned_name = NULL;
|
||||||
|
virtual void warn_once(const char *name, const char *msg);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@@ -105,11 +105,12 @@ is_container_with_internal_policy() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# LXD and LXC set up AppArmor namespaces starting with "lxd-" and
|
# LXD, Incus and LXC set up AppArmor namespaces starting with "lxd-",
|
||||||
# "lxc-", respectively. Return non-zero for all other namespace
|
# "incus-" and "lxc-", respectively. Return non-zero for all other
|
||||||
# identifiers.
|
# namespace identifiers.
|
||||||
read -r ns_name < "$ns_name_path"
|
read -r ns_name < "$ns_name_path"
|
||||||
if [ "${ns_name#lxd-*}" = "$ns_name" ] && \
|
if [ "${ns_name#lxd-*}" = "$ns_name" ] && \
|
||||||
|
[ "${ns_name#incus-*}" = "$ns_name" ] && \
|
||||||
[ "${ns_name#lxc-*}" = "$ns_name" ]; then
|
[ "${ns_name#lxc-*}" = "$ns_name" ]; then
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
@@ -35,8 +35,9 @@ class Profile;
|
|||||||
#define RULE_TYPE_RULE 0
|
#define RULE_TYPE_RULE 0
|
||||||
#define RULE_TYPE_PREFIX 1
|
#define RULE_TYPE_PREFIX 1
|
||||||
#define RULE_TYPE_PERMS 2
|
#define RULE_TYPE_PERMS 2
|
||||||
|
#define RULE_TYPE_ALL 3
|
||||||
// RULE_TYPE_CLASS needs to be last because various class follow it
|
// RULE_TYPE_CLASS needs to be last because various class follow it
|
||||||
#define RULE_TYPE_CLASS 3
|
#define RULE_TYPE_CLASS 4
|
||||||
|
|
||||||
// rule_cast should only be used after a comparison of rule_type to ensure
|
// rule_cast should only be used after a comparison of rule_type to ensure
|
||||||
// that it is valid. Change to dynamic_cast for debugging
|
// that it is valid. Change to dynamic_cast for debugging
|
||||||
@@ -289,6 +290,10 @@ public:
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
virtual bool add_prefix(const prefixes &p) {
|
||||||
|
const char *err;
|
||||||
|
return add_prefix(p, err);
|
||||||
|
}
|
||||||
|
|
||||||
int cmp(prefixes const &rhs) const {
|
int cmp(prefixes const &rhs) const {
|
||||||
return prefixes::cmp(rhs);
|
return prefixes::cmp(rhs);
|
||||||
|
@@ -121,7 +121,7 @@ int parse_signal_perms(const char *str_perms, perms_t *perms, int fail)
|
|||||||
return parse_X_perms("signal", AA_VALID_SIGNAL_PERMS, str_perms, perms, fail);
|
return parse_X_perms("signal", AA_VALID_SIGNAL_PERMS, str_perms, perms, fail);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int find_signal_mapping(const char *sig)
|
int find_signal_mapping(const char *sig)
|
||||||
{
|
{
|
||||||
if (strncmp("rtmin+", sig, 6) == 0) {
|
if (strncmp("rtmin+", sig, 6) == 0) {
|
||||||
char *end;
|
char *end;
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
|
|
||||||
typedef set<int> Signals;
|
typedef set<int> Signals;
|
||||||
|
|
||||||
|
int find_signal_mapping(const char *sig);
|
||||||
int parse_signal_perms(const char *str_perms, perms_t *perms, int fail);
|
int parse_signal_perms(const char *str_perms, perms_t *perms, int fail);
|
||||||
|
|
||||||
class signal_rule: public perms_rule_t {
|
class signal_rule: public perms_rule_t {
|
||||||
|
8
parser/tst/simple_tests/all/bad_01.sd
Normal file
8
parser/tst/simple_tests/all/bad_01.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=Description basic ptrace all rule
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
all read readby trace tracedby ,
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/all/bad_02.sd
Normal file
8
parser/tst/simple_tests/all/bad_02.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=Description basic ptrace all rule
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
owner all,
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/all/ok_01.sd
Normal file
8
parser/tst/simple_tests/all/ok_01.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=Description basic all rule
|
||||||
|
#=EXRESULT PASS
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
all,
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/all/ok_02.sd
Normal file
8
parser/tst/simple_tests/all/ok_02.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=Description basic all rule
|
||||||
|
#=EXRESULT PASS
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
audit all,
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/all/ok_03.sd
Normal file
8
parser/tst/simple_tests/all/ok_03.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=Description basic all rule
|
||||||
|
#=EXRESULT PASS
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
allow all,
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/all/ok_04.sd
Normal file
8
parser/tst/simple_tests/all/ok_04.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=Description basic all rule
|
||||||
|
#=EXRESULT PASS
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
deny all,
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/all/ok_05.sd
Normal file
8
parser/tst/simple_tests/all/ok_05.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=Description basic all rule
|
||||||
|
#=EXRESULT PASS
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
audit deny all,
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/all/ok_06.sd
Normal file
8
parser/tst/simple_tests/all/ok_06.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=Description basic all rule
|
||||||
|
#=EXRESULT PASS
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
audit allow all,
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_10.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_10.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network ip - port conditional test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network peer=(ip=127.0.0.1 port=test),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_11.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_11.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network port range test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network peer=(ip=127.0.0.1 port=65536),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_12.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_12.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network ip - port conditional test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network peer=(ip=[invalid] port=80),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_13.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_13.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network ip - port conditional test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network peer=(ip=::1 port=-1),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_14.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_14.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network ip - port conditional test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network peer=(ip=::1 port=test),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_15.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_15.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network port range test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network peer=(ip=::1 port=65536),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_16.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_16.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network port range test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network peer=(port=65536),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_17.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_17.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network port range test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network peer=(port=-1),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_18.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_18.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network port range test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network peer=(port=test),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_19.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_19.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network range test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network peer=(ip=192.168.0.39-192.168.0.4),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_20.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_20.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network range test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network peer=(ip=192.168.0.39-invalid),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_21.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_21.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network range test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network peer=(ip=192.168.0.39-::58c2),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_22.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_22.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network range test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network peer=(ip=2001:1884:d02e:2759:d30:f166:71c9:288f-192.168.0.39),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_23.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_23.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network range test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network peer=(ip=80-192.168.0.39),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_24.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_24.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network range test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network peer=(port=80-65536),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_25.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_25.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network range test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network peer=(port=443-80),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_26.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_26.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network subnet test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network peer=(ip=invalid/80),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_27.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_27.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network subnet test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network peer=(ip=192.168.0.1/-1),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_28.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_28.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network subnet test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network peer=(ip=192.168.0.1/invalid),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_29.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_29.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network subnet test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network peer=(ip=192.168.0.1/33),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_30.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_30.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network subnet test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network peer=(ip=2001:1884:d02e:2759:d30:f166:71c9:288f/-1),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_31.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_31.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network subnet test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network peer=(ip=2001:1884:d02e:2759:d30:f166:71c9:288f/invalid),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_32.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_32.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network subnet test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network peer=(ip=2001:1884:d02e:2759:d30:f166:71c9:288f/129),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_33.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_33.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network ip - port conditional test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network ip=127.0.0.1 port=test,
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_34.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_34.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network ip - port conditional test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network ip=127.0.0.1 port=test peer=(ip=127.0.0.1 port=test),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_35.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_35.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network port range test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network ip=127.0.0.1 port=65536,
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_36.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_36.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network port range test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network ip=127.0.0.1 port=65536 peer=(ip=127.0.0.1 port=65536),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_37.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_37.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network ip - port conditional test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network ip=[invalid] port=80,
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_38.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_38.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network ip - port conditional test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network ip=[invalid] port=80 peer=(ip=[invalid] port=80),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_39.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_39.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network ip - port conditional test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network ip=::1 port=-1,
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_40.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_40.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network ip - port conditional test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network ip=::1 port=-1 peer=(ip=::1 port=-1),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_41.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_41.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network ip - port conditional test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network ip=::1 port=test,
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_42.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_42.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network ip - port conditional test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network ip=::1 port=test peer=(ip=::1 port=test),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_43.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_43.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network port range test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network ip=::1 port=65536,
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_44.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_44.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network port range test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network ip=::1 port=65536 peer=(ip=::1 port=65536),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_45.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_45.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network port range test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network port=65536,
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_46.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_46.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network port range test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network port=65536 peer=(port=65536),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_47.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_47.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network port range test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network port=-1,
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_48.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_48.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network port range test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network port=-1 peer=(port=-1),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_49.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_49.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network port range test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network port=test,
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_5.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_5.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network ip conditional test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network ip=10,
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_50.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_50.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network port range test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network port=test peer=(port=test),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_51.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_51.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network range test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network ip=192.168.0.39-192.168.0.4,
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_52.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_52.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network range test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network ip=192.168.0.39-192.168.0.4 peer=(ip=192.168.0.39-192.168.0.4),
|
||||||
|
|
||||||
|
}
|
8
parser/tst/simple_tests/network/network_bad_53.sd
Normal file
8
parser/tst/simple_tests/network/network_bad_53.sd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
#=DESCRIPTION invalid network range test
|
||||||
|
#=EXRESULT FAIL
|
||||||
|
#
|
||||||
|
/usr/bin/foo {
|
||||||
|
network ip=192.168.0.39-invalid,
|
||||||
|
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user