add loading from and writing to cache options

Signed-Off-By: Kees Cook <kees.cook@canonical.com>
This commit is contained in:
John Johansen 2009-07-24 07:36:09 +00:00
parent 33d01a980a
commit ab3d7edcdc
3 changed files with 89 additions and 1 deletions

View file

@ -280,6 +280,7 @@ extern int load_codomain(int option, struct codomain *cod);
extern int sd_serialize_profile(sd_serialize *p, struct codomain *cod,
int flatten);
extern int sd_load_buffer(int option, char *buffer, int size);
extern int cache_fd;
/* parser_policy.c */

View file

@ -766,6 +766,7 @@ int sd_serialize_top_profile(sd_serialize *p, struct codomain *profile)
return sd_serialize_profile(p, profile, profile->parent ? 1 : 0);
}
int cache_fd = -1;
int sd_serialize_codomain(int option, struct codomain *cod)
{
int fd;
@ -873,6 +874,17 @@ int sd_serialize_codomain(int option, struct codomain *cod)
} else if (wsize < size) {
PERROR(_("%s: Unable to write entire profile entry\n"),
progname);
error = -EIO;
}
if (cache_fd != -1) {
wsize = write(cache_fd, work_area->buffer, size);
if (wsize < 0) {
error = -errno;
} else if (wsize < size) {
PERROR(_("%s: Unable to write entire profile entry to cache\n"),
progname);
error = -EIO;
}
}
free_sd_serial(work_area);
}

View file

@ -63,6 +63,9 @@ int names_only = 0;
int dump_vars = 0;
int dump_expanded_vars = 0;
int conf_quiet = 0;
int skip_cache = 0;
int show_cache = 0;
int write_cache = 0;
#ifdef FORCE_READ_IMPLIES_EXEC
int read_implies_exec = 1;
#else
@ -104,6 +107,9 @@ struct option long_options[] = {
{"quiet", 0, 0, 'q'},
{"namespace", 1, 0, 'n'},
{"readimpliesX", 0, 0, 'X'},
{"skip-cache", 0, 0, 'K'},
{"write-cache", 0, 0, 'W'},
{"show-cache", 0, 0, 'k'},
{NULL, 0, 0, 0},
};
@ -134,6 +140,9 @@ static void display_usage(char *command)
"-m n, --match-string n Use only match features n\n"
"-n n, --namespace n Set Namespace for the profile\n"
"-X, --readimpliesX Map profile read permissions to mr\n"
"-k, --show-cache Report cache hit/miss details\n"
"-K, --skip-cache Do not attempt to load or save cached profiles\n"
"-W, --write-cache Attempt to save cached profiles\n"
"-q, --quiet Don't emit warnings\n"
"-v, --version Display version info and exit\n"
"-d, --debug Debug apparmor definitions\n"
@ -213,6 +222,7 @@ static int process_args(int argc, char *argv[])
break;
case 'N':
names_only = 1;
skip_cache = 1;
break;
case 'S':
count++;
@ -223,9 +233,11 @@ static int process_args(int argc, char *argv[])
break;
case 'D':
dump_vars = 1;
skip_cache = 1;
break;
case 'E':
dump_expanded_vars = 1;
skip_cache = 1;
break;
case 'm':
match_string = strdup(optarg);
@ -239,6 +251,15 @@ static int process_args(int argc, char *argv[])
case 'X':
read_implies_exec = 1;
break;
case 'K':
skip_cache = 1;
break;
case 'k':
show_cache = 1;
break;
case 'W':
write_cache = 1;
break;
default:
display_usage(progname);
exit(0);
@ -504,6 +525,8 @@ int process_profile(int option, char *profilename)
struct stat stat_text;
struct stat stat_bin;
int retval = 0;
char * cachename = NULL;
char * cachetemp = NULL;
/* per-profile states */
force_complain = opt_force_complain;
@ -516,7 +539,7 @@ int process_profile(int option, char *profilename)
}
}
else {
PERROR("%s: cannot disable or force-complain via stdin\n", progname);
PERROR("%s: cannot use or update cache, disable, or force-complain via stdin\n", progname);
}
if ( profilename && option != OPTION_REMOVE ) {
@ -546,8 +569,38 @@ int process_profile(int option, char *profilename)
force_complain = 1;
}
free(target);
if (!force_complain && !skip_cache) {
fstat(fileno(yyin), &stat_text);
if (asprintf(&cachename, "%s/%s/%s", basedir, "cache", basename)<0) {
perror("asprintf");
exit(1);
}
/* Load a binary cache if it exists and is newest */
if (stat(cachename, &stat_bin) == 0 &&
stat_bin.st_size > 0 &&
stat_bin.st_mtime >= stat_text.st_mtime) {
if (show_cache) PERROR("Cache hit: %s\n", cachename);
retval = process_binary(option, cachename);
goto out;
}
if (write_cache) {
/* Otherwise, set up to save a cached copy */
if (asprintf(&cachetemp, "%s/%s/%s-XXXXXX", basedir, "cache", basename)<0) {
perror("asprintf");
exit(1);
}
if ( (cache_fd = mkstemp(cachetemp)) < 0) {
perror("mkstemp");
exit(1);
}
}
}
}
if (show_cache)
PERROR("Cache miss: %s\n", profilename ? profilename : "stdin");
if (yyin) yyrestart(yyin);
reset_parser();
@ -594,6 +647,28 @@ int process_profile(int option, char *profilename)
retval = load_policy(option);
out:
if (cachetemp) {
/* Only install the generate cache file if it parsed correctly
and did not have write/close errors */
int useable_cache = (cache_fd != -1 && retval == 0);
if (cache_fd != -1) {
if (close(cache_fd)) useable_cache = 0;
cache_fd = -1;
}
if (useable_cache) {
rename(cachetemp, cachename);
if (show_cache)
PERROR("Wrote cache: %s\n", cachename);
}
else {
unlink(cachetemp);
if (show_cache)
PERROR("Removed cache attempt: %s\n", cachetemp);
}
free(cachetemp);
}
if (cachename) free(cachename);
return retval;
}