1#!/bin/bash
2# Copyright (c) 2012 The Chromium OS Authors.
3#
4# Based on:
5# http://bazaar.launchpad.net/~ubuntu-bugcontrol/qa-regression-testing/master/view/head:/scripts/kernel-security/ptrace/ptrace-restrictions.sh
6# Copyright (C) 2010-2011 Canonical Ltd.
7# License: GPLv3
8# Author: Kees Cook <kees.cook@canonical.com>
9set -e
10if [ "$(whoami)" = "root" ]; then
11    echo "Cannot be root for this test" >&2
12    exit 1
13fi
14
15export LANG=C
16pid=
17dir=
18
19function start_sleeper()
20{
21    dir=$(mktemp -d -t sleeper-XXXXXX)
22    mkfifo "$dir"/status
23    ./sleeper "$1" 120 >"$dir"/status &
24    pid=$!
25    # Wait for sleeper to start up.
26    read status < "$dir"/status
27}
28
29function kill_sleeper()
30{
31    disown $pid
32    kill $pid
33    rm -rf "$dir"
34}
35
36rc=0
37
38# Check we can see direct children.
39OUT=$(gdb -ex run -ex quit --batch ./sleeper </dev/null 2>&1)
40if echo "$OUT" | grep -q 'Quit anyway'; then
41    echo "ok: children correctly allow ptrace"
42else
43    echo "FAIL: Children unexpectedly not allow ptrace"
44    rc=1
45fi
46
47# Check we can't see cousins.
48sleep 120 &
49pid=$!
50OUT=$(gdb -ex "attach $pid" -ex "quit" --batch </dev/null 2>&1)
51if echo "$OUT" | grep -q 'Operation not permitted'; then
52    echo "ok: cousins correctly not allow ptrace"
53else
54    echo "FAIL: cousins unexpectedly allow ptrace"
55    rc=1
56fi
57
58# Validate we can see cousin /proc entries.
59if ls -la /proc/$pid/exe >/dev/null 2>&1; then
60    echo "ok: cousins correctly visible in /proc"
61else
62    echo "FAIL: cousins unexpectedly invisible in /proc"
63    rc=1
64fi
65
66# Check we can't attach to init.
67OUT=$(gdb -ex "attach 1" -ex "quit" --batch </dev/null 2>&1)
68if echo "$OUT" | grep -q 'Operation not permitted'; then
69    echo "ok: init correctly not allowing ptrace"
70else
71    echo "FAIL: init unexpectedly allowed ptrace"
72    rc=1
73fi
74
75# Check we can't see init.
76if ! ls -la /proc/1/exe >/dev/null 2>&1; then
77    echo "ok: init correctly invisible in /proc"
78else
79    echo "FAIL: init unexpectedly visible in /proc"
80    rc=1
81fi
82
83# Drop the sleep process and destroy it without disrupting the shell.
84disown $pid
85kill $pid
86
87# Validate that prctl(PR_SET_PTRACER, 0, ...) works to delete tracer.
88start_sleeper 0
89OUT=$(gdb -ex "attach $pid" -ex "quit" --batch </dev/null 2>&1)
90prctl="prctl(PR_SET_PTRACER, 0, ...)"
91if echo "$OUT" | grep -q 'Operation not permitted'; then
92    echo "ok: $prctl correctly not allowed ptrace"
93else
94    echo "FAIL: $prctl unexpectedly allowed ptrace"
95    rc=1
96fi
97kill_sleeper
98
99# Validate near ancestor allowed with PR_SET_PTRACER use.
100start_sleeper $$
101OUT=$(gdb -ex "attach $pid" -ex "quit" --batch </dev/null 2>&1)
102prctl="prctl(PR_SET_PTRACER, parent, ...)"
103if echo "$OUT" | grep -q 'Quit anyway'; then
104    echo "ok: $prctl correctly allowed ptrace"
105else
106    echo "FAIL: $prctl unexpectedly not allowed ptrace"
107    rc=1
108fi
109kill_sleeper
110
111# Validate distant ancestor allowed with PR_SET_PTRACER use.
112start_sleeper 1
113OUT=$(gdb -ex "attach $pid" -ex "quit" --batch </dev/null 2>&1)
114prctl="prctl(PR_SET_PTRACER, 1, ...)"
115if echo "$OUT" | grep -q 'Quit anyway'; then
116    echo "ok: $prctl correctly allowed ptrace"
117else
118    echo "FAIL: $prctl unexpectedly not allowed ptrace"
119    rc=1
120fi
121kill_sleeper
122
123# Validate -1 disables protection.
124start_sleeper -1
125OUT=$(gdb -ex "attach $pid" -ex "quit" --batch </dev/null 2>&1)
126prctl="prctl(PR_SET_PTRACER, -1, ...)"
127if echo "$OUT" | grep -q 'Quit anyway'; then
128    echo "ok: $prctl correctly allowed ptrace"
129else
130    echo "FAIL: $prctl unexpectedly not allowed ptrace"
131    rc=1
132fi
133kill_sleeper
134
135exit $rc
136