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: | |
35 | break; | |
36 | case __SI_SYS >> 16: | |
37 | put_user_ex(from->si_syscall, &to->si_syscall); | |
38 | put_user_ex(from->si_arch, &to->si_arch); | |
39 | break; | |
40 | case __SI_CHLD >> 16: | |
41 | if (ia32) { | |
42 | put_user_ex(from->si_utime, &to->si_utime); | |
43 | put_user_ex(from->si_stime, &to->si_stime); | |
44 | } else { | |
45 | put_user_ex(from->si_utime, &to->_sifields._sigchld_x32._utime); | |
46 | put_user_ex(from->si_stime, &to->_sifields._sigchld_x32._stime); | |
47 | } | |
48 | put_user_ex(from->si_status, &to->si_status); | |
49 | /* FALL THROUGH */ | |
50 | default: | |
51 | case __SI_KILL >> 16: | |
52 | put_user_ex(from->si_uid, &to->si_uid); | |
53 | break; | |
54 | case __SI_POLL >> 16: | |
55 | put_user_ex(from->si_fd, &to->si_fd); | |
56 | break; | |
57 | case __SI_TIMER >> 16: | |
58 | put_user_ex(from->si_overrun, &to->si_overrun); | |
59 | put_user_ex(ptr_to_compat(from->si_ptr), | |
60 | &to->si_ptr); | |
61 | break; | |
62 | /* This is not generated by the kernel as of now. */ | |
63 | case __SI_RT >> 16: | |
64 | case __SI_MESGQ >> 16: | |
65 | put_user_ex(from->si_uid, &to->si_uid); | |
66 | put_user_ex(from->si_int, &to->si_int); | |
67 | break; | |
68 | } | |
69 | } | |
70 | } put_user_catch(err); | |
71 | ||
72 | return err; | |
73 | } | |
74 | ||
75 | int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) | |
76 | { | |
77 | int err = 0; | |
78 | u32 ptr32; | |
79 | ||
80 | if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t))) | |
81 | return -EFAULT; | |
82 | ||
83 | get_user_try { | |
84 | get_user_ex(to->si_signo, &from->si_signo); | |
85 | get_user_ex(to->si_errno, &from->si_errno); | |
86 | get_user_ex(to->si_code, &from->si_code); | |
87 | ||
88 | get_user_ex(to->si_pid, &from->si_pid); | |
89 | get_user_ex(to->si_uid, &from->si_uid); | |
90 | get_user_ex(ptr32, &from->si_ptr); | |
91 | to->si_ptr = compat_ptr(ptr32); | |
92 | } get_user_catch(err); | |
93 | ||
94 | return err; | |
95 | } |