[apparmor] PATCH [1/2] have caching respect include time stamps
John Johansen
john.johansen at canonical.com
Tue Sep 14 11:54:36 BST 2010
And with the patch actually attached
This patch changes how cache validation is done, by moving it post
parsing, and precompilation of policy. This allows finding the most
recent text time stamp during parsing and this is then compared to
the cache file time stamp.
While this is slightly slower than the cache file check that only
validated against the profile file it fixes the bug where abstraction
updates do not cause the cache file to become invalid.
Nominated for 2.5.1
---
parser/parser_lex.l | 2 +
parser/parser_main.c | 98 ++++++++++++++++++++++++++++++++-------------------
2 files changed, 65 insertions(+), 35 deletions(-)
--- master-new.orig/parser/parser_lex.l
+++ master-new/parser/parser_lex.l
@@ -104,6 +104,7 @@
if (S_ISREG(my_stat.st_mode)) {
yyin = include_file;
+ update_mru_tstamp(include_file);
PDEBUG("Opened include \"%s\"\n", fullpath);
push_include_stack(fullpath);
yypush_buffer_state(yy_create_buffer( yyin, YY_BUF_SIZE ));
@@ -152,6 +153,7 @@
if (!(yyin = fopen(dirent_path,"r")))
yyerror(_("Could not open '%s' in '%s'"), dirent_path, filename);
PDEBUG("Opened include \"%s\" in \"%s\"\n", dirent_path, filename);
+ update_mru_tstamp(yyin);
push_include_stack(dirent_path);
yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE));
}
--- master-new.orig/parser/parser_main.c
+++ master-new/parser/parser_main.c
@@ -84,6 +84,7 @@
#endif
int preprocess_only = 0;
int skip_mode_force = 0;
+struct timespec mru_tstamp;
char *subdomainbase = NULL;
char *match_string = NULL;
@@ -726,6 +727,7 @@
void reset_parser(char *filename)
{
+ memset(&mru_tstamp, 0, sizeof(mru_tstamp));
free_aliases();
free_symtabs();
free_policies();
@@ -753,13 +755,28 @@
return rc;
}
+
+/* returns true if time is more recent than mru_tstamp */
+#define mru_t_cmp(a) \
+(((a).tv_sec == (mru_tstamp).tv_sec) ? \
+ (a).tv_nsec > (mru_tstamp).tv_nsec : (a).tv_sec > (mru_tstamp).tv_sec)
+
+void update_mru_tstamp(FILE *file)
+{
+ struct stat stat_file;
+ if (fstat(fileno(file), &stat_file))
+ return;
+ if (mru_t_cmp(stat_file.st_ctim))
+ mru_tstamp = stat_file.st_ctim;
+}
+
int process_profile(int option, char *profilename)
{
- struct stat stat_text;
struct stat stat_bin;
int retval = 0;
char * cachename = NULL;
char * cachetemp = NULL;
+ char *basename = NULL;
/* per-profile states */
force_complain = opt_force_complain;
@@ -777,7 +794,7 @@
if (profilename && option != OPTION_REMOVE) {
/* make decisions about disabled or complain-mode profiles */
- char *basename = strrchr(profilename, '/');
+ basename = strrchr(profilename, '/');
if (basename)
basename++;
else
@@ -794,34 +811,53 @@
force_complain = 1;
}
- if (!force_complain && !skip_cache) {
- fstat(fileno(yyin), &stat_text);
- if (asprintf(&cachename, "%s/%s/%s", basedir, "cache", basename)<0) {
+ /* TODO: add primary cache check.
+ * If .file for cached binary exists get the list of profile
+ * names and check their time stamps.
+ */
+ /* TODO: primary cache miss/hit messages */
+ }
+
+ reset_parser(profilename);
+ if (yyin) {
+ yyrestart(yyin);
+ update_mru_tstamp(yyin);
+ }
+
+ retval = yyparse();
+ if (retval != 0)
+ goto out;
+
+ /* Do secondary test to see if cached binary profile is good,
+ * instead of checking against a presupplied list of files
+ * use the tstampts from the files that were parsed.
+ * Parsing the profile is slower that doing primary cache check
+ * its still faster than doing full compilation
+ */
+ if ((profilename && option != OPTION_REMOVE) && !force_complain &&
+ !skip_cache) {
+ 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 (!skip_read_cache &&
+ stat(cachename, &stat_bin) == 0 &&
+ stat_bin.st_size > 0 && (mru_t_cmp(stat_bin.st_mtim))) {
+ 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);
}
- /* Load a binary cache if it exists and is newest */
- if (!skip_read_cache &&
- stat(cachename, &stat_bin) == 0 &&
- stat_bin.st_size > 0 &&
- (stat_bin.st_mtim.tv_sec > stat_text.st_ctim.tv_sec ||
- (stat_bin.st_mtim.tv_sec == stat_text.st_ctim.tv_sec &&
- stat_bin.st_mtim.tv_nsec >= stat_text.st_ctim.tv_nsec))) {
- 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 ( (cache_fd = mkstemp(cachetemp)) < 0) {
+ perror("mkstemp");
+ exit(1);
}
}
}
@@ -829,14 +865,6 @@
if (show_cache)
PERROR("Cache miss: %s\n", profilename ? profilename : "stdin");
- if (yyin)
- yyrestart(yyin);
- reset_parser(profilename);
-
- retval = yyparse();
- if (retval != 0)
- goto out;
-
if (preprocess_only)
goto out;
More information about the AppArmor
mailing list