Skip to content

Commit 37a9d91

Browse files
walken-googleKAGA-KOKO
authored andcommitted
futex: Sanitize cmpxchg_futex_value_locked API
The cmpxchg_futex_value_locked API was funny in that it returned either the original, user-exposed futex value OR an error code such as -EFAULT. This was confusing at best, and could be a source of livelocks in places that retry the cmpxchg_futex_value_locked after trying to fix the issue by running fault_in_user_writeable(). This change makes the cmpxchg_futex_value_locked API more similar to the get_futex_value_locked one, returning an error code and updating the original value through a reference argument. Signed-off-by: Michel Lespinasse <[email protected]> Acked-by: Chris Metcalf <[email protected]> [tile] Acked-by: Tony Luck <[email protected]> [ia64] Acked-by: Thomas Gleixner <[email protected]> Tested-by: Michal Simek <[email protected]> [microblaze] Acked-by: David Howells <[email protected]> [frv] Cc: Darren Hart <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Matt Turner <[email protected]> Cc: Russell King <[email protected]> Cc: Ralf Baechle <[email protected]> Cc: "James E.J. Bottomley" <[email protected]> Cc: Benjamin Herrenschmidt <[email protected]> Cc: Martin Schwidefsky <[email protected]> Cc: Paul Mundt <[email protected]> Cc: "David S. Miller" <[email protected]> Cc: Linus Torvalds <[email protected]> LKML-Reference: <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]>
1 parent 522d7de commit 37a9d91

File tree

20 files changed

+144
-132
lines changed

20 files changed

+144
-132
lines changed

arch/alpha/include/asm/futex.h

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -81,21 +81,22 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
8181
}
8282

8383
static inline int
84-
futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
84+
futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
85+
int oldval, int newval)
8586
{
86-
int prev, cmp;
87+
int ret = 0, prev, cmp;
8788

8889
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
8990
return -EFAULT;
9091

9192
__asm__ __volatile__ (
9293
__ASM_SMP_MB
93-
"1: ldl_l %0,0(%2)\n"
94-
" cmpeq %0,%3,%1\n"
95-
" beq %1,3f\n"
96-
" mov %4,%1\n"
97-
"2: stl_c %1,0(%2)\n"
98-
" beq %1,4f\n"
94+
"1: ldl_l %1,0(%3)\n"
95+
" cmpeq %1,%4,%2\n"
96+
" beq %2,3f\n"
97+
" mov %5,%2\n"
98+
"2: stl_c %2,0(%3)\n"
99+
" beq %2,4f\n"
99100
"3: .subsection 2\n"
100101
"4: br 1b\n"
101102
" .previous\n"
@@ -105,11 +106,12 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
105106
" .long 2b-.\n"
106107
" lda $31,3b-2b(%0)\n"
107108
" .previous\n"
108-
: "=&r"(prev), "=&r"(cmp)
109+
: "+r"(ret), "=&r"(prev), "=&r"(cmp)
109110
: "r"(uaddr), "r"((long)oldval), "r"(newval)
110111
: "memory");
111112

112-
return prev;
113+
*uval = prev;
114+
return ret;
113115
}
114116

115117
#endif /* __KERNEL__ */

arch/arm/include/asm/futex.h

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,10 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
8888
}
8989

9090
static inline int
91-
futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
91+
futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
92+
int oldval, int newval)
9293
{
93-
int val;
94+
int ret = 0, val;
9495

9596
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
9697
return -EFAULT;
@@ -99,24 +100,25 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
99100
* call sites. */
100101

101102
__asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n"
102-
"1: " T(ldr) " %0, [%3]\n"
103-
" teq %0, %1\n"
103+
"1: " T(ldr) " %1, [%4]\n"
104+
" teq %1, %2\n"
104105
" it eq @ explicit IT needed for the 2b label\n"
105-
"2: " T(streq) " %2, [%3]\n"
106+
"2: " T(streq) " %3, [%4]\n"
106107
"3:\n"
107108
" .pushsection __ex_table,\"a\"\n"
108109
" .align 3\n"
109110
" .long 1b, 4f, 2b, 4f\n"
110111
" .popsection\n"
111112
" .pushsection .fixup,\"ax\"\n"
112-
"4: mov %0, %4\n"
113+
"4: mov %0, %5\n"
113114
" b 3b\n"
114115
" .popsection"
115-
: "=&r" (val)
116+
: "+r" (ret), "=&r" (val)
116117
: "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT)
117118
: "cc", "memory");
118119

119-
return val;
120+
*uval = val;
121+
return ret;
120122
}
121123

122124
#endif /* !SMP */

arch/frv/include/asm/futex.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
extern int futex_atomic_op_inuser(int encoded_op, int __user *uaddr);
1111

1212
static inline int
13-
futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
13+
futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
14+
int oldval, int newval)
1415
{
1516
return -ENOSYS;
1617
}

arch/ia64/include/asm/futex.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,23 +100,26 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
100100
}
101101

102102
static inline int
103-
futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
103+
futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
104+
int oldval, int newval)
104105
{
105106
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
106107
return -EFAULT;
107108

108109
{
109-
register unsigned long r8 __asm ("r8");
110+
register unsigned long r8 __asm ("r8") = 0;
111+
unsigned long prev;
110112
__asm__ __volatile__(
111113
" mf;; \n"
112114
" mov ar.ccv=%3;; \n"
113115
"[1:] cmpxchg4.acq %0=[%1],%2,ar.ccv \n"
114116
" .xdata4 \"__ex_table\", 1b-., 2f-. \n"
115117
"[2:]"
116-
: "=r" (r8)
118+
: "=r" (prev)
117119
: "r" (uaddr), "r" (newval),
118120
"rO" ((long) (unsigned) oldval)
119121
: "memory");
122+
*uval = prev;
120123
return r8;
121124
}
122125
}

arch/microblaze/include/asm/futex.h

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -94,31 +94,33 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
9494
}
9595

9696
static inline int
97-
futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
97+
futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
98+
int oldval, int newval)
9899
{
99-
int prev, cmp;
100+
int ret = 0, prev, cmp;
100101

101102
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
102103
return -EFAULT;
103104

104-
__asm__ __volatile__ ("1: lwx %0, %2, r0; \
105-
cmp %1, %0, %3; \
106-
beqi %1, 3f; \
107-
2: swx %4, %2, r0; \
108-
addic %1, r0, 0; \
109-
bnei %1, 1b; \
105+
__asm__ __volatile__ ("1: lwx %1, %3, r0; \
106+
cmp %2, %1, %4; \
107+
beqi %2, 3f; \
108+
2: swx %5, %3, r0; \
109+
addic %2, r0, 0; \
110+
bnei %2, 1b; \
110111
3: \
111112
.section .fixup,\"ax\"; \
112113
4: brid 3b; \
113-
addik %0, r0, %5; \
114+
addik %0, r0, %6; \
114115
.previous; \
115116
.section __ex_table,\"a\"; \
116117
.word 1b,4b,2b,4b; \
117118
.previous;" \
118-
: "=&r" (prev), "=&r"(cmp) \
119+
: "+r" (ret), "=&r" (prev), "=&r"(cmp) \
119120
: "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT));
120121

121-
return prev;
122+
*uval = prev;
123+
return ret;
122124
}
123125

124126
#endif /* __KERNEL__ */

arch/mips/include/asm/futex.h

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,10 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
132132
}
133133

134134
static inline int
135-
futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
135+
futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
136+
int oldval, int newval)
136137
{
137-
int retval;
138+
int ret = 0, val;
138139

139140
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
140141
return -EFAULT;
@@ -145,25 +146,25 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
145146
" .set push \n"
146147
" .set noat \n"
147148
" .set mips3 \n"
148-
"1: ll %0, %2 \n"
149-
" bne %0, %z3, 3f \n"
149+
"1: ll %1, %3 \n"
150+
" bne %1, %z4, 3f \n"
150151
" .set mips0 \n"
151-
" move $1, %z4 \n"
152+
" move $1, %z5 \n"
152153
" .set mips3 \n"
153-
"2: sc $1, %1 \n"
154+
"2: sc $1, %2 \n"
154155
" beqzl $1, 1b \n"
155156
__WEAK_LLSC_MB
156157
"3: \n"
157158
" .set pop \n"
158159
" .section .fixup,\"ax\" \n"
159-
"4: li %0, %5 \n"
160+
"4: li %0, %6 \n"
160161
" j 3b \n"
161162
" .previous \n"
162163
" .section __ex_table,\"a\" \n"
163164
" "__UA_ADDR "\t1b, 4b \n"
164165
" "__UA_ADDR "\t2b, 4b \n"
165166
" .previous \n"
166-
: "=&r" (retval), "=R" (*uaddr)
167+
: "+r" (ret), "=&r" (val), "=R" (*uaddr)
167168
: "R" (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT)
168169
: "memory");
169170
} else if (cpu_has_llsc) {
@@ -172,31 +173,32 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
172173
" .set push \n"
173174
" .set noat \n"
174175
" .set mips3 \n"
175-
"1: ll %0, %2 \n"
176-
" bne %0, %z3, 3f \n"
176+
"1: ll %1, %3 \n"
177+
" bne %1, %z4, 3f \n"
177178
" .set mips0 \n"
178-
" move $1, %z4 \n"
179+
" move $1, %z5 \n"
179180
" .set mips3 \n"
180-
"2: sc $1, %1 \n"
181+
"2: sc $1, %2 \n"
181182
" beqz $1, 1b \n"
182183
__WEAK_LLSC_MB
183184
"3: \n"
184185
" .set pop \n"
185186
" .section .fixup,\"ax\" \n"
186-
"4: li %0, %5 \n"
187+
"4: li %0, %6 \n"
187188
" j 3b \n"
188189
" .previous \n"
189190
" .section __ex_table,\"a\" \n"
190191
" "__UA_ADDR "\t1b, 4b \n"
191192
" "__UA_ADDR "\t2b, 4b \n"
192193
" .previous \n"
193-
: "=&r" (retval), "=R" (*uaddr)
194+
: "+r" (ret), "=&r" (val), "=R" (*uaddr)
194195
: "R" (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT)
195196
: "memory");
196197
} else
197198
return -ENOSYS;
198199

199-
return retval;
200+
*uval = val;
201+
return ret;
200202
}
201203

202204
#endif

arch/parisc/include/asm/futex.h

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,10 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
5151

5252
/* Non-atomic version */
5353
static inline int
54-
futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
54+
futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
55+
int oldval, int newval)
5556
{
56-
int err = 0;
57-
int uval;
57+
int val;
5858

5959
/* futex.c wants to do a cmpxchg_inatomic on kernel NULL, which is
6060
* our gateway page, and causes no end of trouble...
@@ -65,12 +65,12 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
6565
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
6666
return -EFAULT;
6767

68-
err = get_user(uval, uaddr);
69-
if (err) return -EFAULT;
70-
if (uval == oldval)
71-
err = put_user(newval, uaddr);
72-
if (err) return -EFAULT;
73-
return uval;
68+
if (get_user(val, uaddr))
69+
return -EFAULT;
70+
if (val == oldval && put_user(newval, uaddr))
71+
return -EFAULT;
72+
*uval = val;
73+
return 0;
7474
}
7575

7676
#endif /*__KERNEL__*/

arch/powerpc/include/asm/futex.h

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -82,35 +82,37 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
8282
}
8383

8484
static inline int
85-
futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
85+
futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
86+
int oldval, int newval)
8687
{
87-
int prev;
88+
int ret = 0, prev;
8889

8990
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
9091
return -EFAULT;
9192

9293
__asm__ __volatile__ (
9394
PPC_RELEASE_BARRIER
94-
"1: lwarx %0,0,%2 # futex_atomic_cmpxchg_inatomic\n\
95-
cmpw 0,%0,%3\n\
95+
"1: lwarx %1,0,%3 # futex_atomic_cmpxchg_inatomic\n\
96+
cmpw 0,%1,%4\n\
9697
bne- 3f\n"
97-
PPC405_ERR77(0,%2)
98-
"2: stwcx. %4,0,%2\n\
98+
PPC405_ERR77(0,%3)
99+
"2: stwcx. %5,0,%3\n\
99100
bne- 1b\n"
100101
PPC_ACQUIRE_BARRIER
101102
"3: .section .fixup,\"ax\"\n\
102-
4: li %0,%5\n\
103+
4: li %0,%6\n\
103104
b 3b\n\
104105
.previous\n\
105106
.section __ex_table,\"a\"\n\
106107
.align 3\n\
107108
" PPC_LONG "1b,4b,2b,4b\n\
108109
.previous" \
109-
: "=&r" (prev), "+m" (*uaddr)
110+
: "+r" (ret), "=&r" (prev), "+m" (*uaddr)
110111
: "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT)
111112
: "cc", "memory");
112113

113-
return prev;
114+
*uval = prev;
115+
return ret;
114116
}
115117

116118
#endif /* __KERNEL__ */

arch/s390/include/asm/futex.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,13 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
3939
return ret;
4040
}
4141

42-
static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr,
42+
static inline int futex_atomic_cmpxchg_inatomic(int *uval, int __user *uaddr,
4343
int oldval, int newval)
4444
{
4545
if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
4646
return -EFAULT;
4747

48-
return uaccess.futex_atomic_cmpxchg(uaddr, oldval, newval);
48+
return uaccess.futex_atomic_cmpxchg(uval, uaddr, oldval, newval);
4949
}
5050

5151
#endif /* __KERNEL__ */

arch/s390/include/asm/uaccess.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ struct uaccess_ops {
8484
size_t (*strnlen_user)(size_t, const char __user *);
8585
size_t (*strncpy_from_user)(size_t, const char __user *, char *);
8686
int (*futex_atomic_op)(int op, int __user *, int oparg, int *old);
87-
int (*futex_atomic_cmpxchg)(int __user *, int old, int new);
87+
int (*futex_atomic_cmpxchg)(int *, int __user *, int old, int new);
8888
};
8989

9090
extern struct uaccess_ops uaccess;

arch/s390/lib/uaccess.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ extern size_t copy_from_user_std(size_t, const void __user *, void *);
1212
extern size_t copy_to_user_std(size_t, void __user *, const void *);
1313
extern size_t strnlen_user_std(size_t, const char __user *);
1414
extern size_t strncpy_from_user_std(size_t, const char __user *, char *);
15-
extern int futex_atomic_cmpxchg_std(int __user *, int, int);
15+
extern int futex_atomic_cmpxchg_std(int *, int __user *, int, int);
1616
extern int futex_atomic_op_std(int, int __user *, int, int *);
1717

1818
extern size_t copy_from_user_pt(size_t, const void __user *, void *);
1919
extern size_t copy_to_user_pt(size_t, void __user *, const void *);
2020
extern int futex_atomic_op_pt(int, int __user *, int, int *);
21-
extern int futex_atomic_cmpxchg_pt(int __user *, int, int);
21+
extern int futex_atomic_cmpxchg_pt(int *, int __user *, int, int);
2222

2323
#endif /* __ARCH_S390_LIB_UACCESS_H */

0 commit comments

Comments
 (0)