1 // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
2 /*
3 *
4 * (C) COPYRIGHT 2017, 2020-2021 ARM Limited. All rights reserved.
5 *
6 * This program is free software and is provided to you under the terms of the
7 * GNU General Public License version 2 as published by the Free Software
8 * Foundation, and any use by you of this program is subject to the terms
9 * of such GNU license.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you can access it online at
18 * http://www.gnu.org/licenses/gpl-2.0.html.
19 *
20 */
21
22 /* Kernel UTF test helpers that mirror those for kutf-userside */
23 #include <kutf/kutf_helpers_user.h>
24 #include <kutf/kutf_helpers.h>
25 #include <kutf/kutf_utils.h>
26
27 #include <linux/err.h>
28 #include <linux/slab.h>
29 #include <linux/export.h>
30
31 const char *valtype_names[] = {
32 "INVALID",
33 "U64",
34 "STR",
35 };
36
get_val_type_name(enum kutf_helper_valtype valtype)37 static const char *get_val_type_name(enum kutf_helper_valtype valtype)
38 {
39 /* enums can be signed or unsigned (implementation dependant), so
40 * enforce it to prevent:
41 * a) "<0 comparison on unsigned type" warning - if we did both upper
42 * and lower bound check
43 * b) incorrect range checking if it was a signed type - if we did
44 * upper bound check only
45 */
46 unsigned int type_idx = (unsigned int)valtype;
47
48 if (type_idx >= (unsigned int)KUTF_HELPER_VALTYPE_COUNT)
49 type_idx = (unsigned int)KUTF_HELPER_VALTYPE_INVALID;
50
51 return valtype_names[type_idx];
52 }
53
54 /* Check up to str_len chars of val_str to see if it's a valid value name:
55 *
56 * - Has between 1 and KUTF_HELPER_MAX_VAL_NAME_LEN characters before the \0 terminator
57 * - And, each char is in the character set [A-Z0-9_]
58 */
validate_val_name(const char * val_str,int str_len)59 static int validate_val_name(const char *val_str, int str_len)
60 {
61 int i = 0;
62
63 for (i = 0; str_len && i <= KUTF_HELPER_MAX_VAL_NAME_LEN && val_str[i] != '\0'; ++i, --str_len) {
64 char val_chr = val_str[i];
65
66 if (val_chr >= 'A' && val_chr <= 'Z')
67 continue;
68 if (val_chr >= '0' && val_chr <= '9')
69 continue;
70 if (val_chr == '_')
71 continue;
72
73 /* Character not in the set [A-Z0-9_] - report error */
74 return 1;
75 }
76
77 /* Names of 0 length are not valid */
78 if (i == 0)
79 return 1;
80 /* Length greater than KUTF_HELPER_MAX_VAL_NAME_LEN not allowed */
81 if (i > KUTF_HELPER_MAX_VAL_NAME_LEN || (i == KUTF_HELPER_MAX_VAL_NAME_LEN && val_str[i] != '\0'))
82 return 1;
83
84 return 0;
85 }
86
87 /* Find the length of the valid part of the string when it will be in quotes
88 * e.g. "str"
89 *
90 * That is, before any '\\', '\n' or '"' characters. This is so we don't have
91 * to escape the string
92 */
find_quoted_string_valid_len(const char * str)93 static int find_quoted_string_valid_len(const char *str)
94 {
95 char *ptr;
96 const char *check_chars = "\\\n\"";
97
98 ptr = strpbrk(str, check_chars);
99 if (ptr)
100 return (int)(ptr-str);
101
102 return (int)strlen(str);
103 }
104
kutf_helper_userdata_enqueue(struct kutf_context * context,const char * str)105 static int kutf_helper_userdata_enqueue(struct kutf_context *context,
106 const char *str)
107 {
108 char *str_copy;
109 size_t len;
110 int err;
111
112 len = strlen(str)+1;
113
114 str_copy = kutf_mempool_alloc(&context->fixture_pool, len);
115 if (!str_copy)
116 return -ENOMEM;
117
118 strcpy(str_copy, str);
119
120 err = kutf_add_result(context, KUTF_RESULT_USERDATA, str_copy);
121
122 return err;
123 }
124
125 #define MAX_U64_HEX_LEN 16
126 /* (Name size) + ("=0x" size) + (64-bit hex value size) + (terminator) */
127 #define NAMED_U64_VAL_BUF_SZ (KUTF_HELPER_MAX_VAL_NAME_LEN + 3 + MAX_U64_HEX_LEN + 1)
128
kutf_helper_send_named_u64(struct kutf_context * context,const char * val_name,u64 val)129 int kutf_helper_send_named_u64(struct kutf_context *context,
130 const char *val_name, u64 val)
131 {
132 int ret = 1;
133 char msgbuf[NAMED_U64_VAL_BUF_SZ];
134 const char *errmsg = NULL;
135
136 if (validate_val_name(val_name, KUTF_HELPER_MAX_VAL_NAME_LEN + 1)) {
137 errmsg = kutf_dsprintf(&context->fixture_pool,
138 "Failed to send u64 value named '%s': Invalid value name", val_name);
139 goto out_err;
140 }
141
142 ret = snprintf(msgbuf, NAMED_U64_VAL_BUF_SZ, "%s=0x%llx", val_name, val);
143 if (ret >= NAMED_U64_VAL_BUF_SZ || ret < 0) {
144 errmsg = kutf_dsprintf(&context->fixture_pool,
145 "Failed to send u64 value named '%s': snprintf() problem buffer size==%d ret=%d",
146 val_name, NAMED_U64_VAL_BUF_SZ, ret);
147 goto out_err;
148 }
149
150 ret = kutf_helper_userdata_enqueue(context, msgbuf);
151 if (ret) {
152 errmsg = kutf_dsprintf(&context->fixture_pool,
153 "Failed to send u64 value named '%s': send returned %d",
154 val_name, ret);
155 goto out_err;
156 }
157
158 return ret;
159 out_err:
160 kutf_test_fail(context, errmsg);
161 return ret;
162 }
163 EXPORT_SYMBOL(kutf_helper_send_named_u64);
164
165 #define NAMED_VALUE_SEP "="
166 #define NAMED_STR_START_DELIM NAMED_VALUE_SEP "\""
167 #define NAMED_STR_END_DELIM "\""
168
kutf_helper_max_str_len_for_kern(const char * val_name,int kern_buf_sz)169 int kutf_helper_max_str_len_for_kern(const char *val_name,
170 int kern_buf_sz)
171 {
172 const int val_name_len = strlen(val_name);
173 const int start_delim_len = strlen(NAMED_STR_START_DELIM);
174 const int end_delim_len = strlen(NAMED_STR_END_DELIM);
175 int max_msg_len = kern_buf_sz;
176 int max_str_len;
177
178 max_str_len = max_msg_len - val_name_len - start_delim_len -
179 end_delim_len;
180
181 return max_str_len;
182 }
183 EXPORT_SYMBOL(kutf_helper_max_str_len_for_kern);
184
kutf_helper_send_named_str(struct kutf_context * context,const char * val_name,const char * val_str)185 int kutf_helper_send_named_str(struct kutf_context *context,
186 const char *val_name,
187 const char *val_str)
188 {
189 int val_str_len;
190 int str_buf_sz;
191 char *str_buf = NULL;
192 int ret = 1;
193 char *copy_ptr;
194 int val_name_len;
195 int start_delim_len = strlen(NAMED_STR_START_DELIM);
196 int end_delim_len = strlen(NAMED_STR_END_DELIM);
197 const char *errmsg = NULL;
198
199 if (validate_val_name(val_name, KUTF_HELPER_MAX_VAL_NAME_LEN + 1)) {
200 errmsg = kutf_dsprintf(&context->fixture_pool,
201 "Failed to send u64 value named '%s': Invalid value name", val_name);
202 goto out_err;
203 }
204 val_name_len = strlen(val_name);
205
206 val_str_len = find_quoted_string_valid_len(val_str);
207
208 /* (name length) + ("=\"" length) + (val_str len) + ("\"" length) + terminator */
209 str_buf_sz = val_name_len + start_delim_len + val_str_len + end_delim_len + 1;
210
211 /* Using kmalloc() here instead of mempool since we know we need to free
212 * before we return
213 */
214 str_buf = kmalloc(str_buf_sz, GFP_KERNEL);
215 if (!str_buf) {
216 errmsg = kutf_dsprintf(&context->fixture_pool,
217 "Failed to send str value named '%s': kmalloc failed, str_buf_sz=%d",
218 val_name, str_buf_sz);
219 goto out_err;
220 }
221 copy_ptr = str_buf;
222
223 /* Manually copy each string component instead of snprintf because
224 * val_str may need to end early, and less error path handling
225 */
226
227 /* name */
228 memcpy(copy_ptr, val_name, val_name_len);
229 copy_ptr += val_name_len;
230
231 /* str start delimiter */
232 memcpy(copy_ptr, NAMED_STR_START_DELIM, start_delim_len);
233 copy_ptr += start_delim_len;
234
235 /* str value */
236 memcpy(copy_ptr, val_str, val_str_len);
237 copy_ptr += val_str_len;
238
239 /* str end delimiter */
240 memcpy(copy_ptr, NAMED_STR_END_DELIM, end_delim_len);
241 copy_ptr += end_delim_len;
242
243 /* Terminator */
244 *copy_ptr = '\0';
245
246 ret = kutf_helper_userdata_enqueue(context, str_buf);
247
248 if (ret) {
249 errmsg = kutf_dsprintf(&context->fixture_pool,
250 "Failed to send str value named '%s': send returned %d",
251 val_name, ret);
252 goto out_err;
253 }
254
255 kfree(str_buf);
256 return ret;
257
258 out_err:
259 kutf_test_fail(context, errmsg);
260 kfree(str_buf);
261 return ret;
262 }
263 EXPORT_SYMBOL(kutf_helper_send_named_str);
264
kutf_helper_receive_named_val(struct kutf_context * context,struct kutf_helper_named_val * named_val)265 int kutf_helper_receive_named_val(
266 struct kutf_context *context,
267 struct kutf_helper_named_val *named_val)
268 {
269 size_t recv_sz;
270 char *recv_str;
271 char *search_ptr;
272 char *name_str = NULL;
273 int name_len;
274 int strval_len;
275 enum kutf_helper_valtype type = KUTF_HELPER_VALTYPE_INVALID;
276 char *strval = NULL;
277 u64 u64val = 0;
278 int err = KUTF_HELPER_ERR_INVALID_VALUE;
279
280 recv_str = kutf_helper_input_dequeue(context, &recv_sz);
281 if (!recv_str)
282 return -EBUSY;
283 else if (IS_ERR(recv_str))
284 return PTR_ERR(recv_str);
285
286 /* Find the '=', grab the name and validate it */
287 search_ptr = strnchr(recv_str, recv_sz, NAMED_VALUE_SEP[0]);
288 if (search_ptr) {
289 name_len = search_ptr - recv_str;
290 if (!validate_val_name(recv_str, name_len)) {
291 /* no need to reallocate - just modify string in place */
292 name_str = recv_str;
293 name_str[name_len] = '\0';
294
295 /* Move until after the '=' */
296 recv_str += (name_len + 1);
297 recv_sz -= (name_len + 1);
298 }
299 }
300 if (!name_str) {
301 pr_err("Invalid name part for received string '%s'\n",
302 recv_str);
303 return KUTF_HELPER_ERR_INVALID_NAME;
304 }
305
306 /* detect value type */
307 if (*recv_str == NAMED_STR_START_DELIM[1]) {
308 /* string delimiter start*/
309 ++recv_str;
310 --recv_sz;
311
312 /* Find end of string */
313 search_ptr = strnchr(recv_str, recv_sz, NAMED_STR_END_DELIM[0]);
314 if (search_ptr) {
315 strval_len = search_ptr - recv_str;
316 /* Validate the string to ensure it contains no quotes */
317 if (strval_len == find_quoted_string_valid_len(recv_str)) {
318 /* no need to reallocate - just modify string in place */
319 strval = recv_str;
320 strval[strval_len] = '\0';
321
322 /* Move until after the end delimiter */
323 recv_str += (strval_len + 1);
324 recv_sz -= (strval_len + 1);
325 type = KUTF_HELPER_VALTYPE_STR;
326 } else {
327 pr_err("String value contains invalid characters in rest of received string '%s'\n", recv_str);
328 err = KUTF_HELPER_ERR_CHARS_AFTER_VAL;
329 }
330 } else {
331 pr_err("End of string delimiter not found in rest of received string '%s'\n", recv_str);
332 err = KUTF_HELPER_ERR_NO_END_DELIMITER;
333 }
334 } else {
335 /* possibly a number value - strtoull will parse it */
336 err = kstrtoull(recv_str, 0, &u64val);
337 /* unlike userspace can't get an end ptr, but if kstrtoull()
338 * reads characters after the number it'll report -EINVAL
339 */
340 if (!err) {
341 int len_remain = strnlen(recv_str, recv_sz);
342
343 type = KUTF_HELPER_VALTYPE_U64;
344 recv_str += len_remain;
345 recv_sz -= len_remain;
346 } else {
347 /* special case: not a number, report as such */
348 pr_err("Rest of received string was not a numeric value or quoted string value: '%s'\n", recv_str);
349 }
350 }
351
352 if (type == KUTF_HELPER_VALTYPE_INVALID)
353 return err;
354
355 /* Any remaining characters - error */
356 if (strnlen(recv_str, recv_sz) != 0) {
357 pr_err("Characters remain after value of type %s: '%s'\n",
358 get_val_type_name(type), recv_str);
359 return KUTF_HELPER_ERR_CHARS_AFTER_VAL;
360 }
361
362 /* Success - write into the output structure */
363 switch (type) {
364 case KUTF_HELPER_VALTYPE_U64:
365 named_val->u.val_u64 = u64val;
366 break;
367 case KUTF_HELPER_VALTYPE_STR:
368 named_val->u.val_str = strval;
369 break;
370 default:
371 pr_err("Unreachable, fix kutf_helper_receive_named_val\n");
372 /* Coding error, report as though 'run' file failed */
373 return -EINVAL;
374 }
375
376 named_val->val_name = name_str;
377 named_val->type = type;
378
379 return KUTF_HELPER_ERR_NONE;
380 }
381 EXPORT_SYMBOL(kutf_helper_receive_named_val);
382
383 #define DUMMY_MSG "<placeholder due to test fail>"
kutf_helper_receive_check_val(struct kutf_helper_named_val * named_val,struct kutf_context * context,const char * expect_val_name,enum kutf_helper_valtype expect_val_type)384 int kutf_helper_receive_check_val(
385 struct kutf_helper_named_val *named_val,
386 struct kutf_context *context,
387 const char *expect_val_name,
388 enum kutf_helper_valtype expect_val_type)
389 {
390 int err;
391
392 err = kutf_helper_receive_named_val(context, named_val);
393 if (err < 0) {
394 const char *msg = kutf_dsprintf(&context->fixture_pool,
395 "Failed to receive value named '%s'",
396 expect_val_name);
397 kutf_test_fail(context, msg);
398 return err;
399 } else if (err > 0) {
400 const char *msg = kutf_dsprintf(&context->fixture_pool,
401 "Named-value parse error when expecting value named '%s'",
402 expect_val_name);
403 kutf_test_fail(context, msg);
404 goto out_fail_and_fixup;
405 }
406
407 if (named_val->val_name != NULL &&
408 strcmp(named_val->val_name, expect_val_name) != 0) {
409 const char *msg = kutf_dsprintf(&context->fixture_pool,
410 "Expecting to receive value named '%s' but got '%s'",
411 expect_val_name, named_val->val_name);
412 kutf_test_fail(context, msg);
413 goto out_fail_and_fixup;
414 }
415
416
417 if (named_val->type != expect_val_type) {
418 const char *msg = kutf_dsprintf(&context->fixture_pool,
419 "Expecting value named '%s' to be of type %s but got %s",
420 expect_val_name, get_val_type_name(expect_val_type),
421 get_val_type_name(named_val->type));
422 kutf_test_fail(context, msg);
423 goto out_fail_and_fixup;
424 }
425
426 return err;
427
428 out_fail_and_fixup:
429 /* Produce a valid but incorrect value */
430 switch (expect_val_type) {
431 case KUTF_HELPER_VALTYPE_U64:
432 named_val->u.val_u64 = 0ull;
433 break;
434 case KUTF_HELPER_VALTYPE_STR:
435 {
436 char *str = kutf_mempool_alloc(&context->fixture_pool, sizeof(DUMMY_MSG));
437
438 if (!str)
439 return -1;
440
441 strcpy(str, DUMMY_MSG);
442 named_val->u.val_str = str;
443 break;
444 }
445 default:
446 break;
447 }
448
449 /* Indicate that this is invalid */
450 named_val->type = KUTF_HELPER_VALTYPE_INVALID;
451
452 /* But at least allow the caller to continue in the test with failures */
453 return 0;
454 }
455 EXPORT_SYMBOL(kutf_helper_receive_check_val);
456
kutf_helper_output_named_val(struct kutf_helper_named_val * named_val)457 void kutf_helper_output_named_val(struct kutf_helper_named_val *named_val)
458 {
459 switch (named_val->type) {
460 case KUTF_HELPER_VALTYPE_U64:
461 pr_warn("%s=0x%llx\n", named_val->val_name, named_val->u.val_u64);
462 break;
463 case KUTF_HELPER_VALTYPE_STR:
464 pr_warn("%s=\"%s\"\n", named_val->val_name, named_val->u.val_str);
465 break;
466 case KUTF_HELPER_VALTYPE_INVALID:
467 pr_warn("%s is invalid\n", named_val->val_name);
468 break;
469 default:
470 pr_warn("%s has unknown type %d\n", named_val->val_name, named_val->type);
471 break;
472 }
473 }
474 EXPORT_SYMBOL(kutf_helper_output_named_val);
475