On 2015-03-12 04:17:56, John Johansen wrote:
> On 03/06/2015 01:48 PM, Tyler Hicks wrote:
> > Defines a function that can be called to test features support. It is
> > string based which allows the support tests to work with new kernel
> > features without any changes.
> > 
> > The use of global variables in the parser to store and check features
> > support is still preserved. The parser should probably move over to
> > passing the aa_features object around but that's left for later.
> > 
> > Signed-off-by: Tyler Hicks <tyhi...@canonical.com>
> > ---
> >  parser/features.c    | 128 
> > +++++++++++++++++++++++++++++++++++++++++++++++++++
> >  parser/features.h    |   1 +
> >  parser/parser_main.c |  52 ++++++++++-----------
> >  3 files changed, 155 insertions(+), 26 deletions(-)
> > 
> > diff --git a/parser/features.c b/parser/features.c
> > index 07d6e6c..50e0024 100644
> > --- a/parser/features.c
> > +++ b/parser/features.c
> > @@ -17,6 +17,7 @@
> >   */
> >  
> >  #include <errno.h>
> > +#include <ctype.h>
> >  #include <fcntl.h>
> >  #include <stdio.h>
> >  #include <string.h>
> > @@ -163,6 +164,86 @@ static int load_features_file(const char *name, char 
> > *buffer, size_t size)
> >     return 0;
> >  }
> >  
> > +static bool walk_one(const char **str, const char *component, bool 
> > is_top_level)
> > +{
> > +   const char *cur = *str;
> > +   uint32_t bracket_count = 0;
> > +   int i = 0;
> > +
> > +   /* Empty strings are not accepted */
> > +   if (!*cur || !component[0])
> > +           return false;
> > +
> > +   /**
> > +    * If @component is not top-level, the first character in the string to
> > +    * search MUST be '{'
> > +    */
> > +   if (!is_top_level) {
> > +           if (*cur != '{')
> > +                   return false;
> > +
> > +           cur++;
> > +   }
> > +
> > +   /**
> > +    * This loop tries to find the @component in *@str. When this loops
> > +    * completes, cur will either point one character past the end of the
> > +    * matched @component or to the NUL terminator of *@str.
> > +    */
> > +   while(*cur && component[i]) {
> > +           if (!isascii(*cur)) {
> > +                   /* Only ASCII is expected */
> > +                   return false;
> > +           } else if (*cur == '{') {
> > +                   /* There's a limit to the number of opening brackets */
> > +                   if (bracket_count == UINT32_MAX)
> > +                           return false;
> > +
> > +                   bracket_count++;
> > +           } else if (*cur == '}') {
> > +                   /* Check for unexpected closing brackets */
> > +                   if (bracket_count == 0)
> > +                           return false;
> > +
> > +                   bracket_count--;
> > +           }
> > +
> > +           /**
> > +            * Move to the next character in @component if we have a match
> > +            * and either @component is not top-level or, if @component is
> > +            * top-level, we're not inside of brackets
> > +            */
> > +           if (*cur == component[i] &&
> > +               (!is_top_level || bracket_count == 0))
> > +                   i++;
> > +           else
> > +                   i = 0;
> > +
> This isn't correct. IF we are !is_top_level then we can have a partial leading
> match, hit a bracket, increase bracket_count and continue matching, so that
> the component
>   frontback 
> will match either of
>   front{back
>   front}back

Hmm... I don't think that's possible since there's no 'continue' when we
hit a bracket. The (*cur == component[i]) test will fail and i will be
reset back to 0.

Either way, this is way too complicated of a function for me to be
sending out without tests. I apologize for that. I'll add tests,
including the case you mentioned above, and then fix issues and resend
this patch out.

> > +           cur++;
> > +   }
> > +
> > +   /* A full match was not found if component[i] is non-NUL */
> > +   if (component[i])
> > +           return false;
> > +
> > +   /**
> > +    * This loop eats up valid (ASCII) characters until a non-bracket or
> > +    * non-space character is found so that *@str is properly set to call
> > +    * back into this function, if necessary
> > +    */
> > +   while (*cur) {
> > +           if (!isascii(*cur))
> > +                   return false;
> > +           else if (*cur == '{' || *cur == '}' || !isspace(*cur))
> > +                   break;
> > +
> > +           cur++;
> > +   }
> > +
> > +   *str = cur;
> > +   return true;
> > +}
> > +
> >  /**
> >   * aa_features_new - create a new features based on a path
> >   * @features: will point to the address of an allocated and initialized
> > @@ -299,3 +380,50 @@ bool aa_features_is_equal(aa_features *features1, 
> > aa_features *features2)
> >     return features1 && features2 &&
> >            strcmp(features1->string, features2->string) == 0;
> >  }
> > +
> > +/**
> > + * aa_features_supports - provides features support status
> > + * @features: the features
> > + * @str: the string representation of a feature to check
> > + *
> > + * Example @str values are "dbus/mask/send", "caps/mask/audit_read", and
> > + * "policy/versions/v7".
> > + *
> > + * Returns: a bool specifying the support status of @str feature
> > + */
> > +bool aa_features_supports(aa_features *features, char *str)
> > +{
> > +   const char *features_string = features->string;
> > +   char *components[32];
> > +   char *saveptr = NULL;
> > +   size_t i;
> > +
> > +   /* Empty strings are not accepted. Neither are leading '/' chars. */
> > +   if (!str || str[0] == '/')
> > +           return false;
> > +
> > +   /**
> > +    * Break @str into an array of components. For example,
> > +    * "mount/mask/mount" would turn into "mount" as the first component,
> > +    * "mask" as the second, and "mount" as the third
> > +    */
> > +   for (i = 0; i < sizeof(components); i++) {
> > +           components[i] = strtok_r(str, "/", &saveptr);
> > +           if (!components[i])
> > +                   break;
> > +
> > +           str = NULL;
> > +   }
> I am not a fan of the use of strtok in this fn. It means const strings can
> not be passed, nor could the same query string be used multiple times (not
> that you generally should but ...).
> I would rather see an api that can use constant strings, but at the very
> least @str needs to document that it will be modified.

Yeah, I completely agree. I'll see if I can come up with something that
works off of string lengths instead of NUL terminators.

Tyler

> > +
> > +   /* At least one valid token is required */
> > +   if (!components[0])
> > +           return false;
> > +
> > +   /* Ensure that all components are valid and found */
> > +   for (i = 0; i < sizeof(components) && components[i]; i++) {
> > +           if (!walk_one(&features_string, components[i], i == 0))
> > +                   return false;
> > +   }
> > +
> > +   return true;
> > +}
> > diff --git a/parser/features.h b/parser/features.h
> > index a0c177f..96d0ee9 100644
> > --- a/parser/features.h
> > +++ b/parser/features.h
> > @@ -29,5 +29,6 @@ aa_features *aa_features_ref(aa_features *features);
> >  void aa_features_unref(aa_features *features);
> >  const char *aa_features_get_string(aa_features *features);
> >  bool aa_features_is_equal(aa_features *features1, aa_features *features2);
> > +bool aa_features_supports(aa_features *features, char *str);
> >  
> >  #endif /* __AA_FEATURES_H */
> > diff --git a/parser/parser_main.c b/parser/parser_main.c
> > index 3f8ca6a..2d220a7 100644
> > --- a/parser/parser_main.c
> > +++ b/parser/parser_main.c
> > @@ -574,7 +574,17 @@ no_match:
> >  
> >  static void set_supported_features(void)
> >  {
> > -   const char *features_string;
> > +   char file[] = "file";
> > +   char network[] = "network";
> > +   char af_unix[] = "network/af_unix";
> > +   char mount[] = "mount";
> > +   char dbus[] = "dbus";
> > +   char signal[] = "signal";
> > +   char ptrace[] = "ptrace";
> > +   char set_load[] = "policy/set_load";
> > +   char diff_encode[] = "policy/diff_encode";
> > +   char v7[] = "policy/versions/v7";
> > +   char v6[] = "policy/versions/v6";
> >  
> >     /* has process_args() already assigned a match string? */
> >     if (!features && aa_features_new_from_kernel(&features) == -1) {
> > @@ -582,33 +592,23 @@ static void set_supported_features(void)
> >             return;
> >     }
> >  
> > -   features_string = aa_features_get_string(features);
> >     perms_create = 1;
> > -
> > -   /* TODO: make this real parsing and config setting */
> > -   if (strstr(features_string, "file {"))  /* pre policydb is file= */
> > -           kernel_supports_policydb = 1;
> > -   if (strstr(features_string, "v6"))
> > -           kernel_abi_version = 6;
> > -   if (strstr(features_string, "v7"))
> > +   kernel_supports_policydb = aa_features_supports(features, file);
> > +   kernel_supports_network = aa_features_supports(features, network);
> > +   kernel_supports_unix = aa_features_supports(features, af_unix);
> > +   kernel_supports_mount = aa_features_supports(features, mount);
> > +   kernel_supports_dbus = aa_features_supports(features, dbus);
> > +   kernel_supports_signal = aa_features_supports(features, signal);
> > +   kernel_supports_ptrace = aa_features_supports(features, ptrace);
> > +   kernel_supports_setload = aa_features_supports(features, set_load);
> > +   kernel_supports_diff_encode = aa_features_supports(features, 
> > diff_encode);
> > +
> > +   if (aa_features_supports(features, v7))
> >             kernel_abi_version = 7;
> > -   if (strstr(features_string, "set_load"))
> > -           kernel_supports_setload = 1;
> > -   if (strstr(features_string, "network"))
> > -           kernel_supports_network = 1;
> > -   if (strstr(features_string, "af_unix"))
> > -           kernel_supports_unix = 1;
> > -   if (strstr(features_string, "mount"))
> > -           kernel_supports_mount = 1;
> > -   if (strstr(features_string, "dbus"))
> > -           kernel_supports_dbus = 1;
> > -   if (strstr(features_string, "signal"))
> > -           kernel_supports_signal = 1;
> > -   if (strstr(features_string, "ptrace {"))
> > -           kernel_supports_ptrace = 1;
> > -   if (strstr(features_string, "diff_encode"))
> > -           kernel_supports_diff_encode = 1;
> > -   else if (dfaflags & DFA_CONTROL_DIFF_ENCODE)
> > +   else if (aa_features_supports(features, v6))
> > +           kernel_abi_version = 6;
> > +
> > +   if (!kernel_supports_diff_encode)
> >             /* clear diff_encode because it is not supported */
> >             dfaflags &= ~DFA_CONTROL_DIFF_ENCODE;
> >  }
> > 
> 

Attachment: signature.asc
Description: Digital signature

-- 
AppArmor mailing list
AppArmor@lists.ubuntu.com
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/apparmor

Reply via email to