[PATCH 2/4] security: smack: avoid kmalloc() in smk_parse_long_rule()

From: Tomasz Stanislawski
Date: Wed Jun 19 2013 - 11:14:00 EST


Function smk_parse_long_rule() allocates a number of temporary strings on heap
(kmalloc cache). Moreover, the sizes of those allocations might be large if
user calls write() for a long chunk. A big kmalloc triggers a heavy reclaim
havoc and it is very likely to fail.

This patch introduces smk_parse_substrings() function that parses a string into
substring separated by whitespaces. The buffer for substring is preallocated.
It must store substring the worst case scenario which is SMK_LOAD2LEN in case
of long rule parsing.

Signed-off-by: Tomasz Stanislawski <t.stanislaws@xxxxxxxxxxx>
---
security/smack/smackfs.c | 68 ++++++++++++++++++++++++++--------------------
1 file changed, 38 insertions(+), 30 deletions(-)

diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 5dcd520..34d146b 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -364,6 +364,33 @@ static int smk_parse_rule(const char *data, struct smack_parsed_rule *rule,
}

/**
+ * smk_parse_strings - parse white-space separated substring from a string
+ * @src: a long string to be parsed, null terminated
+ * @dst: a buffer for substrings, should be at least strlen(src)+1 bytes
+ * @args: table for parsed substring
+ * @size: number of slots in args table
+ *
+ * Returns number of parsed substrings
+ */
+static int smk_parse_substrings(const char *src, char *dst,
+ char *args[], int size)
+{
+ int cnt;
+
+ for (cnt = 0; cnt < size; ++cnt) {
+ src = skip_spaces(src);
+ if (*src == 0)
+ break;
+ args[cnt] = dst;
+ for (; *src && !isspace(*src); ++src, ++dst)
+ *dst = *src;
+ *(dst++) = 0;
+ }
+
+ return cnt;
+}
+
+/**
* smk_parse_long_rule - parse Smack rule from rule string
* @data: string to be parsed, null terminated
* @rule: Will be filled with Smack parsed rule
@@ -375,48 +402,29 @@ static int smk_parse_rule(const char *data, struct smack_parsed_rule *rule,
static int smk_parse_long_rule(const char *data, struct smack_parsed_rule *rule,
int import, int change)
{
- char *subject;
- char *object;
- char *access1;
- char *access2;
int datalen;
+ char *buffer;
+ char *args[4];
int rc = -1;

- /* This is inefficient */
- datalen = strlen(data);
+ datalen = strlen(data) + 1;

- /* Our first element can be 64 + \0 with no spaces */
- subject = kzalloc(datalen + 1, GFP_KERNEL);
- if (subject == NULL)
+ buffer = kmalloc(datalen, GFP_KERNEL);
+ if (!buffer)
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,
+ if (smk_parse_substrings(data, buffer, args, 4) == 4)
+ rc = smk_fill_rule(args[0], args[1], args[2], args[3],
rule, import, 0);
} else {
- if (sscanf(data, "%s %s %s", subject, object, access1) == 3)
- rc = smk_fill_rule(subject, object, access1, NULL,
+ if (smk_parse_substrings(data, buffer, args, 3) == 3)
+ rc = smk_fill_rule(args[0], args[1], args[2], NULL,
rule, import, 0);
}

- kfree(access2);
-free_out_a:
- kfree(access1);
-free_out_o:
- kfree(object);
-free_out_s:
- kfree(subject);
+ kfree(buffer);
+
return rc;
}

--
1.7.9.5

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