diff options
| author | H. Peter Anvin <hpa@zytor.com> | 2012-02-19 20:38:00 -0500 |
|---|---|---|
| committer | H. Peter Anvin <hpa@zytor.com> | 2012-02-20 15:48:47 -0500 |
| commit | 6684ba202b5ab2f36d574c72fe50c207d99b3e35 (patch) | |
| tree | 58f692f4f827bba86120c0af385fb8c768889591 /kernel | |
| parent | 45e877812926c69d643d6274347f79513a4ee934 (diff) | |
compat: Add helper functions to read/write struct timeval, timespec
Add helper functions to read and write struct timeval and struct
timespec from userspace. We already had helper functions for reading
and writing struct compat_timespec; add a set of functions to do the
same with struct timeval, and add a second suite of functions which
can be sensitive to COMPAT_USE_64BIT_TIME and access either 32- or
64-bit time structures.
This also exports these helper functions to modules.
Rename the existing inlines for converting between struct
compat_timeval and native struct timespec so we can have a saner
naming convention for the exported functions.
Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/compat.c | 68 |
1 files changed, 60 insertions, 8 deletions
diff --git a/kernel/compat.c b/kernel/compat.c index f346cedfe24..74ff8498809 100644 --- a/kernel/compat.c +++ b/kernel/compat.c | |||
| @@ -31,11 +31,10 @@ | |||
| 31 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
| 32 | 32 | ||
| 33 | /* | 33 | /* |
| 34 | * Note that the native side is already converted to a timespec, because | 34 | * Get/set struct timeval with struct timespec on the native side |
| 35 | * that's what we want anyway. | ||
| 36 | */ | 35 | */ |
| 37 | static int compat_get_timeval(struct timespec *o, | 36 | static int compat_get_timeval_convert(struct timespec *o, |
| 38 | struct compat_timeval __user *i) | 37 | struct compat_timeval __user *i) |
| 39 | { | 38 | { |
| 40 | long usec; | 39 | long usec; |
| 41 | 40 | ||
| @@ -46,8 +45,8 @@ static int compat_get_timeval(struct timespec *o, | |||
| 46 | return 0; | 45 | return 0; |
| 47 | } | 46 | } |
| 48 | 47 | ||
| 49 | static int compat_put_timeval(struct compat_timeval __user *o, | 48 | static int compat_put_timeval_convert(struct compat_timeval __user *o, |
| 50 | struct timeval *i) | 49 | struct timeval *i) |
| 51 | { | 50 | { |
| 52 | return (put_user(i->tv_sec, &o->tv_sec) || | 51 | return (put_user(i->tv_sec, &o->tv_sec) || |
| 53 | put_user(i->tv_usec, &o->tv_usec)) ? -EFAULT : 0; | 52 | put_user(i->tv_usec, &o->tv_usec)) ? -EFAULT : 0; |
| @@ -117,7 +116,7 @@ asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv, | |||
| 117 | if (tv) { | 116 | if (tv) { |
| 118 | struct timeval ktv; | 117 | struct timeval ktv; |
| 119 | do_gettimeofday(&ktv); | 118 | do_gettimeofday(&ktv); |
| 120 | if (compat_put_timeval(tv, &ktv)) | 119 | if (compat_put_timeval_convert(tv, &ktv)) |
| 121 | return -EFAULT; | 120 | return -EFAULT; |
| 122 | } | 121 | } |
| 123 | if (tz) { | 122 | if (tz) { |
| @@ -135,7 +134,7 @@ asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv, | |||
| 135 | struct timezone ktz; | 134 | struct timezone ktz; |
| 136 | 135 | ||
| 137 | if (tv) { | 136 | if (tv) { |
| 138 | if (compat_get_timeval(&kts, tv)) | 137 | if (compat_get_timeval_convert(&kts, tv)) |
| 139 | return -EFAULT; | 138 | return -EFAULT; |
| 140 | } | 139 | } |
| 141 | if (tz) { | 140 | if (tz) { |
| @@ -146,12 +145,29 @@ asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv, | |||
| 146 | return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL); | 145 | return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL); |
| 147 | } | 146 | } |
| 148 | 147 | ||
| 148 | int get_compat_timeval(struct timeval *tv, const struct compat_timeval __user *ctv) | ||
| 149 | { | ||
| 150 | return (!access_ok(VERIFY_READ, ctv, sizeof(*ctv)) || | ||
| 151 | __get_user(tv->tv_sec, &ctv->tv_sec) || | ||
| 152 | __get_user(tv->tv_usec, &ctv->tv_usec)) ? -EFAULT : 0; | ||
| 153 | } | ||
| 154 | EXPORT_SYMBOL_GPL(get_compat_timeval); | ||
| 155 | |||
| 156 | int put_compat_timeval(const struct timeval *tv, struct compat_timeval __user *ctv) | ||
| 157 | { | ||
| 158 | return (!access_ok(VERIFY_WRITE, ctv, sizeof(*ctv)) || | ||
| 159 | __put_user(tv->tv_sec, &ctv->tv_sec) || | ||
| 160 | __put_user(tv->tv_usec, &ctv->tv_usec)) ? -EFAULT : 0; | ||
| 161 | } | ||
| 162 | EXPORT_SYMBOL_GPL(put_compat_timeval); | ||
| 163 | |||
| 149 | int get_compat_timespec(struct timespec *ts, const struct compat_timespec __user *cts) | 164 | int get_compat_timespec(struct timespec *ts, const struct compat_timespec __user *cts) |
| 150 | { | 165 | { |
| 151 | return (!access_ok(VERIFY_READ, cts, sizeof(*cts)) || | 166 | return (!access_ok(VERIFY_READ, cts, sizeof(*cts)) || |
| 152 | __get_user(ts->tv_sec, &cts->tv_sec) || | 167 | __get_user(ts->tv_sec, &cts->tv_sec) || |
| 153 | __get_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0; | 168 | __get_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0; |
| 154 | } | 169 | } |
| 170 | EXPORT_SYMBOL_GPL(get_compat_timespec); | ||
| 155 | 171 | ||
| 156 | int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user *cts) | 172 | int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user *cts) |
| 157 | { | 173 | { |
| @@ -161,6 +177,42 @@ int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user | |||
| 161 | } | 177 | } |
| 162 | EXPORT_SYMBOL_GPL(put_compat_timespec); | 178 | EXPORT_SYMBOL_GPL(put_compat_timespec); |
| 163 | 179 | ||
| 180 | int compat_get_timeval(struct timeval *tv, const void __user *utv) | ||
| 181 | { | ||
| 182 | if (COMPAT_USE_64BIT_TIME) | ||
| 183 | return copy_from_user(tv, utv, sizeof *tv) ? -EFAULT : 0; | ||
| 184 | else | ||
| 185 | return get_compat_timeval(tv, utv); | ||
| 186 | } | ||
| 187 | EXPORT_SYMBOL_GPL(compat_get_timeval); | ||
| 188 | |||
| 189 | int compat_put_timeval(const struct timeval *tv, void __user *utv) | ||
| 190 | { | ||
| 191 | if (COMPAT_USE_64BIT_TIME) | ||
| 192 | return copy_to_user(utv, tv, sizeof *tv) ? -EFAULT : 0; | ||
| 193 | else | ||
| 194 | return put_compat_timeval(tv, utv); | ||
| 195 | } | ||
| 196 | EXPORT_SYMBOL_GPL(compat_put_timeval); | ||
| 197 | |||
| 198 | int compat_get_timespec(struct timespec *ts, const void __user *uts) | ||
| 199 | { | ||
| 200 | if (COMPAT_USE_64BIT_TIME) | ||
| 201 | return copy_from_user(ts, uts, sizeof *ts) ? -EFAULT : 0; | ||
| 202 | else | ||
| 203 | return get_compat_timespec(ts, uts); | ||
| 204 | } | ||
| 205 | EXPORT_SYMBOL_GPL(compat_get_timespec); | ||
| 206 | |||
| 207 | int compat_put_timespec(const struct timespec *ts, void __user *uts) | ||
| 208 | { | ||
| 209 | if (COMPAT_USE_64BIT_TIME) | ||
| 210 | return copy_to_user(uts, ts, sizeof *ts) ? -EFAULT : 0; | ||
| 211 | else | ||
| 212 | return put_compat_timespec(ts, uts); | ||
| 213 | } | ||
| 214 | EXPORT_SYMBOL_GPL(compat_put_timespec); | ||
| 215 | |||
| 164 | static long compat_nanosleep_restart(struct restart_block *restart) | 216 | static long compat_nanosleep_restart(struct restart_block *restart) |
| 165 | { | 217 | { |
| 166 | struct compat_timespec __user *rmtp; | 218 | struct compat_timespec __user *rmtp; |
