summaryrefslogtreecommitdiff
path: root/kernel/compat.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/compat.c')
-rw-r--r--kernel/compat.c86
1 files changed, 86 insertions, 0 deletions
diff --git a/kernel/compat.c b/kernel/compat.c
index 42d56544460f..22764085d530 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -100,6 +100,16 @@ int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user
__put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
}
+static int user_timespec_from_compat(struct timespec __user *uts,
+ const struct compat_timespec __user *ucts)
+{
+ struct timespec ts;
+ return (get_compat_timespec(&ts, ucts) ||
+ !access_ok(VERIFY_WRITE, uts, sizeof(*uts)) ||
+ __put_user(uts->tv_sec, &ts.tv_sec) ||
+ __put_user(uts->tv_nsec, &ts.tv_nsec)) ? -EFAULT : 0;
+}
+
static long compat_nanosleep_restart(struct restart_block *restart)
{
struct compat_timespec __user *rmtp;
@@ -1128,3 +1138,79 @@ compat_sys_sysinfo(struct compat_sysinfo __user *info)
return 0;
}
+
+static int user_sigset_from_compat(sigset_t __user *usigset,
+ const compat_sigset_t __user *ucsigset,
+ compat_size_t sigsetsize)
+{
+ compat_sigset_t csigset;
+ sigset_t sigset;
+
+ if (sigsetsize != sizeof(sigset_t))
+ return -EINVAL;
+ if (copy_from_user(&csigset, ucsigset, sizeof(csigset)))
+ return -EFAULT;
+ sigset_from_compat(&sigset, &csigset);
+ if (copy_to_user(usigset, &sigset, sizeof(sigset)))
+ return -EFAULT;
+ return 0;
+}
+
+asmlinkage long
+compat_sys_acall_ring_pwait(struct acall_completion_ring __user *uring,
+ u32 tail, u32 min,
+ struct compat_timespec __user *ucts,
+ const compat_sigset_t __user *ucsigmask,
+ compat_size_t sigsetsize)
+{
+ struct timespec __user *uts;
+ sigset_t __user *usigmask;
+ long ret;
+
+ if (ucts) {
+ uts = compat_alloc_user_space(sizeof(struct timespec));
+ if (user_timespec_from_compat(uts, ucts))
+ return -EFAULT;
+ } else
+ uts = NULL;
+
+ if (ucsigmask) {
+ usigmask = compat_alloc_user_space(sizeof (sigset_t));
+ ret = user_sigset_from_compat(usigmask, ucsigmask, sigsetsize);
+ if (ret)
+ return ret;
+ } else
+ usigmask = NULL;
+
+ return sys_acall_ring_pwait(uring, tail, min, uts, usigmask,
+ sigsetsize);
+}
+
+asmlinkage long
+compat_sys_acall_comp_pwait(struct acall_id __user *uids,
+ unsigned long nr,
+ struct compat_timespec __user *ucts,
+ const compat_sigset_t __user *ucsigmask,
+ compat_size_t sigsetsize)
+{
+ struct timespec __user *uts;
+ sigset_t __user *usigmask;
+ long ret;
+
+ if (ucts) {
+ uts = compat_alloc_user_space(sizeof(struct timespec));
+ if (user_timespec_from_compat(uts, ucts))
+ return -EFAULT;
+ } else
+ uts = NULL;
+
+ if (ucsigmask) {
+ usigmask = compat_alloc_user_space(sizeof (sigset_t));
+ ret = user_sigset_from_compat(usigmask, ucsigmask, sigsetsize);
+ if (ret)
+ return ret;
+ } else
+ usigmask = NULL;
+
+ return sys_acall_comp_pwait(uids, nr, uts, usigmask, sigsetsize);
+}