kdbus: the driver, original and non-working
[platform/kernel/linux-exynos.git] / ipc / kdbus / util.c
1 /*
2  * Copyright (C) 2013-2015 Kay Sievers
3  * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
4  * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org>
5  * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com>
6  * Copyright (C) 2013-2015 Linux Foundation
7  * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org>
8  *
9  * kdbus is free software; you can redistribute it and/or modify it under
10  * the terms of the GNU Lesser General Public License as published by the
11  * Free Software Foundation; either version 2.1 of the License, or (at
12  * your option) any later version.
13  */
14
15 #include <linux/capability.h>
16 #include <linux/cred.h>
17 #include <linux/ctype.h>
18 #include <linux/err.h>
19 #include <linux/file.h>
20 #include <linux/slab.h>
21 #include <linux/string.h>
22 #include <linux/uaccess.h>
23 #include <linux/uio.h>
24 #include <linux/user_namespace.h>
25
26 #include "limits.h"
27 #include "util.h"
28
29 /**
30  * kdbus_copy_from_user() - copy aligned data from user-space
31  * @dest:       target buffer in kernel memory
32  * @user_ptr:   user-provided source buffer
33  * @size:       memory size to copy from user
34  *
35  * This copies @size bytes from @user_ptr into the kernel, just like
36  * copy_from_user() does. But we enforce an 8-byte alignment and reject any
37  * unaligned user-space pointers.
38  *
39  * Return: 0 on success, negative error code on failure.
40  */
41 int kdbus_copy_from_user(void *dest, void __user *user_ptr, size_t size)
42 {
43         if (!KDBUS_IS_ALIGNED8((uintptr_t)user_ptr))
44                 return -EFAULT;
45
46         if (copy_from_user(dest, user_ptr, size))
47                 return -EFAULT;
48
49         return 0;
50 }
51
52 /**
53  * kdbus_verify_uid_prefix() - verify UID prefix of a user-supplied name
54  * @name:       user-supplied name to verify
55  * @user_ns:    user-namespace to act in
56  * @kuid:       Kernel internal uid of user
57  *
58  * This verifies that the user-supplied name @name has their UID as prefix. This
59  * is the default name-spacing policy we enforce on user-supplied names for
60  * public kdbus entities like buses and endpoints.
61  *
62  * The user must supply names prefixed with "<UID>-", whereas the UID is
63  * interpreted in the user-namespace of the domain. If the user fails to supply
64  * such a prefixed name, we reject it.
65  *
66  * Return: 0 on success, negative error code on failure
67  */
68 int kdbus_verify_uid_prefix(const char *name, struct user_namespace *user_ns,
69                             kuid_t kuid)
70 {
71         uid_t uid;
72         char prefix[16];
73
74         /*
75          * The kuid must have a mapping into the userns of the domain
76          * otherwise do not allow creation of buses nor endpoints.
77          */
78         uid = from_kuid(user_ns, kuid);
79         if (uid == (uid_t) -1)
80                 return -EINVAL;
81
82         snprintf(prefix, sizeof(prefix), "%u-", uid);
83         if (strncmp(name, prefix, strlen(prefix)) != 0)
84                 return -EINVAL;
85
86         return 0;
87 }
88
89 /**
90  * kdbus_sanitize_attach_flags() - Sanitize attach flags from user-space
91  * @flags:              Attach flags provided by userspace
92  * @attach_flags:       A pointer where to store the valid attach flags
93  *
94  * Convert attach-flags provided by user-space into a valid mask. If the mask
95  * is invalid, an error is returned. The sanitized attach flags are stored in
96  * the output parameter.
97  *
98  * Return: 0 on success, negative error on failure.
99  */
100 int kdbus_sanitize_attach_flags(u64 flags, u64 *attach_flags)
101 {
102         /* 'any' degrades to 'all' for compatibility */
103         if (flags == _KDBUS_ATTACH_ANY)
104                 flags = _KDBUS_ATTACH_ALL;
105
106         /* reject unknown attach flags */
107         if (flags & ~_KDBUS_ATTACH_ALL)
108                 return -EINVAL;
109
110         *attach_flags = flags;
111         return 0;
112 }
113
114 /**
115  * kdbus_kvec_set - helper utility to assemble kvec arrays
116  * @kvec:       kvec entry to use
117  * @src:        Source address to set in @kvec
118  * @len:        Number of bytes in @src
119  * @total_len:  Pointer to total length variable
120  *
121  * Set @src and @len in @kvec, and increase @total_len by @len.
122  */
123 void kdbus_kvec_set(struct kvec *kvec, void *src, size_t len, u64 *total_len)
124 {
125         kvec->iov_base = src;
126         kvec->iov_len = len;
127         *total_len += len;
128 }
129
130 static const char * const zeros = "\0\0\0\0\0\0\0";
131
132 /**
133  * kdbus_kvec_pad - conditionally write a padding kvec
134  * @kvec:       kvec entry to use
135  * @len:        Total length used for kvec array
136  *
137  * Check if the current total byte length of the array in @len is aligned to
138  * 8 bytes. If it isn't, fill @kvec with padding information and increase @len
139  * by the number of bytes stored in @kvec.
140  *
141  * Return: the number of added padding bytes.
142  */
143 size_t kdbus_kvec_pad(struct kvec *kvec, u64 *len)
144 {
145         size_t pad = KDBUS_ALIGN8(*len) - *len;
146
147         if (!pad)
148                 return 0;
149
150         kvec->iov_base = (void *)zeros;
151         kvec->iov_len = pad;
152
153         *len += pad;
154
155         return pad;
156 }