001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019 #include <hwcore/paging.h>
020 #include <sos/thread.h>
021 #include <sos/assert.h>
022 #include <sos/kmalloc.h>
023
024 #include "uaccess.h"
025
026
027
028
029
030
031 static sos_ret_t bindto_user_mm_context()
032 {
033 struct sos_thread * current_thread;
034 struct sos_mm_context * process_mm_ctxt;
035
036 current_thread = sos_thread_get_current();
037 SOS_ASSERT_FATAL(NULL != current_thread->process);
038
039
040 process_mm_ctxt
041 = sos_process_get_mm_context(current_thread->process);
042 return sos_thread_change_current_mm_context(process_mm_ctxt);
043 }
044
045
046
047
048
049
050 #define unbindto_user_mm_context() \
051 sos_thread_change_current_mm_context(NULL)
052
053
054 static sos_ret_t nocheck_user_memcpy(sos_vaddr_t dest,
055 sos_vaddr_t src,
056 sos_size_t size,
057 sos_bool_t transfer_from_user)
058 {
059 sos_ret_t retval;
060
061 retval = bindto_user_mm_context();
062 if (SOS_OK != retval)
063 return retval;
064
065 memcpy((void*) dest, (void*) src, size);
066
067 retval = unbindto_user_mm_context();
068 if (SOS_OK != retval)
069 return retval;
070
071 return size;
072 }
073
074
075 sos_ret_t sos_memcpy_from_user(sos_vaddr_t kernel_to,
076 sos_uaddr_t user_from,
077 sos_size_t size)
078 {
079
080 if (user_from < SOS_PAGING_BASE_USER_ADDRESS)
081 return -SOS_EPERM;
082
083 if (user_from > SOS_PAGING_TOP_USER_ADDRESS - size)
084 return -SOS_EPERM;
085
086 return nocheck_user_memcpy(kernel_to, user_from, size, TRUE);
087 }
088
089
090 sos_ret_t sos_memcpy_to_user(sos_uaddr_t user_to,
091 sos_vaddr_t kernel_from,
092 sos_size_t size)
093 {
094
095 if (user_to < SOS_PAGING_BASE_USER_ADDRESS)
096 return -SOS_EPERM;
097
098 if (user_to > SOS_PAGING_TOP_USER_ADDRESS - size)
099 return -SOS_EPERM;
100
101 return nocheck_user_memcpy(user_to, kernel_from, size, FALSE);
102 }
103
104
105 sos_ret_t sos_strnlen_from_user(sos_uaddr_t user_str, sos_size_t max_len)
106 {
107 sos_ret_t retval, len;
108
109
110 if (user_str < SOS_PAGING_BASE_USER_ADDRESS)
111 return -SOS_EPERM;
112
113
114 if ( (max_len < 1) || (max_len > SOS_PAGING_USER_SPACE_SIZE) )
115 return -SOS_EINVAL;
116
117 retval = bindto_user_mm_context();
118 if (SOS_OK != retval)
119 return retval;
120
121 len = strnlen((const char*)user_str, max_len);
122
123 retval = unbindto_user_mm_context();
124 if (SOS_OK != retval)
125 return retval;
126
127 return len;
128 }
129
130
131 static sos_ret_t nocheck_user_strzcpy(char *dst, const char *src,
132 sos_size_t len)
133 {
134 sos_ret_t retval;
135
136 retval = bindto_user_mm_context();
137 if (SOS_OK != retval)
138 return retval;
139
140 strzcpy(dst, src, len);
141
142 retval = unbindto_user_mm_context();
143 if (SOS_OK != retval)
144 return retval;
145
146 return SOS_OK;
147 }
148
149
150 sos_ret_t sos_strzcpy_from_user(char *kernel_to, sos_uaddr_t user_from,
151 sos_size_t max_len)
152 {
153
154 if ((sos_uaddr_t)user_from < SOS_PAGING_BASE_USER_ADDRESS)
155 return -SOS_EPERM;
156
157
158 if ( (max_len < 1) || (max_len > SOS_PAGING_USER_SPACE_SIZE) )
159 return -SOS_EINVAL;
160
161 return nocheck_user_strzcpy(kernel_to, (const char*)user_from, max_len);
162 }
163
164
165 sos_ret_t sos_strzcpy_to_user(sos_uaddr_t user_to, const char *kernel_from,
166 sos_size_t max_len)
167 {
168
169 if ((sos_uaddr_t)user_to < SOS_PAGING_BASE_USER_ADDRESS)
170 return -SOS_EPERM;
171
172
173 if ( (max_len < 1) || (max_len > SOS_PAGING_USER_SPACE_SIZE) )
174 return -SOS_EINVAL;
175
176 return nocheck_user_strzcpy((char*)user_to, kernel_from, max_len);
177 }
178
179
180 sos_ret_t sos_strndup_from_user(char ** kernel_to, sos_uaddr_t from_user,
181 sos_size_t max_len,
182 sos_ui32_t kmalloc_flags)
183 {
184 sos_ret_t retval = sos_strnlen_from_user(from_user, max_len);
185 if (retval < 0)
186 return retval;
187
188 *kernel_to = (char*)sos_kmalloc(retval + 1, kmalloc_flags);
189 if (NULL == *kernel_to)
190 return -SOS_ENOMEM;
191
192 retval = sos_strzcpy_from_user(*kernel_to, from_user, retval + 1);
193 if (SOS_OK != retval)
194 {
195 sos_kfree((sos_vaddr_t)*kernel_to);
196 *kernel_to = NULL;
197 }
198
199 return retval;
200 }