]>
Commit | Line | Data |
---|---|---|
c0bfd26e BG |
1 | #include <linux/compat.h> |
2 | #include <linux/uaccess.h> | |
3 | ||
4 | int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) | |
5 | { | |
6 | int err = 0; | |
7 | bool ia32 = test_thread_flag(TIF_IA32); | |
8 | ||
9 | if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t))) | |
10 | return -EFAULT; | |
11 | ||
12 | put_user_try { | |
13 | /* If you change siginfo_t structure, please make sure that | |
14 | this code is fixed accordingly. | |
15 | It should never copy any pad contained in the structure | |
16 | to avoid security leaks, but must copy the generic | |
17 | 3 ints plus the relevant union member. */ | |
18 | put_user_ex(from->si_signo, &to->si_signo); | |
19 | put_user_ex(from->si_errno, &to->si_errno); | |
20 | put_user_ex((short)from->si_code, &to->si_code); | |
21 | ||
22 | if (from->si_code < 0) { | |
23 | put_user_ex(from->si_pid, &to->si_pid); | |
24 | put_user_ex(from->si_uid, &to->si_uid); | |
25 | put_user_ex(ptr_to_compat(from->si_ptr), &to->si_ptr); | |
26 | } else { | |
27 | /* | |
28 | * First 32bits of unions are always present: | |
29 | * si_pid === si_band === si_tid === si_addr(LS half) | |
30 | */ | |
31 | put_user_ex(from->_sifields._pad[0], | |
32 | &to->_sifields._pad[0]); | |
33 | switch (from->si_code >> 16) { | |
34 | case __SI_FAULT >> 16: | |
a4455082 DH |
35 | if (from->si_signo == SIGBUS && |
36 | (from->si_code == BUS_MCEERR_AR || | |
37 | from->si_code == BUS_MCEERR_AO)) | |
38 | put_user_ex(from->si_addr_lsb, &to->si_addr_lsb); | |
39 | ||
40 | if (from->si_signo == SIGSEGV) { | |
41 | if (from->si_code == SEGV_BNDERR) { | |
42 | compat_uptr_t lower = (unsigned long)&to->si_lower; | |
43 | compat_uptr_t upper = (unsigned long)&to->si_upper; | |
44 | put_user_ex(lower, &to->si_lower); | |
45 | put_user_ex(upper, &to->si_upper); | |
46 | } | |
47 | if (from->si_code == SEGV_PKUERR) | |
48 | put_user_ex(from->si_pkey, &to->si_pkey); | |
49 | } | |
c0bfd26e BG |
50 | break; |
51 | case __SI_SYS >> 16: | |
52 | put_user_ex(from->si_syscall, &to->si_syscall); | |
53 | put_user_ex(from->si_arch, &to->si_arch); | |
54 | break; | |
55 | case __SI_CHLD >> 16: | |
56 | if (ia32) { | |
57 | put_user_ex(from->si_utime, &to->si_utime); | |
58 | put_user_ex(from->si_stime, &to->si_stime); | |
59 | } else { | |
60 | put_user_ex(from->si_utime, &to->_sifields._sigchld_x32._utime); | |
61 | put_user_ex(from->si_stime, &to->_sifields._sigchld_x32._stime); | |
62 | } | |
63 | put_user_ex(from->si_status, &to->si_status); | |
64 | /* FALL THROUGH */ | |
65 | default: | |
66 | case __SI_KILL >> 16: | |
67 | put_user_ex(from->si_uid, &to->si_uid); | |
68 | break; | |
69 | case __SI_POLL >> 16: | |
70 | put_user_ex(from->si_fd, &to->si_fd); | |
71 | break; | |
72 | case __SI_TIMER >> 16: | |
73 | put_user_ex(from->si_overrun, &to->si_overrun); | |
74 | put_user_ex(ptr_to_compat(from->si_ptr), | |
75 | &to->si_ptr); | |
76 | break; | |
77 | /* This is not generated by the kernel as of now. */ | |
78 | case __SI_RT >> 16: | |
79 | case __SI_MESGQ >> 16: | |
80 | put_user_ex(from->si_uid, &to->si_uid); | |
81 | put_user_ex(from->si_int, &to->si_int); | |
82 | break; | |
83 | } | |
84 | } | |
85 | } put_user_catch(err); | |
86 | ||
87 | return err; | |
88 | } | |
89 | ||
90 | int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) | |
91 | { | |
92 | int err = 0; | |
93 | u32 ptr32; | |
94 | ||
95 | if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t))) | |
96 | return -EFAULT; | |
97 | ||
98 | get_user_try { | |
99 | get_user_ex(to->si_signo, &from->si_signo); | |
100 | get_user_ex(to->si_errno, &from->si_errno); | |
101 | get_user_ex(to->si_code, &from->si_code); | |
102 | ||
103 | get_user_ex(to->si_pid, &from->si_pid); | |
104 | get_user_ex(to->si_uid, &from->si_uid); | |
105 | get_user_ex(ptr32, &from->si_ptr); | |
106 | to->si_ptr = compat_ptr(ptr32); | |
107 | } get_user_catch(err); | |
108 | ||
109 | return err; | |
110 | } |