• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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