2525#include <linux/freezer.h>
2626#include <linux/stddef.h>
2727#include <linux/uaccess.h>
28+ #include <linux/sizes.h>
2829#include <linux/string.h>
2930#include <linux/tracehook.h>
3031#include <linux/ratelimit.h>
@@ -60,25 +61,80 @@ struct rt_sigframe_user_layout {
6061
6162 unsigned long fpsimd_offset ;
6263 unsigned long esr_offset ;
64+ unsigned long extra_offset ;
6365 unsigned long end_offset ;
6466};
6567
68+ #define BASE_SIGFRAME_SIZE round_up(sizeof(struct rt_sigframe), 16)
69+ #define TERMINATOR_SIZE round_up(sizeof(struct _aarch64_ctx), 16)
70+ #define EXTRA_CONTEXT_SIZE round_up(sizeof(struct extra_context), 16)
71+
6672static void init_user_layout (struct rt_sigframe_user_layout * user )
6773{
74+ const size_t reserved_size =
75+ sizeof (user -> sigframe -> uc .uc_mcontext .__reserved );
76+
6877 memset (user , 0 , sizeof (* user ));
6978 user -> size = offsetof(struct rt_sigframe , uc .uc_mcontext .__reserved );
7079
71- user -> limit = user -> size +
72- sizeof (user -> sigframe -> uc .uc_mcontext .__reserved ) -
73- round_up (sizeof (struct _aarch64_ctx ), 16 );
74- /* ^ reserve space for terminator */
80+ user -> limit = user -> size + reserved_size ;
81+
82+ user -> limit -= TERMINATOR_SIZE ;
83+ user -> limit -= EXTRA_CONTEXT_SIZE ;
84+ /* Reserve space for extension and terminator ^ */
7585}
7686
7787static size_t sigframe_size (struct rt_sigframe_user_layout const * user )
7888{
7989 return round_up (max (user -> size , sizeof (struct rt_sigframe )), 16 );
8090}
8191
92+ /*
93+ * Sanity limit on the approximate maximum size of signal frame we'll
94+ * try to generate. Stack alignment padding and the frame record are
95+ * not taken into account. This limit is not a guarantee and is
96+ * NOT ABI.
97+ */
98+ #define SIGFRAME_MAXSZ SZ_64K
99+
100+ static int __sigframe_alloc (struct rt_sigframe_user_layout * user ,
101+ unsigned long * offset , size_t size , bool extend )
102+ {
103+ size_t padded_size = round_up (size , 16 );
104+
105+ if (padded_size > user -> limit - user -> size &&
106+ !user -> extra_offset &&
107+ extend ) {
108+ int ret ;
109+
110+ user -> limit += EXTRA_CONTEXT_SIZE ;
111+ ret = __sigframe_alloc (user , & user -> extra_offset ,
112+ sizeof (struct extra_context ), false);
113+ if (ret ) {
114+ user -> limit -= EXTRA_CONTEXT_SIZE ;
115+ return ret ;
116+ }
117+
118+ /* Reserve space for the __reserved[] terminator */
119+ user -> size += TERMINATOR_SIZE ;
120+
121+ /*
122+ * Allow expansion up to SIGFRAME_MAXSZ, ensuring space for
123+ * the terminator:
124+ */
125+ user -> limit = SIGFRAME_MAXSZ - TERMINATOR_SIZE ;
126+ }
127+
128+ /* Still not enough space? Bad luck! */
129+ if (padded_size > user -> limit - user -> size )
130+ return - ENOMEM ;
131+
132+ * offset = user -> size ;
133+ user -> size += padded_size ;
134+
135+ return 0 ;
136+ }
137+
82138/*
83139 * Allocate space for an optional record of <size> bytes in the user
84140 * signal frame. The offset from the signal frame base address to the
@@ -87,11 +143,24 @@ static size_t sigframe_size(struct rt_sigframe_user_layout const *user)
87143static int sigframe_alloc (struct rt_sigframe_user_layout * user ,
88144 unsigned long * offset , size_t size )
89145{
90- size_t padded_size = round_up (size , 16 );
146+ return __sigframe_alloc (user , offset , size , true);
147+ }
91148
92- * offset = user -> size ;
93- user -> size += padded_size ;
149+ /* Allocate the null terminator record and prevent further allocations */
150+ static int sigframe_alloc_end (struct rt_sigframe_user_layout * user )
151+ {
152+ int ret ;
153+
154+ /* Un-reserve the space reserved for the terminator: */
155+ user -> limit += TERMINATOR_SIZE ;
94156
157+ ret = sigframe_alloc (user , & user -> end_offset ,
158+ sizeof (struct _aarch64_ctx ));
159+ if (ret )
160+ return ret ;
161+
162+ /* Prevent further allocation: */
163+ user -> limit = user -> size ;
95164 return 0 ;
96165}
97166
@@ -162,6 +231,8 @@ static int parse_user_sigframe(struct user_ctxs *user,
162231 char __user * base = (char __user * )& sc -> __reserved ;
163232 size_t offset = 0 ;
164233 size_t limit = sizeof (sc -> __reserved );
234+ bool have_extra_context = false;
235+ char const __user * const sfp = (char const __user * )sf ;
165236
166237 user -> fpsimd = NULL ;
167238
@@ -171,6 +242,12 @@ static int parse_user_sigframe(struct user_ctxs *user,
171242 while (1 ) {
172243 int err = 0 ;
173244 u32 magic , size ;
245+ char const __user * userp ;
246+ struct extra_context const __user * extra ;
247+ u64 extra_datap ;
248+ u32 extra_size ;
249+ struct _aarch64_ctx const __user * end ;
250+ u32 end_magic , end_size ;
174251
175252 if (limit - offset < sizeof (* head ))
176253 goto invalid ;
@@ -208,6 +285,64 @@ static int parse_user_sigframe(struct user_ctxs *user,
208285 /* ignore */
209286 break ;
210287
288+ case EXTRA_MAGIC :
289+ if (have_extra_context )
290+ goto invalid ;
291+
292+ if (size < sizeof (* extra ))
293+ goto invalid ;
294+
295+ userp = (char const __user * )head ;
296+
297+ extra = (struct extra_context const __user * )userp ;
298+ userp += size ;
299+
300+ __get_user_error (extra_datap , & extra -> datap , err );
301+ __get_user_error (extra_size , & extra -> size , err );
302+ if (err )
303+ return err ;
304+
305+ /* Check for the dummy terminator in __reserved[]: */
306+
307+ if (limit - offset - size < TERMINATOR_SIZE )
308+ goto invalid ;
309+
310+ end = (struct _aarch64_ctx const __user * )userp ;
311+ userp += TERMINATOR_SIZE ;
312+
313+ __get_user_error (end_magic , & end -> magic , err );
314+ __get_user_error (end_size , & end -> size , err );
315+ if (err )
316+ return err ;
317+
318+ if (end_magic || end_size )
319+ goto invalid ;
320+
321+ /* Prevent looping/repeated parsing of extra_context */
322+ have_extra_context = true;
323+
324+ base = (__force void __user * )extra_datap ;
325+ if (!IS_ALIGNED ((unsigned long )base , 16 ))
326+ goto invalid ;
327+
328+ if (!IS_ALIGNED (extra_size , 16 ))
329+ goto invalid ;
330+
331+ if (base != userp )
332+ goto invalid ;
333+
334+ /* Reject "unreasonably large" frames: */
335+ if (extra_size > sfp + SIGFRAME_MAXSZ - userp )
336+ goto invalid ;
337+
338+ /*
339+ * Ignore trailing terminator in __reserved[]
340+ * and start parsing extra data:
341+ */
342+ offset = 0 ;
343+ limit = extra_size ;
344+ continue ;
345+
211346 default :
212347 goto invalid ;
213348 }
@@ -318,17 +453,7 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user)
318453 return err ;
319454 }
320455
321- /*
322- * Allocate space for the terminator record.
323- * HACK: here we undo the reservation of space for the end record.
324- * This bodge should be replaced with a cleaner approach later on.
325- */
326- user -> limit = offsetof(struct rt_sigframe , uc .uc_mcontext .__reserved ) +
327- sizeof (user -> sigframe -> uc .uc_mcontext .__reserved );
328-
329- err = sigframe_alloc (user , & user -> end_offset ,
330- sizeof (struct _aarch64_ctx ));
331- return err ;
456+ return sigframe_alloc_end (user );
332457}
333458
334459
@@ -369,6 +494,40 @@ static int setup_sigframe(struct rt_sigframe_user_layout *user,
369494 __put_user_error (current -> thread .fault_code , & esr_ctx -> esr , err );
370495 }
371496
497+ if (err == 0 && user -> extra_offset ) {
498+ char __user * sfp = (char __user * )user -> sigframe ;
499+ char __user * userp =
500+ apply_user_offset (user , user -> extra_offset );
501+
502+ struct extra_context __user * extra ;
503+ struct _aarch64_ctx __user * end ;
504+ u64 extra_datap ;
505+ u32 extra_size ;
506+
507+ extra = (struct extra_context __user * )userp ;
508+ userp += EXTRA_CONTEXT_SIZE ;
509+
510+ end = (struct _aarch64_ctx __user * )userp ;
511+ userp += TERMINATOR_SIZE ;
512+
513+ /*
514+ * extra_datap is just written to the signal frame.
515+ * The value gets cast back to a void __user *
516+ * during sigreturn.
517+ */
518+ extra_datap = (__force u64 )userp ;
519+ extra_size = sfp + round_up (user -> size , 16 ) - userp ;
520+
521+ __put_user_error (EXTRA_MAGIC , & extra -> head .magic , err );
522+ __put_user_error (EXTRA_CONTEXT_SIZE , & extra -> head .size , err );
523+ __put_user_error (extra_datap , & extra -> datap , err );
524+ __put_user_error (extra_size , & extra -> size , err );
525+
526+ /* Add the terminator */
527+ __put_user_error (0 , & end -> magic , err );
528+ __put_user_error (0 , & end -> size , err );
529+ }
530+
372531 /* set the "end" magic */
373532 if (err == 0 ) {
374533 struct _aarch64_ctx __user * end =
0 commit comments