diff options
Diffstat (limited to 'ipc/kdbus/util.c')
-rw-r--r-- | ipc/kdbus/util.c | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/ipc/kdbus/util.c b/ipc/kdbus/util.c new file mode 100644 index 000000000..72b188330 --- /dev/null +++ b/ipc/kdbus/util.c @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2013-2015 Kay Sievers + * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> + * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> + * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> + * Copyright (C) 2013-2015 Linux Foundation + * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> + * + * kdbus is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + */ + +#include <linux/capability.h> +#include <linux/cred.h> +#include <linux/ctype.h> +#include <linux/err.h> +#include <linux/file.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/uaccess.h> +#include <linux/uio.h> +#include <linux/user_namespace.h> + +#include "limits.h" +#include "util.h" + +/** + * kdbus_copy_from_user() - copy aligned data from user-space + * @dest: target buffer in kernel memory + * @user_ptr: user-provided source buffer + * @size: memory size to copy from user + * + * This copies @size bytes from @user_ptr into the kernel, just like + * copy_from_user() does. But we enforce an 8-byte alignment and reject any + * unaligned user-space pointers. + * + * Return: 0 on success, negative error code on failure. + */ +int kdbus_copy_from_user(void *dest, void __user *user_ptr, size_t size) +{ + if (!KDBUS_IS_ALIGNED8((uintptr_t)user_ptr)) + return -EFAULT; + + if (copy_from_user(dest, user_ptr, size)) + return -EFAULT; + + return 0; +} + +/** + * kdbus_verify_uid_prefix() - verify UID prefix of a user-supplied name + * @name: user-supplied name to verify + * @user_ns: user-namespace to act in + * @kuid: Kernel internal uid of user + * + * This verifies that the user-supplied name @name has their UID as prefix. This + * is the default name-spacing policy we enforce on user-supplied names for + * public kdbus entities like buses and endpoints. + * + * The user must supply names prefixed with "<UID>-", whereas the UID is + * interpreted in the user-namespace of the domain. If the user fails to supply + * such a prefixed name, we reject it. + * + * Return: 0 on success, negative error code on failure + */ +int kdbus_verify_uid_prefix(const char *name, struct user_namespace *user_ns, + kuid_t kuid) +{ + uid_t uid; + char prefix[16]; + + /* + * The kuid must have a mapping into the userns of the domain + * otherwise do not allow creation of buses nor endpoints. + */ + uid = from_kuid(user_ns, kuid); + if (uid == (uid_t) -1) + return -EINVAL; + + snprintf(prefix, sizeof(prefix), "%u-", uid); + if (strncmp(name, prefix, strlen(prefix)) != 0) + return -EINVAL; + + return 0; +} + +/** + * kdbus_sanitize_attach_flags() - Sanitize attach flags from user-space + * @flags: Attach flags provided by userspace + * @attach_flags: A pointer where to store the valid attach flags + * + * Convert attach-flags provided by user-space into a valid mask. If the mask + * is invalid, an error is returned. The sanitized attach flags are stored in + * the output parameter. + * + * Return: 0 on success, negative error on failure. + */ +int kdbus_sanitize_attach_flags(u64 flags, u64 *attach_flags) +{ + /* 'any' degrades to 'all' for compatibility */ + if (flags == _KDBUS_ATTACH_ANY) + flags = _KDBUS_ATTACH_ALL; + + /* reject unknown attach flags */ + if (flags & ~_KDBUS_ATTACH_ALL) + return -EINVAL; + + *attach_flags = flags; + return 0; +} + +/** + * kdbus_kvec_set - helper utility to assemble kvec arrays + * @kvec: kvec entry to use + * @src: Source address to set in @kvec + * @len: Number of bytes in @src + * @total_len: Pointer to total length variable + * + * Set @src and @len in @kvec, and increase @total_len by @len. + */ +void kdbus_kvec_set(struct kvec *kvec, void *src, size_t len, u64 *total_len) +{ + kvec->iov_base = src; + kvec->iov_len = len; + *total_len += len; +} + +static const char * const zeros = "\0\0\0\0\0\0\0"; + +/** + * kdbus_kvec_pad - conditionally write a padding kvec + * @kvec: kvec entry to use + * @len: Total length used for kvec array + * + * Check if the current total byte length of the array in @len is aligned to + * 8 bytes. If it isn't, fill @kvec with padding information and increase @len + * by the number of bytes stored in @kvec. + * + * Return: the number of added padding bytes. + */ +size_t kdbus_kvec_pad(struct kvec *kvec, u64 *len) +{ + size_t pad = KDBUS_ALIGN8(*len) - *len; + + if (!pad) + return 0; + + kvec->iov_base = (void *)zeros; + kvec->iov_len = pad; + + *len += pad; + + return pad; +} |