about summary refs log tree commit diff
path: root/utils/asan_cgroups/limit_memory.sh
blob: 1f0f04add7085b3c0c92240a9aa79f97685e26ad (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#!/usr/bin/env bash
#
# american fuzzy lop++ - limit memory using cgroups
# -----------------------------------------------
#
# Written by Samir Khakimov <samir.hakim@nyu.edu> and
#            David A. Wheeler <dwheeler@ida.org>
#
# Edits to bring the script in line with afl-cmin and other companion scripts
# by Michal Zalewski. All bugs are my fault.
#
# Copyright 2015 Institute for Defense Analyses.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# This tool allows the amount of actual memory allocated to a program
# to be limited on Linux systems using cgroups, instead of the traditional
# setrlimit() API. This helps avoid the address space problems discussed in
# docs/notes_for_asan.md.
#
# Important: the limit covers *both* afl-fuzz and the fuzzed binary. In some
# hopefully rare circumstances, afl-fuzz could be killed before the fuzzed
# task.
#

echo "cgroup tool for afl-fuzz by <samir.hakim@nyu.edu> and <dwheeler@ida.org>"
echo

unset NEW_USER
MEM_LIMIT="50"

while getopts "+u:m:" opt; do

  case "$opt" in

    "u")
         NEW_USER="$OPTARG"
         ;;

    "m")
         MEM_LIMIT="$[OPTARG]"
         ;;

    "?")
         exit 1
         ;;

   esac

done

if [ "$MEM_LIMIT" -lt "5" ]; then
  echo "[-] Error: malformed or dangerously low value of -m." 1>&2
  exit 1
fi

shift $((OPTIND-1))

TARGET_BIN="$1"

if [ "$TARGET_BIN" = "" -o "$NEW_USER" = "" ]; then

  cat 1>&2 <<_EOF_
Usage: $0 [ options ] -- /path/to/afl-fuzz [ ...afl options... ]

Required parameters:

  -u user   - run the fuzzer as a specific user after setting up limits

Optional parameters:

  -m megs   - set memory limit to a specified value ($MEM_LIMIT MB)

This tool configures cgroups-based memory limits for a fuzzing job to simplify
the task of fuzzing ASAN or MSAN binaries. You would normally want to use it in
conjunction with '-m none' passed to the afl-fuzz binary itself, say:

  $0 -u joe ./afl-fuzz -i input -o output -m none /path/to/target

_EOF_

  exit 1

fi

# Basic sanity checks

if [ ! "`uname -s`" = "Linux" ]; then
 echo "[-] Error: this tool does not support non-Linux systems." 1>&2
 exit 1
fi

if [ ! "`id -u`" = "0" ]; then
 echo "[-] Error: you need to run this script as root (sorry!)." 1>&2
 exit 1
fi

if ! type cgcreate 2>/dev/null 1>&2; then

  echo "[-] Error: you need to install cgroup tools first." 1>&2

  if type apt-get 2>/dev/null 1>&2; then
    echo "    (Perhaps 'apt-get install cgroup-bin' will work.)" 1>&2
  elif type yum 2>/dev/null 1>&2; then
    echo "    (Perhaps 'yum install libcgroup-tools' will work.)" 1>&2
  fi

  exit 1

fi

if ! id -u "$NEW_USER" 2>/dev/null 1>&2; then
  echo "[-] Error: user '$NEW_USER' does not seem to exist." 1>&2
  exit 1
fi

# Create a new cgroup path if necessary... We used PID-keyed groups to keep
# parallel afl-fuzz tasks separate from each other.

CID="afl-$NEW_USER-$$"

CPATH="/sys/fs/cgroup/memory/$CID"

if [ ! -d "$CPATH" ]; then

  cgcreate -a "$NEW_USER" -g memory:"$CID" || exit 1

fi

# Set the appropriate limit...

if [ -f "$CPATH/memory.memsw.limit_in_bytes" ]; then

  echo "${MEM_LIMIT}M" > "$CPATH/memory.limit_in_bytes" 2>/dev/null
  echo "${MEM_LIMIT}M" > "$CPATH/memory.memsw.limit_in_bytes" || exit 1
  echo "${MEM_LIMIT}M" > "$CPATH/memory.limit_in_bytes" || exit 1

elif grep -qE 'partition|file' /proc/swaps; then

  echo "[-] Error: your system requires swap to be disabled first (swapoff -a)." 1>&2
  exit 1

else

  echo "${MEM_LIMIT}M" > "$CPATH/memory.limit_in_bytes" || exit 1

fi

# All right. At this point, we can just run the command.

cgexec -g "memory:$CID" su -c "$*" "$NEW_USER"

cgdelete -g "memory:$CID"