diff mbox series

[1/2] smack: fix bug: unprivileged task can create labels

Message ID 20250306224317.416365-2-andreev@swemel.ru (mailing list archive)
State Handled Elsewhere
Headers show
Series smack: fix two bugs in setting task label | expand

Commit Message

Konstantin Andreev March 6, 2025, 10:43 p.m. UTC
If an unprivileged task is allowed to relabel itself
(/smack/relabel-self is not empty),
it can freely create new labels by writing their
names into own /proc/PID/attr/smack/current

This occurs because do_setattr() imports
the provided label in advance,
before checking "relabel-self" list.

This change ensures that the "relabel-self" list
is checked before importing the label.

Fixes: 38416e53936e ("Smack: limited capability for changing process label")
Signed-off-by: Konstantin Andreev <andreev@swemel.ru>
---
 security/smack/smack_lsm.c | 41 +++++++++++++++++++++++++-------------
 1 file changed, 27 insertions(+), 14 deletions(-)

Comments

Casey Schaufler March 7, 2025, 5:45 p.m. UTC | #1
On 3/6/2025 2:43 PM, Konstantin Andreev wrote:
> If an unprivileged task is allowed to relabel itself
> (/smack/relabel-self is not empty),
> it can freely create new labels by writing their
> names into own /proc/PID/attr/smack/current
>
> This occurs because do_setattr() imports
> the provided label in advance,
> before checking "relabel-self" list.
>
> This change ensures that the "relabel-self" list
> is checked before importing the label.
>
> Fixes: 38416e53936e ("Smack: limited capability for changing process label")
> Signed-off-by: Konstantin Andreev <andreev@swemel.ru>
> ---
>  security/smack/smack_lsm.c | 41 +++++++++++++++++++++++++-------------
>  1 file changed, 27 insertions(+), 14 deletions(-)
>
> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index 99833168604e..95a614ae4c9c 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -3732,8 +3732,8 @@ static int do_setattr(u64 attr, void *value, size_t size)
>  	struct task_smack *tsp = smack_cred(current_cred());
>  	struct cred *new;
>  	struct smack_known *skp;
> -	struct smack_known_list_elem *sklep;
> -	int rc;
> +	char *labelstr;
> +	int rc = 0;
>  
>  	if (!smack_privileged(CAP_MAC_ADMIN) && list_empty(&tsp->smk_relabel))
>  		return -EPERM;
> @@ -3744,28 +3744,41 @@ static int do_setattr(u64 attr, void *value, size_t size)
>  	if (attr != LSM_ATTR_CURRENT)
>  		return -EOPNOTSUPP;
>  
> -	skp = smk_import_entry(value, size);
> -	if (IS_ERR(skp))
> -		return PTR_ERR(skp);
> +	labelstr = smk_parse_smack(value, size);
> +	if (IS_ERR(labelstr))
> +		return PTR_ERR(labelstr);
>  
>  	/*
>  	 * No process is ever allowed the web ("@") label
>  	 * and the star ("*") label.
>  	 */
> -	if (skp == &smack_known_web || skp == &smack_known_star)
> -		return -EINVAL;
> +	if (labelstr[1] == '\0' /* '@', '*' */) {
> +		const char c = labelstr[0];
> +
> +		if (c == *smack_known_web .smk_known ||

No space before ".smk_known". I can fix this if/when I take the patch.

> +		    c == *smack_known_star.smk_known) {
> +			rc = -EPERM;
> +			goto free_labelstr;
> +		}
> +	}
>  
>  	if (!smack_privileged(CAP_MAC_ADMIN)) {
> -		rc = -EPERM;
> +		const struct smack_known_list_elem *sklep;
>  		list_for_each_entry(sklep, &tsp->smk_relabel, list)
> -			if (sklep->smk_label == skp) {
> -				rc = 0;
> -				break;
> -			}
> -		if (rc)
> -			return rc;
> +			if (strcmp(sklep->smk_label->smk_known, labelstr) == 0)
> +				goto free_labelstr;
> +		rc = -EPERM;
>  	}
>  
> +free_labelstr:
> +	kfree(labelstr);
> +	if (rc)
> +		return -EPERM;
> +
> +	skp = smk_import_entry(value, size);
> +	if (IS_ERR(skp))
> +		return PTR_ERR(skp);
> +
>  	new = prepare_creds();
>  	if (new == NULL)
>  		return -ENOMEM;
Konstantin Andreev March 7, 2025, 7:45 p.m. UTC | #2
Casey Schaufler, 07 Mar 2025:
> On 3/6/2025 2:43 PM, Konstantin Andreev wrote:
>> -	if (skp == &smack_known_web || skp == &smack_known_star)
>> -		return -EINVAL;
>> +	if (labelstr[1] == '\0' /* '@', '*' */) {
>> +		const char c = labelstr[0];
>> +
>> +		if (c == *smack_known_web .smk_known ||
> 
> No space before ".smk_known". I can fix this if/when I take the patch.
> 
>> +		    c == *smack_known_star.smk_known) {
>> +			rc = -EPERM;
>> +			goto free_labelstr;
>> +		}
>> +	}

This is to align two ".smk_known"s in two adjacent lines.

I strive to make monotypic operations visually monotypic.
This catches reader's eyes and lets him recognize the pattern faster.

Of course, If this spacing violates the rules, it should be corrected.

--
Konstantin Andreev
Casey Schaufler March 7, 2025, 10:26 p.m. UTC | #3
On 3/7/2025 11:45 AM, Konstantin Andreev wrote:
> Casey Schaufler, 07 Mar 2025:
>> On 3/6/2025 2:43 PM, Konstantin Andreev wrote:
>>> -    if (skp == &smack_known_web || skp == &smack_known_star)
>>> -        return -EINVAL;
>>> +    if (labelstr[1] == '\0' /* '@', '*' */) {
>>> +        const char c = labelstr[0];
>>> +
>>> +        if (c == *smack_known_web .smk_known ||
>>
>> No space before ".smk_known". I can fix this if/when I take the patch.
>>
>>> +            c == *smack_known_star.smk_known) {
>>> +            rc = -EPERM;
>>> +            goto free_labelstr;
>>> +        }
>>> +    }
>
> This is to align two ".smk_known"s in two adjacent lines.
>
> I strive to make monotypic operations visually monotypic.
> This catches reader's eyes and lets him recognize the pattern faster.
>
> Of course, If this spacing violates the rules, it should be corrected.

Yes, the spacing violates the rules. I don't agree with all
the rules, but unnecessary whitespace isn't something I generally
approve of.

>
> -- 
> Konstantin Andreev
>
diff mbox series

Patch

diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 99833168604e..95a614ae4c9c 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -3732,8 +3732,8 @@  static int do_setattr(u64 attr, void *value, size_t size)
 	struct task_smack *tsp = smack_cred(current_cred());
 	struct cred *new;
 	struct smack_known *skp;
-	struct smack_known_list_elem *sklep;
-	int rc;
+	char *labelstr;
+	int rc = 0;
 
 	if (!smack_privileged(CAP_MAC_ADMIN) && list_empty(&tsp->smk_relabel))
 		return -EPERM;
@@ -3744,28 +3744,41 @@  static int do_setattr(u64 attr, void *value, size_t size)
 	if (attr != LSM_ATTR_CURRENT)
 		return -EOPNOTSUPP;
 
-	skp = smk_import_entry(value, size);
-	if (IS_ERR(skp))
-		return PTR_ERR(skp);
+	labelstr = smk_parse_smack(value, size);
+	if (IS_ERR(labelstr))
+		return PTR_ERR(labelstr);
 
 	/*
 	 * No process is ever allowed the web ("@") label
 	 * and the star ("*") label.
 	 */
-	if (skp == &smack_known_web || skp == &smack_known_star)
-		return -EINVAL;
+	if (labelstr[1] == '\0' /* '@', '*' */) {
+		const char c = labelstr[0];
+
+		if (c == *smack_known_web .smk_known ||
+		    c == *smack_known_star.smk_known) {
+			rc = -EPERM;
+			goto free_labelstr;
+		}
+	}
 
 	if (!smack_privileged(CAP_MAC_ADMIN)) {
-		rc = -EPERM;
+		const struct smack_known_list_elem *sklep;
 		list_for_each_entry(sklep, &tsp->smk_relabel, list)
-			if (sklep->smk_label == skp) {
-				rc = 0;
-				break;
-			}
-		if (rc)
-			return rc;
+			if (strcmp(sklep->smk_label->smk_known, labelstr) == 0)
+				goto free_labelstr;
+		rc = -EPERM;
 	}
 
+free_labelstr:
+	kfree(labelstr);
+	if (rc)
+		return -EPERM;
+
+	skp = smk_import_entry(value, size);
+	if (IS_ERR(skp))
+		return PTR_ERR(skp);
+
 	new = prepare_creds();
 	if (new == NULL)
 		return -ENOMEM;