diff mbox

[1/1] checkpolicy: do not leak memory when declaring a type which has been required

Message ID 20170114131255.17598-1-nicolas.iooss@m4x.org (mailing list archive)
State Not Applicable
Headers show

Commit Message

Nicolas Iooss Jan. 14, 2017, 1:12 p.m. UTC
This kind of strange construction is currently accepted by checkmodule
but it makes memory to be leaked in declare_type():

    optional {
        require { type TYPE1; }
    }
    optional {
        require { attribute ATTR; }
        type TYPE1, ATTR;
    }

Moreover reversing the order of these two optional blocks leads to an
(expected) error:

    ERROR 'duplicate declaration of type/attribute' at token 'TYPE1'
    on line 14:
            require { type TYPE1; }

Make checkmodule fails with an error when encourntering the first
construction.

Moreover the construction below also makes memory to be leaked:

    optional {
        require { type TYPE2; attribute ATTR; }
        typeattribute TYPE2 ATTR;
    }
    type TYPE2;

This example is valid and is used by several refpolicy modules. In
declare_type(), declare_symbol() returns 1, stack_top->parent is NULL
and the scope of TYPE2 has been updated when declare_symbol() called
symtab_insert(). When these conditions are met, declare_type() should
return the currently existing type in the policy database.

Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
---

I have tested this patch both with "make test" and by compiling the
current master branch of refpolicy. I have not tested it to build any
Android policy.

 checkpolicy/module_compiler.c | 31 +++++++++++++++++++++++++++++--
 1 file changed, 29 insertions(+), 2 deletions(-)

Comments

Stephen Smalley Jan. 17, 2017, 9:47 p.m. UTC | #1
On Sat, 2017-01-14 at 14:12 +0100, Nicolas Iooss wrote:
> This kind of strange construction is currently accepted by
> checkmodule
> but it makes memory to be leaked in declare_type():
> 
>     optional {
>         require { type TYPE1; }
>     }
>     optional {
>         require { attribute ATTR; }
>         type TYPE1, ATTR;
>     }
> 
> Moreover reversing the order of these two optional blocks leads to an
> (expected) error:
> 
>     ERROR 'duplicate declaration of type/attribute' at token 'TYPE1'
>     on line 14:
>             require { type TYPE1; }

I could be wrong, but this error seems wrong to me.  It isn't declaring
the type multiple times but instead is requiring it in one optional
block (with an empty body besides the require) and then declaring it in
another.  Technically, that should turn on the first optional block
during link/expand IIUC.  cc'ing some others

> 
> Make checkmodule fails with an error when encourntering the first
> construction.
> 
> Moreover the construction below also makes memory to be leaked:
> 
>     optional {
>         require { type TYPE2; attribute ATTR; }
>         typeattribute TYPE2 ATTR;
>     }
>     type TYPE2;
> 
> This example is valid and is used by several refpolicy modules. In
> declare_type(), declare_symbol() returns 1, stack_top->parent is NULL
> and the scope of TYPE2 has been updated when declare_symbol() called
> symtab_insert(). When these conditions are met, declare_type() should
> return the currently existing type in the policy database.
> 
> Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
> ---
> 
> I have tested this patch both with "make test" and by compiling the
> current master branch of refpolicy. I have not tested it to build any
> Android policy.
> 
>  checkpolicy/module_compiler.c | 31 +++++++++++++++++++++++++++++--
>  1 file changed, 29 insertions(+), 2 deletions(-)
> 
> diff --git a/checkpolicy/module_compiler.c
> b/checkpolicy/module_compiler.c
> index 6e5483c17540..04d09d1445a3 100644
> --- a/checkpolicy/module_compiler.c
> +++ b/checkpolicy/module_compiler.c
> @@ -308,7 +308,7 @@ role_datum_t *declare_role(unsigned char isattr)
>  type_datum_t *declare_type(unsigned char primary, unsigned char
> isattr)
>  {
>  	char *id;
> -	type_datum_t *typdatum;
> +	type_datum_t *typdatum, *old_datum;
>  	int retval;
>  	uint32_t value = 0;
>  
> @@ -335,10 +335,37 @@ type_datum_t *declare_type(unsigned char
> primary, unsigned char isattr)
>  	typdatum->flavor = isattr ? TYPE_ATTRIB : TYPE_TYPE;
>  
>  	retval = declare_symbol(SYM_TYPES, id, typdatum, &value,
> &value);
> -	if (retval == 0 || retval == 1) {
> +	if (retval == 0) {
>  		if (typdatum->primary) {
>  			typdatum->s.value = value;
>  		}
> +	} else if (retval == 1) {
> +		/* the type has been previously marked as required
> */
> +		assert(stack_top->type == 1);
> +		if (stack_top->parent == NULL) {
> +			/* in global scope, the type has previously
> been required and is now declared.
> +			 * policydbp->scope[SYM_TYPES] has been
> updated by declare_symbol() */
> +			old_datum = (type_datum_t *)
> hashtab_search(policydbp->p_types.table, id);
> +
> +			/* check that previous symbol has the same
> type/attribute-ness */
> +			if (typdatum->flavor == old_datum->flavor) {
> +				type_datum_destroy(typdatum);
> +				free(typdatum);
> +				typdatum = old_datum;
> +			} else {
> +				yyerror("declaration of
> type/attribute with an unexpected flavor");
> +				type_datum_destroy(typdatum);
> +				free(typdatum);
> +				typdatum = NULL;
> +			}
> +			free(id);
> +		} else {
> +			yyerror("declaration of type/attribute after
> it has been required");
> +			free(id);
> +			type_datum_destroy(typdatum);
> +			free(typdatum);
> +			return NULL;
> +		}
>  	} else {
>  		/* error occurred (can't have duplicate type
> declarations) */
>  		free(id);
James Carter Jan. 18, 2017, 1:37 p.m. UTC | #2
On 01/17/2017 04:47 PM, Stephen Smalley wrote:
> On Sat, 2017-01-14 at 14:12 +0100, Nicolas Iooss wrote:
>> This kind of strange construction is currently accepted by
>> checkmodule
>> but it makes memory to be leaked in declare_type():
>>
>>     optional {
>>         require { type TYPE1; }
>>     }
>>     optional {
>>         require { attribute ATTR; }
>>         type TYPE1, ATTR;
>>     }
>>
>> Moreover reversing the order of these two optional blocks leads to an
>> (expected) error:
>>
>>     ERROR 'duplicate declaration of type/attribute' at token 'TYPE1'
>>     on line 14:
>>             require { type TYPE1; }
>
> I could be wrong, but this error seems wrong to me.  It isn't declaring
> the type multiple times but instead is requiring it in one optional
> block (with an empty body besides the require) and then declaring it in
> another.  Technically, that should turn on the first optional block
> during link/expand IIUC.  cc'ing some others
>

The error looks wrong to me as well.

Jim

>>
>> Make checkmodule fails with an error when encourntering the first
>> construction.
>>
>> Moreover the construction below also makes memory to be leaked:
>>
>>     optional {
>>         require { type TYPE2; attribute ATTR; }
>>         typeattribute TYPE2 ATTR;
>>     }
>>     type TYPE2;
>>
>> This example is valid and is used by several refpolicy modules. In
>> declare_type(), declare_symbol() returns 1, stack_top->parent is NULL
>> and the scope of TYPE2 has been updated when declare_symbol() called
>> symtab_insert(). When these conditions are met, declare_type() should
>> return the currently existing type in the policy database.
>>
>> Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
>> ---
>>
>> I have tested this patch both with "make test" and by compiling the
>> current master branch of refpolicy. I have not tested it to build any
>> Android policy.
>>
>>  checkpolicy/module_compiler.c | 31 +++++++++++++++++++++++++++++--
>>  1 file changed, 29 insertions(+), 2 deletions(-)
>>
>> diff --git a/checkpolicy/module_compiler.c
>> b/checkpolicy/module_compiler.c
>> index 6e5483c17540..04d09d1445a3 100644
>> --- a/checkpolicy/module_compiler.c
>> +++ b/checkpolicy/module_compiler.c
>> @@ -308,7 +308,7 @@ role_datum_t *declare_role(unsigned char isattr)
>>  type_datum_t *declare_type(unsigned char primary, unsigned char
>> isattr)
>>  {
>>  	char *id;
>> -	type_datum_t *typdatum;
>> +	type_datum_t *typdatum, *old_datum;
>>  	int retval;
>>  	uint32_t value = 0;
>>
>> @@ -335,10 +335,37 @@ type_datum_t *declare_type(unsigned char
>> primary, unsigned char isattr)
>>  	typdatum->flavor = isattr ? TYPE_ATTRIB : TYPE_TYPE;
>>
>>  	retval = declare_symbol(SYM_TYPES, id, typdatum, &value,
>> &value);
>> -	if (retval == 0 || retval == 1) {
>> +	if (retval == 0) {
>>  		if (typdatum->primary) {
>>  			typdatum->s.value = value;
>>  		}
>> +	} else if (retval == 1) {
>> +		/* the type has been previously marked as required
>> */
>> +		assert(stack_top->type == 1);
>> +		if (stack_top->parent == NULL) {
>> +			/* in global scope, the type has previously
>> been required and is now declared.
>> +			 * policydbp->scope[SYM_TYPES] has been
>> updated by declare_symbol() */
>> +			old_datum = (type_datum_t *)
>> hashtab_search(policydbp->p_types.table, id);
>> +
>> +			/* check that previous symbol has the same
>> type/attribute-ness */
>> +			if (typdatum->flavor == old_datum->flavor) {
>> +				type_datum_destroy(typdatum);
>> +				free(typdatum);
>> +				typdatum = old_datum;
>> +			} else {
>> +				yyerror("declaration of
>> type/attribute with an unexpected flavor");
>> +				type_datum_destroy(typdatum);
>> +				free(typdatum);
>> +				typdatum = NULL;
>> +			}
>> +			free(id);
>> +		} else {
>> +			yyerror("declaration of type/attribute after
>> it has been required");
>> +			free(id);
>> +			type_datum_destroy(typdatum);
>> +			free(typdatum);
>> +			return NULL;
>> +		}
>>  	} else {
>>  		/* error occurred (can't have duplicate type
>> declarations) */
>>  		free(id);
James Carter Jan. 23, 2017, 4:50 p.m. UTC | #3
On 01/14/2017 08:12 AM, Nicolas Iooss wrote:
> This kind of strange construction is currently accepted by checkmodule
> but it makes memory to be leaked in declare_type():
>
>     optional {
>         require { type TYPE1; }
>     }
>     optional {
>         require { attribute ATTR; }
>         type TYPE1, ATTR;
>     }
>
> Moreover reversing the order of these two optional blocks leads to an
> (expected) error:
>
>     ERROR 'duplicate declaration of type/attribute' at token 'TYPE1'
>     on line 14:
>             require { type TYPE1; }
>
> Make checkmodule fails with an error when encourntering the first
> construction.
>
> Moreover the construction below also makes memory to be leaked:
>
>     optional {
>         require { type TYPE2; attribute ATTR; }
>         typeattribute TYPE2 ATTR;
>     }
>     type TYPE2;
>
> This example is valid and is used by several refpolicy modules. In
> declare_type(), declare_symbol() returns 1, stack_top->parent is NULL
> and the scope of TYPE2 has been updated when declare_symbol() called
> symtab_insert(). When these conditions are met, declare_type() should
> return the currently existing type in the policy database.
>
> Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
> ---
>
> I have tested this patch both with "make test" and by compiling the
> current master branch of refpolicy. I have not tested it to build any
> Android policy.
>
>  checkpolicy/module_compiler.c | 31 +++++++++++++++++++++++++++++--
>  1 file changed, 29 insertions(+), 2 deletions(-)
>
> diff --git a/checkpolicy/module_compiler.c b/checkpolicy/module_compiler.c
> index 6e5483c17540..04d09d1445a3 100644
> --- a/checkpolicy/module_compiler.c
> +++ b/checkpolicy/module_compiler.c
> @@ -308,7 +308,7 @@ role_datum_t *declare_role(unsigned char isattr)
>  type_datum_t *declare_type(unsigned char primary, unsigned char isattr)
>  {
>  	char *id;
> -	type_datum_t *typdatum;
> +	type_datum_t *typdatum, *old_datum;
>  	int retval;
>  	uint32_t value = 0;
>
> @@ -335,10 +335,37 @@ type_datum_t *declare_type(unsigned char primary, unsigned char isattr)
>  	typdatum->flavor = isattr ? TYPE_ATTRIB : TYPE_TYPE;
>
>  	retval = declare_symbol(SYM_TYPES, id, typdatum, &value, &value);
> -	if (retval == 0 || retval == 1) {
> +	if (retval == 0) {
>  		if (typdatum->primary) {
>  			typdatum->s.value = value;
>  		}
> +	} else if (retval == 1) {
> +		/* the type has been previously marked as required */
> +		assert(stack_top->type == 1);
> +		if (stack_top->parent == NULL) {
> +			/* in global scope, the type has previously been required and is now declared.
> +			 * policydbp->scope[SYM_TYPES] has been updated by declare_symbol() */
> +			old_datum = (type_datum_t *) hashtab_search(policydbp->p_types.table, id);
> +
> +			/* check that previous symbol has the same type/attribute-ness */
> +			if (typdatum->flavor == old_datum->flavor) {
> +				type_datum_destroy(typdatum);
> +				free(typdatum);
> +				typdatum = old_datum;
> +			} else {
> +				yyerror("declaration of type/attribute with an unexpected flavor");
> +				type_datum_destroy(typdatum);
> +				free(typdatum);
> +				typdatum = NULL;
> +			}
> +			free(id);
> +		} else {
> +			yyerror("declaration of type/attribute after it has been required");
> +			free(id);
> +			type_datum_destroy(typdatum);
> +			free(typdatum);
> +			return NULL;

This else block causes a slightly older version of fedora policy to fail to 
build. I am looking at refactoring declare_type() and require_type() and will 
try to fix the memory leak and other issues at the same time.

Jim

> +		}
>  	} else {
>  		/* error occurred (can't have duplicate type declarations) */
>  		free(id);
>
diff mbox

Patch

diff --git a/checkpolicy/module_compiler.c b/checkpolicy/module_compiler.c
index 6e5483c17540..04d09d1445a3 100644
--- a/checkpolicy/module_compiler.c
+++ b/checkpolicy/module_compiler.c
@@ -308,7 +308,7 @@  role_datum_t *declare_role(unsigned char isattr)
 type_datum_t *declare_type(unsigned char primary, unsigned char isattr)
 {
 	char *id;
-	type_datum_t *typdatum;
+	type_datum_t *typdatum, *old_datum;
 	int retval;
 	uint32_t value = 0;
 
@@ -335,10 +335,37 @@  type_datum_t *declare_type(unsigned char primary, unsigned char isattr)
 	typdatum->flavor = isattr ? TYPE_ATTRIB : TYPE_TYPE;
 
 	retval = declare_symbol(SYM_TYPES, id, typdatum, &value, &value);
-	if (retval == 0 || retval == 1) {
+	if (retval == 0) {
 		if (typdatum->primary) {
 			typdatum->s.value = value;
 		}
+	} else if (retval == 1) {
+		/* the type has been previously marked as required */
+		assert(stack_top->type == 1);
+		if (stack_top->parent == NULL) {
+			/* in global scope, the type has previously been required and is now declared.
+			 * policydbp->scope[SYM_TYPES] has been updated by declare_symbol() */
+			old_datum = (type_datum_t *) hashtab_search(policydbp->p_types.table, id);
+
+			/* check that previous symbol has the same type/attribute-ness */
+			if (typdatum->flavor == old_datum->flavor) {
+				type_datum_destroy(typdatum);
+				free(typdatum);
+				typdatum = old_datum;
+			} else {
+				yyerror("declaration of type/attribute with an unexpected flavor");
+				type_datum_destroy(typdatum);
+				free(typdatum);
+				typdatum = NULL;
+			}
+			free(id);
+		} else {
+			yyerror("declaration of type/attribute after it has been required");
+			free(id);
+			type_datum_destroy(typdatum);
+			free(typdatum);
+			return NULL;
+		}
 	} else {
 		/* error occurred (can't have duplicate type declarations) */
 		free(id);