Commit c147e13e authored by Konstantin Andreev's avatar Konstantin Andreev Committed by Casey Schaufler
Browse files

smack: fix bug: unprivileged task can create labels



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: 38416e53 ("Smack: limited capability for changing process label")
Signed-off-by: default avatarKonstantin Andreev <andreev@swemel.ru>
Signed-off-by: default avatarCasey Schaufler <casey@schaufler-ca.com>
parent 78fc6a94
Loading
Loading
Loading
Loading
+27 −14
Original line number Diff line number Diff line
@@ -3778,8 +3778,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;
@@ -3790,27 +3790,40 @@ 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 (!smack_privileged(CAP_MAC_ADMIN)) {
		if (c == *smack_known_web.smk_known ||
		    c == *smack_known_star.smk_known) {
			rc = -EPERM;
			goto free_labelstr;
		}
	}

	if (!smack_privileged(CAP_MAC_ADMIN)) {
		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 (strcmp(sklep->smk_label->smk_known, labelstr) == 0)
				goto free_labelstr;
		rc = -EPERM;
	}

free_labelstr:
	kfree(labelstr);
	if (rc)
			return rc;
	}
		return -EPERM;

	skp = smk_import_entry(value, size);
	if (IS_ERR(skp))
		return PTR_ERR(skp);

	new = prepare_creds();
	if (new == NULL)