Newer
Older
#include <iostream>
#include <fstream>
#include <sstream>
#include <memory>
#include <string>
#include <grpcpp/grpcpp.h>
#include <turbo-rpc/turbo.grpc.pb.h>
class TurboServiceImpl final : public TurboService::Service
TurboServiceImpl()
{
pqxx::connection conn{db_connect_options.c_str()};
pqxx::work txn(conn);
cout << "Creating turbod tables" << endl;
txn.exec(turbod_schema.c_str());
txn.commit();
}
Status Ping(ServerContext *context, const Empty_t *request, Empty_t *reply) override final
{
return Status::OK;
}
Status BoostAdd(ServerContext *context, const BoostAddRequest_t *request, BoostAddReply_t *reply) override final
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
{
try
{
pqxx::connection conn{db_connect_options.c_str()};
pqxx::work txn(conn);
cout << "Requested creation of new boost named " << request->name() << endl;
conn.prepare("boostcheck", "select boost_id from boosts where boost_name = $1");
const auto check_res = txn.prepared("boostcheck")(request->name()).exec();
if(check_res.size() != 0)
{
return Status(ABORTED, "Boost already exists");
}
conn.prepare("boostadd", "insert into boosts (boost_name, create_time) values ($1, NOW()) returning boost_id ");
const auto add_res = txn.prepared("boostadd")(request->name()).exec();
if(add_res.size() != 1)
{
return Status(ABORTED, "Unexpected sql reply.");
}
reply->set_boost_id(add_res[0]["boost_id"].as<int>());
txn.commit();
return Status::OK;
}
catch(const std::exception& e)
{
return Status(ABORTED, e.what());
}
}
Status GetZafld (ServerContext *context, const GetZafldRequest_t *request, ZafldBinary_t *reply) override final
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
{
try
{
pqxx::connection conn{db_connect_options.c_str()};
pqxx::work txn(conn);
cout << "Requested zafld binary for " << request->ver_id() << endl;
conn.prepare("getzafld",
R"""(select
case when zafl_binary is null then '' else zafl_binary end as zafl_binary ,
case when err is null then false else err end as err
from boost_versions where ver_id = $1)"""
);
const auto res_table = txn.prepared("getzafld")(request->ver_id()).exec();
if(res_table.size() != 1)
{
return Status(ABORTED, "Invalid version id");
}
const auto zafl_binary_contents = pqxx::binarystring(res_table[0]["zafl_binary"]).str();
cout << "Zafl version is " << zafl_binary_contents.size() << " bytes" << endl;
reply->set_zafld_bin(zafl_binary_contents);
reply->set_err(res_table[0]["err"].as<bool>() );
return Status::OK;
}
catch(const std::exception& e)
{
return Status(ABORTED, e.what());
}
}
Status BoostList(ServerContext *context, const Empty_t *request, ServerWriter<BoostInfo_t> *writer) override final

Jason Hiser
committed
{
try
{
pqxx::connection conn{db_connect_options.c_str()};
pqxx::work txn(conn);
cout << "Requested boost list " << endl;
conn.prepare("boostlist", "select boost_id,encode(boost_name,'escape'), to_char(create_time, 'MM-DD-YYYY HH24:MI:SS') as create_time from boosts");

Jason Hiser
committed
const auto res_table = txn.prepared("boostlist").exec();
if(res_table.size() == 0)
{
return Status(ABORTED, "No Boosts found");
}
for(const auto &res : res_table)
{
auto reply = BoostInfo_t();
reply.set_id (res["boost_id" ].as<int> ());
reply.set_name (res["encode" ].as<string>());
reply.set_create_time (res["create_time"].as<string>());
writer->Write(reply);
}
return Status::OK;
}
catch(const std::exception& e)
{
return Status(ABORTED, e.what());
}
}
Status VersionList(ServerContext *context, const VersionListRequest_t *request, ServerWriter<VersionInfo_t> *writer) override final
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
{
try
{
pqxx::connection conn{db_connect_options.c_str()};
pqxx::work txn(conn);
cout << "Requested version list for boost id " << request->boost_id() << endl;
conn.prepare("boostlist",
R"""(
select
ver_id,
encode(orig_bin_sha,'text') as orig_sha,
encode(zafl_bin_sha,'text') as zafl_sha,
COALESCE(to_char(submit_time, 'MM-DD-YYYY HH24:MI:SS'), '') as submit_time,
COALESCE(to_char(start_time , 'MM-DD-YYYY HH24:MI:SS'), '') as start_time,
COALESCE(to_char(end_time , 'MM-DD-YYYY HH24:MI:SS'), '') as end_time,
err
from boost_versions where boost_id = $1)"""
);
const auto res_table = txn.prepared("boostlist")(request->boost_id()).exec();
if(res_table.size() == 0)
{
return Status(ABORTED, "No versions found");
}
const auto to_string = [](const pqxx::field &res) -> string
{
return res.is_null() ? "" : res.as<string>();
};
for(const auto &res : res_table)
{
auto reply = VersionInfo_t();
reply.set_ver_id (res["ver_id" ].as<int> ());
reply.set_orig_bin_sha (to_string(res["orig_sha" ]));
reply.set_zafl_bin_sha (to_string(res["zafl_sha" ]));
reply.set_submit_time (res["submit_time"].as<string>());
reply.set_start_time (res["start_time" ].as<string>());
reply.set_end_time (res["end_time" ].as<string>());
reply.set_err (res["err"].is_null() ? false : res["err"].as<bool>());

Jason Hiser
committed
writer->Write(reply);
}
return Status::OK;
}
catch(const std::exception& e)
{
return Status(ABORTED, e.what());
}
}
Status VersionAdd(ServerContext *context, const VersionAddRequest_t *request, VersionAddReply_t *reply) override final
{
try
{
pqxx::connection conn{db_connect_options.c_str()};
pqxx::work txn(conn);
cout << "Requested creation of new version for boost id " << request->boost_id() << endl;
conn.prepare("boostcheck", "select boost_id,boost_name from boosts where boost_id = $1");
const auto check_res = txn.prepared("boostcheck")(request->boost_id()).exec();
if(check_res.size() != 1)
{
return Status(ABORTED, "Boost id not found");
}
conn.prepare("versionadd", "insert into boost_versions ( boost_id, orig_binary, submit_time, err )"
" values ($1, $2, NOW(), false) returning ver_id ");
const auto boost_id = check_res[0]["boost_id"].as<int>();
const auto binary_data = pqxx::binarystring(request->version_contents().c_str(), request->version_contents().size());
const auto add_res = txn.prepared("versionadd")(boost_id)(binary_data).exec();
if(add_res.size() != 1)
{
return Status(ABORTED, "Unexpected sql reply.");
}
reply->set_version_id(add_res[0]["ver_id"].as<int>());
txn.commit();
return Status::OK;
}
catch(const std::exception& e)
{
return Status(ABORTED, e.what());
}
}
Status GetZaflLog(ServerContext *context, const GetZaflLogRequest_t *request, LogFile_t *reply) override final
{
try
{
pqxx::connection conn{db_connect_options.c_str()};
pqxx::work txn(conn);
cout << "Requested zafl log for " << request->ver_id() << endl;
conn.prepare("getzafllog",
R"""(select
case when log is null then '' else encode(log,'escape') end as log
from zafl_logs where ver_id = $1)"""
);
const auto res_table = txn.prepared("getzafllog")(request->ver_id()).exec();
if(res_table.size() != 1)
{
return Status(ABORTED, "Invalid version id");
}
const auto zafl_log = res_table[0]["log"].as<string>();
reply->set_log(zafl_log);
return Status::OK;
}
catch(const std::exception& e)
{
return Status(ABORTED, e.what());
}
}
Status GetFuzzLog(ServerContext *context, const GetFuzzLogRequest_t *request, LogFile_t *reply) override final
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
{
try
{
pqxx::connection conn{db_connect_options.c_str()};
pqxx::work txn(conn);
cout << "Requested Fuzz log for " << request->ver_id() << endl;
conn.prepare("getFuzzlog",
R"""(select
case when log is null then '' else encode(log,'escape') end as log
from fuzz_logs where ver_id = $1)"""
);
const auto res_table = txn.prepared("getFuzzlog")(request->ver_id()).exec();
if(res_table.size() != 1)
{
return Status(ABORTED, "Invalid version id");
}
const auto zafl_log = res_table[0]["log"].as<string>();
reply->set_log(zafl_log);
return Status::OK;
}
catch(const std::exception& e)
{
return Status(ABORTED, e.what());
}
}
Status SeedAdd(ServerContext *context, const SeedAddRequest_t *request, SeedAddReply_t *reply) override final
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
{
try
{
pqxx::connection conn{db_connect_options.c_str()};
pqxx::work txn(conn);
cout << "Requested seed add " << request->boost_id() << endl;
// prepare and execute a command to insert an input
conn.prepare("input_add",
R"""(insert into inputs ( boost_id, create_time, prov, input_data) values ($1, NOW(), 'User', $2) returning input_id )""");
const auto res_input = txn.prepared("input_add")(request->boost_id())(request->seed_file()).exec();
if(res_input.size() != 1)
{
return Status(ABORTED, "Invalid boost id");
}
const auto input_id = res_input[0]["input_id"].as<int32_t>();
// prepare and execute a command to mark the input as a seed
conn.prepare("seed_add", R"""(insert into seeds ( input_id ) values ($1) returning seed_id )""");
const auto res_seed = txn.prepared("seed_add")(input_id).exec();
if(res_seed.size() != 1)
{
return Status(ABORTED, "Unexpected error");
}
const auto seed_id = res_seed[0]["seed_id"].as<int32_t>();
// finalize the transaction
txn.commit();
// prepare a reply
reply->set_input_id(input_id);
reply->set_seed_id (seed_id );
return Status::OK;
}
catch(const std::exception& e)
{
return Status(ABORTED, e.what());
}
}
Status InputAdd(ServerContext *context, const InputAddRequest_t *request, InputAddReply_t *reply) override final
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
{
try
{
pqxx::connection conn{db_connect_options.c_str()};
pqxx::work txn(conn);
cout << "Requested input add for ver-id=" << request->ver_id() << endl;
conn.prepare("findboost", "select boost_id from boost_versions where ver_id = $1");
const auto boost_id_res = txn.prepared("findboost")(request->ver_id()).exec();
if(boost_id_res.size() != 1)
{
return Status(ABORTED, "Invalid version id");
}
const auto boost_id = boost_id_res[0]["boost_id"].as<int>();
// prepare and execute a command to insert an input
conn.prepare("aflinputadd", R"""(insert into inputs ( boost_id, create_time, prov, input_data) values ($1, NOW(), 'AFL', $2) returning input_id )""");
const auto res_input = txn.prepared("aflinputadd")(boost_id)(request->input_file()).exec();
if(res_input.size() != 1)
{
return Status(ABORTED, "Invalid boost id");
}
const auto input_id = res_input[0]["input_id"].as<int32_t>();
// finalize the transaction
txn.commit();
// prepare a reply
reply->set_input_id(input_id);
return Status::OK;
}
catch(const std::exception& e)
{
return Status(ABORTED, e.what());
}
}
Status DownloadInputs(ServerContext *context, const DownloadInputsRequest_t *request, ServerWriter<DownloadInputsReply_t> *writer) override final
{
try
{
pqxx::connection conn{db_connect_options.c_str()};
pqxx::work txn(conn);
cout << "Requested boost list " << endl;
conn.prepare("input_download", "select input_id,input_data from inputs where boost_id in (select boost_id from boost_versions where ver_id = $1) ");
const auto res_table = txn.prepared("input_download")(request->ver_id()).exec();
if(res_table.size() == 0)
{
return Status(ABORTED, "No inputs found");
}
for(const auto &res : res_table)
{
// get input id
const auto input_id = res["input_id"].as<uint32_t>();
reply.set_input_id(input_id);
// get yaml string
const auto input_contents = pqxx::binarystring(res["input_data"]).str();
reply.set_yaml_string(input_contents);
writer->Write(reply);
}
return Status::OK;
}
catch(const std::exception& e)
{
return Status(ABORTED, e.what());
}
}
Status DownloadCrashes(ServerContext *context, const DownloadInputsRequest_t *request, ServerWriter<DownloadInputsReply_t> *writer) override final
{
try
{
pqxx::connection conn{db_connect_options.c_str()};
pqxx::work txn(conn);
cout << "Requested boost list " << endl;
conn.prepare("input_download", "select input_id,input_data from inputs where input_id in (select input_id from forensics where ver_id = $1) ");
const auto res_table = txn.prepared("input_download")(request->ver_id()).exec();

Jason Hiser
committed
// OK to have 0 results, just means we haven't found a crash yet.
for(const auto &res : res_table)
{
// create a response
auto reply = DownloadInputsReply_t();
// get input id
const auto input_id = res["input_id"].as<uint32_t>();
reply.set_input_id(input_id);
// get yaml string
const auto input_contents = pqxx::binarystring(res["input_data"]).str();
reply.set_yaml_string(input_contents);
writer->Write(reply);
}
return Status::OK;
}
catch(const std::exception& e)
{
return Status(ABORTED, e.what());
}
}
Status AddFuzzLog(ServerContext *context, const AddFuzzLogRequest_t *request, Empty_t *reply) override final
{
try
{
pqxx::connection conn{db_connect_options.c_str()};
pqxx::work txn(conn);
cout << "Add to Fuzz request" << endl;
conn.prepare("update_fuzz_log",
R"""(
with upsert as (update fuzz_logs set log = log || $2 where ver_id = $1 returning *)
insert into fuzz_logs (ver_id,log) select $1,$2 where not exists (select * from upsert)
)""");
txn.prepared("update_fuzz_log")(request->ver_id())(request->log()).exec();
txn.commit();
return Status::OK;
}
catch(const std::exception& e)
{
return Status(ABORTED, e.what());
}
}
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
Status AddForensics(ServerContext *context, const AddForensicsRequest_t *request, AddForensicsReply_t *reply) override final
{
try
{
pqxx::connection conn{db_connect_options.c_str()};
pqxx::work txn(conn);
cout << "Add to crash request" << endl;
conn.prepare("addfor",
R"""(
insert into forensics (ver_id,input_id) values ($1,$2) returning forensic_id
)""");
const auto res = txn.prepared("addfor")(request->ver_id())(request->input_id()).exec();
txn.commit();
if(res.size() != 1)
{
return Status(ABORTED, "Internal error");
}
reply->set_forensic_id(res[0]["forensic_id"].as<uint32_t>());
return Status::OK;
}
catch(const std::exception& e)
{
return Status(ABORTED, e.what());
}
}
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
private:
string db_connect_options = string("dbname=" TURBODB " host=localhost");
const string turbod_schema =
R"""(
-- avoid NOTICES if tables already exist.
SET client_min_messages = error;
-- avoid error if type already exists
DO $$ BEGIN
create type InputProvenance as ENUM ('User', 'AFL', 'QSym', 'Unknown');
EXCEPTION
when duplicate_object then null;
END $$;
create table if not exists boosts
(
boost_id serial primary key,
boost_name bytea,
create_time timestamp
);
create table if not exists boost_versions
(
ver_id serial primary key,
boost_id integer references boosts(boost_id),
orig_binary bytea,
orig_bin_sha bytea,
zafl_binary bytea,
zafl_bin_sha bytea,
submit_time timestamp,
start_time timestamp,
end_time timestamp,
err bool
);
create table if not exists inputs
(
input_id serial primary key,
boost_id integer references boosts(boost_id),
create_time timestamp,
prov InputProvenance,
input_data bytea,
sha256 bytea
);
create table if not exists forensics
(
forensic_id serial primary key,
input_id integer references inputs(input_id),
ver_id integer references boost_versions(ver_id),
exit_code integer,
backtrace bytea,
prov InputProvenance
);
create table if not exists seeds
(
seed_id serial primary key,
);
create table if not exists zafl_logs
(
log_id serial primary key,
log bytea,
ver_id integer references boost_versions(ver_id)
);
create table if not exists fuzz_logs
(
log_id serial primary key,
log bytea,
ver_id integer references boost_versions(ver_id),
prov InputProvenance
);
)""";
// listening port
const auto server_address=string("0.0.0.0:55155");
// create the service, build it, bind to listening port, and register.
TurboServiceImpl service;
ServerBuilder builder;
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
builder.RegisterService(&service);
// Finally start the server.
auto server = builder.BuildAndStart();
if(server == nullptr)
{
cout << "Could not start server! (Port already in use?)" << endl;
cout << "Server listening on " << server_address << endl;
// Wait for the server to shutdown. Note that some other thread must be
// responsible for shutting down the server for this call to ever return.
server->Wait();
}
int main(int argc, char **argv)
{
const auto create_db_res = system("createdb " TURBODB);
if(create_db_res == -1)
{
cout << "Could not create process for creating database" << endl;
perror("main");
}
RunServer();
return 0;