diff options
author | H. Peter Anvin <hpa@linux.intel.com> | 2014-02-01 21:54:11 -0500 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2014-02-02 17:09:12 -0500 |
commit | 81993e81a994504f4c8b97d3410c9a052cdbcc9d (patch) | |
tree | 7471cde617f11dad2f29187daa764e1d119a9731 /kernel | |
parent | 5cb480f6b488128140c940abff3c36f524a334a8 (diff) |
compat: Get rid of (get|put)_compat_time(val|spec)
We have two APIs for compatiblity timespec/val, with confusingly
similar names. compat_(get|put)_time(val|spec) *do* handle the case
where COMPAT_USE_64BIT_TIME is set, whereas
(get|put)_compat_time(val|spec) do not. This is an accident waiting
to happen.
Clean it up by favoring the full-service version; the limited version
is replaced with double-underscore versions static to kernel/compat.c.
A common pattern is to convert a struct timespec to kernel format in
an allocation on the user stack. Unfortunately it is open-coded in
several places. Since this allocation isn't actually needed if
COMPAT_USE_64BIT_TIME is true (since user format == kernel format)
encapsulate that whole pattern into the function
compat_convert_timespec(). An equivalent function should be written
for struct timeval if it is needed in the future.
Finally, get rid of compat_(get|put)_timeval_convert(): each was only
used once, and the latter was not even doing what the function said
(no conversion actually was being done.) Moving the conversion into
compat_sys_settimeofday() itself makes the code much more similar to
sys_settimeofday() itself.
v3: Remove unused compat_convert_timeval().
v2: Drop bogus "const" in the destination argument for
compat_convert_time*().
Cc: Mauro Carvalho Chehab <m.chehab@samsung.com>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: Manfred Spraul <manfred@colorfullife.com>
Cc: Mateusz Guzik <mguzik@redhat.com>
Cc: Rafael Aquini <aquini@redhat.com>
Cc: Davidlohr Bueso <davidlohr@hp.com>
Cc: Stephen Rothwell <sfr@canb.auug.org.au>
Cc: Dan Carpenter <dan.carpenter@oracle.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Tested-by: H.J. Lu <hjl.tools@gmail.com>
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/compat.c | 108 | ||||
-rw-r--r-- | kernel/futex_compat.c | 2 |
2 files changed, 55 insertions, 55 deletions
diff --git a/kernel/compat.c b/kernel/compat.c index 0a09e481b70b..3afc524a57ad 100644 --- a/kernel/compat.c +++ b/kernel/compat.c | |||
@@ -30,28 +30,6 @@ | |||
30 | 30 | ||
31 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
32 | 32 | ||
33 | /* | ||
34 | * Get/set struct timeval with struct timespec on the native side | ||
35 | */ | ||
36 | static int compat_get_timeval_convert(struct timespec *o, | ||
37 | struct compat_timeval __user *i) | ||
38 | { | ||
39 | long usec; | ||
40 | |||
41 | if (get_user(o->tv_sec, &i->tv_sec) || | ||
42 | get_user(usec, &i->tv_usec)) | ||
43 | return -EFAULT; | ||
44 | o->tv_nsec = usec * 1000; | ||
45 | return 0; | ||
46 | } | ||
47 | |||
48 | static int compat_put_timeval_convert(struct compat_timeval __user *o, | ||
49 | struct timeval *i) | ||
50 | { | ||
51 | return (put_user(i->tv_sec, &o->tv_sec) || | ||
52 | put_user(i->tv_usec, &o->tv_usec)) ? -EFAULT : 0; | ||
53 | } | ||
54 | |||
55 | static int compat_get_timex(struct timex *txc, struct compat_timex __user *utp) | 33 | static int compat_get_timex(struct timex *txc, struct compat_timex __user *utp) |
56 | { | 34 | { |
57 | memset(txc, 0, sizeof(struct timex)); | 35 | memset(txc, 0, sizeof(struct timex)); |
@@ -116,7 +94,7 @@ asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv, | |||
116 | if (tv) { | 94 | if (tv) { |
117 | struct timeval ktv; | 95 | struct timeval ktv; |
118 | do_gettimeofday(&ktv); | 96 | do_gettimeofday(&ktv); |
119 | if (compat_put_timeval_convert(tv, &ktv)) | 97 | if (compat_put_timeval(&ktv, tv)) |
120 | return -EFAULT; | 98 | return -EFAULT; |
121 | } | 99 | } |
122 | if (tz) { | 100 | if (tz) { |
@@ -130,59 +108,58 @@ asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv, | |||
130 | asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv, | 108 | asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv, |
131 | struct timezone __user *tz) | 109 | struct timezone __user *tz) |
132 | { | 110 | { |
133 | struct timespec kts; | 111 | struct timeval user_tv; |
134 | struct timezone ktz; | 112 | struct timespec new_ts; |
113 | struct timezone new_tz; | ||
135 | 114 | ||
136 | if (tv) { | 115 | if (tv) { |
137 | if (compat_get_timeval_convert(&kts, tv)) | 116 | if (compat_get_timeval(&user_tv, tv)) |
138 | return -EFAULT; | 117 | return -EFAULT; |
118 | new_ts.tv_sec = user_tv.tv_sec; | ||
119 | new_ts.tv_nsec = user_tv.tv_usec * NSEC_PER_USEC; | ||
139 | } | 120 | } |
140 | if (tz) { | 121 | if (tz) { |
141 | if (copy_from_user(&ktz, tz, sizeof(ktz))) | 122 | if (copy_from_user(&new_tz, tz, sizeof(*tz))) |
142 | return -EFAULT; | 123 | return -EFAULT; |
143 | } | 124 | } |
144 | 125 | ||
145 | return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL); | 126 | return do_sys_settimeofday(tv ? &new_ts : NULL, tz ? &new_tz : NULL); |
146 | } | 127 | } |
147 | 128 | ||
148 | int get_compat_timeval(struct timeval *tv, const struct compat_timeval __user *ctv) | 129 | static int __compat_get_timeval(struct timeval *tv, const struct compat_timeval __user *ctv) |
149 | { | 130 | { |
150 | return (!access_ok(VERIFY_READ, ctv, sizeof(*ctv)) || | 131 | return (!access_ok(VERIFY_READ, ctv, sizeof(*ctv)) || |
151 | __get_user(tv->tv_sec, &ctv->tv_sec) || | 132 | __get_user(tv->tv_sec, &ctv->tv_sec) || |
152 | __get_user(tv->tv_usec, &ctv->tv_usec)) ? -EFAULT : 0; | 133 | __get_user(tv->tv_usec, &ctv->tv_usec)) ? -EFAULT : 0; |
153 | } | 134 | } |
154 | EXPORT_SYMBOL_GPL(get_compat_timeval); | ||
155 | 135 | ||
156 | int put_compat_timeval(const struct timeval *tv, struct compat_timeval __user *ctv) | 136 | static int __compat_put_timeval(const struct timeval *tv, struct compat_timeval __user *ctv) |
157 | { | 137 | { |
158 | return (!access_ok(VERIFY_WRITE, ctv, sizeof(*ctv)) || | 138 | return (!access_ok(VERIFY_WRITE, ctv, sizeof(*ctv)) || |
159 | __put_user(tv->tv_sec, &ctv->tv_sec) || | 139 | __put_user(tv->tv_sec, &ctv->tv_sec) || |
160 | __put_user(tv->tv_usec, &ctv->tv_usec)) ? -EFAULT : 0; | 140 | __put_user(tv->tv_usec, &ctv->tv_usec)) ? -EFAULT : 0; |
161 | } | 141 | } |
162 | EXPORT_SYMBOL_GPL(put_compat_timeval); | ||
163 | 142 | ||
164 | int get_compat_timespec(struct timespec *ts, const struct compat_timespec __user *cts) | 143 | static int __compat_get_timespec(struct timespec *ts, const struct compat_timespec __user *cts) |
165 | { | 144 | { |
166 | return (!access_ok(VERIFY_READ, cts, sizeof(*cts)) || | 145 | return (!access_ok(VERIFY_READ, cts, sizeof(*cts)) || |
167 | __get_user(ts->tv_sec, &cts->tv_sec) || | 146 | __get_user(ts->tv_sec, &cts->tv_sec) || |
168 | __get_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0; | 147 | __get_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0; |
169 | } | 148 | } |
170 | EXPORT_SYMBOL_GPL(get_compat_timespec); | ||
171 | 149 | ||
172 | int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user *cts) | 150 | static int __compat_put_timespec(const struct timespec *ts, struct compat_timespec __user *cts) |
173 | { | 151 | { |
174 | return (!access_ok(VERIFY_WRITE, cts, sizeof(*cts)) || | 152 | return (!access_ok(VERIFY_WRITE, cts, sizeof(*cts)) || |
175 | __put_user(ts->tv_sec, &cts->tv_sec) || | 153 | __put_user(ts->tv_sec, &cts->tv_sec) || |
176 | __put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0; | 154 | __put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0; |
177 | } | 155 | } |
178 | EXPORT_SYMBOL_GPL(put_compat_timespec); | ||
179 | 156 | ||
180 | int compat_get_timeval(struct timeval *tv, const void __user *utv) | 157 | int compat_get_timeval(struct timeval *tv, const void __user *utv) |
181 | { | 158 | { |
182 | if (COMPAT_USE_64BIT_TIME) | 159 | if (COMPAT_USE_64BIT_TIME) |
183 | return copy_from_user(tv, utv, sizeof *tv) ? -EFAULT : 0; | 160 | return copy_from_user(tv, utv, sizeof *tv) ? -EFAULT : 0; |
184 | else | 161 | else |
185 | return get_compat_timeval(tv, utv); | 162 | return __compat_get_timeval(tv, utv); |
186 | } | 163 | } |
187 | EXPORT_SYMBOL_GPL(compat_get_timeval); | 164 | EXPORT_SYMBOL_GPL(compat_get_timeval); |
188 | 165 | ||
@@ -191,7 +168,7 @@ int compat_put_timeval(const struct timeval *tv, void __user *utv) | |||
191 | if (COMPAT_USE_64BIT_TIME) | 168 | if (COMPAT_USE_64BIT_TIME) |
192 | return copy_to_user(utv, tv, sizeof *tv) ? -EFAULT : 0; | 169 | return copy_to_user(utv, tv, sizeof *tv) ? -EFAULT : 0; |
193 | else | 170 | else |
194 | return put_compat_timeval(tv, utv); | 171 | return __compat_put_timeval(tv, utv); |
195 | } | 172 | } |
196 | EXPORT_SYMBOL_GPL(compat_put_timeval); | 173 | EXPORT_SYMBOL_GPL(compat_put_timeval); |
197 | 174 | ||
@@ -200,7 +177,7 @@ int compat_get_timespec(struct timespec *ts, const void __user *uts) | |||
200 | if (COMPAT_USE_64BIT_TIME) | 177 | if (COMPAT_USE_64BIT_TIME) |
201 | return copy_from_user(ts, uts, sizeof *ts) ? -EFAULT : 0; | 178 | return copy_from_user(ts, uts, sizeof *ts) ? -EFAULT : 0; |
202 | else | 179 | else |
203 | return get_compat_timespec(ts, uts); | 180 | return __compat_get_timespec(ts, uts); |
204 | } | 181 | } |
205 | EXPORT_SYMBOL_GPL(compat_get_timespec); | 182 | EXPORT_SYMBOL_GPL(compat_get_timespec); |
206 | 183 | ||
@@ -209,10 +186,33 @@ int compat_put_timespec(const struct timespec *ts, void __user *uts) | |||
209 | if (COMPAT_USE_64BIT_TIME) | 186 | if (COMPAT_USE_64BIT_TIME) |
210 | return copy_to_user(uts, ts, sizeof *ts) ? -EFAULT : 0; | 187 | return copy_to_user(uts, ts, sizeof *ts) ? -EFAULT : 0; |
211 | else | 188 | else |
212 | return put_compat_timespec(ts, uts); | 189 | return __compat_put_timespec(ts, uts); |
213 | } | 190 | } |
214 | EXPORT_SYMBOL_GPL(compat_put_timespec); | 191 | EXPORT_SYMBOL_GPL(compat_put_timespec); |
215 | 192 | ||
193 | int compat_convert_timespec(struct timespec __user **kts, | ||
194 | const void __user *cts) | ||
195 | { | ||
196 | struct timespec ts; | ||
197 | struct timespec __user *uts; | ||
198 | |||
199 | if (!cts || COMPAT_USE_64BIT_TIME) { | ||
200 | *kts = (struct timespec __user *)cts; | ||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | uts = compat_alloc_user_space(sizeof(ts)); | ||
205 | if (!uts) | ||
206 | return -EFAULT; | ||
207 | if (compat_get_timespec(&ts, cts)) | ||
208 | return -EFAULT; | ||
209 | if (copy_to_user(uts, &ts, sizeof(ts))) | ||
210 | return -EFAULT; | ||
211 | |||
212 | *kts = uts; | ||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static long compat_nanosleep_restart(struct restart_block *restart) | 216 | static long compat_nanosleep_restart(struct restart_block *restart) |
217 | { | 217 | { |
218 | struct compat_timespec __user *rmtp; | 218 | struct compat_timespec __user *rmtp; |
@@ -229,7 +229,7 @@ static long compat_nanosleep_restart(struct restart_block *restart) | |||
229 | if (ret) { | 229 | if (ret) { |
230 | rmtp = restart->nanosleep.compat_rmtp; | 230 | rmtp = restart->nanosleep.compat_rmtp; |
231 | 231 | ||
232 | if (rmtp && put_compat_timespec(&rmt, rmtp)) | 232 | if (rmtp && compat_put_timespec(&rmt, rmtp)) |
233 | return -EFAULT; | 233 | return -EFAULT; |
234 | } | 234 | } |
235 | 235 | ||
@@ -243,7 +243,7 @@ asmlinkage long compat_sys_nanosleep(struct compat_timespec __user *rqtp, | |||
243 | mm_segment_t oldfs; | 243 | mm_segment_t oldfs; |
244 | long ret; | 244 | long ret; |
245 | 245 | ||
246 | if (get_compat_timespec(&tu, rqtp)) | 246 | if (compat_get_timespec(&tu, rqtp)) |
247 | return -EFAULT; | 247 | return -EFAULT; |
248 | 248 | ||
249 | if (!timespec_valid(&tu)) | 249 | if (!timespec_valid(&tu)) |
@@ -263,7 +263,7 @@ asmlinkage long compat_sys_nanosleep(struct compat_timespec __user *rqtp, | |||
263 | restart->fn = compat_nanosleep_restart; | 263 | restart->fn = compat_nanosleep_restart; |
264 | restart->nanosleep.compat_rmtp = rmtp; | 264 | restart->nanosleep.compat_rmtp = rmtp; |
265 | 265 | ||
266 | if (rmtp && put_compat_timespec(&rmt, rmtp)) | 266 | if (rmtp && compat_put_timespec(&rmt, rmtp)) |
267 | return -EFAULT; | 267 | return -EFAULT; |
268 | } | 268 | } |
269 | 269 | ||
@@ -647,8 +647,8 @@ asmlinkage long compat_sys_sched_getaffinity(compat_pid_t pid, unsigned int len, | |||
647 | int get_compat_itimerspec(struct itimerspec *dst, | 647 | int get_compat_itimerspec(struct itimerspec *dst, |
648 | const struct compat_itimerspec __user *src) | 648 | const struct compat_itimerspec __user *src) |
649 | { | 649 | { |
650 | if (get_compat_timespec(&dst->it_interval, &src->it_interval) || | 650 | if (__compat_get_timespec(&dst->it_interval, &src->it_interval) || |
651 | get_compat_timespec(&dst->it_value, &src->it_value)) | 651 | __compat_get_timespec(&dst->it_value, &src->it_value)) |
652 | return -EFAULT; | 652 | return -EFAULT; |
653 | return 0; | 653 | return 0; |
654 | } | 654 | } |
@@ -656,8 +656,8 @@ int get_compat_itimerspec(struct itimerspec *dst, | |||
656 | int put_compat_itimerspec(struct compat_itimerspec __user *dst, | 656 | int put_compat_itimerspec(struct compat_itimerspec __user *dst, |
657 | const struct itimerspec *src) | 657 | const struct itimerspec *src) |
658 | { | 658 | { |
659 | if (put_compat_timespec(&src->it_interval, &dst->it_interval) || | 659 | if (__compat_put_timespec(&src->it_interval, &dst->it_interval) || |
660 | put_compat_timespec(&src->it_value, &dst->it_value)) | 660 | __compat_put_timespec(&src->it_value, &dst->it_value)) |
661 | return -EFAULT; | 661 | return -EFAULT; |
662 | return 0; | 662 | return 0; |
663 | } | 663 | } |
@@ -727,7 +727,7 @@ long compat_sys_clock_settime(clockid_t which_clock, | |||
727 | mm_segment_t oldfs; | 727 | mm_segment_t oldfs; |
728 | struct timespec ts; | 728 | struct timespec ts; |
729 | 729 | ||
730 | if (get_compat_timespec(&ts, tp)) | 730 | if (compat_get_timespec(&ts, tp)) |
731 | return -EFAULT; | 731 | return -EFAULT; |
732 | oldfs = get_fs(); | 732 | oldfs = get_fs(); |
733 | set_fs(KERNEL_DS); | 733 | set_fs(KERNEL_DS); |
@@ -749,7 +749,7 @@ long compat_sys_clock_gettime(clockid_t which_clock, | |||
749 | err = sys_clock_gettime(which_clock, | 749 | err = sys_clock_gettime(which_clock, |
750 | (struct timespec __user *) &ts); | 750 | (struct timespec __user *) &ts); |
751 | set_fs(oldfs); | 751 | set_fs(oldfs); |
752 | if (!err && put_compat_timespec(&ts, tp)) | 752 | if (!err && compat_put_timespec(&ts, tp)) |
753 | return -EFAULT; | 753 | return -EFAULT; |
754 | return err; | 754 | return err; |
755 | } | 755 | } |
@@ -789,7 +789,7 @@ long compat_sys_clock_getres(clockid_t which_clock, | |||
789 | err = sys_clock_getres(which_clock, | 789 | err = sys_clock_getres(which_clock, |
790 | (struct timespec __user *) &ts); | 790 | (struct timespec __user *) &ts); |
791 | set_fs(oldfs); | 791 | set_fs(oldfs); |
792 | if (!err && tp && put_compat_timespec(&ts, tp)) | 792 | if (!err && tp && compat_put_timespec(&ts, tp)) |
793 | return -EFAULT; | 793 | return -EFAULT; |
794 | return err; | 794 | return err; |
795 | } | 795 | } |
@@ -808,7 +808,7 @@ static long compat_clock_nanosleep_restart(struct restart_block *restart) | |||
808 | set_fs(oldfs); | 808 | set_fs(oldfs); |
809 | 809 | ||
810 | if ((err == -ERESTART_RESTARTBLOCK) && rmtp && | 810 | if ((err == -ERESTART_RESTARTBLOCK) && rmtp && |
811 | put_compat_timespec(&tu, rmtp)) | 811 | compat_put_timespec(&tu, rmtp)) |
812 | return -EFAULT; | 812 | return -EFAULT; |
813 | 813 | ||
814 | if (err == -ERESTART_RESTARTBLOCK) { | 814 | if (err == -ERESTART_RESTARTBLOCK) { |
@@ -827,7 +827,7 @@ long compat_sys_clock_nanosleep(clockid_t which_clock, int flags, | |||
827 | struct timespec in, out; | 827 | struct timespec in, out; |
828 | struct restart_block *restart; | 828 | struct restart_block *restart; |
829 | 829 | ||
830 | if (get_compat_timespec(&in, rqtp)) | 830 | if (compat_get_timespec(&in, rqtp)) |
831 | return -EFAULT; | 831 | return -EFAULT; |
832 | 832 | ||
833 | oldfs = get_fs(); | 833 | oldfs = get_fs(); |
@@ -838,7 +838,7 @@ long compat_sys_clock_nanosleep(clockid_t which_clock, int flags, | |||
838 | set_fs(oldfs); | 838 | set_fs(oldfs); |
839 | 839 | ||
840 | if ((err == -ERESTART_RESTARTBLOCK) && rmtp && | 840 | if ((err == -ERESTART_RESTARTBLOCK) && rmtp && |
841 | put_compat_timespec(&out, rmtp)) | 841 | compat_put_timespec(&out, rmtp)) |
842 | return -EFAULT; | 842 | return -EFAULT; |
843 | 843 | ||
844 | if (err == -ERESTART_RESTARTBLOCK) { | 844 | if (err == -ERESTART_RESTARTBLOCK) { |
@@ -1130,7 +1130,7 @@ COMPAT_SYSCALL_DEFINE2(sched_rr_get_interval, | |||
1130 | set_fs(KERNEL_DS); | 1130 | set_fs(KERNEL_DS); |
1131 | ret = sys_sched_rr_get_interval(pid, (struct timespec __user *)&t); | 1131 | ret = sys_sched_rr_get_interval(pid, (struct timespec __user *)&t); |
1132 | set_fs(old_fs); | 1132 | set_fs(old_fs); |
1133 | if (put_compat_timespec(&t, interval)) | 1133 | if (compat_put_timespec(&t, interval)) |
1134 | return -EFAULT; | 1134 | return -EFAULT; |
1135 | return ret; | 1135 | return ret; |
1136 | } | 1136 | } |
diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c index f9f44fd4d34d..55c8c9349cfe 100644 --- a/kernel/futex_compat.c +++ b/kernel/futex_compat.c | |||
@@ -183,7 +183,7 @@ COMPAT_SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val, | |||
183 | if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI || | 183 | if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI || |
184 | cmd == FUTEX_WAIT_BITSET || | 184 | cmd == FUTEX_WAIT_BITSET || |
185 | cmd == FUTEX_WAIT_REQUEUE_PI)) { | 185 | cmd == FUTEX_WAIT_REQUEUE_PI)) { |
186 | if (get_compat_timespec(&ts, utime)) | 186 | if (compat_get_timespec(&ts, utime)) |
187 | return -EFAULT; | 187 | return -EFAULT; |
188 | if (!timespec_valid(&ts)) | 188 | if (!timespec_valid(&ts)) |
189 | return -EINVAL; | 189 | return -EINVAL; |