blob: f1560cca8eb72d6388998ce27db6a24882d7422e [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// This is a fake 'smart door memory' component for security codelab.
// It CONTAINS vulnerability intentionally.
// DO NOT COPY ANY OF THE CODE IN THIS FILE!
#include "smart_door_memory_server_app.h"
#include <lib/sys/cpp/component_context.h>
#include <lib/syslog/cpp/macros.h>
#include <zircon/time.h>
#include <ctime>
#include "dirent.h"
#include "fcntl.h"
#include "stdint.h"
#include "sys/stat.h"
namespace smart_door_memory {
using fuchsia::security::codelabsmartdoor::Error;
using fuchsia::security::codelabsmartdoor::Memory_GenerateToken_Response;
using fuchsia::security::codelabsmartdoor::Memory_GenerateToken_Result;
using fuchsia::security::codelabsmartdoor::Memory_GetReader_Response;
using fuchsia::security::codelabsmartdoor::Memory_GetReader_Result;
using fuchsia::security::codelabsmartdoor::Memory_GetWriter_Response;
using fuchsia::security::codelabsmartdoor::Memory_GetWriter_Result;
using fuchsia::security::codelabsmartdoor::Reader;
using fuchsia::security::codelabsmartdoor::Reader_Read_Response;
using fuchsia::security::codelabsmartdoor::Reader_Read_Result;
using fuchsia::security::codelabsmartdoor::Token;
using fuchsia::security::codelabsmartdoor::TOKEN_ID_SIZE;
using fuchsia::security::codelabsmartdoor::Writer;
using fuchsia::security::codelabsmartdoor::Writer_Write_Response;
using fuchsia::security::codelabsmartdoor::Writer_Write_Result;
const char* STORAGE_FOLDER = "/data/storage/";
const char* LOG_FILE = "/data/log";
SmartDoorMemoryServer::SmartDoorMemoryServer() {
// Create the storage folder.
mkdir(STORAGE_FOLDER, 0700);
}
void SmartDoorMemoryServer::GenerateToken(GenerateTokenCallback callback) {
FX_LOGS(INFO) << "Generating random token" << std::endl;
Token token;
uint8_t id[TOKEN_ID_SIZE / 2];
zx_cprng_draw(id, TOKEN_ID_SIZE / 2);
char id_hex[TOKEN_ID_SIZE + 1] = {};
for (size_t i = 0; i < TOKEN_ID_SIZE / 2; i++) {
snprintf(&id_hex[i * 2], sizeof(id_hex) - (i * 2), "%02X", id[i]);
}
token.set_id(std::string(id_hex));
callback(
Memory_GenerateToken_Result::WithResponse(Memory_GenerateToken_Response(std::move(token))));
}
bool SmartDoorMemoryServer::Log(std::string file_path, bool read_or_write) {
std::timespec ts;
if (!std::timespec_get(&ts, TIME_UTC)) {
return false;
}
zx_time_t now = zx_time_from_timespec(ts);
char time[256] = {};
int written = snprintf(time, sizeof(time), "%" PRIi64, now);
if (written < 0 || written > (int)sizeof(time)) {
return false;
}
std::string log = std::string(time) + " " + file_path;
if (read_or_write) {
log += " read";
} else {
log += " write";
}
log += "\n";
int fd = 0;
FX_LOGS(INFO) << "logging to file " << LOG_FILE << std::endl;
if (fdio_open_fd(LOG_FILE,
fuchsia::io::OPEN_RIGHT_WRITABLE | fuchsia::io::OPEN_FLAG_CREATE |
fuchsia::io::OPEN_FLAG_APPEND,
&fd) != ZX_OK) {
return false;
}
const char* log_c = log.c_str();
if (write(fd, log_c, strlen(log_c) + 1) != static_cast<ssize_t>(strlen(log_c) + 1)) {
close(fd);
return false;
}
close(fd);
return true;
}
bool SmartDoorMemoryServer::tokenToFilePath(const Token* token, std::string* file_path) {
if (!token->has_id() || token->id().size() != TOKEN_ID_SIZE) {
return false;
}
*file_path = STORAGE_FOLDER + token->id();
return true;
}
void SmartDoorMemoryServer::GetReader(Token token, ::fidl::InterfaceRequest<Reader> request,
GetReaderCallback callback) {
FX_LOGS(INFO) << "Getting reader" << std::endl;
std::string file_path;
if (!tokenToFilePath(&token, &file_path)) {
callback(Memory_GetReader_Result::WithErr(Error::INVALID_INPUT));
return;
}
int fd = open(file_path.c_str(), O_RDONLY);
if (fd < 0) {
callback(Memory_GetReader_Result::WithErr(Error::INVALID_INPUT));
return;
}
reader_bindings_.AddBinding(std::make_unique<SmartDoorMemoryReader>(fd, std::move(file_path)),
std::move(request));
callback(Memory_GetReader_Result::WithResponse(Memory_GetReader_Response()));
}
void SmartDoorMemoryServer::GetWriter(Token token, ::fidl::InterfaceRequest<Writer> request,
GetWriterCallback callback) {
FX_LOGS(INFO) << "Getting writer" << std::endl;
std::string file_path;
if (!tokenToFilePath(&token, &file_path)) {
callback(Memory_GetWriter_Result::WithErr(Error::INVALID_INPUT));
return;
}
int fd = open(file_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC);
if (fd < 0) {
callback(Memory_GetWriter_Result::WithErr(Error::INVALID_INPUT));
return;
}
writer_bindings_.AddBinding(std::make_unique<SmartDoorMemoryWriter>(fd, std::move(file_path)),
std::move(request));
callback(Memory_GetWriter_Result::WithResponse(Memory_GetWriter_Response()));
}
void SmartDoorMemoryServer::Reset(ResetCallback callback) {
// Erase every files under the storage folder.
DIR* dir = opendir(STORAGE_FOLDER);
ZX_ASSERT(dir);
struct dirent* de;
while ((de = readdir(dir)) != NULL) {
if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
continue;
char tmp[PATH_MAX];
tmp[0] = 0;
size_t bytes_left = PATH_MAX - 1;
strncat(tmp, STORAGE_FOLDER, bytes_left);
bytes_left -= strlen(STORAGE_FOLDER);
strncat(tmp, "/", bytes_left);
bytes_left--;
strncat(tmp, de->d_name, bytes_left);
unlink(tmp);
}
closedir(dir);
// Erase log file.
unlink(LOG_FILE);
callback();
return;
}
void SmartDoorMemoryWriter::Write(std::vector<uint8_t> data, WriteCallback callback) {
if (lseek(fd_, 0, SEEK_SET) == -1) {
callback(Writer_Write_Result::WithErr(Error::INVALID_INPUT));
return;
}
if (ftruncate(fd_, 0) == -1) {
callback(Writer_Write_Result::WithErr(Error::INVALID_INPUT));
return;
}
if (data.size() > UINT32_MAX) {
callback(Writer_Write_Result::WithErr(Error::INVALID_INPUT));
return;
}
ssize_t written = write(fd_, data.data(), data.size());
if (written != static_cast<ssize_t>(data.size())) {
callback(Writer_Write_Result::WithErr(Error::INVALID_INPUT));
return;
}
sync();
if (!SmartDoorMemoryServer::Log(file_path_, false)) {
callback(Writer_Write_Result::WithErr(Error::INTERNAL));
return;
}
ZX_ASSERT(written <= UINT32_MAX);
callback(
Writer_Write_Result::WithResponse(Writer_Write_Response(static_cast<uint32_t>(written))));
return;
}
void SmartDoorMemoryReader::Read(ReadCallback callback) {
// Get file size.
ssize_t size = lseek(fd_, 0, SEEK_END);
std::vector<uint8_t> data;
data.resize(size);
if (lseek(fd_, 0, SEEK_SET) == -1) {
callback(Reader_Read_Result::WithErr(Error::INVALID_INPUT));
return;
}
ssize_t read_bytes = read(fd_, data.data(), data.size());
if (read_bytes != static_cast<ssize_t>(data.size())) {
callback(Reader_Read_Result::WithErr(Error::INVALID_INPUT));
return;
}
if (!SmartDoorMemoryServer::Log(file_path_, true)) {
callback(Reader_Read_Result::WithErr(Error::INTERNAL));
return;
}
callback(Reader_Read_Result::WithResponse(Reader_Read_Response(std::move(data))));
return;
}
SmartDoorMemoryServerApp::SmartDoorMemoryServerApp()
: SmartDoorMemoryServerApp(sys::ComponentContext::CreateAndServeOutgoingDirectory()) {}
SmartDoorMemoryServerApp::SmartDoorMemoryServerApp(std::unique_ptr<sys::ComponentContext> context)
: service_(new SmartDoorMemoryServer()), context_(std::move(context)) {
context_->outgoing()->AddPublicService(bindings_.GetHandler(service_.get()));
context_->outgoing()->AddPublicService(reset_bindings_.GetHandler(service_.get()));
}
} // namespace smart_door_memory