proxy/rom_verify: serve ROMs verified by hash
Supports SHA1, SHA2, and SHA3. Fix #59
This commit is contained in:
committed by
Norman Feske
parent
3499858ad8
commit
08b0e5df02
85
run/rom_verify.run
Normal file
85
run/rom_verify.run
Normal file
@@ -0,0 +1,85 @@
|
||||
if {![have_spec linux]} {
|
||||
puts "ROM padding requires that this script run on linux!"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Build program images
|
||||
build {
|
||||
core init
|
||||
proxy/rom_verify
|
||||
test/log
|
||||
}
|
||||
|
||||
create_boot_directory
|
||||
|
||||
set sha256sum [check_installed sha256sum]
|
||||
|
||||
|
||||
set rom_file bin/test-log
|
||||
set test_digest [exec $sha256sum $rom_file]
|
||||
|
||||
append config {
|
||||
<config>
|
||||
<parent-provides>
|
||||
<service name="ROM"/>
|
||||
<service name="RAM"/>
|
||||
<service name="IRQ"/>
|
||||
<service name="IO_MEM"/>
|
||||
<service name="IO_PORT"/>
|
||||
<service name="PD"/>
|
||||
<service name="RM"/>
|
||||
<service name="CPU"/>
|
||||
<service name="LOG"/>
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service><parent/><any-child/></any-service>
|
||||
</default-route>
|
||||
<start name="rom_verify">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides> <service name="ROM"/> </provides>
|
||||
<config>}
|
||||
append config "<policy label=\"init -> test-log\" sha256=\"$test_digest\"/>"
|
||||
append config {
|
||||
</config>
|
||||
</start>
|
||||
<start name="init" verbose="yes">
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
<route>
|
||||
<service name="ROM" label_suffix="test-log">
|
||||
<child name="rom_verify"/> </service>
|
||||
<any-service>
|
||||
<parent/>
|
||||
</any-service>
|
||||
</route>
|
||||
<config>
|
||||
<parent-provides>
|
||||
<service name="CPU"/>
|
||||
<service name="LOG"/>
|
||||
<service name="PD"/>
|
||||
<service name="RAM"/>
|
||||
<service name="RM"/>
|
||||
<service name="ROM"/>
|
||||
</parent-provides>
|
||||
<start name="test-log">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<route> <any-service> <parent/> </any-service> </route>
|
||||
</start>
|
||||
</config>
|
||||
</start>
|
||||
</config>
|
||||
}
|
||||
|
||||
install_config $config
|
||||
|
||||
build_boot_image {
|
||||
core init ld.lib.so
|
||||
libc.lib.so
|
||||
libm.lib.so
|
||||
rom_verify
|
||||
stdcxx.lib.so
|
||||
test-log
|
||||
}
|
||||
|
||||
append qemu_args " -nographic"
|
||||
|
||||
run_genode_until {Test done.} 20
|
||||
242
src/proxy/rom_verify/main.cc
Normal file
242
src/proxy/rom_verify/main.cc
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* \brief ROM verification server
|
||||
* \author Emery Hemingway
|
||||
* \date 2016-12-30
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Crypto++ includes */
|
||||
#include <sha3.h>
|
||||
#include <sha.h>
|
||||
|
||||
/* Genode includes */
|
||||
#include <os/session_policy.h>
|
||||
#include <rom_session/connection.h>
|
||||
#include <base/attached_rom_dataspace.h>
|
||||
#include <base/heap.h>
|
||||
#include <base/service.h>
|
||||
#include <base/session_label.h>
|
||||
#include <base/component.h>
|
||||
#include <base/log.h>
|
||||
|
||||
static char const alph[0x10] = {
|
||||
'0','1','2','3','4','5','6','7',
|
||||
'8','9','a','b','c','d','e','f'
|
||||
};
|
||||
|
||||
namespace Rom_hash {
|
||||
using namespace Genode;
|
||||
|
||||
struct Session;
|
||||
struct Main;
|
||||
|
||||
typedef Session_state::Args Args;
|
||||
}
|
||||
|
||||
|
||||
struct Rom_hash::Session :
|
||||
Genode::Parent::Server,
|
||||
Genode::Connection<Rom_session>
|
||||
{
|
||||
Parent::Client parent_client;
|
||||
|
||||
Id_space<Parent::Client>::Element client_id;
|
||||
Id_space<Parent::Server>::Element server_id;
|
||||
|
||||
void verify(CryptoPP::HashTransformation &hash,
|
||||
Genode::Xml_attribute &attr);
|
||||
|
||||
Session(Id_space<Parent::Client> &client_space,
|
||||
Id_space<Parent::Server> &server_space,
|
||||
Parent::Server::Id server_id,
|
||||
Genode::Env &env, Args const &args,
|
||||
Session_policy const &policy);
|
||||
};
|
||||
|
||||
|
||||
void Rom_hash::Session::verify(CryptoPP::HashTransformation &hash,
|
||||
Genode::Xml_attribute &attr)
|
||||
{
|
||||
unsigned const digest_size = hash.DigestSize();
|
||||
|
||||
uint8_t digest[digest_size];
|
||||
|
||||
/* read the connection dataspace */
|
||||
Rom_session_client rom(cap());
|
||||
Attached_dataspace ds(_env.rm(), rom.dataspace());
|
||||
|
||||
hash.CalculateDigest(digest, ds.local_addr<const byte>(), ds.size());
|
||||
|
||||
/* compare with hexadecimal */
|
||||
char const *text = attr.value_base();
|
||||
for (unsigned i = 0, j = 0; i < digest_size && j < attr.value_size(); ++i)
|
||||
if ((alph[digest[i] >> 4] != text[j++]) ||
|
||||
(alph[digest[i]&0x0F] != text[j++]))
|
||||
throw ~0;
|
||||
}
|
||||
|
||||
|
||||
Rom_hash::Session::Session(Id_space<Parent::Client> &client_space,
|
||||
Id_space<Parent::Server> &server_space,
|
||||
Parent::Server::Id server_id,
|
||||
Genode::Env &env, Args const &args,
|
||||
Session_policy const &policy)
|
||||
:
|
||||
Connection<Rom_session>(env, session(env.parent(), args.string())),
|
||||
client_id(parent_client, client_space),
|
||||
server_id(*this, server_space, server_id)
|
||||
{
|
||||
try {
|
||||
Xml_attribute attr = policy.attribute("sha3");
|
||||
CryptoPP::SHA3 hash(attr.value_size()/2);
|
||||
verify(hash, attr);
|
||||
return;
|
||||
} catch (Xml_node::Nonexistent_attribute) { }
|
||||
|
||||
try {
|
||||
Xml_attribute attr = policy.attribute("sha512");
|
||||
CryptoPP::SHA512 hash;
|
||||
verify(hash, attr);
|
||||
return;
|
||||
} catch (Xml_node::Nonexistent_attribute) { }
|
||||
|
||||
try {
|
||||
Xml_attribute attr = policy.attribute("sha256");
|
||||
CryptoPP::SHA256 hash;
|
||||
verify(hash, attr);
|
||||
return;
|
||||
} catch (Xml_node::Nonexistent_attribute) { }
|
||||
|
||||
try {
|
||||
Xml_attribute attr = policy.attribute("sha1");
|
||||
CryptoPP::SHA1 hash;
|
||||
verify(hash, attr);
|
||||
return;
|
||||
} catch (Xml_node::Nonexistent_attribute) { }
|
||||
|
||||
error("no hash policy found");
|
||||
throw ~0;
|
||||
}
|
||||
|
||||
|
||||
struct Rom_hash::Main
|
||||
{
|
||||
Id_space<Parent::Server> server_id_space;
|
||||
|
||||
Genode::Env &env;
|
||||
|
||||
Attached_rom_dataspace config_rom { env, "config" };
|
||||
|
||||
Attached_rom_dataspace session_requests { env, "session_requests" };
|
||||
|
||||
Sliced_heap alloc { env.ram(), env.rm() };
|
||||
|
||||
bool config_stale = false;
|
||||
|
||||
void handle_config() {
|
||||
config_stale = true; }
|
||||
|
||||
void handle_session_request(Xml_node request);
|
||||
|
||||
void handle_session_requests()
|
||||
{
|
||||
if (config_stale) {
|
||||
config_rom.update();
|
||||
config_stale = false;
|
||||
}
|
||||
|
||||
session_requests.update();
|
||||
|
||||
Xml_node const requests = session_requests.xml();
|
||||
|
||||
requests.for_each_sub_node([&] (Xml_node request) {
|
||||
handle_session_request(request);
|
||||
});
|
||||
}
|
||||
|
||||
Signal_handler<Main> config_handler {
|
||||
env.ep(), *this, &Main::handle_config };
|
||||
|
||||
Signal_handler<Main> session_request_handler {
|
||||
env.ep(), *this, &Main::handle_session_requests };
|
||||
|
||||
Main(Genode::Env &env) : env(env)
|
||||
{
|
||||
config_rom.sigh(config_handler);
|
||||
session_requests.sigh(session_request_handler);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void Rom_hash::Main::handle_session_request(Xml_node request)
|
||||
{
|
||||
if (!request.has_attribute("id"))
|
||||
return;
|
||||
|
||||
Id_space<Parent::Server>::Id const server_id {
|
||||
request.attribute_value("id", 0UL) };
|
||||
|
||||
if (request.has_type("create")) {
|
||||
if (!request.has_sub_node("args"))
|
||||
return;
|
||||
|
||||
typedef Session_state::Args Args;
|
||||
Args const args = request.sub_node("args").decoded_content<Args>();
|
||||
|
||||
/* fetch and serve it again */
|
||||
Session_label const label = label_from_args(args.string());
|
||||
try {
|
||||
Session_policy const policy(label, config_rom.xml());
|
||||
|
||||
Session *session = new (alloc)
|
||||
Session(env.id_space(), server_id_space, server_id, env, args, policy);
|
||||
if (session) {
|
||||
env.parent().deliver_session_cap(server_id, session->cap());
|
||||
return;
|
||||
}
|
||||
return;
|
||||
} catch (Session_policy::No_policy_defined) {
|
||||
warning("no policy for '",label,"'");
|
||||
} catch (...) { }
|
||||
|
||||
env.parent().session_response(server_id, Parent::INVALID_ARGS);
|
||||
}
|
||||
|
||||
if (request.has_type("upgrade")) {
|
||||
server_id_space.apply<Session>(server_id, [&] (Session &session) {
|
||||
size_t ram_quota = request.attribute_value("ram_quota", 0UL);
|
||||
|
||||
char buf[64];
|
||||
Genode::snprintf(buf, sizeof(buf), "ram_quota=%ld", ram_quota);
|
||||
|
||||
// XXX handle Root::Invalid_args
|
||||
env.upgrade(session.client_id.id(), buf);
|
||||
env.parent().session_response(server_id, Parent::SESSION_OK);
|
||||
});
|
||||
}
|
||||
|
||||
if (request.has_type("close")) {
|
||||
server_id_space.apply<Session>(server_id, [&] (Session &session) {
|
||||
env.close(session.client_id.id());
|
||||
destroy(alloc, &session);
|
||||
env.parent().session_response(server_id, Parent::SESSION_CLOSED);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/***************
|
||||
** Component **
|
||||
***************/
|
||||
|
||||
void Component::construct(Genode::Env &env)
|
||||
{
|
||||
static Rom_hash::Main inst(env);
|
||||
env.parent().announce("ROM");
|
||||
}
|
||||
3
src/proxy/rom_verify/target.mk
Normal file
3
src/proxy/rom_verify/target.mk
Normal file
@@ -0,0 +1,3 @@
|
||||
TARGET = rom_verify
|
||||
SRC_CC = main.cc
|
||||
LIBS = base cryptopp stdcxx
|
||||
Reference in New Issue
Block a user