From patchwork Thu Jul 31 03:26:47 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Damian Hobson-Garcia X-Patchwork-Id: 4653041 Return-Path: X-Original-To: patchwork-ltsi-dev@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 30F229F36A for ; Thu, 31 Jul 2014 03:28:10 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 29E7A2015E for ; Thu, 31 Jul 2014 03:28:09 +0000 (UTC) Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 0F8B9201B4 for ; Thu, 31 Jul 2014 03:28:08 +0000 (UTC) Received: from mail.linux-foundation.org (localhost [IPv6:::1]) by mail.linuxfoundation.org (Postfix) with ESMTP id EDAAFA8A; Thu, 31 Jul 2014 03:27:15 +0000 (UTC) X-Original-To: ltsi-dev@lists.linuxfoundation.org Delivered-To: ltsi-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 415F4A8A for ; Thu, 31 Jul 2014 03:27:15 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pa0-f50.google.com (mail-pa0-f50.google.com [209.85.220.50]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 7CF2D1FD2D for ; Thu, 31 Jul 2014 03:27:14 +0000 (UTC) Received: by mail-pa0-f50.google.com with SMTP id et14so2728498pad.23 for ; Wed, 30 Jul 2014 20:27:14 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=NgzOLS6UxnlKkvAC50V1I98+IQCAwg/78SqSvslm+mE=; b=RMug0P1ZTVIKfYpe/M0e2tYsyt42ajuPd+/BtJyuZOj1s1vGkNgl9P7y2h92yiA66l 4M7msQ6SgDH8BDB1+NcHISgrBpfaq/TZf99AOTTkFfzWsTmJl8EPk9wjPqhxS/f6p3Ug O0m64nKjzP4gJNuI1eKuiFnTM4RrhuI5innhYwbQ8q7oqdFFl7DfN5VwMXBqudo2OlXY ezjMvZmDLXHKh/gwOjtuB8H34EmOmU5pJYUCUxSWCriXhPjODDyM4HjpCXHO5jj1LdGA 4GpMCB4F/ndaGsiO7z8XVBfTnqjzPexXnAQ4GMqWGbjr1dNV6bQPCGEcLWM+sWCH2CKH T1wg== X-Gm-Message-State: ALoCoQlAn/cak2BK2hs/O4rw03JO1N3QHMrPL7ZBdVmSMa/5+Ir0ekPib9pdMfwiSiNUNll58XBT X-Received: by 10.66.100.170 with SMTP id ez10mr1249383pab.12.1406777234278; Wed, 30 Jul 2014 20:27:14 -0700 (PDT) Received: from v400.hq.igel.co.jp (napt.igel.co.jp. [219.106.231.132]) by mx.google.com with ESMTPSA id d13sm3843861pbu.72.2014.07.30.20.27.13 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Wed, 30 Jul 2014 20:27:13 -0700 (PDT) From: Damian Hobson-Garcia To: ltsi-dev@lists.linuxfoundation.org Date: Thu, 31 Jul 2014 12:26:47 +0900 Message-Id: <1406777210-28425-14-git-send-email-dhobsong@igel.co.jp> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1406777210-28425-1-git-send-email-dhobsong@igel.co.jp> References: <1406777210-28425-1-git-send-email-dhobsong@igel.co.jp> X-Spam-Status: No, score=-4.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org Subject: [LTSI-dev] [PATCH 13/16] Smack: parse multiple rules per write to load2, up to PAGE_SIZE-1 bytes X-BeenThere: ltsi-dev@lists.linuxfoundation.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: "A list to discuss patches, development, and other things related to the LTSI project" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ltsi-dev-bounces@lists.linuxfoundation.org Errors-To: ltsi-dev-bounces@lists.linuxfoundation.org X-Virus-Scanned: ClamAV using ClamSMTP From: Rafal Krypa 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 (cherry picked from commit 10289b0f738e8b301969f2288c4942455f1b1e59) Signed-off-by: Damian Hobson-Garcia Signed-off-by: Tomohito Esaki --- 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,