|
6 | 6 | #define pr_fmt(fmt) "%s: " fmt, __func__
|
7 | 7 |
|
8 | 8 | #include <linux/cdev.h>
|
| 9 | +#include <linux/cred.h> |
9 | 10 | #include <linux/fs.h>
|
10 | 11 | #include <linux/idr.h>
|
11 | 12 | #include <linux/module.h>
|
12 | 13 | #include <linux/slab.h>
|
13 | 14 | #include <linux/tee_drv.h>
|
14 | 15 | #include <linux/uaccess.h>
|
| 16 | +#include <crypto/hash.h> |
| 17 | +#include <crypto/sha.h> |
15 | 18 | #include "tee_private.h"
|
16 | 19 |
|
17 | 20 | #define TEE_NUM_DEVICES 32
|
18 | 21 |
|
19 | 22 | #define TEE_IOCTL_PARAM_SIZE(x) (sizeof(struct tee_param) * (x))
|
20 | 23 |
|
| 24 | +#define TEE_UUID_NS_NAME_SIZE 128 |
| 25 | + |
| 26 | +/* |
| 27 | + * TEE Client UUID name space identifier (UUIDv4) |
| 28 | + * |
| 29 | + * Value here is random UUID that is allocated as name space identifier for |
| 30 | + * forming Client UUID's for TEE environment using UUIDv5 scheme. |
| 31 | + */ |
| 32 | +static const uuid_t tee_client_uuid_ns = UUID_INIT(0x58ac9ca0, 0x2086, 0x4683, |
| 33 | + 0xa1, 0xb8, 0xec, 0x4b, |
| 34 | + 0xc0, 0x8e, 0x01, 0xb6); |
| 35 | + |
21 | 36 | /*
|
22 | 37 | * Unprivileged devices in the lower half range and privileged devices in
|
23 | 38 | * the upper half range.
|
@@ -110,6 +125,143 @@ static int tee_release(struct inode *inode, struct file *filp)
|
110 | 125 | return 0;
|
111 | 126 | }
|
112 | 127 |
|
| 128 | +/** |
| 129 | + * uuid_v5() - Calculate UUIDv5 |
| 130 | + * @uuid: Resulting UUID |
| 131 | + * @ns: Name space ID for UUIDv5 function |
| 132 | + * @name: Name for UUIDv5 function |
| 133 | + * @size: Size of name |
| 134 | + * |
| 135 | + * UUIDv5 is specific in RFC 4122. |
| 136 | + * |
| 137 | + * This implements section (for SHA-1): |
| 138 | + * 4.3. Algorithm for Creating a Name-Based UUID |
| 139 | + */ |
| 140 | +static int uuid_v5(uuid_t *uuid, const uuid_t *ns, const void *name, |
| 141 | + size_t size) |
| 142 | +{ |
| 143 | + unsigned char hash[SHA1_DIGEST_SIZE]; |
| 144 | + struct crypto_shash *shash = NULL; |
| 145 | + struct shash_desc *desc = NULL; |
| 146 | + int rc; |
| 147 | + |
| 148 | + shash = crypto_alloc_shash("sha1", 0, 0); |
| 149 | + if (IS_ERR(shash)) { |
| 150 | + rc = PTR_ERR(shash); |
| 151 | + pr_err("shash(sha1) allocation failed\n"); |
| 152 | + return rc; |
| 153 | + } |
| 154 | + |
| 155 | + desc = kzalloc(sizeof(*desc) + crypto_shash_descsize(shash), |
| 156 | + GFP_KERNEL); |
| 157 | + if (!desc) { |
| 158 | + rc = -ENOMEM; |
| 159 | + goto out_free_shash; |
| 160 | + } |
| 161 | + |
| 162 | + desc->tfm = shash; |
| 163 | + |
| 164 | + rc = crypto_shash_init(desc); |
| 165 | + if (rc < 0) |
| 166 | + goto out_free_desc; |
| 167 | + |
| 168 | + rc = crypto_shash_update(desc, (const u8 *)ns, sizeof(*ns)); |
| 169 | + if (rc < 0) |
| 170 | + goto out_free_desc; |
| 171 | + |
| 172 | + rc = crypto_shash_update(desc, (const u8 *)name, size); |
| 173 | + if (rc < 0) |
| 174 | + goto out_free_desc; |
| 175 | + |
| 176 | + rc = crypto_shash_final(desc, hash); |
| 177 | + if (rc < 0) |
| 178 | + goto out_free_desc; |
| 179 | + |
| 180 | + memcpy(uuid->b, hash, UUID_SIZE); |
| 181 | + |
| 182 | + /* Tag for version 5 */ |
| 183 | + uuid->b[6] = (hash[6] & 0x0F) | 0x50; |
| 184 | + uuid->b[8] = (hash[8] & 0x3F) | 0x80; |
| 185 | + |
| 186 | +out_free_desc: |
| 187 | + kfree(desc); |
| 188 | + |
| 189 | +out_free_shash: |
| 190 | + crypto_free_shash(shash); |
| 191 | + return rc; |
| 192 | +} |
| 193 | + |
| 194 | +int tee_session_calc_client_uuid(uuid_t *uuid, u32 connection_method, |
| 195 | + const u8 connection_data[TEE_IOCTL_UUID_LEN]) |
| 196 | +{ |
| 197 | + gid_t ns_grp = (gid_t)-1; |
| 198 | + kgid_t grp = INVALID_GID; |
| 199 | + char *name = NULL; |
| 200 | + int name_len; |
| 201 | + int rc; |
| 202 | + |
| 203 | + if (connection_method == TEE_IOCTL_LOGIN_PUBLIC) { |
| 204 | + /* Nil UUID to be passed to TEE environment */ |
| 205 | + uuid_copy(uuid, &uuid_null); |
| 206 | + return 0; |
| 207 | + } |
| 208 | + |
| 209 | + /* |
| 210 | + * In Linux environment client UUID is based on UUIDv5. |
| 211 | + * |
| 212 | + * Determine client UUID with following semantics for 'name': |
| 213 | + * |
| 214 | + * For TEEC_LOGIN_USER: |
| 215 | + * uid=<uid> |
| 216 | + * |
| 217 | + * For TEEC_LOGIN_GROUP: |
| 218 | + * gid=<gid> |
| 219 | + * |
| 220 | + */ |
| 221 | + |
| 222 | + name = kzalloc(TEE_UUID_NS_NAME_SIZE, GFP_KERNEL); |
| 223 | + if (!name) |
| 224 | + return -ENOMEM; |
| 225 | + |
| 226 | + switch (connection_method) { |
| 227 | + case TEE_IOCTL_LOGIN_USER: |
| 228 | + name_len = snprintf(name, TEE_UUID_NS_NAME_SIZE, "uid=%x", |
| 229 | + current_euid().val); |
| 230 | + if (name_len >= TEE_UUID_NS_NAME_SIZE) { |
| 231 | + rc = -E2BIG; |
| 232 | + goto out_free_name; |
| 233 | + } |
| 234 | + break; |
| 235 | + |
| 236 | + case TEE_IOCTL_LOGIN_GROUP: |
| 237 | + memcpy(&ns_grp, connection_data, sizeof(gid_t)); |
| 238 | + grp = make_kgid(current_user_ns(), ns_grp); |
| 239 | + if (!gid_valid(grp) || !in_egroup_p(grp)) { |
| 240 | + rc = -EPERM; |
| 241 | + goto out_free_name; |
| 242 | + } |
| 243 | + |
| 244 | + name_len = snprintf(name, TEE_UUID_NS_NAME_SIZE, "gid=%x", |
| 245 | + grp.val); |
| 246 | + if (name_len >= TEE_UUID_NS_NAME_SIZE) { |
| 247 | + rc = -E2BIG; |
| 248 | + goto out_free_name; |
| 249 | + } |
| 250 | + break; |
| 251 | + |
| 252 | + default: |
| 253 | + rc = -EINVAL; |
| 254 | + goto out_free_name; |
| 255 | + } |
| 256 | + |
| 257 | + rc = uuid_v5(uuid, &tee_client_uuid_ns, name, name_len); |
| 258 | +out_free_name: |
| 259 | + kfree(name); |
| 260 | + |
| 261 | + return rc; |
| 262 | +} |
| 263 | +EXPORT_SYMBOL_GPL(tee_session_calc_client_uuid); |
| 264 | + |
113 | 265 | static int tee_ioctl_version(struct tee_context *ctx,
|
114 | 266 | struct tee_ioctl_version_data __user *uvers)
|
115 | 267 | {
|
|
0 commit comments