Skip to content

Commit eaf7c2f

Browse files
Andrew Boienashif
authored andcommitted
kernel: fix CONFIG_THREAD_NAME from user mode.
This mechanism had multiple problems: - Missing parameter documentation strings. - Multiple calls to k_thread_name_set() from user mode would leak memory, since the copied string was never freed - k_thread_name_get() returns memory to user mode with no guarantees on whether user mode can actually read it; in the case where the string was in thread resource pool memory (which happens when k_thread_name_set() is called from user mode) it would never be readable. - There was no test case coverage for these functions from user mode. To properly fix this, thread objects now have a buffer region reserved specifically for the thread name. Setting the thread name copies the string into the buffer. Getting the thread name with k_thread_name_get() still returns a pointer, but the system call has been removed. A new API k_thread_name_copy() is introduced to copy the thread name into a destination buffer, and a system call has been provided for that instead. We now have full test case coverge for these APIs in both user and supervisor mode. Some of the code has been cleaned up to place system call handler functions in proximity with their implementations. Signed-off-by: Andrew Boie <[email protected]>
1 parent d5b83ae commit eaf7c2f

File tree

6 files changed

+229
-56
lines changed

6 files changed

+229
-56
lines changed

include/kernel.h

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ struct k_thread {
540540

541541
#if defined(CONFIG_THREAD_NAME)
542542
/* Thread name */
543-
const char *name;
543+
char name[CONFIG_THREAD_MAX_NAME_LEN];
544544
#endif
545545

546546
#ifdef CONFIG_THREAD_CUSTOM_DATA
@@ -1263,18 +1263,38 @@ __syscall void *k_thread_custom_data_get(void);
12631263
* Set the name of the thread to be used when THREAD_MONITOR is enabled for
12641264
* tracing and debugging.
12651265
*
1266+
* @param thread_id Thread to set name, or NULL to set the current thread
1267+
* @param value Name string
1268+
* @retval 0 on success
1269+
* @retval -EFAULT Memory access error with supplied string
1270+
* @retval -ENOSYS Thread name configuration option not enabled
1271+
* @retval -EINVAL Thread name too long
12661272
*/
1267-
__syscall void k_thread_name_set(k_tid_t thread_id, const char *value);
1273+
__syscall int k_thread_name_set(k_tid_t thread_id, const char *value);
12681274

12691275
/**
12701276
* @brief Get thread name
12711277
*
12721278
* Get the name of a thread
12731279
*
12741280
* @param thread_id Thread ID
1281+
* @retval Thread name, or NULL if configuration not enabled
1282+
*/
1283+
const char *k_thread_name_get(k_tid_t thread_id);
1284+
1285+
/**
1286+
* @brief Copy the thread name into a supplied buffer
12751287
*
1288+
* @param thread_id Thread to obtain name information
1289+
* @param buf Destination buffer
1290+
* @param size Destinatiomn buffer size
1291+
* @retval -ENOSPC Destination buffer too small
1292+
* @retval -EFAULT Memory access error
1293+
* @retval -ENOSYS Thread name feature not enabled
1294+
* @retval 0 Success
12761295
*/
1277-
__syscall const char *k_thread_name_get(k_tid_t thread_id);
1296+
__syscall int k_thread_name_copy(k_tid_t thread_id, char *buf,
1297+
size_t size);
12781298

12791299
/**
12801300
* @}

kernel/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,16 @@ config THREAD_NAME
361361
bool "Thread name [EXPERIMENTAL]"
362362
help
363363
This option allows to set a name for a thread.
364+
365+
config THREAD_MAX_NAME_LEN
366+
int "Max length of a thread name"
367+
default 32
368+
range 8 128
369+
depends on THREAD_NAME
370+
help
371+
Thread names get stored in the k_thread struct. Indicate the max
372+
name length, including the terminating NULL byte. Reduce this value
373+
to conserve memory.
364374
endmenu
365375

366376
menu "Work Queue Options"

kernel/include/kernel_structs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ static ALWAYS_INLINE void z_new_thread_init(struct k_thread *thread,
244244
#endif
245245

246246
#ifdef CONFIG_THREAD_NAME
247-
thread->name = NULL;
247+
thread->name[0] = '\0';
248248
#endif
249249

250250
#if defined(CONFIG_USERSPACE)

kernel/thread.c

Lines changed: 99 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,22 @@ void z_impl_k_thread_custom_data_set(void *value)
138138
_current->custom_data = value;
139139
}
140140

141+
#ifdef CONFIG_USERSPACE
142+
Z_SYSCALL_HANDLER(k_thread_custom_data_set, data)
143+
{
144+
z_impl_k_thread_custom_data_set((void *)data);
145+
return 0;
146+
}
147+
#endif
148+
141149
void *z_impl_k_thread_custom_data_get(void)
142150
{
143151
return _current->custom_data;
144152
}
145153

154+
#ifdef CONFIG_USERSPACE
155+
Z_SYSCALL_HANDLER0_SIMPLE(k_thread_custom_data_get);
156+
#endif /* CONFIG_USERSPACE */
146157
#endif /* CONFIG_THREAD_CUSTOM_DATA */
147158

148159
#if defined(CONFIG_THREAD_MONITOR)
@@ -172,61 +183,109 @@ void z_thread_monitor_exit(struct k_thread *thread)
172183
}
173184
#endif
174185

175-
#ifdef CONFIG_THREAD_NAME
176-
void z_impl_k_thread_name_set(struct k_thread *thread, const char *value)
186+
int z_impl_k_thread_name_set(struct k_thread *thread, const char *value)
177187
{
188+
#ifdef CONFIG_THREAD_NAME
178189
if (thread == NULL) {
179-
_current->name = value;
180-
} else {
181-
thread->name = value;
190+
thread = _current;
182191
}
192+
193+
strncpy(thread->name, value, CONFIG_THREAD_MAX_NAME_LEN);
194+
thread->name[CONFIG_THREAD_MAX_NAME_LEN - 1] = '\0';
195+
return 0;
196+
#else
197+
ARG_UNUSED(thread);
198+
ARG_UNUSED(value);
199+
return -ENOSYS;
200+
#endif /* CONFIG_THREAD_NAME */
183201
}
184202

185-
const char *z_impl_k_thread_name_get(struct k_thread *thread)
203+
#ifdef CONFIG_USERSPACE
204+
Z_SYSCALL_HANDLER(k_thread_name_set, thread, str_param)
186205
{
187-
return (const char *)thread->name;
188-
}
206+
#ifdef CONFIG_THREAD_NAME
207+
struct k_thread *t = (struct k_thread *)thread;
208+
size_t len;
209+
int err;
210+
const char *str = (const char *)str_param;
211+
212+
if (t != NULL) {
213+
if (Z_SYSCALL_OBJ(t, K_OBJ_THREAD) != 0) {
214+
return -EINVAL;
215+
}
216+
}
189217

218+
len = z_user_string_nlen(str, CONFIG_THREAD_MAX_NAME_LEN, &err);
219+
if (err != 0) {
220+
return -EFAULT;
221+
}
222+
if (Z_SYSCALL_MEMORY_READ(str, len) != 0) {
223+
return -EFAULT;
224+
}
225+
226+
return z_impl_k_thread_name_set(t, str);
190227
#else
191-
void z_impl_k_thread_name_set(k_tid_t thread_id, const char *value)
192-
{
193-
ARG_UNUSED(thread_id);
194-
ARG_UNUSED(value);
228+
return -ENOSYS;
229+
#endif /* CONFIG_THREAD_NAME */
195230
}
231+
#endif /* CONFIG_USERSPACE */
196232

197-
const char *z_impl_k_thread_name_get(k_tid_t thread_id)
233+
const char *k_thread_name_get(struct k_thread *thread)
198234
{
199-
ARG_UNUSED(thread_id);
235+
#ifdef CONFIG_THREAD_NAME
236+
return (const char *)thread->name;
237+
#else
238+
ARG_UNUSED(thread);
200239
return NULL;
201-
}
202240
#endif /* CONFIG_THREAD_NAME */
241+
}
203242

204-
#ifdef CONFIG_USERSPACE
205-
206-
#if defined(CONFIG_THREAD_NAME)
207-
Z_SYSCALL_HANDLER(k_thread_name_set, thread, data)
243+
int z_impl_k_thread_name_copy(k_tid_t thread_id, char *buf, size_t size)
208244
{
209-
char *name_copy = NULL;
210-
211-
name_copy = z_user_string_alloc_copy((char *)data, 64);
212-
z_impl_k_thread_name_set((struct k_thread *)thread, name_copy);
245+
#ifdef CONFIG_THREAD_NAME
246+
strncpy(buf, thread_id->name, size);
213247
return 0;
248+
#else
249+
ARG_UNUSED(thread_id);
250+
ARG_UNUSED(buf);
251+
ARG_UNUSED(size);
252+
return -ENOSYS;
253+
#endif /* CONFIG_THREAD_NAME */
214254
}
215255

216-
Z_SYSCALL_HANDLER1_SIMPLE(k_thread_name_get, K_OBJ_THREAD, k_tid_t);
217-
#endif
218-
219-
#ifdef CONFIG_THREAD_CUSTOM_DATA
220-
Z_SYSCALL_HANDLER(k_thread_custom_data_set, data)
256+
#ifdef CONFIG_USERSPACE
257+
Z_SYSCALL_HANDLER(k_thread_name_copy, thread_id, buf, size)
221258
{
222-
z_impl_k_thread_custom_data_set((void *)data);
223-
return 0;
224-
}
259+
#ifdef CONFIG_THREAD_NAME
260+
size_t len;
261+
struct k_thread *t = (struct k_thread *)thread_id;
262+
struct _k_object *ko = z_object_find(t);
225263

226-
Z_SYSCALL_HANDLER0_SIMPLE(k_thread_custom_data_get);
227-
#endif /* CONFIG_THREAD_CUSTOM_DATA */
264+
/* Special case: we allow reading the names of initialized threads
265+
* even if we don't have permission on them
266+
*/
267+
if (t == NULL || ko->type != K_OBJ_THREAD ||
268+
(ko->flags & K_OBJ_FLAG_INITIALIZED) == 0) {
269+
return -EINVAL;
270+
}
271+
if (Z_SYSCALL_MEMORY_WRITE(buf, size) != 0) {
272+
return -EFAULT;
273+
}
274+
len = strlen(t->name);
275+
if (len + 1 > size) {
276+
return -ENOSPC;
277+
}
278+
279+
return z_user_to_copy((void *)buf, t->name, len + 1);
280+
#else
281+
ARG_UNUSED(thread_id);
282+
ARG_UNUSED(buf);
283+
ARG_UNUSED(size);
284+
return -ENOSYS;
285+
#endif /* CONFIG_THREAD_NAME */
286+
}
287+
#endif /* CONFIG_USERSPACE */
228288

229-
#endif
230289

231290
#ifdef CONFIG_STACK_SENTINEL
232291
/* Check that the stack sentinel is still present
@@ -386,7 +445,12 @@ void z_setup_new_thread(struct k_thread *new_thread,
386445
k_spin_unlock(&lock, key);
387446
#endif
388447
#ifdef CONFIG_THREAD_NAME
389-
new_thread->name = name;
448+
if (name != NULL) {
449+
strncpy(new_thread->name, name,
450+
CONFIG_THREAD_MAX_NAME_LEN - 1);
451+
/* Ensure NULL termination, truncate if longer */
452+
new_thread->name[CONFIG_THREAD_MAX_NAME_LEN - 1] = '\0';
453+
}
390454
#endif
391455
#ifdef CONFIG_USERSPACE
392456
z_object_init(new_thread);

0 commit comments

Comments
 (0)