/* * Copyright (C) 2013-2015 Kay Sievers * Copyright (C) 2013-2015 Greg Kroah-Hartman * Copyright (C) 2013-2015 Daniel Mack * Copyright (C) 2013-2015 David Herrmann * Copyright (C) 2013-2015 Linux Foundation * Copyright (C) 2014-2015 Djalal Harouni * * 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 #include #include #include #include #include #include #include #include #include #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 "-", 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; }