Skip to content

Commit 432b1cc

Browse files
Janis Schoetterl-GlauschVasily Gorbik
authored andcommitted
s390/uaccess: Add copy_from/to_user_key functions
Add copy_from/to_user_key functions, which perform storage key checking. These functions can be used by KVM for emulating instructions that need to be key checked. These functions differ from their non _key counterparts in include/linux/uaccess.h only in the additional key argument and must be kept in sync with those. Since the existing uaccess implementation on s390 makes use of move instructions that support having an additional access key supplied, we can implement raw_copy_from/to_user_key by enhancing the existing implementation. Signed-off-by: Janis Schoetterl-Glausch <scgl@linux.ibm.com> Acked-by: Heiko Carstens <hca@linux.ibm.com> Reviewed-by: Christian Borntraeger <borntraeger@linux.ibm.com> Acked-by: Janosch Frank <frankja@linux.ibm.com> Link: https://lore.kernel.org/r/20220211182215.2730017-2-scgl@linux.ibm.com Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
1 parent 602bf16 commit 432b1cc

2 files changed

Lines changed: 85 additions & 18 deletions

File tree

arch/s390/include/asm/uaccess.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,28 @@ raw_copy_to_user(void __user *to, const void *from, unsigned long n);
4545
#define INLINE_COPY_TO_USER
4646
#endif
4747

48+
unsigned long __must_check
49+
_copy_from_user_key(void *to, const void __user *from, unsigned long n, unsigned long key);
50+
51+
static __always_inline unsigned long __must_check
52+
copy_from_user_key(void *to, const void __user *from, unsigned long n, unsigned long key)
53+
{
54+
if (likely(check_copy_size(to, n, false)))
55+
n = _copy_from_user_key(to, from, n, key);
56+
return n;
57+
}
58+
59+
unsigned long __must_check
60+
_copy_to_user_key(void __user *to, const void *from, unsigned long n, unsigned long key);
61+
62+
static __always_inline unsigned long __must_check
63+
copy_to_user_key(void __user *to, const void *from, unsigned long n, unsigned long key)
64+
{
65+
if (likely(check_copy_size(from, n, true)))
66+
n = _copy_to_user_key(to, from, n, key);
67+
return n;
68+
}
69+
4870
int __put_user_bad(void) __attribute__((noreturn));
4971
int __get_user_bad(void) __attribute__((noreturn));
5072

arch/s390/lib/uaccess.c

Lines changed: 63 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,13 @@ static inline int copy_with_mvcos(void)
6060
#endif
6161

6262
static inline unsigned long copy_from_user_mvcos(void *x, const void __user *ptr,
63-
unsigned long size)
63+
unsigned long size, unsigned long key)
6464
{
6565
unsigned long tmp1, tmp2;
6666
union oac spec = {
67+
.oac2.key = key,
6768
.oac2.as = PSW_BITS_AS_SECONDARY,
69+
.oac2.k = 1,
6870
.oac2.a = 1,
6971
};
7072

@@ -95,19 +97,19 @@ static inline unsigned long copy_from_user_mvcos(void *x, const void __user *ptr
9597
}
9698

9799
static inline unsigned long copy_from_user_mvcp(void *x, const void __user *ptr,
98-
unsigned long size)
100+
unsigned long size, unsigned long key)
99101
{
100102
unsigned long tmp1, tmp2;
101103

102104
tmp1 = -256UL;
103105
asm volatile(
104106
" sacf 0\n"
105-
"0: mvcp 0(%0,%2),0(%1),%3\n"
107+
"0: mvcp 0(%0,%2),0(%1),%[key]\n"
106108
"7: jz 5f\n"
107109
"1: algr %0,%3\n"
108110
" la %1,256(%1)\n"
109111
" la %2,256(%2)\n"
110-
"2: mvcp 0(%0,%2),0(%1),%3\n"
112+
"2: mvcp 0(%0,%2),0(%1),%[key]\n"
111113
"8: jnz 1b\n"
112114
" j 5f\n"
113115
"3: la %4,255(%1)\n" /* %4 = ptr + 255 */
@@ -116,32 +118,57 @@ static inline unsigned long copy_from_user_mvcp(void *x, const void __user *ptr,
116118
" slgr %4,%1\n"
117119
" clgr %0,%4\n" /* copy crosses next page boundary? */
118120
" jnh 6f\n"
119-
"4: mvcp 0(%4,%2),0(%1),%3\n"
121+
"4: mvcp 0(%4,%2),0(%1),%[key]\n"
120122
"9: slgr %0,%4\n"
121123
" j 6f\n"
122124
"5: slgr %0,%0\n"
123125
"6: sacf 768\n"
124126
EX_TABLE(0b,3b) EX_TABLE(2b,3b) EX_TABLE(4b,6b)
125127
EX_TABLE(7b,3b) EX_TABLE(8b,3b) EX_TABLE(9b,6b)
126128
: "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
127-
: : "cc", "memory");
129+
: [key] "d" (key << 4)
130+
: "cc", "memory");
128131
return size;
129132
}
130133

131-
unsigned long raw_copy_from_user(void *to, const void __user *from, unsigned long n)
134+
static unsigned long raw_copy_from_user_key(void *to, const void __user *from,
135+
unsigned long n, unsigned long key)
132136
{
133137
if (copy_with_mvcos())
134-
return copy_from_user_mvcos(to, from, n);
135-
return copy_from_user_mvcp(to, from, n);
138+
return copy_from_user_mvcos(to, from, n, key);
139+
return copy_from_user_mvcp(to, from, n, key);
140+
}
141+
142+
unsigned long raw_copy_from_user(void *to, const void __user *from, unsigned long n)
143+
{
144+
return raw_copy_from_user_key(to, from, n, 0);
136145
}
137146
EXPORT_SYMBOL(raw_copy_from_user);
138147

148+
unsigned long _copy_from_user_key(void *to, const void __user *from,
149+
unsigned long n, unsigned long key)
150+
{
151+
unsigned long res = n;
152+
153+
might_fault();
154+
if (!should_fail_usercopy()) {
155+
instrument_copy_from_user(to, from, n);
156+
res = raw_copy_from_user_key(to, from, n, key);
157+
}
158+
if (unlikely(res))
159+
memset(to + (n - res), 0, res);
160+
return res;
161+
}
162+
EXPORT_SYMBOL(_copy_from_user_key);
163+
139164
static inline unsigned long copy_to_user_mvcos(void __user *ptr, const void *x,
140-
unsigned long size)
165+
unsigned long size, unsigned long key)
141166
{
142167
unsigned long tmp1, tmp2;
143168
union oac spec = {
169+
.oac1.key = key,
144170
.oac1.as = PSW_BITS_AS_SECONDARY,
171+
.oac1.k = 1,
145172
.oac1.a = 1,
146173
};
147174

@@ -172,19 +199,19 @@ static inline unsigned long copy_to_user_mvcos(void __user *ptr, const void *x,
172199
}
173200

174201
static inline unsigned long copy_to_user_mvcs(void __user *ptr, const void *x,
175-
unsigned long size)
202+
unsigned long size, unsigned long key)
176203
{
177204
unsigned long tmp1, tmp2;
178205

179206
tmp1 = -256UL;
180207
asm volatile(
181208
" sacf 0\n"
182-
"0: mvcs 0(%0,%1),0(%2),%3\n"
209+
"0: mvcs 0(%0,%1),0(%2),%[key]\n"
183210
"7: jz 5f\n"
184211
"1: algr %0,%3\n"
185212
" la %1,256(%1)\n"
186213
" la %2,256(%2)\n"
187-
"2: mvcs 0(%0,%1),0(%2),%3\n"
214+
"2: mvcs 0(%0,%1),0(%2),%[key]\n"
188215
"8: jnz 1b\n"
189216
" j 5f\n"
190217
"3: la %4,255(%1)\n" /* %4 = ptr + 255 */
@@ -193,26 +220,44 @@ static inline unsigned long copy_to_user_mvcs(void __user *ptr, const void *x,
193220
" slgr %4,%1\n"
194221
" clgr %0,%4\n" /* copy crosses next page boundary? */
195222
" jnh 6f\n"
196-
"4: mvcs 0(%4,%1),0(%2),%3\n"
223+
"4: mvcs 0(%4,%1),0(%2),%[key]\n"
197224
"9: slgr %0,%4\n"
198225
" j 6f\n"
199226
"5: slgr %0,%0\n"
200227
"6: sacf 768\n"
201228
EX_TABLE(0b,3b) EX_TABLE(2b,3b) EX_TABLE(4b,6b)
202229
EX_TABLE(7b,3b) EX_TABLE(8b,3b) EX_TABLE(9b,6b)
203230
: "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
204-
: : "cc", "memory");
231+
: [key] "d" (key << 4)
232+
: "cc", "memory");
205233
return size;
206234
}
207235

208-
unsigned long raw_copy_to_user(void __user *to, const void *from, unsigned long n)
236+
static unsigned long raw_copy_to_user_key(void __user *to, const void *from,
237+
unsigned long n, unsigned long key)
209238
{
210239
if (copy_with_mvcos())
211-
return copy_to_user_mvcos(to, from, n);
212-
return copy_to_user_mvcs(to, from, n);
240+
return copy_to_user_mvcos(to, from, n, key);
241+
return copy_to_user_mvcs(to, from, n, key);
242+
}
243+
244+
unsigned long raw_copy_to_user(void __user *to, const void *from, unsigned long n)
245+
{
246+
return raw_copy_to_user_key(to, from, n, 0);
213247
}
214248
EXPORT_SYMBOL(raw_copy_to_user);
215249

250+
unsigned long _copy_to_user_key(void __user *to, const void *from,
251+
unsigned long n, unsigned long key)
252+
{
253+
might_fault();
254+
if (should_fail_usercopy())
255+
return n;
256+
instrument_copy_to_user(to, from, n);
257+
return raw_copy_to_user_key(to, from, n, key);
258+
}
259+
EXPORT_SYMBOL(_copy_to_user_key);
260+
216261
static inline unsigned long clear_user_mvcos(void __user *to, unsigned long size)
217262
{
218263
unsigned long tmp1, tmp2;

0 commit comments

Comments
 (0)