| #!/bin/bash |
| # Copyright (c) 2012 The Chromium OS Authors. |
| # |
| # Based on: |
| # http://bazaar.launchpad.net/~ubuntu-bugcontrol/qa-regression-testing/master/view/head:/scripts/kernel-security/ptrace/ptrace-restrictions.sh |
| # Copyright (C) 2010-2011 Canonical Ltd. |
| # License: GPLv3 |
| # Author: Kees Cook <kees.cook@canonical.com> |
| set -e |
| if [ "$(whoami)" = "root" ]; then |
| echo "Cannot be root for this test" >&2 |
| exit 1 |
| fi |
| |
| export LANG=C |
| pid= |
| dir= |
| |
| function start_sleeper() |
| { |
| dir=$(mktemp -d -t sleeper-XXXXXX) |
| mkfifo "$dir"/status |
| ./sleeper "$1" 120 >"$dir"/status & |
| pid=$! |
| # Wait for sleeper to start up. |
| read status < "$dir"/status |
| } |
| |
| function kill_sleeper() |
| { |
| disown $pid |
| kill $pid |
| rm -rf "$dir" |
| } |
| |
| rc=0 |
| |
| # Check we can see direct children. |
| OUT=$(gdb -ex run -ex quit --batch ./sleeper </dev/null 2>&1) |
| if echo "$OUT" | grep -q 'Quit anyway'; then |
| echo "ok: children correctly allow ptrace" |
| else |
| echo "FAIL: Children unexpectedly not allow ptrace" |
| rc=1 |
| fi |
| |
| # Check we can't see cousins. |
| sleep 120 & |
| pid=$! |
| OUT=$(gdb -ex "attach $pid" -ex "quit" --batch </dev/null 2>&1) |
| if echo "$OUT" | grep -q 'Operation not permitted'; then |
| echo "ok: cousins correctly not allow ptrace" |
| else |
| echo "FAIL: cousins unexpectedly allow ptrace" |
| rc=1 |
| fi |
| |
| # Validate we can see cousin /proc entries. |
| if ls -la /proc/$pid/exe >/dev/null 2>&1; then |
| echo "ok: cousins correctly visible in /proc" |
| else |
| echo "FAIL: cousins unexpectedly invisible in /proc" |
| rc=1 |
| fi |
| |
| # Check we can't attach to init. |
| OUT=$(gdb -ex "attach 1" -ex "quit" --batch </dev/null 2>&1) |
| if echo "$OUT" | grep -q 'Operation not permitted'; then |
| echo "ok: init correctly not allowing ptrace" |
| else |
| echo "FAIL: init unexpectedly allowed ptrace" |
| rc=1 |
| fi |
| |
| # Check we can't see init. |
| if ! ls -la /proc/1/exe >/dev/null 2>&1; then |
| echo "ok: init correctly invisible in /proc" |
| else |
| echo "FAIL: init unexpectedly visible in /proc" |
| rc=1 |
| fi |
| |
| # Drop the sleep process and destroy it without disrupting the shell. |
| disown $pid |
| kill $pid |
| |
| # Validate that prctl(PR_SET_PTRACER, 0, ...) works to delete tracer. |
| start_sleeper 0 |
| OUT=$(gdb -ex "attach $pid" -ex "quit" --batch </dev/null 2>&1) |
| prctl="prctl(PR_SET_PTRACER, 0, ...)" |
| if echo "$OUT" | grep -q 'Operation not permitted'; then |
| echo "ok: $prctl correctly not allowed ptrace" |
| else |
| echo "FAIL: $prctl unexpectedly allowed ptrace" |
| rc=1 |
| fi |
| kill_sleeper |
| |
| # Validate near ancestor allowed with PR_SET_PTRACER use. |
| start_sleeper $$ |
| OUT=$(gdb -ex "attach $pid" -ex "quit" --batch </dev/null 2>&1) |
| prctl="prctl(PR_SET_PTRACER, parent, ...)" |
| if echo "$OUT" | grep -q 'Quit anyway'; then |
| echo "ok: $prctl correctly allowed ptrace" |
| else |
| echo "FAIL: $prctl unexpectedly not allowed ptrace" |
| rc=1 |
| fi |
| kill_sleeper |
| |
| # Validate distant ancestor allowed with PR_SET_PTRACER use. |
| start_sleeper 1 |
| OUT=$(gdb -ex "attach $pid" -ex "quit" --batch </dev/null 2>&1) |
| prctl="prctl(PR_SET_PTRACER, 1, ...)" |
| if echo "$OUT" | grep -q 'Quit anyway'; then |
| echo "ok: $prctl correctly allowed ptrace" |
| else |
| echo "FAIL: $prctl unexpectedly not allowed ptrace" |
| rc=1 |
| fi |
| kill_sleeper |
| |
| # Validate -1 disables protection. |
| start_sleeper -1 |
| OUT=$(gdb -ex "attach $pid" -ex "quit" --batch </dev/null 2>&1) |
| prctl="prctl(PR_SET_PTRACER, -1, ...)" |
| if echo "$OUT" | grep -q 'Quit anyway'; then |
| echo "ok: $prctl correctly allowed ptrace" |
| else |
| echo "FAIL: $prctl unexpectedly not allowed ptrace" |
| rc=1 |
| fi |
| kill_sleeper |
| |
| exit $rc |