diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 5b42140e12e8..9df06fdd894f 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -919,7 +919,7 @@ static void profile_query_cb(const struct aa_profile *profile, static ssize_t query_data(char *buf, size_t buf_len, char *query, size_t query_len) { - char *out; + char *out, *keydup; const char *key; struct label_it i; struct aa_label *label, *curr; @@ -941,11 +941,18 @@ static ssize_t query_data(char *buf, size_t buf_len, if (buf_len < sizeof(bytes) + sizeof(blocks)) return -EINVAL; /* not enough space */ + /* buf overlaps query, keep a copy of the key for the later lookups */ + keydup = kstrdup(key, GFP_KERNEL); + if (!keydup) + return -ENOMEM; + curr = begin_current_label_crit_section(&needput); label = aa_label_parse(curr, query, GFP_KERNEL, false, false); end_current_label_crit_section(curr, needput); - if (IS_ERR(label)) + if (IS_ERR(label)) { + kfree(keydup); return PTR_ERR(label); + } /* We are going to leave space for two numbers. The first is the total * number of bytes we are writing after the first number. This is so @@ -963,13 +970,14 @@ static ssize_t query_data(char *buf, size_t buf_len, if (!profile->data) continue; - data = rhashtable_lookup_fast(profile->data, &key, + data = rhashtable_lookup_fast(profile->data, &keydup, profile->data->p); if (data) { if (out + sizeof(outle32) + data->size > buf + buf_len) { aa_put_label(label); + kfree(keydup); return -EINVAL; /* not enough space */ } outle32 = __cpu_to_le32(data->size); @@ -981,6 +989,7 @@ static ssize_t query_data(char *buf, size_t buf_len, } } aa_put_label(label); + kfree(keydup); outle32 = __cpu_to_le32(out - buf - sizeof(bytes)); memcpy(buf, &outle32, sizeof(outle32));