Skip to content

Commit 09dc929

Browse files
Andrew Boienashif
authored andcommitted
userspace: fix copy from user locking
We don't actually need spinlocks here. For user_copy(), we are checking that the pointer/size passed in from user mode represents an area that the thread can read or write to. Then we do a memcpy into the kernel-side buffer, which is used from then on. It's OK if another thread scribbles on the buffer contents during the copy, as we have not yet begun any examination of its contents yet. For the z_user_string*_copy() functions, it's also possible that another thread could scribble on the string contents, but we do no analysis of the string other than to establish a length. We just need to ensure that when these functions exit, the copied string is NULL terminated. For SMP, the spinlocks are removed as they will not prevent a thread running on another CPU from changing the buffer/string contents, we just need to safely deal with that possibility. For UP, the locks do prevent another thread from stepping in, but it's better to just safely deal with it rather than affect the interrupt latency of the system. Signed-off-by: Andrew Boie <[email protected]>
1 parent 4097a5b commit 09dc929

File tree

1 file changed

+11
-10
lines changed

1 file changed

+11
-10
lines changed

kernel/userspace.c

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@ static struct k_spinlock lists_lock; /* kobj rbtree/dlist */
5050
static struct k_spinlock objfree_lock; /* k_object_free */
5151
#endif
5252
static struct k_spinlock obj_lock; /* kobj struct data */
53-
static struct k_spinlock ucopy_lock; /* copy to/from userspace */
54-
static struct k_spinlock ucopy_outer_lock; /* code that calls copies */
5553

5654
#define MAX_THREAD_BITS (CONFIG_MAX_THREAD_BYTES * 8)
5755

@@ -629,7 +627,6 @@ void z_object_uninit(void *obj)
629627
void *z_user_alloc_from_copy(const void *src, size_t size)
630628
{
631629
void *dst = NULL;
632-
k_spinlock_key_t key = k_spin_lock(&ucopy_lock);
633630

634631
/* Does the caller in user mode have access to read this memory? */
635632
if (Z_SYSCALL_MEMORY_READ(src, size)) {
@@ -644,14 +641,12 @@ void *z_user_alloc_from_copy(const void *src, size_t size)
644641

645642
(void)memcpy(dst, src, size);
646643
out_err:
647-
k_spin_unlock(&ucopy_lock, key);
648644
return dst;
649645
}
650646

651647
static int user_copy(void *dst, const void *src, size_t size, bool to_user)
652648
{
653649
int ret = EFAULT;
654-
k_spinlock_key_t key = k_spin_lock(&ucopy_lock);
655650

656651
/* Does the caller in user mode have access to this memory? */
657652
if (to_user ? Z_SYSCALL_MEMORY_WRITE(dst, size) :
@@ -662,7 +657,6 @@ static int user_copy(void *dst, const void *src, size_t size, bool to_user)
662657
(void)memcpy(dst, src, size);
663658
ret = 0;
664659
out_err:
665-
k_spin_unlock(&ucopy_lock, key);
666660
return ret;
667661
}
668662

@@ -681,7 +675,6 @@ char *z_user_string_alloc_copy(const char *src, size_t maxlen)
681675
unsigned long actual_len;
682676
int err;
683677
char *ret = NULL;
684-
k_spinlock_key_t key = k_spin_lock(&ucopy_outer_lock);
685678

686679
actual_len = z_user_string_nlen(src, maxlen, &err);
687680
if (err != 0) {
@@ -698,16 +691,22 @@ char *z_user_string_alloc_copy(const char *src, size_t maxlen)
698691
}
699692

700693
ret = z_user_alloc_from_copy(src, actual_len);
694+
695+
/* Someone may have modified the source string during the above
696+
* checks. Ensure what we actually copied is still terminated
697+
* properly.
698+
*/
699+
if (ret != NULL) {
700+
ret[actual_len - 1] = '\0';
701+
}
701702
out:
702-
k_spin_unlock(&ucopy_outer_lock, key);
703703
return ret;
704704
}
705705

706706
int z_user_string_copy(char *dst, const char *src, size_t maxlen)
707707
{
708708
unsigned long actual_len;
709709
int ret, err;
710-
k_spinlock_key_t key = k_spin_lock(&ucopy_outer_lock);
711710

712711
actual_len = z_user_string_nlen(src, maxlen, &err);
713712
if (err != 0) {
@@ -727,8 +726,10 @@ int z_user_string_copy(char *dst, const char *src, size_t maxlen)
727726
}
728727

729728
ret = z_user_from_copy(dst, src, actual_len);
729+
730+
/* See comment above in z_user_string_alloc_copy() */
731+
dst[actual_len - 1] = '\0';
730732
out:
731-
k_spin_unlock(&ucopy_outer_lock, key);
732733
return ret;
733734
}
734735

0 commit comments

Comments
 (0)