diff options
Diffstat (limited to 'doc/HACKING')
-rw-r--r-- | doc/HACKING/CodingStandards.md | 11 | ||||
-rw-r--r-- | doc/HACKING/Fuzzing.md | 123 | ||||
-rw-r--r-- | doc/HACKING/HelpfulTools.md | 68 | ||||
-rw-r--r-- | doc/HACKING/ReleasingTor.md | 89 | ||||
-rw-r--r-- | doc/HACKING/Tracing.md | 91 | ||||
-rw-r--r-- | doc/HACKING/WritingTests.md | 2 |
6 files changed, 326 insertions, 58 deletions
diff --git a/doc/HACKING/CodingStandards.md b/doc/HACKING/CodingStandards.md index f1c65850a4..c7787a72cc 100644 --- a/doc/HACKING/CodingStandards.md +++ b/doc/HACKING/CodingStandards.md @@ -4,9 +4,10 @@ Coding conventions for Tor tl;dr: - Run configure with `--enable-fatal-warnings` - - Run `make check-spaces` to catch whitespace errors - Document your functions - Write unit tests + - Run `make test-full` to test against all unit and integration tests. + - Run `make distcheck` to ensure the distribution works - Add a file in `changes` for your branch. Patch checklist @@ -22,10 +23,12 @@ preference) Did you remember... - To build your code while configured with `--enable-fatal-warnings`? - - To run `make check-spaces` on your code? - To run `make check-docs` to see whether all new options are on the manpage? - To write unit tests, as possible? + - To run `make test-full` to test against all unit and integration tests (or + `make test-full-online` if you have a working connection to the internet)? + - To test that the distribution will actually work via `make distcheck`? - To base your code on the appropriate branch? - To include a file in the `changes` directory as appropriate? @@ -93,6 +96,10 @@ What needs a changes file? rewrites. Anything about which somebody might plausibly wonder "when did that happen, and/or why did we do that" 6 months down the line. +What does not need a changes file? + + * Bugfixes for code that hasn't shipped in any released version of Tor + Why use changes files instead of Git commit messages? * Git commit messages are written for developers, not users, and they diff --git a/doc/HACKING/Fuzzing.md b/doc/HACKING/Fuzzing.md new file mode 100644 index 0000000000..2039d6a4c0 --- /dev/null +++ b/doc/HACKING/Fuzzing.md @@ -0,0 +1,123 @@ += Fuzzing Tor + +== The simple version (no fuzzing, only tests) + +Check out fuzzing-corpora, and set TOR_FUZZ_CORPORA to point to the place +where you checked it out. + +To run the fuzzing test cases in a deterministic fashion, use: + make test-fuzz-corpora + +This won't actually fuzz Tor! It will just run all the fuzz binaries +on our existing set of testcases for the fuzzer. + + +== Different kinds of fuzzing + +Right now we support three different kinds of fuzzer. + +First, there's American Fuzzy Lop (AFL), a fuzzer that works by forking +a target binary and passing it lots of different inputs on stdin. It's the +trickiest one to set up, so I'll be describing it more below. + +Second, there's libFuzzer, a llvm-based fuzzer that you link in as a library, +and it runs a target function over and over. To use this one, you'll need to +have a reasonably recent clang and libfuzzer installed. At that point, you +just build with --enable-expensive-hardening and --enable-libfuzzer. That +will produce a set of binaries in src/test/fuzz/lf-fuzz-* . These programs +take as input a series of directories full of fuzzing examples. For more +information on libfuzzer, see http://llvm.org/docs/LibFuzzer.html + +Third, there's Google's OSS-Fuzz infrastructure, which expects to get all of +its. For more on this, see https://github.com/google/oss-fuzz and the +projects/tor subdirectory. You'll need to mess around with Docker a bit to +test this one out; it's meant to run on Google's infrastructure. + +In all cases, you'll need some starting examples to give the fuzzer when it +starts out. There's a set in the "fuzzing-corpora" git repository. Try +setting TOR_FUZZ_CORPORA to point to a checkout of that repository + +== Writing Tor fuzzers + +A tor fuzzing harness should have: +* a fuzz_init() function to set up any necessary global state. +* a fuzz_main() function to receive input and pass it to a parser. +* a fuzz_cleanup() function to clear global state. + +Most fuzzing frameworks will produce many invalid inputs - a tor fuzzing +harness should rejecting invalid inputs without crashing or behaving badly. + +But the fuzzing harness should crash if tor fails an assertion, triggers a +bug, or accesses memory it shouldn't. This helps fuzzing frameworks detect +"interesting" cases. + + +== Guided Fuzzing with AFL + +There is no HTTPS, hash, or signature for American Fuzzy Lop's source code, so +its integrity can't be verified. That said, you really shouldn't fuzz on a +machine you care about, anyway. + +To Build: + Get AFL from http://lcamtuf.coredump.cx/afl/ and unpack it + cd afl + make + cd ../tor + PATH=$PATH:../afl/ CC="../afl/afl-gcc" ./configure --enable-expensive-hardening + AFL_HARDEN=1 make clean fuzzers + +To Find The ASAN Memory Limit: (64-bit only) + +On 64-bit platforms, afl needs to know how much memory ASAN uses, +because ASAN tends to allocate a ridiculous amount of virtual memory, +and then not actually use it. + +Read afl/docs/notes_for_asan.txt for more details. + + Download recidivm from http://jwilk.net/software/recidivm + Download the signature + Check the signature + tar xvzf recidivm*.tar.gz + cd recidivm* + make + /path/to/recidivm -v src/test/fuzz/fuzz-http + Use the final "ok" figure as the input to -m when calling afl-fuzz + (Normally, recidivm would output a figure automatically, but in some cases, + the fuzzing harness will hang when the memory limit is too small.) + +You could also just say "none" instead of the memory limit below, if you +don't care about memory limits. + + +To Run: + mkdir -p src/test/fuzz/fuzz_http_findings + ../afl/afl-fuzz -i ${TOR_FUZZ_CORPORA}/http -o src/test/fuzz/fuzz_http_findings -m <asan-memory-limit> -- src/test/fuzz/fuzz-http + + +AFL has a multi-core mode, check the documentation for details. +You might find the included fuzz-multi.sh script useful for this. + +macOS (OS X) requires slightly more preparation, including: +* using afl-clang (or afl-clang-fast from the llvm directory) +* disabling external crash reporting (AFL will guide you through this step) + +== Triaging Issues + +Crashes are usually interesting, particularly if using AFL_HARDEN=1 and --enable-expensive-hardening. Sometimes crashes are due to bugs in the harness code. + +Hangs might be interesting, but they might also be spurious machine slowdowns. +Check if a hang is reproducible before reporting it. Sometimes, processing +valid inputs may take a second or so, particularly with the fuzzer and +sanitizers enabled. + +To see what fuzz-http is doing with a test case, call it like this: + src/test/fuzz/fuzz-http --debug < /path/to/test.case + +(Logging is disabled while fuzzing to increase fuzzing speed.) + +== Reporting Issues + +Please report any issues discovered using the process in Tor's security issue +policy: + +https://trac.torproject.org/projects/tor/wiki/org/meetings/2016SummerDevMeeting/Notes/SecurityIssuePolicy diff --git a/doc/HACKING/HelpfulTools.md b/doc/HACKING/HelpfulTools.md index a7f36e6c7e..b8ba2aa408 100644 --- a/doc/HACKING/HelpfulTools.md +++ b/doc/HACKING/HelpfulTools.md @@ -142,6 +142,12 @@ run `make test-network`. We also have scripts to run integration tests using Stem. To try them, set `STEM_SOURCE_DIR` to your Stem source directory, and run `test-stem`. +Profiling Tor +------------- + +Ongoing notes about Tor profiling can be found at +https://pad.riseup.net/p/profiling-tor + Profiling Tor with oprofile --------------------------- @@ -168,20 +174,62 @@ Here are some basic instructions * `opreport -l that_dir/*` - Profit +Profiling Tor with perf +----------------------- + +This works with a running Tor, and requires root. + +1. Decide how long you want to profile for. Start with (say) 30 seconds. If that + works, try again with longer times. + +2. Find the PID of your running tor process. + +3. Run `perf record --call-graph dwarf -p <PID> sleep <SECONDS>` + + (You may need to do this as root.) + + You might need to add `-e cpu-clock` as an option to the perf record line + above, if you are on an older CPU without access to hardware profiling + events, or in a VM, or something. + +4. Now you have a perf.data file. Have a look at it with `perf report + --no-children --sort symbol,dso` or `perf report --no-children --sort + symbol,dso --stdio --header`. How does it look? + +5a. Once you have a nice big perf.data file, you can compress it, encrypt it, + and send it to your favorite Tor developers. + +5b. Or maybe you'd rather not send a nice big perf.data file. Who knows what's + in that!? It's kinda scary. To generate a less scary file, you can use `perf + report -g > <FILENAME>.out`. Then you can compress that and put it somewhere + public. + +Profiling Tor with gperftools aka Google-performance-tools +---------------------------------------------------------- + +This should work on nearly any unixy system. It doesn't seem to be compatible +with RunAsDaemon though. + +Beforehand, install google-perftools. + +1. You need to rebuild Tor, hack the linking steps to add `-lprofiler` to the + libs. You can do this by adding `LIBS=-lprofiler` when you call `./configure`. + +Now you can run Tor with profiling enabled, and use the pprof utility to look at +performance! See the gperftools manual for more info, but basically: + +2. Run `env CPUPROFILE=/tmp/profile src/or/tor -f <path/torrc>`. The profile file + is not written to until Tor finishes execuction. + +3. Run `pprof src/or/tor /tm/profile` to start the REPL. + Generating and analyzing a callgraph ------------------------------------ -1. Run `./scripts/maint/generate_callgraph.sh`. This will generate a - bunch of files in a new ./callgraph directory. - -2. Run `./scripts/maint/analyze_callgraph.py callgraph/src/*/*`. This - will do a lot of graph operations and then dump out a new - `callgraph.pkl` file, containing data in Python's 'pickle' format. +0. Build Tor on linux or mac, ideally with -O0 or -fno-inline. -3. Run `./scripts/maint/display_callgraph.py`. It will display: - - the number of functions reachable from each function. - - all strongly-connnected components in the Tor callgraph - - the largest bottlenecks in the largest SCC in the Tor callgraph. +1. Clone 'https://gitweb.torproject.org/user/nickm/calltool.git/' . + Follow the README in that repository. Note that currently the callgraph generator can't detect calls that pass through function pointers. diff --git a/doc/HACKING/ReleasingTor.md b/doc/HACKING/ReleasingTor.md index 7595398241..4ece4d7a1d 100644 --- a/doc/HACKING/ReleasingTor.md +++ b/doc/HACKING/ReleasingTor.md @@ -26,9 +26,7 @@ new Tor release: What about Coverity Scan? - Is make check-spaces happy? - - Does 'make distcheck' compain? + Does 'make distcheck' complain? How about 'make test-stem' and 'make test-network'? @@ -44,21 +42,16 @@ new Tor release: of them and reordering to focus on what users and funders would find interesting and understandable. - 1. Make sure that everything that wants a bug number has one. - Make sure that everything which is a bugfix says what version - it was a bugfix on. - - 2. Concatenate them. - - 3. Sort them by section. Within each section, sort by "version it's - a bugfix on", else by numerical ticket order. + To do this, first run `./scripts/maint/lintChanges.py changes/*` and + fix as many warnings as you can. Then run `./scripts/maint/sortChanges.py + changes/* > changelog.in` to combine headings and sort the entries. + After that, it's time to hand-edit and fix the issues that lintChanges + can't find: - 4. Clean them up: + 1. Within each section, sort by "version it's a bugfix on", else by + numerical ticket order. - Standard idioms: - `Fixes bug 9999; bugfix on 0.3.3.3-alpha.` - - One space after a period. + 2. Clean them up: Make stuff very terse @@ -86,19 +79,23 @@ new Tor release: maint-0.2.1), be sure to make the stanzas identical (so people can distinguish if these are the same change). - 5. Merge them in. + 3. Clean everything one last time. - 6. Clean everything one last time. + 4. Run `./scripts/maint/format_changelog.py --inplace` to make it prettier - 7. Run `./scripts/maint/format_changelog.py` to make it prettier. 2. Compose a short release blurb to highlight the user-facing changes. Insert said release blurb into the ChangeLog stanza. If it's a stable release, add it to the ReleaseNotes file too. If we're adding - to a release-0.2.x branch, manually commit the changelogs to the later + to a release-* branch, manually commit the changelogs to the later git branches too. -3. If you're doing the first stable release in a series, you need to +3. If there are changes that require or suggest operator intervention + before or during the update, mail operators (either dirauth or relays + list) with a headline that indicates that an action is required or + appreciated. + +4. If you're doing the first stable release in a series, you need to create a ReleaseNotes for the series as a whole. To get started there, copy all of the Changelog entries from the series into a new file, and run `./scripts/maint/sortChanges.py` on it. That will @@ -111,38 +108,40 @@ new Tor release: === III. Making the source release. -1. In `maint-0.2.x`, bump the version number in `configure.ac` and run +1. In `maint-0.?.x`, bump the version number in `configure.ac` and run `scripts/maint/updateVersions.pl` to update version numbers in other - places, and commit. Then merge `maint-0.2.x` into `release-0.2.x`. + places, and commit. Then merge `maint-0.?.x` into `release-0.?.x`. (NOTE: To bump the version number, edit `configure.ac`, and then run either `make`, or `perl scripts/maint/updateVersions.pl`, depending on your version.) -2. Make distcheck, put the tarball up somewhere, and tell `#tor` about - it. Wait a while to see if anybody has problems building it. Try to - get Sebastian or somebody to try building it on Windows. +2. Make distcheck, put the tarball up in somewhere (how about your + homedir on your homedir on people.torproject.org?) , and tell `#tor` + about it. Wait a while to see if anybody has problems building it. + (Though jenkins is usually pretty good about catching these things.) === IV. Commit, upload, announce 1. Sign the tarball, then sign and push the git tag: gpg -ba <the_tarball> - git tag -u <keyid> tor-0.2.x.y-status - git push origin tag tor-0.2.x.y-status + git tag -u <keyid> tor-0.3.x.y-status + git push origin tag tor-0.3.x.y-status 2. scp the tarball and its sig to the dist website, i.e. `/srv/dist-master.torproject.org/htdocs/` on dist-master. When you want it to go live, you run "static-update-component dist.torproject.org" on dist-master. - Edit `include/versions.wmi` and `Makefile` to note the new version. + In the webwml.git repository, `include/versions.wmi` and `Makefile` + to note the new version. (NOTE: Due to #17805, there can only be one stable version listed at once. Nonetheless, do not call your version "alpha" if it is stable, or people will get confused.) -3. Email the packagers (cc'ing tor-assistants) that a new tarball is up. +3. Email the packagers (cc'ing tor-team) that a new tarball is up. The current list of packagers is: - {weasel,gk,mikeperry} at torproject dot org @@ -151,11 +150,7 @@ new Tor release: - {lfleischer} at archlinux dot org - {Nathan} at freitas dot net - {mike} at tig dot as - - {tails-rm} at boum dot org (for pre-release announcments) - - - - {tails-dev} at boum dot org (for at-release announcements) - + - {tails-rm} at boum dot org 4. Add the version number to Trac. To do this, go to Trac, log in, select "Admin" near the top of the screen, then select "Versions" from @@ -164,22 +159,26 @@ new Tor release: 0.2.2.23-alpha" (or whatever the version is), and we select the date as the date in the ChangeLog. -5. Wait up to a day or two (for a development release), or until most - packages are up (for a stable release), and mail the release blurb and - changelog to tor-talk or tor-announce. +5. Mail the release blurb and ChangeLog to tor-talk (development release) or + tor-announce (stable). + + Post the changelog on the the blog as well. You can generate a + blog-formatted version of the changelog with the -B option to + format-changelog. - (We might be moving to faster announcements, but don't announce until - the website is at least updated.) + When you post, include an estimate of when the next TorBrowser + releases will come out that include this Tor release. This will + usually track https://wiki.mozilla.org/RapidRelease/Calendar , but it + can vary. === V. Aftermath and cleanup -1. If it's a stable release, bump the version number in the `maint-x.y.z` - branch to "newversion-dev", and do a `merge -s ours` merge to avoid - taking that change into master. Do a similar `merge -s theirs` - merge to get the change (and only that change) into release. (Some - of the build scripts require that maint merge cleanly into release.) +1. If it's a stable release, bump the version number in the + `maint-x.y.z` branch to "newversion-dev", and do a `merge -s ours` + merge to avoid taking that change into master. 2. Forward-port the ChangeLog (and ReleaseNotes if appropriate). +3. Keep an eye on the blog post, to moderate comments and answer questions. diff --git a/doc/HACKING/Tracing.md b/doc/HACKING/Tracing.md new file mode 100644 index 0000000000..a5fb5165e2 --- /dev/null +++ b/doc/HACKING/Tracing.md @@ -0,0 +1,91 @@ +# Tracing # + +This document describes how the event tracing subsystem works in tor so +developers can add events to the code base but also hook them to an event +tracing framework. + +## Basics ### + +Event tracing is seperated in two concepts, trace events and a tracer. The +tracing subsystem can be found in `src/trace`. The `events.h` header file is +the main file that maps the different tracers to trace events. + +### Events ### + +A trace event is basically a function from which we can pass any data that +we want to collect. In addition, we specify a context for the event such as +a subsystem and an event name. + +A trace event in tor has the following standard format: + + tor_trace(subsystem, event\_name, args...) + +The `subsystem` parameter is the name of the subsytem the trace event is in. +For example that could be "scheduler" or "vote" or "hs". The idea is to add +some context to the event so when we collect them we know where it's coming +from. The `event_name` is the name of the event which helps a lot with +adding some semantic to the event. Finally, `args` is any number of +arguments we want to collect. + +Here is an example of a possible tracepoint in main(): + + tor_trace(main, init_phase, argc) + +The above is a tracepoint in the `main` subsystem with `init_phase` as the +event name and the `int argc` is passed to the event as well. + +How `argc` is collected or used has nothing to do with the instrumentation +(adding trace events to the code). It is the work of the tracer so this is why +the trace events and collection framework (tracer) are decoupled. You _can_ +have trace events without a tracer. + +### Tracer ### + +In `src/trace/events.h`, we map the `tor_trace()` function to the right +tracer. A tracer support is only enabled at compile time. For instance, the +file `src/trace/debug.h` contains the mapping of the generic tracing function +`tor_trace()` to the `log_debug()` function. More specialized function can be +mapped depending on the tracepoint. + +## Build System ## + +This section describes how it is integrated into the build system of tor. + +By default, every tracing events are disabled in tor that is `tor_trace()` +is a NOP. + +To enable a tracer, there is a configure option on the form of: + + --enable-tracing-<tracer> + +We have an option that will send every trace events to a `log_debug()` (as +mentionned above) which will print you the subsystem and name of the event but +not the arguments for technical reasons. This is useful if you want to quickly +see if your trace event is being hit or well written. To do so, use this +configure option: + + --enable-tracing-debug + +## Instrument Tor ## + +This is pretty easy. Let's say you want to add a trace event in +`src/or/rendcache.c`, you only have to add this include statement: + + #include "trace/events.h" + +Once done, you can add as many as you want `tor_trace()` that you need. +Please use the right subsystem (here it would be `hs`) and a unique name that +tells what the event is for. For example: + + tor_trace(hs, store_desc_as_client, desc, desc_id); + +If you look in `src/trace/events.h`, you'll see that if tracing is enabled it +will be mapped to a function called: + + tor_trace_hs_store_desc_as_client(desc, desc_id) + +And the point of all this is for that function to be defined in a new file +that you might want to add named `src/trace/hs.{c|h}` which would defined how +to collect the data for the `tor_trace_hs_store_desc_as_client()` function +like for instance sending it to a `log_debug()` or do more complex operations +or use a userspace tracer like LTTng (https://lttng.org). diff --git a/doc/HACKING/WritingTests.md b/doc/HACKING/WritingTests.md index de80bbdef2..4dae41e922 100644 --- a/doc/HACKING/WritingTests.md +++ b/doc/HACKING/WritingTests.md @@ -48,7 +48,7 @@ isolation, you just run `./src/test/test-memwipe`. To run tests within the unit test programs, you can specify the name of the test. The string ".." can be used as a wildcard at the end of the test name. For example, to run all the cell format tests, enter -`./src/test/test cellfmt/..`. To run +`./src/test/test cellfmt/..`. Many tests that need to mess with global state run in forked subprocesses in order to keep from contaminating one another. But when debugging a failing test, |