aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Martin <Dave.Martin@arm.com>2017-06-15 10:03:39 -0400
committerWill Deacon <will.deacon@arm.com>2017-06-20 07:42:58 -0400
commit47ccb02868cead34578d953b5fe0cdd58394605e (patch)
tree0aa4f06e85f3f80b9fe8cd34d711e1e0ef750bbe
parent20987de3c2c45c314e0386f724aa85f55d984ef2 (diff)
arm64: signal: Refactor sigcontext parsing in rt_sigreturn
Currently, rt_sigreturn does very limited checking on the sigcontext coming from userspace. Future additions to the sigcontext data will increase the potential for surprises. Also, it is not clear whether the sigcontext extension records are supposed to occur in a particular order. To allow the parsing code to be extended more easily, this patch factors out the sigcontext parsing into a separate function, and adds extra checks to validate the well-formedness of the sigcontext structure. Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> Signed-off-by: Dave Martin <Dave.Martin@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r--arch/arm64/kernel/signal.c86
1 files changed, 80 insertions, 6 deletions
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 1e5ed3be78ed..67769f68ae06 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -23,6 +23,7 @@
23#include <linux/signal.h> 23#include <linux/signal.h>
24#include <linux/personality.h> 24#include <linux/personality.h>
25#include <linux/freezer.h> 25#include <linux/freezer.h>
26#include <linux/stddef.h>
26#include <linux/uaccess.h> 27#include <linux/uaccess.h>
27#include <linux/tracehook.h> 28#include <linux/tracehook.h>
28#include <linux/ratelimit.h> 29#include <linux/ratelimit.h>
@@ -101,12 +102,86 @@ static int restore_fpsimd_context(struct fpsimd_context __user *ctx)
101 return err ? -EFAULT : 0; 102 return err ? -EFAULT : 0;
102} 103}
103 104
105struct user_ctxs {
106 struct fpsimd_context __user *fpsimd;
107};
108
109static int parse_user_sigframe(struct user_ctxs *user,
110 struct rt_sigframe __user *sf)
111{
112 struct sigcontext __user *const sc = &sf->uc.uc_mcontext;
113 struct _aarch64_ctx __user *head =
114 (struct _aarch64_ctx __user *)&sc->__reserved;
115 size_t offset = 0;
116
117 user->fpsimd = NULL;
118
119 while (1) {
120 int err;
121 u32 magic, size;
122
123 head = (struct _aarch64_ctx __user *)&sc->__reserved[offset];
124 if (!IS_ALIGNED((unsigned long)head, 16))
125 goto invalid;
126
127 err = 0;
128 __get_user_error(magic, &head->magic, err);
129 __get_user_error(size, &head->size, err);
130 if (err)
131 return err;
132
133 switch (magic) {
134 case 0:
135 if (size)
136 goto invalid;
137
138 goto done;
139
140 case FPSIMD_MAGIC:
141 if (user->fpsimd)
142 goto invalid;
143
144 if (offset > sizeof(sc->__reserved) -
145 sizeof(*user->fpsimd) ||
146 size < sizeof(*user->fpsimd))
147 goto invalid;
148
149 user->fpsimd = (struct fpsimd_context __user *)head;
150 break;
151
152 case ESR_MAGIC:
153 /* ignore */
154 break;
155
156 default:
157 goto invalid;
158 }
159
160 if (size < sizeof(*head))
161 goto invalid;
162
163 if (size > sizeof(sc->__reserved) - (sizeof(*head) + offset))
164 goto invalid;
165
166 offset += size;
167 }
168
169done:
170 if (!user->fpsimd)
171 goto invalid;
172
173 return 0;
174
175invalid:
176 return -EINVAL;
177}
178
104static int restore_sigframe(struct pt_regs *regs, 179static int restore_sigframe(struct pt_regs *regs,
105 struct rt_sigframe __user *sf) 180 struct rt_sigframe __user *sf)
106{ 181{
107 sigset_t set; 182 sigset_t set;
108 int i, err; 183 int i, err;
109 void *aux = sf->uc.uc_mcontext.__reserved; 184 struct user_ctxs user;
110 185
111 err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set)); 186 err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set));
112 if (err == 0) 187 if (err == 0)
@@ -125,12 +200,11 @@ static int restore_sigframe(struct pt_regs *regs,
125 regs->syscallno = ~0UL; 200 regs->syscallno = ~0UL;
126 201
127 err |= !valid_user_regs(&regs->user_regs, current); 202 err |= !valid_user_regs(&regs->user_regs, current);
203 if (err == 0)
204 err = parse_user_sigframe(&user, sf);
128 205
129 if (err == 0) { 206 if (err == 0)
130 struct fpsimd_context *fpsimd_ctx = 207 err = restore_fpsimd_context(user.fpsimd);
131 container_of(aux, struct fpsimd_context, head);
132 err |= restore_fpsimd_context(fpsimd_ctx);
133 }
134 208
135 return err; 209 return err;
136} 210}