mirror of
https://github.com/torvalds/linux.git
synced 2024-11-25 21:51:40 +00:00
big_keys: Use struct for internal payload
The randstruct GCC plugin gets upset when it sees struct path (which is randomized) being assigned from a "void *" (which it cannot type-check). There's no need for these casts, as the entire internal payload use is following a normal struct layout. Convert the enum-based void * offset dereferencing to the new big_key_payload struct. No meaningful machine code changes result after this change, and source readability is improved. Drop the randstruct exception now that there is no "confusing" cross-type assignment. Cc: David Howells <dhowells@redhat.com> Cc: Eric Biggers <ebiggers@kernel.org> Cc: Christoph Hellwig <hch@infradead.org> Cc: Jarkko Sakkinen <jarkko@kernel.org> Cc: James Morris <jmorris@namei.org> Cc: "Serge E. Hallyn" <serge@hallyn.com> Cc: linux-hardening@vger.kernel.org Cc: keyrings@vger.kernel.org Cc: linux-security-module@vger.kernel.org Signed-off-by: Kees Cook <keescook@chromium.org>
This commit is contained in:
parent
61f60bac8c
commit
c1298a3a11
@ -50,8 +50,6 @@ static const struct whitelist_entry whitelist[] = {
|
|||||||
{ "drivers/net/ethernet/sun/niu.c", "page", "address_space" },
|
{ "drivers/net/ethernet/sun/niu.c", "page", "address_space" },
|
||||||
/* unix_skb_parms via UNIXCB() buffer */
|
/* unix_skb_parms via UNIXCB() buffer */
|
||||||
{ "net/unix/af_unix.c", "unix_skb_parms", "char" },
|
{ "net/unix/af_unix.c", "unix_skb_parms", "char" },
|
||||||
/* big_key payload.data struct splashing */
|
|
||||||
{ "security/keys/big_key.c", "path", "void *" },
|
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -20,12 +20,13 @@
|
|||||||
/*
|
/*
|
||||||
* Layout of key payload words.
|
* Layout of key payload words.
|
||||||
*/
|
*/
|
||||||
enum {
|
struct big_key_payload {
|
||||||
big_key_data,
|
u8 *data;
|
||||||
big_key_path,
|
struct path path;
|
||||||
big_key_path_2nd_part,
|
size_t length;
|
||||||
big_key_len,
|
|
||||||
};
|
};
|
||||||
|
#define to_big_key_payload(payload) \
|
||||||
|
(struct big_key_payload *)((payload).data)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the data is under this limit, there's no point creating a shm file to
|
* If the data is under this limit, there's no point creating a shm file to
|
||||||
@ -55,7 +56,7 @@ struct key_type key_type_big_key = {
|
|||||||
*/
|
*/
|
||||||
int big_key_preparse(struct key_preparsed_payload *prep)
|
int big_key_preparse(struct key_preparsed_payload *prep)
|
||||||
{
|
{
|
||||||
struct path *path = (struct path *)&prep->payload.data[big_key_path];
|
struct big_key_payload *payload = to_big_key_payload(prep->payload);
|
||||||
struct file *file;
|
struct file *file;
|
||||||
u8 *buf, *enckey;
|
u8 *buf, *enckey;
|
||||||
ssize_t written;
|
ssize_t written;
|
||||||
@ -63,13 +64,15 @@ int big_key_preparse(struct key_preparsed_payload *prep)
|
|||||||
size_t enclen = datalen + CHACHA20POLY1305_AUTHTAG_SIZE;
|
size_t enclen = datalen + CHACHA20POLY1305_AUTHTAG_SIZE;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
BUILD_BUG_ON(sizeof(*payload) != sizeof(prep->payload.data));
|
||||||
|
|
||||||
if (datalen <= 0 || datalen > 1024 * 1024 || !prep->data)
|
if (datalen <= 0 || datalen > 1024 * 1024 || !prep->data)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* Set an arbitrary quota */
|
/* Set an arbitrary quota */
|
||||||
prep->quotalen = 16;
|
prep->quotalen = 16;
|
||||||
|
|
||||||
prep->payload.data[big_key_len] = (void *)(unsigned long)datalen;
|
payload->length = datalen;
|
||||||
|
|
||||||
if (datalen > BIG_KEY_FILE_THRESHOLD) {
|
if (datalen > BIG_KEY_FILE_THRESHOLD) {
|
||||||
/* Create a shmem file to store the data in. This will permit the data
|
/* Create a shmem file to store the data in. This will permit the data
|
||||||
@ -117,9 +120,9 @@ int big_key_preparse(struct key_preparsed_payload *prep)
|
|||||||
/* Pin the mount and dentry to the key so that we can open it again
|
/* Pin the mount and dentry to the key so that we can open it again
|
||||||
* later
|
* later
|
||||||
*/
|
*/
|
||||||
prep->payload.data[big_key_data] = enckey;
|
payload->data = enckey;
|
||||||
*path = file->f_path;
|
payload->path = file->f_path;
|
||||||
path_get(path);
|
path_get(&payload->path);
|
||||||
fput(file);
|
fput(file);
|
||||||
kvfree_sensitive(buf, enclen);
|
kvfree_sensitive(buf, enclen);
|
||||||
} else {
|
} else {
|
||||||
@ -129,7 +132,7 @@ int big_key_preparse(struct key_preparsed_payload *prep)
|
|||||||
if (!data)
|
if (!data)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
prep->payload.data[big_key_data] = data;
|
payload->data = data;
|
||||||
memcpy(data, prep->data, prep->datalen);
|
memcpy(data, prep->data, prep->datalen);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -148,12 +151,11 @@ error:
|
|||||||
*/
|
*/
|
||||||
void big_key_free_preparse(struct key_preparsed_payload *prep)
|
void big_key_free_preparse(struct key_preparsed_payload *prep)
|
||||||
{
|
{
|
||||||
if (prep->datalen > BIG_KEY_FILE_THRESHOLD) {
|
struct big_key_payload *payload = to_big_key_payload(prep->payload);
|
||||||
struct path *path = (struct path *)&prep->payload.data[big_key_path];
|
|
||||||
|
|
||||||
path_put(path);
|
if (prep->datalen > BIG_KEY_FILE_THRESHOLD)
|
||||||
}
|
path_put(&payload->path);
|
||||||
kfree_sensitive(prep->payload.data[big_key_data]);
|
kfree_sensitive(payload->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -162,13 +164,12 @@ void big_key_free_preparse(struct key_preparsed_payload *prep)
|
|||||||
*/
|
*/
|
||||||
void big_key_revoke(struct key *key)
|
void big_key_revoke(struct key *key)
|
||||||
{
|
{
|
||||||
struct path *path = (struct path *)&key->payload.data[big_key_path];
|
struct big_key_payload *payload = to_big_key_payload(key->payload);
|
||||||
|
|
||||||
/* clear the quota */
|
/* clear the quota */
|
||||||
key_payload_reserve(key, 0);
|
key_payload_reserve(key, 0);
|
||||||
if (key_is_positive(key) &&
|
if (key_is_positive(key) && payload->length > BIG_KEY_FILE_THRESHOLD)
|
||||||
(size_t)key->payload.data[big_key_len] > BIG_KEY_FILE_THRESHOLD)
|
vfs_truncate(&payload->path, 0);
|
||||||
vfs_truncate(path, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -176,17 +177,15 @@ void big_key_revoke(struct key *key)
|
|||||||
*/
|
*/
|
||||||
void big_key_destroy(struct key *key)
|
void big_key_destroy(struct key *key)
|
||||||
{
|
{
|
||||||
size_t datalen = (size_t)key->payload.data[big_key_len];
|
struct big_key_payload *payload = to_big_key_payload(key->payload);
|
||||||
|
|
||||||
if (datalen > BIG_KEY_FILE_THRESHOLD) {
|
if (payload->length > BIG_KEY_FILE_THRESHOLD) {
|
||||||
struct path *path = (struct path *)&key->payload.data[big_key_path];
|
path_put(&payload->path);
|
||||||
|
payload->path.mnt = NULL;
|
||||||
path_put(path);
|
payload->path.dentry = NULL;
|
||||||
path->mnt = NULL;
|
|
||||||
path->dentry = NULL;
|
|
||||||
}
|
}
|
||||||
kfree_sensitive(key->payload.data[big_key_data]);
|
kfree_sensitive(payload->data);
|
||||||
key->payload.data[big_key_data] = NULL;
|
payload->data = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -211,14 +210,14 @@ int big_key_update(struct key *key, struct key_preparsed_payload *prep)
|
|||||||
*/
|
*/
|
||||||
void big_key_describe(const struct key *key, struct seq_file *m)
|
void big_key_describe(const struct key *key, struct seq_file *m)
|
||||||
{
|
{
|
||||||
size_t datalen = (size_t)key->payload.data[big_key_len];
|
struct big_key_payload *payload = to_big_key_payload(key->payload);
|
||||||
|
|
||||||
seq_puts(m, key->description);
|
seq_puts(m, key->description);
|
||||||
|
|
||||||
if (key_is_positive(key))
|
if (key_is_positive(key))
|
||||||
seq_printf(m, ": %zu [%s]",
|
seq_printf(m, ": %zu [%s]",
|
||||||
datalen,
|
payload->length,
|
||||||
datalen > BIG_KEY_FILE_THRESHOLD ? "file" : "buff");
|
payload->length > BIG_KEY_FILE_THRESHOLD ? "file" : "buff");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -227,16 +226,16 @@ void big_key_describe(const struct key *key, struct seq_file *m)
|
|||||||
*/
|
*/
|
||||||
long big_key_read(const struct key *key, char *buffer, size_t buflen)
|
long big_key_read(const struct key *key, char *buffer, size_t buflen)
|
||||||
{
|
{
|
||||||
size_t datalen = (size_t)key->payload.data[big_key_len];
|
struct big_key_payload *payload = to_big_key_payload(key->payload);
|
||||||
|
size_t datalen = payload->length;
|
||||||
long ret;
|
long ret;
|
||||||
|
|
||||||
if (!buffer || buflen < datalen)
|
if (!buffer || buflen < datalen)
|
||||||
return datalen;
|
return datalen;
|
||||||
|
|
||||||
if (datalen > BIG_KEY_FILE_THRESHOLD) {
|
if (datalen > BIG_KEY_FILE_THRESHOLD) {
|
||||||
struct path *path = (struct path *)&key->payload.data[big_key_path];
|
|
||||||
struct file *file;
|
struct file *file;
|
||||||
u8 *buf, *enckey = (u8 *)key->payload.data[big_key_data];
|
u8 *buf, *enckey = payload->data;
|
||||||
size_t enclen = datalen + CHACHA20POLY1305_AUTHTAG_SIZE;
|
size_t enclen = datalen + CHACHA20POLY1305_AUTHTAG_SIZE;
|
||||||
loff_t pos = 0;
|
loff_t pos = 0;
|
||||||
|
|
||||||
@ -244,7 +243,7 @@ long big_key_read(const struct key *key, char *buffer, size_t buflen)
|
|||||||
if (!buf)
|
if (!buf)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
file = dentry_open(path, O_RDONLY, current_cred());
|
file = dentry_open(&payload->path, O_RDONLY, current_cred());
|
||||||
if (IS_ERR(file)) {
|
if (IS_ERR(file)) {
|
||||||
ret = PTR_ERR(file);
|
ret = PTR_ERR(file);
|
||||||
goto error;
|
goto error;
|
||||||
@ -274,7 +273,7 @@ error:
|
|||||||
kvfree_sensitive(buf, enclen);
|
kvfree_sensitive(buf, enclen);
|
||||||
} else {
|
} else {
|
||||||
ret = datalen;
|
ret = datalen;
|
||||||
memcpy(buffer, key->payload.data[big_key_data], datalen);
|
memcpy(buffer, payload->data, datalen);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
Loading…
Reference in New Issue
Block a user