source: src/linux/universal/linux-4.9/arch/x86/kernel/signal_compat.c @ 31885

Last change on this file since 31885 was 31885, checked in by brainslayer, 5 weeks ago

update

File size: 7.0 KB
Line 
1#include <linux/compat.h>
2#include <linux/uaccess.h>
3#include <linux/ptrace.h>
4
5/*
6 * The compat_siginfo_t structure and handing code is very easy
7 * to break in several ways.  It must always be updated when new
8 * updates are made to the main siginfo_t, and
9 * copy_siginfo_to_user32() must be updated when the
10 * (arch-independent) copy_siginfo_to_user() is updated.
11 *
12 * It is also easy to put a new member in the compat_siginfo_t
13 * which has implicit alignment which can move internal structure
14 * alignment around breaking the ABI.  This can happen if you,
15 * for instance, put a plain 64-bit value in there.
16 */
17static inline void signal_compat_build_tests(void)
18{
19        int _sifields_offset = offsetof(compat_siginfo_t, _sifields);
20
21        /*
22         * If adding a new si_code, there is probably new data in
23         * the siginfo.  Make sure folks bumping the si_code
24         * limits also have to look at this code.  Make sure any
25         * new fields are handled in copy_siginfo_to_user32()!
26         */
27        BUILD_BUG_ON(NSIGILL  != 8);
28        BUILD_BUG_ON(NSIGFPE  != 8);
29        BUILD_BUG_ON(NSIGSEGV != 4);
30        BUILD_BUG_ON(NSIGBUS  != 5);
31        BUILD_BUG_ON(NSIGTRAP != 4);
32        BUILD_BUG_ON(NSIGCHLD != 6);
33        BUILD_BUG_ON(NSIGSYS  != 1);
34
35        /* This is part of the ABI and can never change in size: */
36        BUILD_BUG_ON(sizeof(compat_siginfo_t) != 128);
37        /*
38         * The offsets of all the (unioned) si_fields are fixed
39         * in the ABI, of course.  Make sure none of them ever
40         * move and are always at the beginning:
41         */
42        BUILD_BUG_ON(offsetof(compat_siginfo_t, _sifields) != 3 * sizeof(int));
43#define CHECK_CSI_OFFSET(name)    BUILD_BUG_ON(_sifields_offset != offsetof(compat_siginfo_t, _sifields.name))
44
45         /*
46         * Ensure that the size of each si_field never changes.
47         * If it does, it is a sign that the
48         * copy_siginfo_to_user32() code below needs to updated
49         * along with the size in the CHECK_SI_SIZE().
50         *
51         * We repeat this check for both the generic and compat
52         * siginfos.
53         *
54         * Note: it is OK for these to grow as long as the whole
55         * structure stays within the padding size (checked
56         * above).
57         */
58#define CHECK_CSI_SIZE(name, size) BUILD_BUG_ON(size != sizeof(((compat_siginfo_t *)0)->_sifields.name))
59#define CHECK_SI_SIZE(name, size) BUILD_BUG_ON(size != sizeof(((siginfo_t *)0)->_sifields.name))
60
61        CHECK_CSI_OFFSET(_kill);
62        CHECK_CSI_SIZE  (_kill, 2*sizeof(int));
63        CHECK_SI_SIZE   (_kill, 2*sizeof(int));
64
65        CHECK_CSI_OFFSET(_timer);
66        CHECK_CSI_SIZE  (_timer, 5*sizeof(int));
67        CHECK_SI_SIZE   (_timer, 6*sizeof(int));
68
69        CHECK_CSI_OFFSET(_rt);
70        CHECK_CSI_SIZE  (_rt, 3*sizeof(int));
71        CHECK_SI_SIZE   (_rt, 4*sizeof(int));
72
73        CHECK_CSI_OFFSET(_sigchld);
74        CHECK_CSI_SIZE  (_sigchld, 5*sizeof(int));
75        CHECK_SI_SIZE   (_sigchld, 8*sizeof(int));
76
77        CHECK_CSI_OFFSET(_sigchld_x32);
78        CHECK_CSI_SIZE  (_sigchld_x32, 7*sizeof(int));
79        /* no _sigchld_x32 in the generic siginfo_t */
80
81        CHECK_CSI_OFFSET(_sigfault);
82        CHECK_CSI_SIZE  (_sigfault, 4*sizeof(int));
83        CHECK_SI_SIZE   (_sigfault, 8*sizeof(int));
84
85        CHECK_CSI_OFFSET(_sigpoll);
86        CHECK_CSI_SIZE  (_sigpoll, 2*sizeof(int));
87        CHECK_SI_SIZE   (_sigpoll, 4*sizeof(int));
88
89        CHECK_CSI_OFFSET(_sigsys);
90        CHECK_CSI_SIZE  (_sigsys, 3*sizeof(int));
91        CHECK_SI_SIZE   (_sigsys, 4*sizeof(int));
92
93        /* any new si_fields should be added here */
94}
95
96void sigaction_compat_abi(struct k_sigaction *act, struct k_sigaction *oact)
97{
98        /* Don't leak in-kernel non-uapi flags to user-space */
99        if (oact)
100                oact->sa.sa_flags &= ~(SA_IA32_ABI | SA_X32_ABI);
101
102        if (!act)
103                return;
104
105        /* Don't let flags to be set from userspace */
106        act->sa.sa_flags &= ~(SA_IA32_ABI | SA_X32_ABI);
107
108        if (in_ia32_syscall())
109                act->sa.sa_flags |= SA_IA32_ABI;
110        if (in_x32_syscall())
111                act->sa.sa_flags |= SA_X32_ABI;
112}
113
114int __copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from,
115                bool x32_ABI)
116{
117        int err = 0;
118
119        signal_compat_build_tests();
120
121        if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
122                return -EFAULT;
123
124        put_user_try {
125                /* If you change siginfo_t structure, please make sure that
126                   this code is fixed accordingly.
127                   It should never copy any pad contained in the structure
128                   to avoid security leaks, but must copy the generic
129                   3 ints plus the relevant union member.  */
130                put_user_ex(from->si_signo, &to->si_signo);
131                put_user_ex(from->si_errno, &to->si_errno);
132                put_user_ex((short)from->si_code, &to->si_code);
133
134                if (from->si_code < 0) {
135                        put_user_ex(from->si_pid, &to->si_pid);
136                        put_user_ex(from->si_uid, &to->si_uid);
137                        put_user_ex(ptr_to_compat(from->si_ptr), &to->si_ptr);
138                } else {
139                        /*
140                         * First 32bits of unions are always present:
141                         * si_pid === si_band === si_tid === si_addr(LS half)
142                         */
143                        put_user_ex(from->_sifields._pad[0],
144                                          &to->_sifields._pad[0]);
145                        switch (from->si_code >> 16) {
146                        case __SI_FAULT >> 16:
147                                if (from->si_signo == SIGBUS &&
148                                    (from->si_code == BUS_MCEERR_AR ||
149                                     from->si_code == BUS_MCEERR_AO))
150                                        put_user_ex(from->si_addr_lsb, &to->si_addr_lsb);
151
152                                if (from->si_signo == SIGSEGV) {
153                                        if (from->si_code == SEGV_BNDERR) {
154                                                compat_uptr_t lower = (unsigned long)from->si_lower;
155                                                compat_uptr_t upper = (unsigned long)from->si_upper;
156                                                put_user_ex(lower, &to->si_lower);
157                                                put_user_ex(upper, &to->si_upper);
158                                        }
159                                        if (from->si_code == SEGV_PKUERR)
160                                                put_user_ex(from->si_pkey, &to->si_pkey);
161                                }
162                                break;
163                        case __SI_SYS >> 16:
164                                put_user_ex(from->si_syscall, &to->si_syscall);
165                                put_user_ex(from->si_arch, &to->si_arch);
166                                break;
167                        case __SI_CHLD >> 16:
168                                if (!x32_ABI) {
169                                        put_user_ex(from->si_utime, &to->si_utime);
170                                        put_user_ex(from->si_stime, &to->si_stime);
171                                } else {
172                                        put_user_ex(from->si_utime, &to->_sifields._sigchld_x32._utime);
173                                        put_user_ex(from->si_stime, &to->_sifields._sigchld_x32._stime);
174                                }
175                                put_user_ex(from->si_status, &to->si_status);
176                                /* FALL THROUGH */
177                        default:
178                        case __SI_KILL >> 16:
179                                put_user_ex(from->si_uid, &to->si_uid);
180                                break;
181                        case __SI_POLL >> 16:
182                                put_user_ex(from->si_fd, &to->si_fd);
183                                break;
184                        case __SI_TIMER >> 16:
185                                put_user_ex(from->si_overrun, &to->si_overrun);
186                                put_user_ex(ptr_to_compat(from->si_ptr),
187                                            &to->si_ptr);
188                                break;
189                                 /* This is not generated by the kernel as of now.  */
190                        case __SI_RT >> 16:
191                        case __SI_MESGQ >> 16:
192                                put_user_ex(from->si_uid, &to->si_uid);
193                                put_user_ex(from->si_int, &to->si_int);
194                                break;
195                        }
196                }
197        } put_user_catch(err);
198
199        return err;
200}
201
202/* from syscall's path, where we know the ABI */
203int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
204{
205        return __copy_siginfo_to_user32(to, from, in_x32_syscall());
206}
207
208int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
209{
210        int err = 0;
211        u32 ptr32;
212
213        if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t)))
214                return -EFAULT;
215
216        get_user_try {
217                get_user_ex(to->si_signo, &from->si_signo);
218                get_user_ex(to->si_errno, &from->si_errno);
219                get_user_ex(to->si_code, &from->si_code);
220
221                get_user_ex(to->si_pid, &from->si_pid);
222                get_user_ex(to->si_uid, &from->si_uid);
223                get_user_ex(ptr32, &from->si_ptr);
224                to->si_ptr = compat_ptr(ptr32);
225        } get_user_catch(err);
226
227        return err;
228}
Note: See TracBrowser for help on using the repository browser.