aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2006-01-08 04:02:33 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-08 23:13:51 -0500
commit6b9c7ed84837753a436415097063232422e29a35 (patch)
tree6ad59a7bebcec359e08b3a211701781db819450d
parent6b34350f490b2c8508717541ec1fd2bbaadded94 (diff)
[PATCH] use ptrace_get_task_struct in various places
The ptrace_get_task_struct() helper that I added as part of the ptrace consolidation is useful in variety of places that currently opencode it. Switch them to the common helpers. Add a ptrace_traceme() helper that needs to be explicitly called, and simplify the ptrace_get_task_struct() interface. We don't need the request argument now, and we return the task_struct directly, using ERR_PTR() for error returns. It's a bit more code in the callers, but we have two sane routines that do one thing well now. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--arch/alpha/kernel/ptrace.c24
-rw-r--r--arch/ia64/ia32/sys_ia32.c16
-rw-r--r--arch/ia64/kernel/ptrace.c9
-rw-r--r--arch/m32r/kernel/ptrace.c22
-rw-r--r--arch/mips/kernel/ptrace32.c26
-rw-r--r--arch/powerpc/kernel/ptrace32.c28
-rw-r--r--arch/s390/kernel/ptrace.c29
-rw-r--r--arch/sparc/kernel/ptrace.c35
-rw-r--r--arch/sparc64/kernel/ptrace.c34
-rw-r--r--arch/x86_64/ia32/ptrace32.c44
-rw-r--r--include/linux/ptrace.h2
-rw-r--r--kernel/ptrace.c77
12 files changed, 105 insertions, 241 deletions
diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c
index bbd37536d14e..9969d212e94d 100644
--- a/arch/alpha/kernel/ptrace.c
+++ b/arch/alpha/kernel/ptrace.c
@@ -265,30 +265,16 @@ do_sys_ptrace(long request, long pid, long addr, long data,
265 lock_kernel(); 265 lock_kernel();
266 DBG(DBG_MEM, ("request=%ld pid=%ld addr=0x%lx data=0x%lx\n", 266 DBG(DBG_MEM, ("request=%ld pid=%ld addr=0x%lx data=0x%lx\n",
267 request, pid, addr, data)); 267 request, pid, addr, data));
268 ret = -EPERM;
269 if (request == PTRACE_TRACEME) { 268 if (request == PTRACE_TRACEME) {
270 /* are we already being traced? */ 269 ret = ptrace_traceme();
271 if (current->ptrace & PT_PTRACED)
272 goto out_notsk;
273 ret = security_ptrace(current->parent, current);
274 if (ret)
275 goto out_notsk;
276 /* set the ptrace bit in the process ptrace flags. */
277 current->ptrace |= PT_PTRACED;
278 ret = 0;
279 goto out_notsk; 270 goto out_notsk;
280 } 271 }
281 if (pid == 1) /* you may not mess with init */
282 goto out_notsk;
283 272
284 ret = -ESRCH; 273 child = ptrace_get_task_struct(pid);
285 read_lock(&tasklist_lock); 274 if (IS_ERR(child)) {
286 child = find_task_by_pid(pid); 275 ret = PTR_ERR(child);
287 if (child)
288 get_task_struct(child);
289 read_unlock(&tasklist_lock);
290 if (!child)
291 goto out_notsk; 276 goto out_notsk;
277 }
292 278
293 if (request == PTRACE_ATTACH) { 279 if (request == PTRACE_ATTACH) {
294 ret = ptrace_attach(child); 280 ret = ptrace_attach(child);
diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
index dc282710421a..9f8e8d558873 100644
--- a/arch/ia64/ia32/sys_ia32.c
+++ b/arch/ia64/ia32/sys_ia32.c
@@ -1761,21 +1761,15 @@ sys32_ptrace (int request, pid_t pid, unsigned int addr, unsigned int data)
1761 1761
1762 lock_kernel(); 1762 lock_kernel();
1763 if (request == PTRACE_TRACEME) { 1763 if (request == PTRACE_TRACEME) {
1764 ret = sys_ptrace(request, pid, addr, data); 1764 ret = ptrace_traceme();
1765 goto out; 1765 goto out;
1766 } 1766 }
1767 1767
1768 ret = -ESRCH; 1768 child = ptrace_get_task_struct(pid);
1769 read_lock(&tasklist_lock); 1769 if (IS_ERR(child)) {
1770 child = find_task_by_pid(pid); 1770 ret = PTR_ERR(child);
1771 if (child)
1772 get_task_struct(child);
1773 read_unlock(&tasklist_lock);
1774 if (!child)
1775 goto out; 1771 goto out;
1776 ret = -EPERM; 1772 }
1777 if (pid == 1) /* no messing around with init! */
1778 goto out_tsk;
1779 1773
1780 if (request == PTRACE_ATTACH) { 1774 if (request == PTRACE_ATTACH) {
1781 ret = sys_ptrace(request, pid, addr, data); 1775 ret = sys_ptrace(request, pid, addr, data);
diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c
index 4b19d0410632..8d88eeea02d1 100644
--- a/arch/ia64/kernel/ptrace.c
+++ b/arch/ia64/kernel/ptrace.c
@@ -1422,14 +1422,7 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data)
1422 lock_kernel(); 1422 lock_kernel();
1423 ret = -EPERM; 1423 ret = -EPERM;
1424 if (request == PTRACE_TRACEME) { 1424 if (request == PTRACE_TRACEME) {
1425 /* are we already being traced? */ 1425 ret = ptrace_traceme();
1426 if (current->ptrace & PT_PTRACED)
1427 goto out;
1428 ret = security_ptrace(current->parent, current);
1429 if (ret)
1430 goto out;
1431 current->ptrace |= PT_PTRACED;
1432 ret = 0;
1433 goto out; 1426 goto out;
1434 } 1427 }
1435 1428
diff --git a/arch/m32r/kernel/ptrace.c b/arch/m32r/kernel/ptrace.c
index 078d2a0e71c2..9b75caaf5cec 100644
--- a/arch/m32r/kernel/ptrace.c
+++ b/arch/m32r/kernel/ptrace.c
@@ -762,28 +762,16 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
762 int ret; 762 int ret;
763 763
764 lock_kernel(); 764 lock_kernel();
765 ret = -EPERM;
766 if (request == PTRACE_TRACEME) { 765 if (request == PTRACE_TRACEME) {
767 /* are we already being traced? */ 766 ret = ptrace_traceme();
768 if (current->ptrace & PT_PTRACED)
769 goto out;
770 /* set the ptrace bit in the process flags. */
771 current->ptrace |= PT_PTRACED;
772 ret = 0;
773 goto out; 767 goto out;
774 } 768 }
775 ret = -ESRCH;
776 read_lock(&tasklist_lock);
777 child = find_task_by_pid(pid);
778 if (child)
779 get_task_struct(child);
780 read_unlock(&tasklist_lock);
781 if (!child)
782 goto out;
783 769
784 ret = -EPERM; 770 child = ptrace_get_task_struct(pid);
785 if (pid == 1) /* you may not mess with init */ 771 if (IS_ERR(child)) {
772 ret = PTR_ERR(child);
786 goto out; 773 goto out;
774 }
787 775
788 if (request == PTRACE_ATTACH) { 776 if (request == PTRACE_ATTACH) {
789 ret = ptrace_attach(child); 777 ret = ptrace_attach(child);
diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c
index 9a9b04972132..7e55457a491f 100644
--- a/arch/mips/kernel/ptrace32.c
+++ b/arch/mips/kernel/ptrace32.c
@@ -57,30 +57,16 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data)
57 (unsigned long) data); 57 (unsigned long) data);
58#endif 58#endif
59 lock_kernel(); 59 lock_kernel();
60 ret = -EPERM;
61 if (request == PTRACE_TRACEME) { 60 if (request == PTRACE_TRACEME) {
62 /* are we already being traced? */ 61 ret = ptrace_traceme();
63 if (current->ptrace & PT_PTRACED)
64 goto out;
65 if ((ret = security_ptrace(current->parent, current)))
66 goto out;
67 /* set the ptrace bit in the process flags. */
68 current->ptrace |= PT_PTRACED;
69 ret = 0;
70 goto out; 62 goto out;
71 } 63 }
72 ret = -ESRCH;
73 read_lock(&tasklist_lock);
74 child = find_task_by_pid(pid);
75 if (child)
76 get_task_struct(child);
77 read_unlock(&tasklist_lock);
78 if (!child)
79 goto out;
80 64
81 ret = -EPERM; 65 child = ptrace_get_task_struct(pid);
82 if (pid == 1) /* you may not mess with init */ 66 if (IS_ERR(child)) {
83 goto out_tsk; 67 ret = PTR_ERR(child);
68 goto out;
69 }
84 70
85 if (request == PTRACE_ATTACH) { 71 if (request == PTRACE_ATTACH) {
86 ret = ptrace_attach(child); 72 ret = ptrace_attach(child);
diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c
index 61762640b877..826ee3d056de 100644
--- a/arch/powerpc/kernel/ptrace32.c
+++ b/arch/powerpc/kernel/ptrace32.c
@@ -45,33 +45,19 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
45 unsigned long data) 45 unsigned long data)
46{ 46{
47 struct task_struct *child; 47 struct task_struct *child;
48 int ret = -EPERM; 48 int ret;
49 49
50 lock_kernel(); 50 lock_kernel();
51 if (request == PTRACE_TRACEME) { 51 if (request == PTRACE_TRACEME) {
52 /* are we already being traced? */ 52 ret = ptrace_traceme();
53 if (current->ptrace & PT_PTRACED)
54 goto out;
55 ret = security_ptrace(current->parent, current);
56 if (ret)
57 goto out;
58 /* set the ptrace bit in the process flags. */
59 current->ptrace |= PT_PTRACED;
60 ret = 0;
61 goto out; 53 goto out;
62 } 54 }
63 ret = -ESRCH;
64 read_lock(&tasklist_lock);
65 child = find_task_by_pid(pid);
66 if (child)
67 get_task_struct(child);
68 read_unlock(&tasklist_lock);
69 if (!child)
70 goto out;
71 55
72 ret = -EPERM; 56 child = ptrace_get_task_struct(pid);
73 if (pid == 1) /* you may not mess with init */ 57 if (IS_ERR(child)) {
74 goto out_tsk; 58 ret = PTR_ERR(child);
59 goto out;
60 }
75 61
76 if (request == PTRACE_ATTACH) { 62 if (request == PTRACE_ATTACH) {
77 ret = ptrace_attach(child); 63 ret = ptrace_attach(child);
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index 8ecda6d66de4..cc02232aa96e 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -712,35 +712,18 @@ sys_ptrace(long request, long pid, long addr, long data)
712 int ret; 712 int ret;
713 713
714 lock_kernel(); 714 lock_kernel();
715
716 if (request == PTRACE_TRACEME) { 715 if (request == PTRACE_TRACEME) {
717 /* are we already being traced? */ 716 ret = ptrace_traceme();
718 ret = -EPERM; 717 goto out;
719 if (current->ptrace & PT_PTRACED)
720 goto out;
721 ret = security_ptrace(current->parent, current);
722 if (ret)
723 goto out;
724 /* set the ptrace bit in the process flags. */
725 current->ptrace |= PT_PTRACED;
726 goto out;
727 } 718 }
728 719
729 ret = -EPERM; 720 child = ptrace_get_task_struct(pid);
730 if (pid == 1) /* you may not mess with init */ 721 if (IS_ERR(child)) {
731 goto out; 722 ret = PTR_ERR(child);
732
733 ret = -ESRCH;
734 read_lock(&tasklist_lock);
735 child = find_task_by_pid(pid);
736 if (child)
737 get_task_struct(child);
738 read_unlock(&tasklist_lock);
739 if (!child)
740 goto out; 723 goto out;
724 }
741 725
742 ret = do_ptrace(child, request, addr, data); 726 ret = do_ptrace(child, request, addr, data);
743
744 put_task_struct(child); 727 put_task_struct(child);
745out: 728out:
746 unlock_kernel(); 729 unlock_kernel();
diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c
index 475c4c13462c..fc470c0e9dc6 100644
--- a/arch/sparc/kernel/ptrace.c
+++ b/arch/sparc/kernel/ptrace.c
@@ -286,40 +286,17 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
286 s, (int) request, (int) pid, addr, data, addr2); 286 s, (int) request, (int) pid, addr, data, addr2);
287 } 287 }
288#endif 288#endif
289 if (request == PTRACE_TRACEME) {
290 int my_ret;
291
292 /* are we already being traced? */
293 if (current->ptrace & PT_PTRACED) {
294 pt_error_return(regs, EPERM);
295 goto out;
296 }
297 my_ret = security_ptrace(current->parent, current);
298 if (my_ret) {
299 pt_error_return(regs, -my_ret);
300 goto out;
301 }
302 289
303 /* set the ptrace bit in the process flags. */ 290 if (request == PTRACE_TRACEME) {
304 current->ptrace |= PT_PTRACED; 291 ret = ptrace_traceme();
305 pt_succ_return(regs, 0); 292 pt_succ_return(regs, 0);
306 goto out; 293 goto out;
307 } 294 }
308#ifndef ALLOW_INIT_TRACING
309 if (pid == 1) {
310 /* Can't dork with init. */
311 pt_error_return(regs, EPERM);
312 goto out;
313 }
314#endif
315 read_lock(&tasklist_lock);
316 child = find_task_by_pid(pid);
317 if (child)
318 get_task_struct(child);
319 read_unlock(&tasklist_lock);
320 295
321 if (!child) { 296 child = ptrace_get_task_struct(pid);
322 pt_error_return(regs, ESRCH); 297 if (IS_ERR(child)) {
298 ret = PTR_ERR(child);
299 pt_error_return(regs, -ret);
323 goto out; 300 goto out;
324 } 301 }
325 302
diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c
index 774ecbb8a031..84d3df2264cb 100644
--- a/arch/sparc64/kernel/ptrace.c
+++ b/arch/sparc64/kernel/ptrace.c
@@ -198,39 +198,15 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
198 } 198 }
199#endif 199#endif
200 if (request == PTRACE_TRACEME) { 200 if (request == PTRACE_TRACEME) {
201 int ret; 201 ret = ptrace_traceme();
202
203 /* are we already being traced? */
204 if (current->ptrace & PT_PTRACED) {
205 pt_error_return(regs, EPERM);
206 goto out;
207 }
208 ret = security_ptrace(current->parent, current);
209 if (ret) {
210 pt_error_return(regs, -ret);
211 goto out;
212 }
213
214 /* set the ptrace bit in the process flags. */
215 current->ptrace |= PT_PTRACED;
216 pt_succ_return(regs, 0); 202 pt_succ_return(regs, 0);
217 goto out; 203 goto out;
218 } 204 }
219#ifndef ALLOW_INIT_TRACING
220 if (pid == 1) {
221 /* Can't dork with init. */
222 pt_error_return(regs, EPERM);
223 goto out;
224 }
225#endif
226 read_lock(&tasklist_lock);
227 child = find_task_by_pid(pid);
228 if (child)
229 get_task_struct(child);
230 read_unlock(&tasklist_lock);
231 205
232 if (!child) { 206 child = ptrace_get_task_struct(pid);
233 pt_error_return(regs, ESRCH); 207 if (IS_ERR(child)) {
208 ret = PTR_ERR(child);
209 pt_error_return(regs, -ret);
234 goto out; 210 goto out;
235 } 211 }
236 212
diff --git a/arch/x86_64/ia32/ptrace32.c b/arch/x86_64/ia32/ptrace32.c
index 2a925e2af390..5f4cdfa56901 100644
--- a/arch/x86_64/ia32/ptrace32.c
+++ b/arch/x86_64/ia32/ptrace32.c
@@ -196,36 +196,6 @@ static int getreg32(struct task_struct *child, unsigned regno, u32 *val)
196 196
197#undef R32 197#undef R32
198 198
199static struct task_struct *find_target(int request, int pid, int *err)
200{
201 struct task_struct *child;
202
203 *err = -EPERM;
204 if (pid == 1)
205 return NULL;
206
207 *err = -ESRCH;
208 read_lock(&tasklist_lock);
209 child = find_task_by_pid(pid);
210 if (child)
211 get_task_struct(child);
212 read_unlock(&tasklist_lock);
213 if (child) {
214 *err = -EPERM;
215 if (child->pid == 1)
216 goto out;
217 *err = ptrace_check_attach(child, request == PTRACE_KILL);
218 if (*err < 0)
219 goto out;
220 return child;
221 }
222 out:
223 if (child)
224 put_task_struct(child);
225 return NULL;
226
227}
228
229asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data) 199asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
230{ 200{
231 struct task_struct *child; 201 struct task_struct *child;
@@ -254,9 +224,16 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
254 break; 224 break;
255 } 225 }
256 226
257 child = find_target(request, pid, &ret); 227 if (request == PTRACE_TRACEME)
258 if (!child) 228 return ptrace_traceme();
259 return ret; 229
230 child = ptrace_get_task_struct(pid);
231 if (IS_ERR(child))
232 return PTR_ERR(child);
233
234 ret = ptrace_check_attach(child, request == PTRACE_KILL);
235 if (ret < 0)
236 goto out;
260 237
261 childregs = (struct pt_regs *)(child->thread.rsp0 - sizeof(struct pt_regs)); 238 childregs = (struct pt_regs *)(child->thread.rsp0 - sizeof(struct pt_regs));
262 239
@@ -373,6 +350,7 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
373 break; 350 break;
374 } 351 }
375 352
353 out:
376 put_task_struct(child); 354 put_task_struct(child);
377 return ret; 355 return ret;
378} 356}
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index b2b3dba1298d..864791996b5f 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -80,6 +80,8 @@
80 80
81 81
82extern long arch_ptrace(struct task_struct *child, long request, long addr, long data); 82extern long arch_ptrace(struct task_struct *child, long request, long addr, long data);
83extern struct task_struct *ptrace_get_task_struct(pid_t pid);
84extern int ptrace_traceme(void);
83extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len); 85extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len);
84extern int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len); 86extern int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len);
85extern int ptrace_attach(struct task_struct *tsk); 87extern int ptrace_attach(struct task_struct *tsk);
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 656476eedb1b..cceaf09ac413 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -408,54 +408,62 @@ int ptrace_request(struct task_struct *child, long request,
408 return ret; 408 return ret;
409} 409}
410 410
411#ifndef __ARCH_SYS_PTRACE 411/**
412static int ptrace_get_task_struct(long request, long pid, 412 * ptrace_traceme -- helper for PTRACE_TRACEME
413 struct task_struct **childp) 413 *
414 * Performs checks and sets PT_PTRACED.
415 * Should be used by all ptrace implementations for PTRACE_TRACEME.
416 */
417int ptrace_traceme(void)
414{ 418{
415 struct task_struct *child;
416 int ret; 419 int ret;
417 420
418 /* 421 /*
419 * Callers use child == NULL as an indication to exit early even 422 * Are we already being traced?
420 * when the return value is 0, so make sure it is non-NULL here. 423 */
424 if (current->ptrace & PT_PTRACED)
425 return -EPERM;
426 ret = security_ptrace(current->parent, current);
427 if (ret)
428 return -EPERM;
429 /*
430 * Set the ptrace bit in the process ptrace flags.
421 */ 431 */
422 *childp = NULL; 432 current->ptrace |= PT_PTRACED;
433 return 0;
434}
423 435
424 if (request == PTRACE_TRACEME) { 436/**
425 /* 437 * ptrace_get_task_struct -- grab a task struct reference for ptrace
426 * Are we already being traced? 438 * @pid: process id to grab a task_struct reference of
427 */ 439 *
428 if (current->ptrace & PT_PTRACED) 440 * This function is a helper for ptrace implementations. It checks
429 return -EPERM; 441 * permissions and then grabs a task struct for use of the actual
430 ret = security_ptrace(current->parent, current); 442 * ptrace implementation.
431 if (ret) 443 *
432 return -EPERM; 444 * Returns the task_struct for @pid or an ERR_PTR() on failure.
433 /* 445 */
434 * Set the ptrace bit in the process ptrace flags. 446struct task_struct *ptrace_get_task_struct(pid_t pid)
435 */ 447{
436 current->ptrace |= PT_PTRACED; 448 struct task_struct *child;
437 return 0;
438 }
439 449
440 /* 450 /*
441 * You may not mess with init 451 * Tracing init is not allowed.
442 */ 452 */
443 if (pid == 1) 453 if (pid == 1)
444 return -EPERM; 454 return ERR_PTR(-EPERM);
445 455
446 ret = -ESRCH;
447 read_lock(&tasklist_lock); 456 read_lock(&tasklist_lock);
448 child = find_task_by_pid(pid); 457 child = find_task_by_pid(pid);
449 if (child) 458 if (child)
450 get_task_struct(child); 459 get_task_struct(child);
451 read_unlock(&tasklist_lock); 460 read_unlock(&tasklist_lock);
452 if (!child) 461 if (!child)
453 return -ESRCH; 462 return ERR_PTR(-ESRCH);
454 463 return child;
455 *childp = child;
456 return 0;
457} 464}
458 465
466#ifndef __ARCH_SYS_PTRACE
459asmlinkage long sys_ptrace(long request, long pid, long addr, long data) 467asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
460{ 468{
461 struct task_struct *child; 469 struct task_struct *child;
@@ -465,9 +473,16 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
465 * This lock_kernel fixes a subtle race with suid exec 473 * This lock_kernel fixes a subtle race with suid exec
466 */ 474 */
467 lock_kernel(); 475 lock_kernel();
468 ret = ptrace_get_task_struct(request, pid, &child); 476 if (request == PTRACE_TRACEME) {
469 if (!child) 477 ret = ptrace_traceme();
470 goto out; 478 goto out;
479 }
480
481 child = ptrace_get_task_struct(pid);
482 if (IS_ERR(child)) {
483 ret = PTR_ERR(child);
484 goto out;
485 }
471 486
472 if (request == PTRACE_ATTACH) { 487 if (request == PTRACE_ATTACH) {
473 ret = ptrace_attach(child); 488 ret = ptrace_attach(child);