1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <limits.h>
6 #include <stdarg.h>
7 #include <stdio.h>
8 #include <string.h>
9
10 #include <fbl/auto_call.h>
11 #include <fbl/string_printf.h>
12 #include <unittest/unittest.h>
13
14 #include "fuzzer-fixture.h"
15 #include "test-fuzzer.h"
16
17 namespace fuzzing {
18 namespace testing {
19
20 #define ZXDEBUG 0
21
22 // Public methods
23
TestFuzzer()24 TestFuzzer::TestFuzzer()
25 : out_(nullptr), outbuf_(nullptr), outbuflen_(0), err_(nullptr), errbuf_(nullptr),
26 errbuflen_(0) {}
27
~TestFuzzer()28 TestFuzzer::~TestFuzzer() {
29 Reset();
30 }
31
Reset()32 void TestFuzzer::Reset() {
33 Fuzzer::Reset();
34 args_.clear();
35 executable_.clear();
36 manifest_.clear();
37 dictionary_.clear();
38 data_path_.Reset();
39
40 if (out_) {
41 fclose(out_);
42 #if ZXDEBUG
43 fprintf(stdout, "%s", outbuf_);
44 fflush(stdout);
45 #endif
46 free(outbuf_);
47 outbuflen_ = 0;
48 outbuf_ = nullptr;
49 out_ = nullptr;
50 }
51
52 if (err_) {
53 fclose(err_);
54 #if ZXDEBUG
55 fprintf(stderr, "%s", errbuf_);
56 fflush(stderr);
57 #endif
58 free(errbuf_);
59 errbuflen_ = 0;
60 errbuf_ = nullptr;
61 err_ = nullptr;
62 }
63 }
64
InitZircon()65 bool TestFuzzer::InitZircon() {
66 BEGIN_HELPER;
67 ASSERT_TRUE(fixture_.CreateZircon());
68 ASSERT_TRUE(Init());
69 END_HELPER;
70 }
71
InitFuchsia()72 bool TestFuzzer::InitFuchsia() {
73 BEGIN_HELPER;
74 ASSERT_TRUE(fixture_.CreateFuchsia());
75 ASSERT_TRUE(Init());
76 END_HELPER;
77 }
78
Eval(const char * cmdline)79 zx_status_t TestFuzzer::Eval(const char* cmdline) {
80 BEGIN_HELPER;
81 ASSERT_TRUE(Init());
82
83 char* buf = strdup(cmdline);
84 ASSERT_NONNULL(buf);
85 auto cleanup = fbl::MakeAutoCall([&buf]() { free(buf); });
86 char* ptr = buf;
87 char* arg;
88 while ((arg = strsep(&ptr, " "))) {
89 if (arg && *arg) {
90 args_.push_back(arg);
91 }
92 }
93
94 END_HELPER;
95 }
96
InStdOut(const char * needle)97 bool TestFuzzer::InStdOut(const char* needle) {
98 fflush(out_);
99 return strcasestr(outbuf_, needle) != nullptr;
100 }
101
InStdErr(const char * needle)102 bool TestFuzzer::InStdErr(const char* needle) {
103 fflush(err_);
104 return strcasestr(errbuf_, needle) != nullptr;
105 }
106
FindArg(const char * fmt,const fbl::String & arg)107 int TestFuzzer::FindArg(const char* fmt, const fbl::String& arg) {
108 fbl::StringBuffer<PATH_MAX> buffer;
109 buffer.AppendPrintf(fmt, arg.c_str());
110 int result = 0;
111 for (const char* arg = args_.first(); arg; arg = args_.next()) {
112 if (strcmp(arg, buffer.c_str()) == 0) {
113 return result;
114 }
115 ++result;
116 }
117 return -1;
118 }
119
CheckProcess(zx_handle_t process,const char * target)120 bool TestFuzzer::CheckProcess(zx_handle_t process, const char* target) {
121 if (target) {
122 set_target(target);
123 }
124 return Fuzzer::CheckProcess(process);
125 }
126
127 // Protected methods
128
Execute()129 zx_status_t TestFuzzer::Execute() {
130 zx_status_t rc;
131
132 GetArgs(&args_);
133
134 fbl::String package, target;
135 const char* s = args_.first();
136 executable_.Set(s);
137 if (strcmp(s, "/bin/run") != 0) {
138 // BootFS path
139 // .../boot/test/fuzz/<target>
140 package.Set("zircon_fuzzers");
141 target.Set(s + fixture_.path("boot/test/fuzz/").length());
142 } else {
143 // PkgFS path
144 // fuchsia-pkg://fuchsia.com/<package>#meta/<target>.cmx
145 s = args_.next();
146 s += strlen("fuchsia-pkg://fuchsia.com/");
147 const char* t = strchr(s, '#');
148 package.Set(s, t - s);
149 s = t + strlen("#meta/");
150 t = strrchr(s, '.');
151 target.Set(s, t - s);
152 }
153 manifest_ = fbl::StringPrintf("fuchsia-pkg://fuchsia.com/%s#meta/%s.cmx", package.c_str(),
154 target.c_str());
155 dictionary_ = fixture_.path("pkgfs/packages/%s/%s/data/%s/dictionary", package.c_str(),
156 fixture_.max_version(package.c_str()), target.c_str());
157 data_path_.Reset();
158 if ((rc = data_path_.Push(fixture_.path("data/fuzzing"))) != ZX_OK ||
159 (rc = data_path_.Push(package)) != ZX_OK || (rc = data_path_.Push(target)) != ZX_OK) {
160 return rc;
161 }
162
163 return ZX_OK;
164 }
165
166 // Private methods
167
Init()168 bool TestFuzzer::Init() {
169 BEGIN_HELPER;
170 Reset();
171
172 out_ = open_memstream(&outbuf_, &outbuflen_);
173 ASSERT_NONNULL(out_);
174
175 err_ = open_memstream(&errbuf_, &errbuflen_);
176 ASSERT_NONNULL(err_);
177
178 // Configure base object
179 set_root(fixture_.path());
180 set_out(out_);
181 set_err(err_);
182
183 END_HELPER;
184 }
185
186 } // namespace testing
187 } // namespace fuzzing
188