1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2015, Joyent, Inc.
14 */
15
16 #include <sys/types.h>
17 #include <sys/sunddi.h>
18 #include <sys/proc.h>
19 #include <sys/procfs.h>
20 #include <sys/sysmacros.h>
21 #include <vm/as.h>
22
23 /*
24 * Safely read a contiguous region of memory from 'addr' in the address space
25 * of a particular process into the supplied kernel buffer (*buf, sz).
26 * Partially mapped regions will result in a partial read terminating at the
27 * first hole in the address space. The number of bytes actually read is
28 * returned to the caller via 'rdsz'.
29 */
30 int
31 prreadbuf(proc_t *p, uintptr_t ustart, uint8_t *buf, size_t sz, size_t *rdsz)
32 {
33 int error = 0;
34 size_t rem = sz;
35 off_t pos = 0;
36
37 if (rdsz != NULL)
38 *rdsz = 0;
39
40 while (rem != 0) {
41 uintptr_t addr = ustart + pos;
42 size_t len = MIN(rem, PAGESIZE - (addr & PAGEOFFSET));
43
44 if ((error = uread(p, buf + pos, len, addr)) != 0) {
45 if (error == ENXIO) {
46 /*
47 * ENXIO from uread() indicates that the page
48 * does not exist. This will simply be a
49 * partial read.
50 */
51 error = 0;
52 }
53 break;
54 }
55
56 rem -= len;
57 pos += len;
58 }
59
60 if (rdsz != NULL)
61 *rdsz = pos;
62
63 return (error);
64 }
65
66 /*
67 * Attempt to read the argument vector (argv) from this process. The caller
68 * must hold the p_lock mutex, and have marked the process P_PR_LOCK (e.g. via
69 * prlock or lx_prlock).
70 *
71 * The caller must provide a buffer (buf, buflen). We will concatenate each
72 * argument string (including the NUL terminator) into this buffer. The number
73 * of characters written to this buffer (including the final NUL terminator)
74 * will be stored in 'slen'.
75 */
76 int
77 prreadargv(proc_t *p, char *buf, size_t bufsz, size_t *slen)
78 {
79 int error;
80 user_t *up;
81 struct as *as;
82 size_t pos = 0;
83 caddr_t *argv = NULL;
84 size_t argvsz = 0;
85 int i;
86
87 VERIFY(MUTEX_HELD(&p->p_lock));
88 VERIFY(p->p_proc_flag & P_PR_LOCK);
89
90 up = PTOU(p);
91 as = p->p_as;
92
93 if ((p->p_flag & SSYS) || as == &kas || up->u_argv == NULL) {
94 /*
95 * Return the regular psargs string to the caller.
96 */
97 bcopy(up->u_psargs, buf, MIN(bufsz, sizeof (up->u_psargs)));
98 buf[bufsz - 1] = '\0';
99 *slen = strlen(buf) + 1;
100
101 return (0);
102 }
103
104 /*
105 * Allocate space to store argv array.
106 */
107 argvsz = up->u_argc * (p->p_model == DATAMODEL_ILP32 ?
108 sizeof (caddr32_t) : sizeof (caddr_t));
109 argv = kmem_alloc(argvsz, KM_SLEEP);
110
111 /*
112 * Extract the argv array from the target process. Drop p_lock
113 * while we do I/O to avoid deadlock with the clock thread.
114 */
115 mutex_exit(&p->p_lock);
116 if ((error = prreadbuf(p, up->u_argv, (uint8_t *)argv, argvsz,
117 NULL)) != 0) {
118 kmem_free(argv, argvsz);
119 mutex_enter(&p->p_lock);
120 VERIFY(p->p_proc_flag & P_PR_LOCK);
121 return (-1);
122 }
123
124 /*
125 * Read each argument string from the pointers in the argv array.
126 */
127 pos = 0;
128 for (i = 0; i < up->u_argc; i++) {
129 size_t rdsz, trysz;
130 uintptr_t arg;
131 off_t j;
132 boolean_t found_nul;
133 boolean_t do_retry = B_TRUE;
134
135 #ifdef _SYSCALL32_IMPL
136 if (p->p_model == DATAMODEL_ILP32) {
137 arg = (uintptr_t)((caddr32_t *)argv)[i];
138 } else {
139 arg = (uintptr_t)argv[i];
140 }
141 #else
142 arg = (uintptr_t)argv[i];
143 #endif
144
145 /*
146 * Stop trying to read arguments if we reach a NULL
147 * pointer in the vector.
148 */
149 if (arg == NULL)
150 break;
151
152 /*
153 * Stop reading if we have read the maximum length
154 * we can return to the user.
155 */
156 if (pos >= bufsz)
157 break;
158
159 /*
160 * Initially we try a short read, on the assumption that
161 * most individual argument strings are less than 80
162 * characters long.
163 */
164 if ((trysz = MIN(80, bufsz - pos - 1)) < 80) {
165 /*
166 * We don't have room in the target buffer for even
167 * an entire short read, so there is no need to retry
168 * with a longer read.
169 */
170 do_retry = B_FALSE;
171 }
172
173 retry:
174 /*
175 * Read string data for this argument. Leave room
176 * in the buffer for a final NUL terminator.
177 */
178 if ((error = prreadbuf(p, arg, (uint8_t *)&buf[pos], trysz,
179 &rdsz)) != 0) {
180 /*
181 * There was a problem reading this string
182 * from the process. Give up.
183 */
184 break;
185 }
186
187 /*
188 * Find the NUL terminator.
189 */
190 found_nul = B_FALSE;
191 for (j = 0; j < rdsz; j++) {
192 if (buf[pos + j] == '\0') {
193 found_nul = B_TRUE;
194 break;
195 }
196 }
197
198 if (!found_nul && do_retry) {
199 /*
200 * We did not find a NUL terminator, but this
201 * was a first pass short read. Try once more
202 * with feeling.
203 */
204 trysz = bufsz - pos - 1;
205 do_retry = B_FALSE;
206 goto retry;
207 }
208
209 /*
210 * Commit the string we read to the buffer.
211 */
212 pos += j + 1;
213 if (!found_nul && pos < bufsz) {
214 /*
215 * A NUL terminator was not found; add one.
216 */
217 buf[pos++] = '\0';
218 }
219 }
220
221 /*
222 * Ensure the entire string is NUL-terminated.
223 */
224 buf[bufsz - 1] = '\0';
225
226 mutex_enter(&p->p_lock);
227 VERIFY(p->p_proc_flag & P_PR_LOCK);
228 kmem_free(argv, argvsz);
229
230 /*
231 * If the operation was a success, return the copied string length
232 * to the caller.
233 */
234 *slen = (error == 0) ? pos : 0;
235
236 return (error);
237 }
238
239 /*
240 * Similar to prreadargv except reads the env vector. This is slightly more
241 * complex because there is no count for the env vector that corresponds to
242 * u_argc.
243 */
244 int
245 prreadenvv(proc_t *p, char *buf, size_t bufsz, size_t *slen)
246 {
247 int error;
248 user_t *up;
249 struct as *as;
250 size_t pos = 0;
251 caddr_t *envp = NULL;
252 uintptr_t tmpp = NULL;
253 size_t envpsz = 0, rdsz = 0;
254 int i;
255 int cnt, bound;
256
257 VERIFY(MUTEX_HELD(&p->p_lock));
258 VERIFY(p->p_proc_flag & P_PR_LOCK);
259
260 up = PTOU(p);
261 as = p->p_as;
262
263 if ((p->p_flag & SSYS) || as == &kas || up->u_envp == NULL) {
264 /*
265 * Return empty string.
266 */
267 buf[0] = '\0';
268 *slen = 1;
269
270 return (0);
271 }
272
273 /*
274 * Drop p_lock while we do I/O to avoid deadlock with the clock thread.
275 */
276 mutex_exit(&p->p_lock);
277
278 /*
279 * We first have to count how many env entries we have. This is
280 * somewhat painful. We extract the env entries from the target process
281 * one entry at a time. Stop trying to read env entries if we reach a
282 * NULL pointer in the vector or hit our upper bound (which we take
283 * as the bufsz/4) to ensure we don't run off.
284 */
285 rdsz = (p->p_model == DATAMODEL_ILP32 ?
286 sizeof (caddr32_t) : sizeof (caddr_t));
287 bound = (int)(bufsz / 4);
288 for (cnt = 0, tmpp = up->u_envp; cnt < bound; cnt++, tmpp += rdsz) {
289 caddr_t tmp = NULL;
290
291 if ((error = prreadbuf(p, tmpp, (uint8_t *)&tmp, rdsz,
292 NULL)) != 0) {
293 mutex_enter(&p->p_lock);
294 VERIFY(p->p_proc_flag & P_PR_LOCK);
295 return (-1);
296 }
297
298 if (tmp == NULL)
299 break;
300 }
301 if (cnt == 0) {
302 /* Return empty string. */
303 buf[0] = '\0';
304 *slen = 1;
305 mutex_enter(&p->p_lock);
306 VERIFY(p->p_proc_flag & P_PR_LOCK);
307 return (0);
308 }
309
310 /*
311 * Allocate space to store env array.
312 */
313 envpsz = cnt * (p->p_model == DATAMODEL_ILP32 ?
314 sizeof (caddr32_t) : sizeof (caddr_t));
315 envp = kmem_alloc(envpsz, KM_SLEEP);
316
317 /*
318 * Extract the env array from the target process.
319 */
320 if ((error = prreadbuf(p, up->u_envp, (uint8_t *)envp, envpsz,
321 NULL)) != 0) {
322 kmem_free(envp, envpsz);
323 mutex_enter(&p->p_lock);
324 VERIFY(p->p_proc_flag & P_PR_LOCK);
325 return (-1);
326 }
327
328 /*
329 * Read each env string from the pointers in the env array.
330 */
331 pos = 0;
332 for (i = 0; i < cnt; i++) {
333 size_t rdsz, trysz;
334 uintptr_t ev;
335 off_t j;
336 boolean_t found_nul;
337 boolean_t do_retry = B_TRUE;
338
339 #ifdef _SYSCALL32_IMPL
340 if (p->p_model == DATAMODEL_ILP32) {
341 ev = (uintptr_t)((caddr32_t *)envp)[i];
342 } else {
343 ev = (uintptr_t)envp[i];
344 }
345 #else
346 ev = (uintptr_t)envp[i];
347 #endif
348
349 /*
350 * Stop trying to read env entries if we reach a NULL
351 * pointer in the vector.
352 */
353 if (ev == NULL)
354 break;
355
356 /*
357 * Stop reading if we have read the maximum length
358 * we can return to the user.
359 */
360 if (pos >= bufsz)
361 break;
362
363 /*
364 * Initially we try a short read, on the assumption that
365 * most individual env strings are less than 80
366 * characters long.
367 */
368 if ((trysz = MIN(80, bufsz - pos - 1)) < 80) {
369 /*
370 * We don't have room in the target buffer for even
371 * an entire short read, so there is no need to retry
372 * with a longer read.
373 */
374 do_retry = B_FALSE;
375 }
376
377 retry:
378 /*
379 * Read string data for this env var. Leave room
380 * in the buffer for a final NUL terminator.
381 */
382 if ((error = prreadbuf(p, ev, (uint8_t *)&buf[pos], trysz,
383 &rdsz)) != 0) {
384 /*
385 * There was a problem reading this string
386 * from the process. Give up.
387 */
388 break;
389 }
390
391 /*
392 * Find the NUL terminator.
393 */
394 found_nul = B_FALSE;
395 for (j = 0; j < rdsz; j++) {
396 if (buf[pos + j] == '\0') {
397 found_nul = B_TRUE;
398 break;
399 }
400 }
401
402 if (!found_nul && do_retry) {
403 /*
404 * We did not find a NUL terminator, but this
405 * was a first pass short read. Try once more
406 * with feeling.
407 */
408 trysz = bufsz - pos - 1;
409 do_retry = B_FALSE;
410 goto retry;
411 }
412
413 /*
414 * Commit the string we read to the buffer.
415 */
416 pos += j + 1;
417 if (!found_nul && pos < bufsz) {
418 /*
419 * A NUL terminator was not found; add one.
420 */
421 buf[pos++] = '\0';
422 }
423 }
424
425 /*
426 * Ensure the entire string is NUL-terminated.
427 */
428 buf[bufsz - 1] = '\0';
429
430 mutex_enter(&p->p_lock);
431 VERIFY(p->p_proc_flag & P_PR_LOCK);
432 kmem_free(envp, envpsz);
433
434 /*
435 * If the operation was a success, return the copied string length
436 * to the caller.
437 */
438 *slen = (error == 0) ? pos : 0;
439
440 return (error);
441 }