83
87
/* per-profile settings */
84
88
int force_complain = 0;
90
/* Make sure to update BOTH the short and long_options */
91
static const char *short_options = "adf:h::rRVvI:b:BCD:NSm:qQn:XKTWkL:O:po:";
86
92
struct option long_options[] = {
87
93
{"add", 0, 0, 'a'},
88
94
{"binary", 0, 0, 'B'},
89
95
{"base", 1, 0, 'b'},
90
{"subdomainfs", 0, 0, 'f'},
96
{"subdomainfs", 1, 0, 'f'},
91
97
{"help", 2, 0, 'h'},
92
98
{"replace", 0, 0, 'r'},
93
99
{"reload", 0, 0, 'r'}, /* undocumented reload option == replace */
109
115
{"skip-read-cache", 0, 0, 'T'},
110
116
{"write-cache", 0, 0, 'W'},
111
117
{"show-cache", 0, 0, 'k'},
118
{"skip-bad-cache", 0, 0, 129}, /* no short option */
119
{"purge-cache", 0, 0, 130}, /* no short option */
120
{"create-cache-dir", 0, 0, 131}, /* no short option */
112
121
{"cache-loc", 1, 0, 'L'},
113
122
{"debug", 0, 0, 'd'},
114
123
{"dump", 1, 0, 'D'},
151
160
"-K, --skip-cache Do not attempt to load or save cached profiles\n"
152
161
"-T, --skip-read-cache Do not attempt to load cached profiles\n"
153
162
"-W, --write-cache Save cached profile (force with -T)\n"
163
" --skip-bad-cache Don't clear cache if out of sync\n"
164
" --purge-cache Clear cache regardless of its state\n"
165
" --create-cache-dir Create the cache dir if missing\n"
154
166
"-L, --cache-loc n Set the location of the profile cache\n"
155
167
"-q, --quiet Don't emit warnings\n"
156
168
"-v, --verbose Show profile names as they load\n"
184
196
DFA_DUMP_SIMPLE_TREE },
185
197
{ 1, "stats", "Dump all compile stats",
186
198
DFA_DUMP_TREE_STATS | DFA_DUMP_STATS | DFA_DUMP_TRANS_STATS |
187
DFA_DUMP_EQUIV_STATS },
199
DFA_DUMP_EQUIV_STATS | DFA_DUMP_DIFF_STATS },
188
200
{ 1, "progress", "Dump progress for all compile phases",
189
201
DFA_DUMP_PROGRESS | DFA_DUMP_STATS | DFA_DUMP_TRANS_PROGRESS |
190
DFA_DUMP_TRANS_STATS },
202
DFA_DUMP_TRANS_STATS | DFA_DUMP_DIFF_PROGRESS | DFA_DUMP_DIFF_STATS },
191
203
{ 1, "dfa-progress", "Dump dfa creation as in progress",
192
204
DFA_DUMP_PROGRESS | DFA_DUMP_STATS },
193
205
{ 1, "dfa-stats", "Dump dfa creation stats", DFA_DUMP_STATS },
212
224
{ 1, "equiv-stats", "Dump equivance class stats",
213
225
DFA_DUMP_EQUIV_STATS },
214
226
{ 1, "equiv", "Dump equivance class", DFA_DUMP_EQUIV },
227
{ 1, "diff-encode", "Dump differential encoding",
228
DFA_DUMP_DIFF_ENCODE },
229
{ 1, "diff-stats", "Dump differential encoding stats",
230
DFA_DUMP_DIFF_STATS },
231
{ 1, "diff-progress", "Dump progress of differential encoding",
232
DFA_DUMP_DIFF_PROGRESS | DFA_DUMP_DIFF_STATS },
215
233
{ 0, NULL, NULL, 0 },
218
236
optflag_table_t optflag_table[] = {
219
237
{ 2, "0", "no optimizations",
220
238
DFA_CONTROL_TREE_NORMAL | DFA_CONTROL_TREE_SIMPLE |
221
DFA_CONTROL_MINIMIZE | DFA_CONTROL_REMOVE_UNREACHABLE
239
DFA_CONTROL_MINIMIZE | DFA_CONTROL_REMOVE_UNREACHABLE |
240
DFA_CONTROL_DIFF_ENCODE
223
242
{ 1, "equiv", "use equivalent classes", DFA_CONTROL_EQUIV },
224
243
{ 1, "expr-normalize", "expression tree normalization",
230
249
{ 2, "expr-right-simplify", "right simplification first",
231
250
DFA_CONTROL_TREE_LEFT },
232
251
{ 1, "minimize", "dfa state minimization", DFA_CONTROL_MINIMIZE },
233
{ 1, "hash-trans", "minimization - hash transitions during setup",
234
DFA_CONTROL_MINIMIZE_HASH_TRANS },
235
252
{ 1, "filter-deny", "filter out deny information from final dfa",
236
253
DFA_CONTROL_FILTER_DENY },
237
254
{ 1, "remove-unreachable", "dfa unreachable state removal",
584
614
while ((c = getopt_long_file(f, long_options, &optarg, &o)) != -1)
585
615
process_arg(c, optarg);
589
static inline char *try_subdomainfs_mountpoint(const char *mntpnt,
592
char *proposed_base = NULL;
596
if (asprintf(&proposed_base, "%s%s", mntpnt, path)<0 || !proposed_base) {
597
PERROR(_("%s: Could not allocate memory for subdomainbase mount point\n"),
601
if (stat(proposed_base, &buf) == 0) {
602
retval = proposed_base;
609
621
int find_subdomainfs_mountpoint(void)
612
struct mntent *mntpt;
614
if ((mntfile = setmntent(MOUNTED_FS, "r"))) {
615
while ((mntpt = getmntent(mntfile))) {
616
char *proposed = NULL;
617
if (strcmp(mntpt->mnt_type, "securityfs") == 0) {
618
proposed = try_subdomainfs_mountpoint(mntpt->mnt_dir, "/" MODULE_NAME);
619
if (proposed != NULL) {
620
subdomainbase = proposed;
623
proposed = try_subdomainfs_mountpoint(mntpt->mnt_dir, "/" OLD_MODULE_NAME);
624
if (proposed != NULL) {
625
subdomainbase = proposed;
629
if (strcmp(mntpt->mnt_type, "subdomainfs") == 0) {
630
proposed = try_subdomainfs_mountpoint(mntpt->mnt_dir, "");
631
if (proposed != NULL) {
632
subdomainbase = proposed;
640
if (!subdomainbase) {
623
if (aa_find_mountpoint(&subdomainbase) == -1) {
642
625
if (stat(DEFAULT_APPARMORFS, &buf) == -1) {
643
626
PERROR(_("Warning: unable to find a suitable fs in %s, is it "
644
627
"mounted?\nUse --subdomainfs to override.\n"),
647
subdomainbase = DEFAULT_APPARMORFS;
630
subdomainbase = strdup(DEFAULT_APPARMORFS);
651
634
return (subdomainbase == NULL);
655
637
int have_enough_privilege(void)
677
struct features_struct {
683
static int features_dir_cb(DIR *dir, const char *name, struct stat *st,
686
struct features_struct *fst = (struct features_struct *) data;
688
/* skip dot files and files with no name */
689
if (*name == '.' || !strlen(name))
692
fst->pos = snprintf_buffer(*fst->buffer, fst->pos, fst->size, "%s {", name);
694
if (S_ISREG(st->st_mode)) {
696
int remaining = fst->size - (fst->pos - *fst->buffer);
697
if (!(file = openat(dirfd(dir), name, O_RDONLY))) {
698
PDEBUG("Could not open '%s'", name);
701
PDEBUG("Opened features \"%s\"\n", name);
702
if (st->st_size > remaining) {
703
PDEBUG("Feature buffer full.");
708
len = read(file, fst->pos, remaining);
716
PDEBUG("Error reading feature file '%s'\n", name);
720
} else if (S_ISDIR(st->st_mode)) {
721
if (dirat_for_each(dir, name, fst, features_dir_cb))
725
fst->pos = snprintf_buffer(*fst->buffer, fst->pos, fst->size, "}\n");
695
730
static char *handle_features_dir(const char *filename, char **buffer, int size,
699
char *dirent_path = NULL;
700
struct dirent *dirent;
733
struct features_struct fst = { buffer, size, pos };
704
PDEBUG("Opened features directory \"%s\"\n", filename);
705
if (!(dir = opendir(filename))) {
706
PDEBUG("opendir failed '%s'", filename);
735
if (dirat_for_each(NULL, filename, &fst, features_dir_cb)) {
736
PDEBUG("Failed evaluating .features\n");
710
while ((dirent = readdir(dir)) != NULL) {
712
/* skip dotfiles silently. */
713
if (dirent->d_name[0] == '.')
718
if (asprintf(&dirent_path, "%s/%s", filename, dirent->d_name) < 0)
720
PERROR(_("Memory allocation error."));
724
name_len = strlen(dirent->d_name);
728
if (stat(dirent_path, &my_stat)) {
729
PERROR(_("stat failed for '%s'"), dirent_path);
733
pos = snprintf_buffer(*buffer, pos, size, "%s {", dirent->d_name);
734
if (S_ISREG(my_stat.st_mode)) {
736
int remaining = size - (pos - *buffer);
737
if (!(file = open(dirent_path, O_RDONLY))) {
738
PDEBUG("Could not open '%s' in '%s'", dirent_path, filename);
742
PDEBUG("Opened features \"%s\" in \"%s\"\n", dirent_path, filename);
743
if (my_stat.st_size > remaining) {
744
PERROR(_("Feature buffer full."));
749
len = read(file, pos, remaining);
757
PDEBUG("Error reading feature file '%s'\n",
763
} else if (S_ISDIR(my_stat.st_mode)) {
764
pos = handle_features_dir(dirent_path, buffer, size,
771
pos = snprintf_buffer(*buffer, pos, size, "}\n");
780
743
/* match_string == NULL --> no match_string available
1115
/* data - name of parent dir */
1116
static int profile_dir_cb(__unused DIR *dir, const char *name, struct stat *st,
1121
if (!S_ISDIR(st->st_mode) && !is_blacklisted(name, NULL)) {
1122
const char *dirname = (const char *)data;
1124
if (asprintf(&path, "%s/%s", dirname, name) < 0)
1125
PERROR(_("Out of memory"));
1126
rc = process_profile(option, path);
1132
/* data - name of parent dir */
1133
static int binary_dir_cb(__unused DIR *dir, const char *name, struct stat *st,
1138
if (!S_ISDIR(st->st_mode) && !is_blacklisted(name, NULL)) {
1139
const char *dirname = (const char *)data;
1141
if (asprintf(&path, "%s/%s", dirname, name) < 0)
1142
PERROR(_("Out of memory"));
1143
rc = process_binary(option, path);
1149
static int clear_cache_cb(DIR *dir, const char *path, struct stat *st,
1150
__unused void *data)
1152
/* remove regular files */
1153
if (S_ISREG(st->st_mode))
1154
return unlinkat(dirfd(dir), path, 0);
1156
/* do nothing with other file types */
1160
static int clear_cache_files(const char *path)
1162
return dirat_for_each(NULL, path, NULL, clear_cache_cb);
1165
static int create_cache(const char *cachedir, const char *path,
1166
const char *features)
1168
struct stat stat_file;
1171
if (clear_cache_files(cacheloc) != 0)
1175
f = fopen(path, "w");
1177
if (fwrite(features, strlen(features), 1, f) != 1 )
1187
/* does the dir exist? */
1188
if (stat(cachedir, &stat_file) == -1 && create_cache_dir) {
1189
if (mkdir(cachedir, 0700) == 0)
1192
PERROR(_("Can't create cache directory: %s\n"), cachedir);
1193
} else if (!S_ISDIR(stat_file.st_mode)) {
1195
PERROR(_("File in cache directory location: %s\n"), cachedir);
1198
PERROR(_("Can't update cache directory: %s\n"), cachedir);
1202
PERROR("Cache write disabled: cannot create %s\n", path);
1168
1208
static void setup_flags(void)
1170
1210
char *cache_features_path = NULL;
1190
1235
* - If cache/.features exists, and does not match flags_string,
1191
1236
* force cache reading/writing off.
1193
if (asprintf(&cache_features_path, "%s/cache/.features", basedir) == -1) {
1238
if (asprintf(&cache_features_path, "%s/.features", cacheloc) == -1) {
1239
PERROR(_("Memory allocation error."));
1198
1243
get_flags_string(&cache_flags, cache_features_path);
1199
1244
if (cache_flags) {
1200
1245
if (strcmp(flags_string, cache_flags) != 0) {
1201
if (show_cache) PERROR("Cache read/write disabled: %s does not match %s\n", FLAGS_FILE, cache_features_path);
1203
skip_read_cache = 1;
1246
if (write_cache && cond_clear_cache) {
1247
if (create_cache(cacheloc, cache_features_path,
1249
skip_read_cache = 1;
1252
PERROR("Cache read/write disabled: %s does not match %s\n", FLAGS_FILE, cache_features_path);
1254
skip_read_cache = 1;
1205
1257
free(cache_flags);
1206
1258
cache_flags = NULL;
1208
else if (write_cache) {
1212
f = fopen(cache_features_path, "w");
1213
if (!f) failure = 1;
1215
if (fwrite(flags_string, strlen(flags_string), 1, f) != 1 ) {
1218
if (fclose(f) != 0) failure = 1;
1222
if (show_cache) PERROR("Cache write disabled: cannot write to %s\n", cache_features_path);
1259
} else if (write_cache) {
1260
create_cache(cacheloc, cache_features_path, flags_string);
1227
1263
free(cache_features_path);
1271
1320
if (i == argc && optind != argc)
1323
if (profilename && stat(profilename, &stat_file) == -1) {
1324
PERROR("File %s not found, skipping...\n", profilename);
1328
if (profilename && S_ISDIR(stat_file.st_mode)) {
1329
int (*cb)(DIR *dir, const char *name, struct stat *st,
1331
cb = binary_input ? binary_dir_cb : profile_dir_cb;
1332
if (dirat_for_each(NULL, profilename, profilename, cb)) {
1333
PDEBUG("Failed loading profiles from %s\n",
1337
} else if (binary_input) {
1275
1338
retval = process_binary(option, profilename);
1277
1340
retval = process_profile(option, profilename);