[apparmor] [patch 2/2] parser: add implicit set variable @{profile_name} to profile symbol table

Seth Arnold seth.arnold at canonical.com
Wed Apr 23 22:51:54 UTC 2014


On Fri, Mar 28, 2014 at 11:15:51AM -0700, Steve Beattie wrote:
> parser: add implicit set variable @{profile_name} to profile symbol table
> 
> This patch adds the creation of an implicit set variable
> @{profile_name} for use within policy. It expands to:
> 
>   - a given profile name if specified; e.g. for
>       'profile flappy_bird /some/pattern/match* { [...] }'
>     @{profile_name} would expand to 'flappy_bird'
>   - if no given name, the match pattern; e.g. for
>       '/usr/bin/doge_bird { [...] }'
>     @{profile_name} would expand to '/usr/bin/doge_bird'
>   - hats and child profiles will include the fully qualified name; e.g.
>     the 'doge' hat in the /usr/bin/flappy_bird profile would cause
>     @{profile_name} to expand to '/usr/bin/flappy_bird//doge' within the
>     'doge' hat, and '/usr/bin/flappy_bird' outside of it in the profile.
> 
> There are some parsing tests added, but more tests are needed to verify
> that expansion occurs properly (I've verified manually using parser
> dumps of the added tests, but automated checks are needed).
> 
> [A side question is whether a @{profile_hatname} or
> @{profile_childname} implicit variable that doesn't include the
> fully qualified path would be useful for writing template profiles
> for multiple nearly identical hats.]

Might be useful, but we can await the day when we have a use for it :)

> Signed-off-by: Steve Beattie <steve at nxnw.org>

Acked-by: Seth Arnold <seth.arnold at canonical.com>

Thanks!

> ---
>  parser/parser.h                                           |    4 
>  parser/parser_symtab.c                                    |   63 ++++++++++++++
>  parser/parser_variable.c                                  |   17 +++
>  parser/profile.h                                          |   24 ++++-
>  parser/tst/simple_tests/vars/vars_auto_profile_name_01.sd |    9 ++
>  parser/tst/simple_tests/vars/vars_auto_profile_name_02.sd |    9 ++
>  parser/tst/simple_tests/vars/vars_auto_profile_name_03.sd |    9 ++
>  parser/tst/simple_tests/vars/vars_auto_profile_name_04.sd |   18 ++++
>  parser/tst/simple_tests/vars/vars_auto_profile_name_05.sd |   40 ++++++++
>  parser/tst/simple_tests/vars/vars_auto_profile_name_06.sd |   19 ++++
>  parser/tst/simple_tests/vars/vars_auto_profile_name_07.sd |   22 ++++
>  11 files changed, 226 insertions(+), 8 deletions(-)
> 
> Index: b/parser/parser_symtab.c
> ===================================================================
> --- a/parser/parser_symtab.c
> +++ b/parser/parser_symtab.c
> @@ -330,6 +330,50 @@ char *get_next_set_value(struct set_valu
>  	return ret;
>  }
>  
> +/* delete_symbol
> + * removes an individual variable from the symbol table. We don't
> + * support this in the language, but for special variables that change
> + * between profiles, we need this.
> + */
> +int delete_set_var(const char *var_name)
> +{
> +	int rc = 0;
> +	struct symtab **result, *n, *var;
> +
> +	n = new_symtab_entry(var_name);
> +	if (!n) {
> +		rc = ENOMEM;
> +		goto out;
> +	}
> +
> +	result = (struct symtab **) tfind(n, &my_symtab, (comparison_fn_t) &compare_symtabs);
> +	if (!result) {
> +		/* XXX Warning? */
> +		goto out;
> +	}
> +
> +	var = (*result);
> +
> +	result = (struct symtab **) tdelete(n, &my_symtab, (comparison_fn_t) &compare_symtabs);
> +	if (!result) {
> +		PERROR("ASSERT: delete_set_var: tfind found var %s but tdelete failed to delete it\n",
> +				var_name);
> +		exit(1);
> +	}
> +
> +	if (var->type != sd_set) {
> +		PERROR("ASSERT: delete_set_var: deleting %s but is a boolean variable\n",
> +				var_name);
> +		exit(1);
> +	}
> +
> +	free_symtab(var);
> +
> +out:
> +	free_symtab(n);
> +	return rc;
> +}
> +
>  static void *seenlist = NULL;
>  
>  static int is_seen(const char *var)
> @@ -708,6 +752,21 @@ int test_expand_set_var_during_dump(void
>  	return rc;
>  }
>  
> +int test_delete_set_var(void)
> +{
> +	int rc = 0;
> +	int retval;
> +
> +	retval = new_set_var("deleteme", "delete this variable");
> +	MY_TEST(retval == 0, "new delete set variable");
> +	retval = delete_set_var("deleteme");
> +	MY_TEST(retval == 0, "delete set variable");
> +
> +	free_symtabs();
> +
> +	return rc;
> +}
> +
>  int main(void)
>  {
>  	int rc = 0;
> @@ -740,6 +799,10 @@ int main(void)
>  	if (rc == 0)
>  		rc = retval;
>  
> +	retval = test_delete_set_var();
> +	if (rc == 0)
> +		rc = retval;
> +
>  	retval = new_set_var("test", "test value");
>  	MY_TEST(retval == 0, "new set variable 1");
>  
> Index: b/parser/parser.h
> ===================================================================
> --- a/parser/parser.h
> +++ b/parser/parser.h
> @@ -284,6 +284,9 @@ do {								\
>  	version;					\
>  })
>  
> +/* The parser fills this variable in automatically */
> +#define PROFILE_NAME_VARIABLE "profile_name"
> +
>  /* from parser_common.c */
>  extern uint32_t policy_version;
>  extern uint32_t parser_abi_version;
> @@ -404,6 +407,7 @@ extern int new_set_var(const char *var,
>  extern int add_set_value(const char *var, const char *value);
>  extern struct set_value *get_set_var(const char *var);
>  extern char *get_next_set_value(struct set_value **context);
> +extern int delete_set_var(const char *var_name);
>  extern void dump_symtab(void);
>  extern void dump_expanded_symtab(void);
>  void free_symtabs(void);
> Index: b/parser/parser_variable.c
> ===================================================================
> --- a/parser/parser_variable.c
> +++ b/parser/parser_variable.c
> @@ -276,11 +276,22 @@ static int process_variables_in_rules(Pr
>  
>  int process_profile_variables(Profile *prof)
>  {
> -	int error = 0;
> -       	error = process_variables_in_entries(prof->entries);
> -       	if (!error)
> +	int error = 0, rc;
> +	std::string *buf = prof->get_name(true);
> +
> +	error = new_set_var(PROFILE_NAME_VARIABLE, buf->c_str());
> +	delete buf;
> +
> +	if (!error)
> +		error = process_variables_in_entries(prof->entries);
> +
> +	if (!error)
>  		error = process_variables_in_rules(*prof);
>  
> +	rc = delete_set_var(PROFILE_NAME_VARIABLE);
> +	if (!error)
> +		error = rc;
> +
>  	return error;
>  }
>  
> Index: b/parser/tst/simple_tests/vars/vars_auto_profile_name_01.sd
> ===================================================================
> --- /dev/null
> +++ b/parser/tst/simple_tests/vars/vars_auto_profile_name_01.sd
> @@ -0,0 +1,9 @@
> +#=DESCRIPTION reference auto profile_name variable in rules
> +#=EXRESULT PASS
> +
> +/a/test/profile {
> +  /a/test/profile rix,
> +
> +  /var/run/@{profile_name} rwk,
> +
> +}
> Index: b/parser/tst/simple_tests/vars/vars_auto_profile_name_02.sd
> ===================================================================
> --- /dev/null
> +++ b/parser/tst/simple_tests/vars/vars_auto_profile_name_02.sd
> @@ -0,0 +1,9 @@
> +#=DESCRIPTION reference auto profile_name variable in rules
> +#=EXRESULT PASS
> +
> +profile /a/test/profile {
> +  /a/test/profile rix,
> +
> +  /var/@{profile_name}/tmp rwk,
> +
> +}
> Index: b/parser/tst/simple_tests/vars/vars_auto_profile_name_03.sd
> ===================================================================
> --- /dev/null
> +++ b/parser/tst/simple_tests/vars/vars_auto_profile_name_03.sd
> @@ -0,0 +1,9 @@
> +#=DESCRIPTION reference auto profile_name variable in rules
> +#=EXRESULT PASS
> +
> +profile this_is_a_test /a/test/profile {
> +  /a/test/profile rix,
> +
> +  /run/@{profile_name}/tmp rwk,
> +
> +}
> Index: b/parser/tst/simple_tests/vars/vars_auto_profile_name_04.sd
> ===================================================================
> --- /dev/null
> +++ b/parser/tst/simple_tests/vars/vars_auto_profile_name_04.sd
> @@ -0,0 +1,18 @@
> +#=DESCRIPTION reference auto profile_name variable in rules w/hats
> +#=EXRESULT PASS
> +
> +/test/profile {
> +  /test/profile rix,
> +
> +  /run/@{profile_name}/tmp rwk,
> +
> +  ^spork {
> +    owner /tmp/* r,
> +    /spork/@{profile_name}/** rw,
> +  }
> +
> +  ^spelunkk {
> +    owner /tmp/* r,
> +    /spelunk/@{profile_name}/** rw,
> +  }
> +}
> Index: b/parser/profile.h
> ===================================================================
> --- a/parser/profile.h
> +++ b/parser/profile.h
> @@ -15,6 +15,8 @@
>  #define __AA_PROFILE_H
>  
>  #include <set>
> +#include <string>
> +#include <iostream>
>  
>  #include "parser.h"
>  #include "rule.h"
> @@ -225,13 +227,25 @@ public:
>  		hat_table.dump();
>  	}
>  
> -	void dump_name(bool fqp)
> +	std::string* get_name(bool fqp)
>  	{
> +		std::string *buf;
>  		if (fqp && parent) {
> -			parent->dump_name(fqp);
> -			printf("//%s", name);
> -		} else
> -			printf("%s", name);
> +			buf = parent->get_name(fqp);
> +			buf->append("//");
> +			buf->append(name);
> +		} else {
> +			return new std::string(name);
> +		}
> +
> +		return buf;
> +	}
> +
> +	void dump_name(bool fqp)
> +	{
> +		std::string *buf = get_name(fqp);;
> +		cout << *buf;
> +		delete buf;
>  	}
>  };
>  
> Index: b/parser/tst/simple_tests/vars/vars_auto_profile_name_05.sd
> ===================================================================
> --- /dev/null
> +++ b/parser/tst/simple_tests/vars/vars_auto_profile_name_05.sd
> @@ -0,0 +1,40 @@
> +#=DESCRIPTION reference auto profile_name variable in rules w/hats
> +#=EXRESULT PASS
> +
> +profile idf3s2A6GX8vrk /simple/profile {
> +  /test/profile rix,
> +
> +  /run/@{profile_name}/tmp rwk,
> +
> +  ^spork {
> +    owner /tmp/* r,
> +    /spork/@{profile_name}/** rw,
> +  }
> +
> +  ^spelunkk {
> +    owner /tmp/* r,
> +    /spelunk/@{profile_name}/** rw,
> +  }
> +}
> +
> +profile LzdZb9bKTMN6y /not/simple/profile {
> +  /test/profile rix,
> +
> +  /run/@{profile_name}/tmp rwk,
> +
> +  ^spork {
> +    owner /tmp/* r,
> +    /run/@{profile_name}/** rw,
> +  }
> +
> +  ^spelunkk {
> +    owner /tmp/* r,
> +    /run/@{profile_name}/** rw,
> +  }
> +
> +  ^spry {
> +    owner /tmp/* r,
> +    /run/@{profile_name}/** rw,
> +  }
> +
> +}
> Index: b/parser/tst/simple_tests/vars/vars_auto_profile_name_06.sd
> ===================================================================
> --- /dev/null
> +++ b/parser/tst/simple_tests/vars/vars_auto_profile_name_06.sd
> @@ -0,0 +1,19 @@
> +#=DESCRIPTION reference auto profile_name variable in rules w/Cx profiles
> +#=EXRESULT PASS
> +
> +profile top_profile /test/profile {
> +  /test/profile rix,
> +
> +  /run/@{profile_name}/tmp rwk,
> +  /bin/spork Cx -> spork,
> +
> +  profile spork {
> +    owner /tmp/* r,
> +    /run/@{profile_name}/** rw,
> +  }
> +
> +  profile spelunkk {
> +    owner /tmp/* r,
> +    /run/@{profile_name}/** rw,
> +  }
> +}
> Index: b/parser/tst/simple_tests/vars/vars_auto_profile_name_07.sd
> ===================================================================
> --- /dev/null
> +++ b/parser/tst/simple_tests/vars/vars_auto_profile_name_07.sd
> @@ -0,0 +1,22 @@
> +#=DESCRIPTION ensure profile_name expansion after subprofiles works
> +#=EXRESULT PASS
> +
> +profile top_profile /test/profile {
> +  /test/profile rix,
> +
> +  /first/path/@{profile_name}/tmp rwk,
> +  /bin/spork Cx -> spork,
> +
> +  profile spork {
> +    owner /tmp/* r,
> +    /run/@{profile_name}/** rw,
> +  }
> +
> +  hat spelunkk {
> +    owner /tmp/* r,
> +    /run/@{profile_name}/** rw,
> +  }
> +
> +  # Does this expand properly?
> +  /second/path/@{profile_name}/tmp rk,
> +}
> 
> -- 
> Steve Beattie
> <sbeattie at ubuntu.com>
> http://NxNW.org/~steve/



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

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: Digital signature
URL: <https://lists.ubuntu.com/archives/apparmor/attachments/20140423/79b7cd89/attachment-0001.pgp>


More information about the AppArmor mailing list