@@ -2844,27 +2844,48 @@ COMPAT_SYSCALL_DEFINE2(rt_sigpending, compat_sigset_t __user *, uset,
28442844}
28452845#endif
28462846
2847+ static const struct {
2848+ unsigned char limit , layout ;
2849+ } sig_sicodes [] = {
2850+ [SIGILL ] = { NSIGILL , SIL_FAULT },
2851+ [SIGFPE ] = { NSIGFPE , SIL_FAULT },
2852+ [SIGSEGV ] = { NSIGSEGV , SIL_FAULT },
2853+ [SIGBUS ] = { NSIGBUS , SIL_FAULT },
2854+ [SIGTRAP ] = { NSIGTRAP , SIL_FAULT },
2855+ #if defined(SIGEMT )
2856+ [SIGEMT ] = { NSIGEMT , SIL_FAULT },
2857+ #endif
2858+ [SIGCHLD ] = { NSIGCHLD , SIL_CHLD },
2859+ [SIGPOLL ] = { NSIGPOLL , SIL_POLL },
2860+ [SIGSYS ] = { NSIGSYS , SIL_SYS },
2861+ };
2862+
2863+ static bool known_siginfo_layout (int sig , int si_code )
2864+ {
2865+ if (si_code == SI_KERNEL )
2866+ return true;
2867+ else if ((si_code > SI_USER )) {
2868+ if (sig_specific_sicodes (sig )) {
2869+ if (si_code <= sig_sicodes [sig ].limit )
2870+ return true;
2871+ }
2872+ else if (si_code <= NSIGPOLL )
2873+ return true;
2874+ }
2875+ else if (si_code >= SI_DETHREAD )
2876+ return true;
2877+ else if (si_code == SI_ASYNCNL )
2878+ return true;
2879+ return false;
2880+ }
2881+
28472882enum siginfo_layout siginfo_layout (int sig , int si_code )
28482883{
28492884 enum siginfo_layout layout = SIL_KILL ;
28502885 if ((si_code > SI_USER ) && (si_code < SI_KERNEL )) {
2851- static const struct {
2852- unsigned char limit , layout ;
2853- } filter [] = {
2854- [SIGILL ] = { NSIGILL , SIL_FAULT },
2855- [SIGFPE ] = { NSIGFPE , SIL_FAULT },
2856- [SIGSEGV ] = { NSIGSEGV , SIL_FAULT },
2857- [SIGBUS ] = { NSIGBUS , SIL_FAULT },
2858- [SIGTRAP ] = { NSIGTRAP , SIL_FAULT },
2859- #if defined(SIGEMT )
2860- [SIGEMT ] = { NSIGEMT , SIL_FAULT },
2861- #endif
2862- [SIGCHLD ] = { NSIGCHLD , SIL_CHLD },
2863- [SIGPOLL ] = { NSIGPOLL , SIL_POLL },
2864- [SIGSYS ] = { NSIGSYS , SIL_SYS },
2865- };
2866- if ((sig < ARRAY_SIZE (filter )) && (si_code <= filter [sig ].limit )) {
2867- layout = filter [sig ].layout ;
2886+ if ((sig < ARRAY_SIZE (sig_sicodes )) &&
2887+ (si_code <= sig_sicodes [sig ].limit )) {
2888+ layout = sig_sicodes [sig ].layout ;
28682889 /* Handle the exceptions */
28692890 if ((sig == SIGBUS ) &&
28702891 (si_code >= BUS_MCEERR_AR ) && (si_code <= BUS_MCEERR_AO ))
@@ -2889,17 +2910,42 @@ enum siginfo_layout siginfo_layout(int sig, int si_code)
28892910 return layout ;
28902911}
28912912
2913+ static inline char __user * si_expansion (const siginfo_t __user * info )
2914+ {
2915+ return ((char __user * )info ) + sizeof (struct kernel_siginfo );
2916+ }
2917+
28922918int copy_siginfo_to_user (siginfo_t __user * to , const kernel_siginfo_t * from )
28932919{
2920+ char __user * expansion = si_expansion (to );
28942921 if (copy_to_user (to , from , sizeof (struct kernel_siginfo )))
28952922 return - EFAULT ;
2923+ if (clear_user (expansion , SI_EXPANSION_SIZE ))
2924+ return - EFAULT ;
28962925 return 0 ;
28972926}
28982927
28992928int copy_siginfo_from_user (kernel_siginfo_t * to , const siginfo_t __user * from )
29002929{
2901- if (copy_from_user (to , from , sizeof (struct siginfo )))
2930+ if (copy_from_user (to , from , sizeof (struct kernel_siginfo )))
29022931 return - EFAULT ;
2932+ if (unlikely (!known_siginfo_layout (to -> si_signo , to -> si_code ))) {
2933+ char __user * expansion = si_expansion (from );
2934+ char buf [SI_EXPANSION_SIZE ];
2935+ int i ;
2936+ /*
2937+ * An unknown si_code might need more than
2938+ * sizeof(struct kernel_siginfo) bytes. Verify all of the
2939+ * extra bytes are 0. This guarantees copy_siginfo_to_user
2940+ * will return this data to userspace exactly.
2941+ */
2942+ if (copy_from_user (& buf , expansion , SI_EXPANSION_SIZE ))
2943+ return - EFAULT ;
2944+ for (i = 0 ; i < SI_EXPANSION_SIZE ; i ++ ) {
2945+ if (buf [i ] != 0 )
2946+ return - E2BIG ;
2947+ }
2948+ }
29032949 return 0 ;
29042950}
29052951
0 commit comments