lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <52093122.2050506@schaufler-ca.com>
Date:	Mon, 12 Aug 2013 12:01:54 -0700
From:	Casey Schaufler <casey@...aufler-ca.com>
To:	Rafal Krypa <r.krypa@...sung.com>
CC:	linux-security-module@...r.kernel.org,
	linux-kernel@...r.kernel.org,
	Casey Schaufler <casey@...aufler-ca.com>
Subject: Re: [PATCH] Smack: parse multiple rules per write to load2, up to
 PAGE_SIZE-1 bytes

On 8/9/2013 2:47 AM, Rafal Krypa wrote:
> Smack interface for loading rules has always parsed only single rule from
> data written to it. This requires user program to call one write() per
> each rule it wants to load.
> This change makes it possible to write multiple rules, separated by new
> line character. Smack will load at most PAGE_SIZE-1 characters and properly
> return number of processed bytes. In case when user buffer is larger, it
> will be additionally truncated. All characters after last \n will not get
> parsed to avoid partial rule near input buffer boundary.
>
> Signed-off-by: Rafal Krypa <r.krypa@...sung.com>

Acked-by: Casey Schaufler <casey@...aufler-ca.com>

Applied to git://git.gitorious.org/smack-next/kernel.git smack-for-3.12

> ---
>  security/smack/smackfs.c |  167 +++++++++++++++++++++++-----------------------
>  1 file changed, 82 insertions(+), 85 deletions(-)
>
> diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
> index a07e93f..80f4b4a 100644
> --- a/security/smack/smackfs.c
> +++ b/security/smack/smackfs.c
> @@ -368,56 +368,43 @@ static int smk_parse_rule(const char *data, struct smack_parsed_rule *rule,
>   * @data: string to be parsed, null terminated
>   * @rule: Will be filled with Smack parsed rule
>   * @import: if non-zero, import labels
> - * @change: if non-zero, data is from /smack/change-rule
> + * @tokens: numer of substrings expected in data
>   *
> - * Returns 0 on success, -1 on failure
> + * Returns number of processed bytes on success, -1 on failure.
>   */
> -static int smk_parse_long_rule(const char *data, struct smack_parsed_rule *rule,
> -				int import, int change)
> +static ssize_t smk_parse_long_rule(char *data, struct smack_parsed_rule *rule,
> +				int import, int tokens)
>  {
> -	char *subject;
> -	char *object;
> -	char *access1;
> -	char *access2;
> -	int datalen;
> -	int rc = -1;
> +	ssize_t cnt = 0;
> +	char *tok[4];
> +	int i;
>  
> -	/* This is inefficient */
> -	datalen = strlen(data);
> +	/*
> +	 * Parsing the rule in-place, filling all white-spaces with '\0'
> +	 */
> +	for (i = 0; i < tokens; ++i) {
> +		while (isspace(data[cnt]))
> +			data[cnt++] = '\0';
>  
> -	/* Our first element can be 64 + \0 with no spaces */
> -	subject = kzalloc(datalen + 1, GFP_KERNEL);
> -	if (subject == NULL)
> -		return -1;
> -	object = kzalloc(datalen, GFP_KERNEL);
> -	if (object == NULL)
> -		goto free_out_s;
> -	access1 = kzalloc(datalen, GFP_KERNEL);
> -	if (access1 == NULL)
> -		goto free_out_o;
> -	access2 = kzalloc(datalen, GFP_KERNEL);
> -	if (access2 == NULL)
> -		goto free_out_a;
> -
> -	if (change) {
> -		if (sscanf(data, "%s %s %s %s",
> -			subject, object, access1, access2) == 4)
> -			rc = smk_fill_rule(subject, object, access1, access2,
> -				rule, import, 0);
> -	} else {
> -		if (sscanf(data, "%s %s %s", subject, object, access1) == 3)
> -			rc = smk_fill_rule(subject, object, access1, NULL,
> -				rule, import, 0);
> +		if (data[cnt] == '\0')
> +			/* Unexpected end of data */
> +			return -1;
> +
> +		tok[i] = data + cnt;
> +
> +		while (data[cnt] && !isspace(data[cnt]))
> +			++cnt;
>  	}
> +	while (isspace(data[cnt]))
> +		data[cnt++] = '\0';
>  
> -	kfree(access2);
> -free_out_a:
> -	kfree(access1);
> -free_out_o:
> -	kfree(object);
> -free_out_s:
> -	kfree(subject);
> -	return rc;
> +	while (i < 4)
> +		tok[i++] = NULL;
> +
> +	if (smk_fill_rule(tok[0], tok[1], tok[2], tok[3], rule, import, 0))
> +		return -1;
> +
> +	return cnt;
>  }
>  
>  #define SMK_FIXED24_FMT	0	/* Fixed 24byte label format */
> @@ -449,9 +436,10 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
>  {
>  	struct smack_parsed_rule rule;
>  	char *data;
> -	int datalen;
> -	int rc = -EINVAL;
> -	int load = 0;
> +	int rc;
> +	int trunc = 0;
> +	int tokens;
> +	ssize_t cnt = 0;
>  
>  	/*
>  	 * No partial writes.
> @@ -466,11 +454,14 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
>  		 */
>  		if (count != SMK_OLOADLEN && count != SMK_LOADLEN)
>  			return -EINVAL;
> -		datalen = SMK_LOADLEN;
> -	} else
> -		datalen = count + 1;
> +	} else {
> +		if (count >= PAGE_SIZE) {
> +			count = PAGE_SIZE - 1;
> +			trunc = 1;
> +		}
> +	}
>  
> -	data = kzalloc(datalen, GFP_KERNEL);
> +	data = kmalloc(count + 1, GFP_KERNEL);
>  	if (data == NULL)
>  		return -ENOMEM;
>  
> @@ -479,36 +470,49 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
>  		goto out;
>  	}
>  
> -	if (format == SMK_LONG_FMT) {
> -		/*
> -		 * Be sure the data string is terminated.
> -		 */
> -		data[count] = '\0';
> -		if (smk_parse_long_rule(data, &rule, 1, 0))
> -			goto out;
> -	} else if (format == SMK_CHANGE_FMT) {
> -		data[count] = '\0';
> -		if (smk_parse_long_rule(data, &rule, 1, 1))
> -			goto out;
> -	} else {
> -		/*
> -		 * More on the minor hack for backward compatibility
> -		 */
> -		if (count == (SMK_OLOADLEN))
> -			data[SMK_OLOADLEN] = '-';
> -		if (smk_parse_rule(data, &rule, 1))
> +	/*
> +	 * In case of parsing only part of user buf,
> +	 * avoid having partial rule at the data buffer
> +	 */
> +	if (trunc) {
> +		while (count > 0 && (data[count - 1] != '\n'))
> +			--count;
> +		if (count == 0) {
> +			rc = -EINVAL;
>  			goto out;
> +		}
>  	}
>  
> -	if (rule_list == NULL) {
> -		load = 1;
> -		rule_list = &rule.smk_subject->smk_rules;
> -		rule_lock = &rule.smk_subject->smk_rules_lock;
> +	data[count] = '\0';
> +	tokens = (format == SMK_CHANGE_FMT ? 4 : 3);
> +	while (cnt < count) {
> +		if (format == SMK_FIXED24_FMT) {
> +			rc = smk_parse_rule(data, &rule, 1);
> +			if (rc != 0) {
> +				rc = -EINVAL;
> +				goto out;
> +			}
> +			cnt = count;
> +		} else {
> +			rc = smk_parse_long_rule(data + cnt, &rule, 1, tokens);
> +			if (rc <= 0) {
> +				rc = -EINVAL;
> +				goto out;
> +			}
> +			cnt += rc;
> +		}
> +
> +		if (rule_list == NULL)
> +			rc = smk_set_access(&rule, &rule.smk_subject->smk_rules,
> +				&rule.smk_subject->smk_rules_lock, 1);
> +		else
> +			rc = smk_set_access(&rule, rule_list, rule_lock, 0);
> +
> +		if (rc)
> +			goto out;
>  	}
>  
> -	rc = smk_set_access(&rule, rule_list, rule_lock, load);
> -	if (rc == 0)
> -		rc = count;
> +	rc = cnt;
>  out:
>  	kfree(data);
>  	return rc;
> @@ -1829,7 +1833,6 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf,
>  {
>  	struct smack_parsed_rule rule;
>  	char *data;
> -	char *cod;
>  	int res;
>  
>  	data = simple_transaction_get(file, buf, count);
> @@ -1842,18 +1845,12 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf,
>  		res = smk_parse_rule(data, &rule, 0);
>  	} else {
>  		/*
> -		 * Copy the data to make sure the string is terminated.
> +		 * simple_transaction_get() returns null-terminated data
>  		 */
> -		cod = kzalloc(count + 1, GFP_KERNEL);
> -		if (cod == NULL)
> -			return -ENOMEM;
> -		memcpy(cod, data, count);
> -		cod[count] = '\0';
> -		res = smk_parse_long_rule(cod, &rule, 0, 0);
> -		kfree(cod);
> +		res = smk_parse_long_rule(data, &rule, 0, 3);
>  	}
>  
> -	if (res)
> +	if (res < 0)
>  		return -EINVAL;
>  
>  	res = smk_access(rule.smk_subject, rule.smk_object,

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ