• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
signal_compat_build_tests(void)17 static 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 
sigaction_compat_abi(struct k_sigaction * act,struct k_sigaction * oact)96 void 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 
__copy_siginfo_to_user32(compat_siginfo_t __user * to,const siginfo_t * from,bool x32_ABI)114 int __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 */
copy_siginfo_to_user32(compat_siginfo_t __user * to,const siginfo_t * from)203 int 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 
copy_siginfo_from_user32(siginfo_t * to,compat_siginfo_t __user * from)208 int 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 }
229