Merge pull request #39 from frdeso/lava_improve_fuzzing
authorJonathan Rajotte Julien <jonathan.rajotte-julien@efficios.com>
Wed, 14 Mar 2018 19:51:16 +0000 (15:51 -0400)
committerGitHub <noreply@github.com>
Wed, 14 Mar 2018 19:51:16 +0000 (15:51 -0400)
jjb: lava: Reimplement kprobe fuzzing job

lava/system-tests/kprobe-fuzzing-generate-data.yml [new file with mode: 0644]
lava/system-tests/kprobe-fuzzing-tests.yml
scripts/system-tests/kprobe-fuzzing.sh [deleted file]
scripts/system-tests/lava-submit.py
scripts/system-tests/run-kprobe-fuzzing.py [new file with mode: 0644]
scripts/system-tests/run-kprobe-generate-instr-points.py [new file with mode: 0644]

diff --git a/lava/system-tests/kprobe-fuzzing-generate-data.yml b/lava/system-tests/kprobe-fuzzing-generate-data.yml
new file mode 100644 (file)
index 0000000..d9d5e49
--- /dev/null
@@ -0,0 +1,14 @@
+metadata:
+        format: Lava-Test Test Definition 1.0
+        name: lttng-fuzzing-kprobe-generate-data
+        description: "Run kprobe fuzzing data generation"
+install:
+        git-repos:
+                - url: https://github.com/lttng/lttng-ci
+                  destination: ci
+                  branch: master
+run:
+        steps:
+                - cd ci/
+                - lava-test-case generate-fuzzing-data --shell "python3 ./scripts/system-tests/run-kprobe-generate-instr-points.py $((1 + RANDOM))"
+                - sync
index cf650678bb3c1d1a13f839066ee283371fd6cba9..56812bac329b6896227e3905875f07bf3d420c10 100644 (file)
@@ -8,15 +8,14 @@ install:
                   destination: ci
                   branch: master
         steps:
-                - export TMPDIR="/tmp"
                 - cd
                 - ulimit -c unlimited
                 - mkdir -p coredump
                 - echo "$(pwd)/coredump/core.%e.%p.%h.%t" > /proc/sys/kernel/core_pattern
 run:
         steps:
-                - source /root/lttngvenv/activate
                 - cd ci/
-                - lava-test-case run-tests --shell "./scripts/system-tests/kprobe-fuzzing.sh"
+                - lava-test-case run-fuzzing --shell "python3 ./scripts/system-tests/run-kprobe-fuzzing.py /root/instr_points.txt.gz"
+                - cd ..
                 - tar czf coredump.tar.gz coredump
-                - lava-test-case-attach run-tests coredump.tar.gz
+                - lava-test-case-attach run-fuzzing coredump.tar.gz
diff --git a/scripts/system-tests/kprobe-fuzzing.sh b/scripts/system-tests/kprobe-fuzzing.sh
deleted file mode 100755 (executable)
index fab987b..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-#!/bin/bash -xeu
-# Copyright (C) 2017 - Francis Deslauriers <francis.deslauriers@efficios.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-NB_KPROBE_PER_ITER=500
-SESSION_NAME="my_kprobe_session"
-
-# Silence the script to avoid redirection of kallsyms to fill the screen
-set +x
-syms=$(awk '{print $3;}' /proc/kallsyms | sort -R)
-nb_syms=$(echo "$syms" | wc -l)
-set -x
-
-# Loop over the list of symbols and enable the symbols in groups of
-# $NB_KPROBE_PER_ITER
-for i in $(seq 0 "$NB_KPROBE_PER_ITER" "$nb_syms"); do
-       # Print time in UTC at each iteration to easily see when the script
-       # hangs
-       date --utc
-
-       # Pick $NB_KPROBE_PER_ITER symbols to instrument, craft enable-event
-       # command and save them to a file. We craft the commands and executed
-       # them in two steps so that the pipeline can be done without the bash
-       # '-x' option that would fill the serial buffer because of the multiple
-       # pipe redirections.
-       set +x
-       echo "$syms" | head -n $((i+NB_KPROBE_PER_ITER)) | tail -n $NB_KPROBE_PER_ITER |awk '{print "lttng enable-event --kernel --function=" $1 " " $1}' > lttng-enable-event.sh
-       set -x
-
-       # Print what iteration we are at
-       echo "$i" $((i+NB_KPROBE_PER_ITER))
-
-       # Destroy previous session and create a new one
-       lttng create "$SESSION_NAME"
-
-       # Expect commands to fail, turn off early exit of shell script on
-       # non-zero return value
-       set +e
-       source  ./lttng-enable-event.sh
-       set -e
-
-       # Run stress util to generate some kernel activity
-       stress --cpu 2 --io 4 --vm 2 --vm-bytes 128M --hdd 3 --timeout 5s
-
-       lttng list "$SESSION_NAME"
-       lttng destroy "$SESSION_NAME"
-done
index 94ecba2d0953c031c95ed69a223d4e2344cb41e4..4ee70779a228c332c865a2a4c6f7650c567e5bce 100644 (file)
@@ -267,6 +267,23 @@ def get_kvm_tests_cmd():
             }
         })
     return command
+
+def get_kprobes_generate_data_cmd():
+    command = OrderedDict({
+        'command': 'lava_test_shell',
+        'parameters': {
+            'testdef_repos': [
+                {
+                    'git-repo': 'https://github.com/lttng/lttng-ci.git',
+                    'revision': 'master',
+                    'testdef': 'lava/system-tests/kprobe-fuzzing-generate-data.yml'
+                }
+                ],
+            'timeout': 60
+            }
+        })
+    return command
+
 def get_kprobes_test_cmd():
     command = OrderedDict({
         'command': 'lava_test_shell',
@@ -447,6 +464,7 @@ def main():
             return -1
         j['actions'].append(get_config_cmd('kvm'))
         j['actions'].append(get_env_setup_cmd('kvm', args.tools_commit, args.ust_commit))
+        j['actions'].append(get_kprobes_generate_data_cmd())
         j['actions'].append(get_kprobes_test_cmd())
         j['actions'].append(get_results_cmd(stream_name='tests-kernel'))
     else:
diff --git a/scripts/system-tests/run-kprobe-fuzzing.py b/scripts/system-tests/run-kprobe-fuzzing.py
new file mode 100644 (file)
index 0000000..ef79077
--- /dev/null
@@ -0,0 +1,109 @@
+# Copyright (C) 2018 - Francis Deslauriers <francis.deslauriers@efficios.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+import datetime
+import gzip
+import os
+import pprint
+import subprocess
+import sys
+
+NB_KPROBES_PER_ITER=500
+
+def load_instr_points(instr_points_archive):
+    print('Reading instrumentation points from \'{}\'.'.format(instr_points_archive), end='')
+    sys.stdout.flush()
+
+    with gzip.open(instr_points_archive, 'r') as f:
+        data = f.read()
+    print(' Done.')
+
+    return [x.decode('utf-8') for x in data.split()]
+
+def enable_kprobe_events(instr_points):
+    print('Enabling events...', end='')
+    sys.stdout.flush()
+
+    # Use os module directly, because this is a sysfs file and seeking inside
+    # the file is not supported. The python open() function with the append
+    # ('a') flag uses lseek(, SEEK_END) to move the write pointer to the end.
+    fd = os.open('/sys/kernel/debug/tracing/kprobe_events', os.O_WRONLY|os.O_CREAT|os.O_APPEND)
+    for i, point in enumerate(instr_points):
+
+        kprobe_cmd = 'r:event_{} {}\n'.format(i, point).encode('utf-8')
+        try:
+            os.write(fd, kprobe_cmd)
+        except OSError:
+            continue
+    os.close(fd)
+    print(' Done.')
+
+def set_kprobe_tracing_state(state):
+    if state not in (0 ,1):
+        raise ValueError
+
+    if state == 0:
+        # Clear the content of the trace.
+        open('/sys/kernel/debug/tracing/trace', 'w').close()
+
+    try:
+        with open('/sys/kernel/debug/tracing/events/kprobes/enable', 'w') as enable_kprobe_file:
+            enable_kprobe_file.write('{}\n'.format(state))
+    except IOError:
+        print('kprobes/enable file does not exist')
+
+def run_workload():
+    print('Running workload...', end='')
+    sys.stdout.flush()
+    workload = ['stress', '--cpu', '2', '--io', '4', '--vm', '2',
+                '--vm-bytes', '128M', '--hdd', '3', '--timeout', '3s']
+    try:
+        with open(os.devnull) as devnull:
+            subprocess.call(workload, stdout=devnull, stderr=devnull)
+    except OSError as e:
+        print("Workload execution failed:", e, file=sys.stderr)
+        pprint.pprint(workload)
+
+    print(' Done.')
+
+def mount_tracingfs():
+    with open(os.devnull) as devnull:
+        subprocess.call(['mount', '-t', 'debugfs', 'nodev', '/sys/kernel/debug/'],
+                stdout=devnull, stderr=devnull)
+
+def print_dashed_line():
+    print('-'*100)
+
+def main():
+    assert(len(sys.argv) == 2)
+
+    instr_point_archive = sys.argv[1]
+    # Load instrumentation points to disk and attach it to lava test run.
+    instrumentation_points = load_instr_points(instr_point_archive)
+
+    mount_tracingfs()
+
+    # Loop over the list by enabling ranges of NB_KPROBES_PER_ITER kprobes.
+    for i in range(int(len(instrumentation_points)/NB_KPROBES_PER_ITER)):
+        print_dashed_line()
+        print('Time now: {}, {} to {}'.format(datetime.datetime.now(), i*NB_KPROBES_PER_ITER, (i+1)*NB_KPROBES_PER_ITER))
+        set_kprobe_tracing_state(0)
+        enable_kprobe_events(instrumentation_points[i*NB_KPROBES_PER_ITER:(i+1)*NB_KPROBES_PER_ITER])
+        set_kprobe_tracing_state(1)
+        run_workload()
+        print('\n')
+
+if __name__ == "__main__":
+    main()
diff --git a/scripts/system-tests/run-kprobe-generate-instr-points.py b/scripts/system-tests/run-kprobe-generate-instr-points.py
new file mode 100644 (file)
index 0000000..072ff3d
--- /dev/null
@@ -0,0 +1,89 @@
+# Copyright (C) 2018 - Francis Deslauriers <francis.deslauriers@efficios.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+import datetime
+import gzip
+import os
+import pprint
+import random
+import subprocess
+import sys
+
+def save_instr_points(instr_points):
+
+    # Save in /root to be persistent across lava slave reboots.
+    instrumenation_points_arch = '/root/instr_points.txt.gz'
+
+    print('Saving instrumentation points to \'{}\' ...'.format(instrumenation_points_arch), end='')
+    sys.stdout.flush()
+
+    text = "\n".join(instr_points)
+
+    with gzip.open(instrumenation_points_arch, 'w') as f:
+        f.write(text.encode('utf-8'))
+
+    # Attach fuzzing data to test case.
+    events = ['lava-test-case-attach', 'generate-fuzzing-data', instrumenation_points_arch]
+
+    try:
+        subprocess.call(events)
+    except OSError as e:
+        print("Execution failed:", e, file=sys.stderr)
+        print("Probably not running on the lava worker")
+        pprint.pprint(events)
+    print('Done.')
+
+def main():
+    assert(len(sys.argv) == 2)
+
+    seed = int(sys.argv[1])
+    print('Random seed: {}'.format(seed))
+
+    rng = random.Random(seed)
+
+    # Get all the symbols from kallsyms.
+    with open('/proc/kallsyms') as kallsyms_file:
+        raw_symbol_list = kallsyms_file.readlines()
+
+    # Keep only the symbol name.
+    raw_symbol_list = [x.split()[2].strip() for x in raw_symbol_list]
+
+    instrumentation_points = []
+
+    # Add all symbols.
+    instrumentation_points.extend(raw_symbol_list)
+
+    # For each symbol, create 2 new instrumentation points by random offsets.
+    for s in raw_symbol_list:
+        offsets = rng.sample(range(1, 10), 2)
+        for offset in offsets:
+            instrumentation_points.append(s + "+" + str(hex(offset)))
+
+    lower_bound = 0x0
+    upper_bound = 0xffffffffffffffff
+    address_list = []
+
+    # Add random addresses to the instrumentation points.
+    for _ in range(1000):
+        instrumentation_points.append(hex(rng.randint(lower_bound, upper_bound)))
+
+    # Shuffle the entire list.
+    rng.shuffle(instrumentation_points)
+
+    # Save instrumentation points to disk and attach it to lava test run.
+    save_instr_points(instrumentation_points)
+
+if __name__ == "__main__":
+    main()
This page took 0.028319 seconds and 4 git commands to generate.