diff --git a/parser/apparmor.d.pod b/parser/apparmor.d.pod index 62eef766c..ecbbecf3b 100644 --- a/parser/apparmor.d.pod +++ b/parser/apparmor.d.pod @@ -1727,6 +1727,17 @@ If the policy abi is specified as B then the running kernel's abi will be used. This should never be used in shipped policy as it can cause system breakage when a new kernel is installed. +=head3 ABI compatability with AppArmor 2.x + +AppArmor 3 remains compatible with AppArmor 2.x by detecting when a +profile does not have a feature ABI specified. In this case the policy +compile will either apply the pinned feature ABI as specified by the +config file or the command line, or if neither of those are applied by +using a default feature ABI. + +It is important to note that the default feature ABI does not support +new features added in AppArmor 3 or later. + =head1 EXAMPLE An example AppArmor profile: diff --git a/parser/parser.h b/parser/parser.h index ef1ca032f..0dc25bedb 100644 --- a/parser/parser.h +++ b/parser/parser.h @@ -295,6 +295,7 @@ extern uint32_t policy_version; extern uint32_t parser_abi_version; extern uint32_t kernel_abi_version; +extern aa_features *pinned_features; extern aa_features *policy_features; extern aa_features *kernel_features; diff --git a/parser/parser_main.c b/parser/parser_main.c index d807bab25..a860c4610 100644 --- a/parser/parser_main.c +++ b/parser/parser_main.c @@ -109,8 +109,8 @@ static const char *cacheloc[MAX_CACHE_LOCS]; static int cacheloc_n = 0; static bool print_cache_dir = false; +aa_features *pinned_features = NULL; aa_features *policy_features = NULL; -bool specified_policy_features = false; aa_features *kernel_features = NULL; static const char *config_file = "/etc/apparmor/parser.conf"; @@ -407,6 +407,7 @@ bool early_arg(int c) { */ static int process_arg(int c, char *optarg) { + struct aa_features *tmp_features = NULL; int count = 0; switch (c) { @@ -529,32 +530,32 @@ static int process_arg(int c, char *optarg) } break; case 'm': - if (policy_features) - aa_features_unref(policy_features); + if (pinned_features) + aa_features_unref(pinned_features); if (kernel_features) aa_features_unref(kernel_features); - if (aa_features_new_from_string(&policy_features, + if (aa_features_new_from_string(&tmp_features, optarg, strlen(optarg))) { fprintf(stderr, "Failed to parse features string: %m\n"); exit(1); } - kernel_features = aa_features_ref(policy_features); - specified_policy_features = true; + kernel_features = aa_features_ref(tmp_features); + pinned_features = tmp_features; break; case 'M': - if (policy_features) - aa_features_unref(policy_features); + if (pinned_features) + aa_features_unref(pinned_features); if (kernel_features) aa_features_unref(kernel_features); - if (aa_features_new(&policy_features, AT_FDCWD, optarg)) { + if (aa_features_new(&tmp_features, AT_FDCWD, optarg)) { fprintf(stderr, "Failed to load features from '%s': %m\n", optarg); exit(1); } - kernel_features = aa_features_ref(policy_features); - specified_policy_features = true; + kernel_features = aa_features_ref(tmp_features); + pinned_features = tmp_features; break; case 138: if (kernel_features) @@ -567,21 +568,21 @@ static int process_arg(int c, char *optarg) } break; case 139: - if (policy_features) - aa_features_unref(policy_features); + if (pinned_features) + aa_features_unref(pinned_features); if (strcmp(optarg, "") == 0) { - if (aa_features_new_from_kernel(&policy_features)) { + if (aa_features_new_from_kernel(&tmp_features)) { fprintf(stderr, "Failed to load kernel features into the policy-features abi: %m\n"); exit(1); } - } else if (aa_features_new(&policy_features, AT_FDCWD, optarg)) { + } else if (aa_features_new(&tmp_features, AT_FDCWD, optarg)) { fprintf(stderr, "Failed to load policy-features from '%s': %m\n", optarg); exit(1); } - specified_policy_features = true; + pinned_features = tmp_features; break; case 'q': conf_verbose = 0; @@ -920,11 +921,9 @@ void reset_parser(const char *filename) free_symtabs(); free_policies(); reset_include_stack(filename); - if (!specified_policy_features) { - aa_features_unref(policy_features); - policy_features = NULL; - clear_cap_flag(CAPFLAG_POLICY_FEATURE); - } + aa_features_unref(policy_features); + policy_features = NULL; + clear_cap_flag(CAPFLAG_POLICY_FEATURE); } int test_for_dir_mode(const char *basename, const char *linkdir) diff --git a/parser/parser_yacc.y b/parser/parser_yacc.y index 7a8c2cac7..076b04011 100644 --- a/parser/parser_yacc.y +++ b/parser/parser_yacc.y @@ -292,13 +292,17 @@ list: preamble { /* make sure abi is setup */ if (policy_features == NULL) { + if (pinned_features) { + policy_features = aa_features_ref(pinned_features); /* use default feature abi */ - if (aa_features_new_from_string(&policy_features, - default_features_abi, - strlen(default_features_abi))) { - yyerror(_("Failed to setup default policy feature abi")); + } else { + if (aa_features_new_from_string(&policy_features, + default_features_abi, + strlen(default_features_abi))) { + yyerror(_("Failed to setup default policy feature abi")); + } + pwarn(_("%s: File '%s' missing feature abi, falling back to default policy feature abi\n"), progname, current_filename); } - pwarn(_("%s: File '%s' missing feature abi, falling back to default policy feature abi\n"), progname, current_filename); } if (!add_cap_feature_mask(policy_features, CAPFLAG_POLICY_FEATURE))