1d8af9cfced2410afda008bd83c404836ff1834acKees Cook/*
209bfe684ba65168204569fa51072c80f025058cdKees Cook * Copyright (c) 2012 The Chromium OS Authors.
3d8af9cfced2410afda008bd83c404836ff1834acKees Cook *
4d8af9cfced2410afda008bd83c404836ff1834acKees Cook * Based on:
5d8af9cfced2410afda008bd83c404836ff1834acKees Cook * http://bazaar.launchpad.net/~ubuntu-bugcontrol/qa-regression-testing/master/view/head:/scripts/kernel-security/ptrace/thread-prctl.c
6d8af9cfced2410afda008bd83c404836ff1834acKees Cook * Copyright 2011 Canonical, Ltd
7d8af9cfced2410afda008bd83c404836ff1834acKees Cook * License: GPLv3
8d8af9cfced2410afda008bd83c404836ff1834acKees Cook * Author: Kees Cook <kees.cook@canonical.com>
9d8af9cfced2410afda008bd83c404836ff1834acKees Cook *
10d8af9cfced2410afda008bd83c404836ff1834acKees Cook * Based on reproducer written by Philippe Waroquiers in:
11d8af9cfced2410afda008bd83c404836ff1834acKees Cook * https://launchpad.net/bugs/729839
12d8af9cfced2410afda008bd83c404836ff1834acKees Cook */
13d8af9cfced2410afda008bd83c404836ff1834acKees Cook#include <unistd.h>
14d8af9cfced2410afda008bd83c404836ff1834acKees Cook#include <stdio.h>
15d8af9cfced2410afda008bd83c404836ff1834acKees Cook#include <stdlib.h>
16d8af9cfced2410afda008bd83c404836ff1834acKees Cook#include <sys/types.h>
17d8af9cfced2410afda008bd83c404836ff1834acKees Cook#include <sys/wait.h>
18d8af9cfced2410afda008bd83c404836ff1834acKees Cook#include <signal.h>
19d8af9cfced2410afda008bd83c404836ff1834acKees Cook#include <string.h>
20d8af9cfced2410afda008bd83c404836ff1834acKees Cook#include <pthread.h>
21d8af9cfced2410afda008bd83c404836ff1834acKees Cook#include <sys/ptrace.h>
22d8af9cfced2410afda008bd83c404836ff1834acKees Cook#include <sys/prctl.h>
23d8af9cfced2410afda008bd83c404836ff1834acKees Cook#ifndef PR_SET_PTRACER
24d8af9cfced2410afda008bd83c404836ff1834acKees Cook# define PR_SET_PTRACER 0x59616d61
25d8af9cfced2410afda008bd83c404836ff1834acKees Cook#endif
26d8af9cfced2410afda008bd83c404836ff1834acKees Cook
27d8af9cfced2410afda008bd83c404836ff1834acKees Cookint tracee_method = 0;
28d8af9cfced2410afda008bd83c404836ff1834acKees Cook#define TRACEE_FORKS_FROM_TRACER        0
29d8af9cfced2410afda008bd83c404836ff1834acKees Cook#define TRACEE_CALLS_PRCTL_FROM_MAIN    1
30d8af9cfced2410afda008bd83c404836ff1834acKees Cook#define TRACEE_CALLS_PRCTL_FROM_THREAD  2
31d8af9cfced2410afda008bd83c404836ff1834acKees Cook
32d8af9cfced2410afda008bd83c404836ff1834acKees Cook/* Define some distinct exit values to aid failure debugging. */
33d8af9cfced2410afda008bd83c404836ff1834acKees Cook#define EXIT_FORK_TRACEE             1
34d8af9cfced2410afda008bd83c404836ff1834acKees Cook#define EXIT_FORK_TRACER             2
35d8af9cfced2410afda008bd83c404836ff1834acKees Cook#define EXIT_PIPE_COMMUNICATION      3
36d8af9cfced2410afda008bd83c404836ff1834acKees Cook#define EXIT_PIPE_NOTIFICATION       4
37d8af9cfced2410afda008bd83c404836ff1834acKees Cook#define EXIT_TRACEE_PIPE_READ        5
38d8af9cfced2410afda008bd83c404836ff1834acKees Cook#define EXIT_TRACEE_UNREACHABLE      6
39d8af9cfced2410afda008bd83c404836ff1834acKees Cook#define EXIT_TRACER_PIPE_READ        7
40d8af9cfced2410afda008bd83c404836ff1834acKees Cook#define EXIT_TRACER_PTRACE_ATTACH    8
41d8af9cfced2410afda008bd83c404836ff1834acKees Cook#define EXIT_TRACER_PTRACE_CONTINUE  9
42d8af9cfced2410afda008bd83c404836ff1834acKees Cook#define EXIT_TRACER_UNREACHABLE     10
43d8af9cfced2410afda008bd83c404836ff1834acKees Cook
44d8af9cfced2410afda008bd83c404836ff1834acKees Cookint main_does_ptrace = 0;
45d8af9cfced2410afda008bd83c404836ff1834acKees Cook
46d8af9cfced2410afda008bd83c404836ff1834acKees Cookint ret;
47d8af9cfced2410afda008bd83c404836ff1834acKees Cookint pipes[2];
48d8af9cfced2410afda008bd83c404836ff1834acKees Cookint notification[2];
49d8af9cfced2410afda008bd83c404836ff1834acKees Cookpid_t tracer, tracee;
50d8af9cfced2410afda008bd83c404836ff1834acKees Cook
51d8af9cfced2410afda008bd83c404836ff1834acKees Cookstatic void *thr_fn(void *v)
52d8af9cfced2410afda008bd83c404836ff1834acKees Cook{
53d8af9cfced2410afda008bd83c404836ff1834acKees Cook    printf("tracee thread started\n");
54d8af9cfced2410afda008bd83c404836ff1834acKees Cook    if (tracee_method == TRACEE_CALLS_PRCTL_FROM_THREAD) {
55d8af9cfced2410afda008bd83c404836ff1834acKees Cook        ret = prctl (PR_SET_PTRACER, tracer, 0, 0, 0);
56d8af9cfced2410afda008bd83c404836ff1834acKees Cook        printf("tracee thread prtctl result: %d\n", ret);
57d8af9cfced2410afda008bd83c404836ff1834acKees Cook    }
58d8af9cfced2410afda008bd83c404836ff1834acKees Cook    printf("tracee thread finishing\n");
59d8af9cfced2410afda008bd83c404836ff1834acKees Cook    return NULL;
60d8af9cfced2410afda008bd83c404836ff1834acKees Cook}
61d8af9cfced2410afda008bd83c404836ff1834acKees Cook
62d8af9cfced2410afda008bd83c404836ff1834acKees Cookvoid start_tracee(void);
63d8af9cfced2410afda008bd83c404836ff1834acKees Cook
64d8af9cfced2410afda008bd83c404836ff1834acKees Cookvoid * tracer_main(void * data)
65d8af9cfced2410afda008bd83c404836ff1834acKees Cook{
66d8af9cfced2410afda008bd83c404836ff1834acKees Cook    long ptrace_result;
67d8af9cfced2410afda008bd83c404836ff1834acKees Cook    char buf[8];
68d8af9cfced2410afda008bd83c404836ff1834acKees Cook    int saw;
69d8af9cfced2410afda008bd83c404836ff1834acKees Cook
70d8af9cfced2410afda008bd83c404836ff1834acKees Cook    tracer = getpid();
71d8af9cfced2410afda008bd83c404836ff1834acKees Cook    printf("tracer %d waiting\n", tracer);
72d8af9cfced2410afda008bd83c404836ff1834acKees Cook
73d8af9cfced2410afda008bd83c404836ff1834acKees Cook    if (tracee_method == TRACEE_FORKS_FROM_TRACER) {
74d8af9cfced2410afda008bd83c404836ff1834acKees Cook        printf("forking tracee from tracer\n");
75d8af9cfced2410afda008bd83c404836ff1834acKees Cook        start_tracee();
76d8af9cfced2410afda008bd83c404836ff1834acKees Cook    }
77d8af9cfced2410afda008bd83c404836ff1834acKees Cook
78d8af9cfced2410afda008bd83c404836ff1834acKees Cook    close(pipes[1]);
79d8af9cfced2410afda008bd83c404836ff1834acKees Cook    close(notification[0]);
80d8af9cfced2410afda008bd83c404836ff1834acKees Cook    close(notification[1]);
81d8af9cfced2410afda008bd83c404836ff1834acKees Cook
82d8af9cfced2410afda008bd83c404836ff1834acKees Cook    saw = read(pipes[0], buf, 3);
83d8af9cfced2410afda008bd83c404836ff1834acKees Cook    if (saw < 3) {
84d8af9cfced2410afda008bd83c404836ff1834acKees Cook        perror("tracer pipe read");
85d8af9cfced2410afda008bd83c404836ff1834acKees Cook        exit(EXIT_TRACER_PIPE_READ);
86d8af9cfced2410afda008bd83c404836ff1834acKees Cook    }
87d8af9cfced2410afda008bd83c404836ff1834acKees Cook
88d8af9cfced2410afda008bd83c404836ff1834acKees Cook    printf("tracer to PTRACE_ATTACH my tracee %d\n", tracee);
89d8af9cfced2410afda008bd83c404836ff1834acKees Cook    ptrace_result = ptrace(PTRACE_ATTACH, tracee, NULL, NULL);
90d8af9cfced2410afda008bd83c404836ff1834acKees Cook    if (ptrace_result != 0) {
91d8af9cfced2410afda008bd83c404836ff1834acKees Cook        fflush(NULL);
92d8af9cfced2410afda008bd83c404836ff1834acKees Cook        perror ("tracer ptrace attach has failed");
93d8af9cfced2410afda008bd83c404836ff1834acKees Cook        exit(EXIT_TRACER_PTRACE_ATTACH);
94d8af9cfced2410afda008bd83c404836ff1834acKees Cook    }
95d8af9cfced2410afda008bd83c404836ff1834acKees Cook    printf ("tracer ptrace attach successful\n");
96d8af9cfced2410afda008bd83c404836ff1834acKees Cook
97d8af9cfced2410afda008bd83c404836ff1834acKees Cook    /* Wait for signal. */
98d8af9cfced2410afda008bd83c404836ff1834acKees Cook    printf("tracer waiting for tracee to SIGSTOP\n");
99d8af9cfced2410afda008bd83c404836ff1834acKees Cook    waitpid(tracee, NULL, 0);
100d8af9cfced2410afda008bd83c404836ff1834acKees Cook
101d8af9cfced2410afda008bd83c404836ff1834acKees Cook    printf("tracer to PTRACE_CONT tracee\n");
102d8af9cfced2410afda008bd83c404836ff1834acKees Cook    ptrace_result = ptrace(PTRACE_CONT, tracee, NULL, NULL);
103d8af9cfced2410afda008bd83c404836ff1834acKees Cook    if (ptrace_result != 0) {
104d8af9cfced2410afda008bd83c404836ff1834acKees Cook        fflush(NULL);
105d8af9cfced2410afda008bd83c404836ff1834acKees Cook        perror ("tracer ptrace continue has failed");
106d8af9cfced2410afda008bd83c404836ff1834acKees Cook        exit(EXIT_TRACER_PTRACE_CONTINUE);
107d8af9cfced2410afda008bd83c404836ff1834acKees Cook    }
108d8af9cfced2410afda008bd83c404836ff1834acKees Cook    printf ("tracer ptrace continue successful\n");
109d8af9cfced2410afda008bd83c404836ff1834acKees Cook
110d8af9cfced2410afda008bd83c404836ff1834acKees Cook    printf("tracer returning 0\n");
111d8af9cfced2410afda008bd83c404836ff1834acKees Cook    fflush(NULL);
112d8af9cfced2410afda008bd83c404836ff1834acKees Cook    exit(EXIT_SUCCESS);
113d8af9cfced2410afda008bd83c404836ff1834acKees Cook
114d8af9cfced2410afda008bd83c404836ff1834acKees Cook    return NULL;
115d8af9cfced2410afda008bd83c404836ff1834acKees Cook}
116d8af9cfced2410afda008bd83c404836ff1834acKees Cook
117d8af9cfced2410afda008bd83c404836ff1834acKees Cook/* Tracee knows nothing, needs tracee and tracer pid. */
118d8af9cfced2410afda008bd83c404836ff1834acKees Cookvoid tracee_main(void) {
119d8af9cfced2410afda008bd83c404836ff1834acKees Cook    char buf[1024];
120d8af9cfced2410afda008bd83c404836ff1834acKees Cook    int saw;
121d8af9cfced2410afda008bd83c404836ff1834acKees Cook    pthread_t thr;
122d8af9cfced2410afda008bd83c404836ff1834acKees Cook
123d8af9cfced2410afda008bd83c404836ff1834acKees Cook    tracee = getpid();
124d8af9cfced2410afda008bd83c404836ff1834acKees Cook    close(pipes[0]);
125d8af9cfced2410afda008bd83c404836ff1834acKees Cook
126d8af9cfced2410afda008bd83c404836ff1834acKees Cook    printf("tracee %d reading tracer pid\n", tracee);
127d8af9cfced2410afda008bd83c404836ff1834acKees Cook    close(notification[1]);
128d8af9cfced2410afda008bd83c404836ff1834acKees Cook    saw = read(notification[0], buf, 1024);
129d8af9cfced2410afda008bd83c404836ff1834acKees Cook    if (saw < 1) {
130d8af9cfced2410afda008bd83c404836ff1834acKees Cook        perror("pipe read");
131d8af9cfced2410afda008bd83c404836ff1834acKees Cook        exit(EXIT_TRACEE_PIPE_READ);
132d8af9cfced2410afda008bd83c404836ff1834acKees Cook    }
133d8af9cfced2410afda008bd83c404836ff1834acKees Cook    buf[saw]='\0';
134d8af9cfced2410afda008bd83c404836ff1834acKees Cook    tracer = atoi(buf);
135d8af9cfced2410afda008bd83c404836ff1834acKees Cook
136d8af9cfced2410afda008bd83c404836ff1834acKees Cook    printf("tracee %d started (expecting %d as tracer)\n", tracee, tracer);
137d8af9cfced2410afda008bd83c404836ff1834acKees Cook
138d8af9cfced2410afda008bd83c404836ff1834acKees Cook    /* Handle setting PR_SET_PTRACER. */
139d8af9cfced2410afda008bd83c404836ff1834acKees Cook    switch (tracee_method) {
140d8af9cfced2410afda008bd83c404836ff1834acKees Cook        case TRACEE_CALLS_PRCTL_FROM_MAIN:
141d8af9cfced2410afda008bd83c404836ff1834acKees Cook            ret = prctl (PR_SET_PTRACER, tracer, 0, 0, 0);
142d8af9cfced2410afda008bd83c404836ff1834acKees Cook            printf("tracee main prtctl result: %d \n", ret);
143d8af9cfced2410afda008bd83c404836ff1834acKees Cook            break;
144d8af9cfced2410afda008bd83c404836ff1834acKees Cook        case TRACEE_CALLS_PRCTL_FROM_THREAD:
145d8af9cfced2410afda008bd83c404836ff1834acKees Cook            printf("tracee thread starting\n");
146d8af9cfced2410afda008bd83c404836ff1834acKees Cook            pthread_create(&thr, NULL, thr_fn, NULL);
147d8af9cfced2410afda008bd83c404836ff1834acKees Cook            pthread_join(thr, NULL);
148d8af9cfced2410afda008bd83c404836ff1834acKees Cook            printf("tracee thread finished\n");
149d8af9cfced2410afda008bd83c404836ff1834acKees Cook            break;
150d8af9cfced2410afda008bd83c404836ff1834acKees Cook        default:
151d8af9cfced2410afda008bd83c404836ff1834acKees Cook            break;
152d8af9cfced2410afda008bd83c404836ff1834acKees Cook    }
153d8af9cfced2410afda008bd83c404836ff1834acKees Cook
154d8af9cfced2410afda008bd83c404836ff1834acKees Cook    /* Wait for Oedipal action. */
155d8af9cfced2410afda008bd83c404836ff1834acKees Cook    printf("tracee triggering tracer\n");
156d8af9cfced2410afda008bd83c404836ff1834acKees Cook    fflush(NULL);
157d8af9cfced2410afda008bd83c404836ff1834acKees Cook    write(pipes[1], "ok\n", 3);
158d8af9cfced2410afda008bd83c404836ff1834acKees Cook
159d8af9cfced2410afda008bd83c404836ff1834acKees Cook    printf("tracee waiting for master\n");
160d8af9cfced2410afda008bd83c404836ff1834acKees Cook    saw = read(notification[0], buf, 1024);
161d8af9cfced2410afda008bd83c404836ff1834acKees Cook    buf[saw] = '\0';
162d8af9cfced2410afda008bd83c404836ff1834acKees Cook
163d8af9cfced2410afda008bd83c404836ff1834acKees Cook    printf("tracee finished (%s)\n", buf);
164d8af9cfced2410afda008bd83c404836ff1834acKees Cook    exit(EXIT_SUCCESS);
165d8af9cfced2410afda008bd83c404836ff1834acKees Cook}
166d8af9cfced2410afda008bd83c404836ff1834acKees Cook
167d8af9cfced2410afda008bd83c404836ff1834acKees Cookvoid start_tracee(void)
168d8af9cfced2410afda008bd83c404836ff1834acKees Cook{
169d8af9cfced2410afda008bd83c404836ff1834acKees Cook    fflush(NULL);
170d8af9cfced2410afda008bd83c404836ff1834acKees Cook    tracee = fork();
171d8af9cfced2410afda008bd83c404836ff1834acKees Cook    if (tracee < 0) {
172d8af9cfced2410afda008bd83c404836ff1834acKees Cook        perror("fork tracee");
173d8af9cfced2410afda008bd83c404836ff1834acKees Cook        exit(EXIT_FORK_TRACEE);
174d8af9cfced2410afda008bd83c404836ff1834acKees Cook    }
175d8af9cfced2410afda008bd83c404836ff1834acKees Cook    if (tracee == 0) {
176d8af9cfced2410afda008bd83c404836ff1834acKees Cook        tracee_main();
177d8af9cfced2410afda008bd83c404836ff1834acKees Cook        exit(EXIT_TRACEE_UNREACHABLE);
178d8af9cfced2410afda008bd83c404836ff1834acKees Cook    }
179d8af9cfced2410afda008bd83c404836ff1834acKees Cook}
180d8af9cfced2410afda008bd83c404836ff1834acKees Cook
181d8af9cfced2410afda008bd83c404836ff1834acKees Cook/* Tracer knows tracee, needs tracer pid. */
182d8af9cfced2410afda008bd83c404836ff1834acKees Cookint main(int argc, char*argv[])
183d8af9cfced2410afda008bd83c404836ff1834acKees Cook{
184d8af9cfced2410afda008bd83c404836ff1834acKees Cook    int status;
185d8af9cfced2410afda008bd83c404836ff1834acKees Cook    char buf[1024];
186d8af9cfced2410afda008bd83c404836ff1834acKees Cook
187d8af9cfced2410afda008bd83c404836ff1834acKees Cook    if (argc > 1) {
188d8af9cfced2410afda008bd83c404836ff1834acKees Cook        /* Operational states:
189d8af9cfced2410afda008bd83c404836ff1834acKees Cook         * 0: tracer forks tracee.
190d8af9cfced2410afda008bd83c404836ff1834acKees Cook         * 1: tracee calls prctl from main process.
191d8af9cfced2410afda008bd83c404836ff1834acKees Cook         * 2: tracee calls prctl from non-leader thread.
192d8af9cfced2410afda008bd83c404836ff1834acKees Cook         */
193d8af9cfced2410afda008bd83c404836ff1834acKees Cook        tracee_method = atoi(argv[1]);
194d8af9cfced2410afda008bd83c404836ff1834acKees Cook    }
195d8af9cfced2410afda008bd83c404836ff1834acKees Cook    if (argc > 2) {
196d8af9cfced2410afda008bd83c404836ff1834acKees Cook        /* Operational states:
197d8af9cfced2410afda008bd83c404836ff1834acKees Cook         * 0: ptrace happens from non-leader thread.
198d8af9cfced2410afda008bd83c404836ff1834acKees Cook         * 1: ptrace happens from main process.
199d8af9cfced2410afda008bd83c404836ff1834acKees Cook         */
200d8af9cfced2410afda008bd83c404836ff1834acKees Cook        main_does_ptrace = atoi(argv[2]) != 0;
201d8af9cfced2410afda008bd83c404836ff1834acKees Cook    }
202d8af9cfced2410afda008bd83c404836ff1834acKees Cook
203d8af9cfced2410afda008bd83c404836ff1834acKees Cook    if (tracee_method != TRACEE_FORKS_FROM_TRACER) {
204d8af9cfced2410afda008bd83c404836ff1834acKees Cook        printf("will issue prctl from %s\n",
205d8af9cfced2410afda008bd83c404836ff1834acKees Cook               tracee_method == TRACEE_CALLS_PRCTL_FROM_MAIN ?
206d8af9cfced2410afda008bd83c404836ff1834acKees Cook                    "main" : "thread");
207d8af9cfced2410afda008bd83c404836ff1834acKees Cook    }
208d8af9cfced2410afda008bd83c404836ff1834acKees Cook    else {
209d8af9cfced2410afda008bd83c404836ff1834acKees Cook        printf("will fork tracee from tracer\n");
210d8af9cfced2410afda008bd83c404836ff1834acKees Cook    }
211d8af9cfced2410afda008bd83c404836ff1834acKees Cook    printf("will issue ptrace from tracer %s\n",
212d8af9cfced2410afda008bd83c404836ff1834acKees Cook           main_does_ptrace ? "main" : "thread");
213d8af9cfced2410afda008bd83c404836ff1834acKees Cook
214d8af9cfced2410afda008bd83c404836ff1834acKees Cook    printf("master is %d\n", getpid());
215d8af9cfced2410afda008bd83c404836ff1834acKees Cook
216d8af9cfced2410afda008bd83c404836ff1834acKees Cook    if (pipe(notification)<0) {
217d8af9cfced2410afda008bd83c404836ff1834acKees Cook        perror("pipe");
218d8af9cfced2410afda008bd83c404836ff1834acKees Cook        exit(EXIT_PIPE_NOTIFICATION);
219d8af9cfced2410afda008bd83c404836ff1834acKees Cook    }
220d8af9cfced2410afda008bd83c404836ff1834acKees Cook    if (pipe(pipes)<0) {
221d8af9cfced2410afda008bd83c404836ff1834acKees Cook        perror("pipe");
222d8af9cfced2410afda008bd83c404836ff1834acKees Cook        exit(EXIT_PIPE_COMMUNICATION);
223d8af9cfced2410afda008bd83c404836ff1834acKees Cook    }
224d8af9cfced2410afda008bd83c404836ff1834acKees Cook
225d8af9cfced2410afda008bd83c404836ff1834acKees Cook    if (tracee_method != TRACEE_FORKS_FROM_TRACER) {
226d8af9cfced2410afda008bd83c404836ff1834acKees Cook        printf("forking tracee from master\n");
227d8af9cfced2410afda008bd83c404836ff1834acKees Cook        start_tracee();
228d8af9cfced2410afda008bd83c404836ff1834acKees Cook    }
229d8af9cfced2410afda008bd83c404836ff1834acKees Cook
230d8af9cfced2410afda008bd83c404836ff1834acKees Cook    fflush(NULL);
231d8af9cfced2410afda008bd83c404836ff1834acKees Cook    tracer = fork();
232d8af9cfced2410afda008bd83c404836ff1834acKees Cook    if (tracer < 0) {
233d8af9cfced2410afda008bd83c404836ff1834acKees Cook        perror("fork tracer");
234d8af9cfced2410afda008bd83c404836ff1834acKees Cook        exit(EXIT_FORK_TRACER);
235d8af9cfced2410afda008bd83c404836ff1834acKees Cook    }
236d8af9cfced2410afda008bd83c404836ff1834acKees Cook    if (tracer == 0) {
237d8af9cfced2410afda008bd83c404836ff1834acKees Cook        printf("tracer is %d\n", getpid());
238d8af9cfced2410afda008bd83c404836ff1834acKees Cook        if (main_does_ptrace) {
239d8af9cfced2410afda008bd83c404836ff1834acKees Cook            tracer_main(NULL);
240d8af9cfced2410afda008bd83c404836ff1834acKees Cook        }
241d8af9cfced2410afda008bd83c404836ff1834acKees Cook        else {
242d8af9cfced2410afda008bd83c404836ff1834acKees Cook            pthread_t thread;
243d8af9cfced2410afda008bd83c404836ff1834acKees Cook            pthread_create(&thread, NULL, tracer_main, NULL);
244d8af9cfced2410afda008bd83c404836ff1834acKees Cook            pthread_join(thread, NULL);
245d8af9cfced2410afda008bd83c404836ff1834acKees Cook        }
246d8af9cfced2410afda008bd83c404836ff1834acKees Cook        exit(EXIT_TRACER_UNREACHABLE);
247d8af9cfced2410afda008bd83c404836ff1834acKees Cook    }
248d8af9cfced2410afda008bd83c404836ff1834acKees Cook
249d8af9cfced2410afda008bd83c404836ff1834acKees Cook    /* Leave the pipes for the tracee and tracer. */
250d8af9cfced2410afda008bd83c404836ff1834acKees Cook    close(pipes[0]);
251d8af9cfced2410afda008bd83c404836ff1834acKees Cook    close(pipes[1]);
252d8af9cfced2410afda008bd83c404836ff1834acKees Cook
253d8af9cfced2410afda008bd83c404836ff1834acKees Cook    /* Close our end of pid notification. */
254d8af9cfced2410afda008bd83c404836ff1834acKees Cook    close(notification[0]);
255d8af9cfced2410afda008bd83c404836ff1834acKees Cook    sprintf(buf, "%d", tracer);
256d8af9cfced2410afda008bd83c404836ff1834acKees Cook    write(notification[1], buf, strlen(buf));
257d8af9cfced2410afda008bd83c404836ff1834acKees Cook
258d8af9cfced2410afda008bd83c404836ff1834acKees Cook    printf("master waiting for tracer to finish\n");
259d8af9cfced2410afda008bd83c404836ff1834acKees Cook    fflush(NULL);
260d8af9cfced2410afda008bd83c404836ff1834acKees Cook    waitpid(tracer, &status, 0);
261d8af9cfced2410afda008bd83c404836ff1834acKees Cook
262d8af9cfced2410afda008bd83c404836ff1834acKees Cook    printf("master waiting for tracee to finish\n");
263d8af9cfced2410afda008bd83c404836ff1834acKees Cook    fflush(NULL);
264d8af9cfced2410afda008bd83c404836ff1834acKees Cook    write(notification[1], "stop", 4);
265d8af9cfced2410afda008bd83c404836ff1834acKees Cook    kill(tracee, SIGCONT); // Just in case.
266d8af9cfced2410afda008bd83c404836ff1834acKees Cook    waitpid(tracee, NULL, 0);
267d8af9cfced2410afda008bd83c404836ff1834acKees Cook
268d8af9cfced2410afda008bd83c404836ff1834acKees Cook    status = WEXITSTATUS(status);
269d8af9cfced2410afda008bd83c404836ff1834acKees Cook    printf("master saw rc %d from tracer\n", status);
270d8af9cfced2410afda008bd83c404836ff1834acKees Cook    return status;
271d8af9cfced2410afda008bd83c404836ff1834acKees Cook}
272d8af9cfced2410afda008bd83c404836ff1834acKees Cook
273