2011-12-22 15:19:25 +00:00
|
|
|
/*
|
|
|
|
* \brief Fork bomb to stress Genode
|
|
|
|
* \author Christian Helmuth
|
|
|
|
* \date 2007-08-16
|
|
|
|
*
|
|
|
|
* The better part of this code is derived from the original init
|
|
|
|
* implementation by Norman.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2013-01-10 20:44:47 +00:00
|
|
|
* Copyright (C) 2007-2013 Genode Labs GmbH
|
2011-12-22 15:19:25 +00:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
|
|
* under the terms of the GNU General Public License version 2.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <base/env.h>
|
|
|
|
#include <base/child.h>
|
|
|
|
#include <base/sleep.h>
|
|
|
|
#include <base/service.h>
|
|
|
|
#include <base/snprintf.h>
|
|
|
|
#include <init/child_policy.h>
|
|
|
|
#include <ram_session/connection.h>
|
|
|
|
#include <cpu_session/connection.h>
|
|
|
|
#include <rom_session/connection.h>
|
|
|
|
#include <cap_session/connection.h>
|
2015-05-05 06:50:16 +00:00
|
|
|
#include <pd_session/connection.h>
|
2011-12-22 15:19:25 +00:00
|
|
|
#include <timer_session/connection.h>
|
|
|
|
|
2013-08-05 10:16:43 +00:00
|
|
|
#include <os/config.h>
|
2015-07-02 12:24:51 +00:00
|
|
|
#include <os/child_policy_dynamic_rom.h>
|
2013-08-05 10:16:43 +00:00
|
|
|
#include <util/xml_node.h>
|
|
|
|
|
2011-12-22 15:19:25 +00:00
|
|
|
using namespace Genode;
|
|
|
|
|
|
|
|
|
|
|
|
class Bomb_child_resources
|
|
|
|
{
|
|
|
|
protected:
|
|
|
|
|
2015-05-05 06:50:16 +00:00
|
|
|
Genode::Pd_connection _pd;
|
2011-12-22 15:19:25 +00:00
|
|
|
Genode::Rom_connection _rom;
|
|
|
|
Genode::Ram_connection _ram;
|
|
|
|
Genode::Cpu_connection _cpu;
|
|
|
|
char _name[32];
|
|
|
|
|
|
|
|
Bomb_child_resources(const char *file_name, const char *name,
|
|
|
|
Genode::size_t ram_quota)
|
2015-05-05 06:50:16 +00:00
|
|
|
: _pd(name), _rom(file_name, name), _ram(name), _cpu(name)
|
2011-12-22 15:19:25 +00:00
|
|
|
{
|
|
|
|
Genode::strncpy(_name, name, sizeof(_name));
|
|
|
|
|
|
|
|
_ram.ref_account(env()->ram_session_cap());
|
|
|
|
Genode::env()->ram_session()->transfer_quota(_ram.cap(), ram_quota);
|
|
|
|
|
|
|
|
if (!_ram.cap().valid() || !_cpu.cap().valid()) {
|
|
|
|
class Ram_or_cpu_session_not_valid { };
|
|
|
|
throw Ram_or_cpu_session_not_valid();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class Bomb_child : private Bomb_child_resources,
|
|
|
|
public Genode::Child_policy,
|
|
|
|
private Init::Child_policy_enforce_labeling,
|
|
|
|
public Genode::List<Bomb_child>::Element
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Entry point used for serving the parent interface
|
|
|
|
*/
|
2012-11-14 15:36:59 +00:00
|
|
|
enum { STACK_SIZE = 2048 * sizeof(Genode::addr_t) };
|
2011-12-22 15:19:25 +00:00
|
|
|
Genode::Rpc_entrypoint _entrypoint;
|
|
|
|
|
2015-07-02 12:24:51 +00:00
|
|
|
Genode::Child _child;
|
|
|
|
Genode::Service_registry *_parent_services;
|
|
|
|
Genode::Child_policy_dynamic_rom_file _config_policy;
|
2011-12-22 15:19:25 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
Bomb_child(const char *file_name,
|
|
|
|
const char *unique_name,
|
|
|
|
Genode::size_t ram_quota,
|
|
|
|
Cap_session *cap_session,
|
2015-07-02 12:24:51 +00:00
|
|
|
Service_registry *parent_services,
|
|
|
|
unsigned generation)
|
2011-12-22 15:19:25 +00:00
|
|
|
:
|
|
|
|
Bomb_child_resources(file_name, unique_name, ram_quota),
|
|
|
|
Init::Child_policy_enforce_labeling(Bomb_child_resources::_name),
|
2015-07-02 12:24:51 +00:00
|
|
|
_entrypoint(cap_session, STACK_SIZE, "bomb_ep_child", false),
|
2015-05-05 06:50:16 +00:00
|
|
|
_child(_rom.dataspace(), _pd.cap(), _ram.cap(), _cpu.cap(),
|
2016-04-15 13:19:22 +00:00
|
|
|
&_entrypoint, this),
|
2015-07-02 12:24:51 +00:00
|
|
|
_parent_services(parent_services),
|
|
|
|
_config_policy("config", _entrypoint, &_ram)
|
|
|
|
{
|
|
|
|
char client_config[64];
|
|
|
|
snprintf(client_config, sizeof(client_config),
|
|
|
|
"<config generations=\"%u\"/>", generation);
|
|
|
|
_config_policy.load(client_config, strlen(client_config) + 1);
|
|
|
|
|
|
|
|
_entrypoint.activate();
|
|
|
|
}
|
2011-12-22 15:19:25 +00:00
|
|
|
|
2012-11-14 15:36:59 +00:00
|
|
|
~Bomb_child() { PLOG("%s", __PRETTY_FUNCTION__); }
|
2011-12-22 15:19:25 +00:00
|
|
|
|
|
|
|
|
|
|
|
/****************************
|
|
|
|
** Child-policy interface **
|
|
|
|
****************************/
|
|
|
|
|
|
|
|
const char *name() const { return Bomb_child_resources::_name; }
|
|
|
|
|
2015-07-02 12:24:51 +00:00
|
|
|
void filter_session_args(const char * x, char *args, Genode::size_t args_len)
|
2011-12-22 15:19:25 +00:00
|
|
|
{
|
|
|
|
Child_policy_enforce_labeling::filter_session_args(0, args, args_len);
|
|
|
|
}
|
|
|
|
|
|
|
|
Service *resolve_session_request(const char *service_name,
|
|
|
|
const char *args)
|
|
|
|
{
|
2015-07-02 12:24:51 +00:00
|
|
|
Service * service = nullptr;
|
|
|
|
|
|
|
|
/* check for config file request */
|
|
|
|
if ((service = _config_policy.resolve_session_request(service_name,
|
|
|
|
args)))
|
|
|
|
return service;
|
|
|
|
|
2011-12-22 15:19:25 +00:00
|
|
|
return _parent_services->find(service_name);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* List of children
|
|
|
|
*
|
|
|
|
* Access to the children list from different threads
|
|
|
|
* must be synchronized via the children lock.
|
|
|
|
*/
|
|
|
|
static Lock _children_lock;
|
|
|
|
static List<Bomb_child> _children;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if a program with the specified name already exists
|
|
|
|
*/
|
|
|
|
static bool child_name_exists(const char *name)
|
|
|
|
{
|
|
|
|
Bomb_child *c = _children.first();
|
|
|
|
|
|
|
|
for ( ; c; c = c->List<Bomb_child>::Element::next())
|
|
|
|
if (strcmp(c->name(), name) == 0)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a unique name based on the filename
|
|
|
|
*
|
|
|
|
* If a program with the filename as name already exists, we
|
|
|
|
* add a counting number as suffix.
|
|
|
|
*/
|
2015-07-02 12:24:51 +00:00
|
|
|
static void get_unique_child_name(const char *filename, char *dst,
|
|
|
|
size_t dst_len, unsigned generation)
|
2011-12-22 15:19:25 +00:00
|
|
|
{
|
|
|
|
Lock::Guard lock_guard(_children_lock);
|
|
|
|
|
|
|
|
char buf[32];
|
|
|
|
char suffix[8];
|
|
|
|
suffix[0] = 0;
|
|
|
|
|
|
|
|
for (int cnt = 1; true; cnt++) {
|
|
|
|
|
|
|
|
/* build program name composed of filename and numeric suffix */
|
2015-07-02 12:24:51 +00:00
|
|
|
snprintf(buf, sizeof(buf), "%s_g%u%s", filename, generation, suffix);
|
2011-12-22 15:19:25 +00:00
|
|
|
|
|
|
|
/* if such a program name does not exist yet, we are happy */
|
|
|
|
if (!child_name_exists(buf)) {
|
|
|
|
strncpy(dst, buf, dst_len);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* increase number of suffix */
|
|
|
|
snprintf(suffix, sizeof(suffix), ".%d", cnt + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Start a child
|
|
|
|
*/
|
|
|
|
static int start_child(const char *file_name, Cap_session *cap_session,
|
2015-07-02 12:24:51 +00:00
|
|
|
size_t ram_quota, Service_registry *parent_services,
|
|
|
|
unsigned generation)
|
2011-12-22 15:19:25 +00:00
|
|
|
{
|
|
|
|
char name[64];
|
2015-07-02 12:24:51 +00:00
|
|
|
get_unique_child_name(file_name, name, sizeof(name), generation);
|
2011-12-22 15:19:25 +00:00
|
|
|
|
|
|
|
Bomb_child *c = new (env()->heap())
|
2015-07-02 12:24:51 +00:00
|
|
|
Bomb_child(file_name, name, ram_quota, cap_session, parent_services,
|
|
|
|
generation);
|
2011-12-22 15:19:25 +00:00
|
|
|
|
|
|
|
Lock::Guard lock_guard(_children_lock);
|
|
|
|
_children.insert(c);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Kill child
|
|
|
|
*/
|
|
|
|
static void exit_child(Bomb_child *child)
|
|
|
|
{
|
|
|
|
destroy(env()->heap(), child);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Request timer service
|
|
|
|
*
|
|
|
|
* \return timer session, or 0 if bomb is our parent
|
|
|
|
*/
|
|
|
|
Timer::Session *timer()
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
static Timer::Connection timer_inst;
|
|
|
|
return &timer_inst;
|
|
|
|
} catch (Parent::Service_denied) { }
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
2015-07-02 12:24:51 +00:00
|
|
|
Genode::Xml_node node = config()->xml_node();
|
2013-08-05 10:16:43 +00:00
|
|
|
|
2015-07-02 12:24:51 +00:00
|
|
|
unsigned const rounds = node.attribute_value("rounds", 1U);
|
|
|
|
unsigned const generation = node.attribute_value("generations", 1U);
|
|
|
|
unsigned const children = node.attribute_value("children", 2U);
|
|
|
|
unsigned const sleeptime = node.attribute_value("sleep", 2000U);
|
|
|
|
unsigned long const demand = node.attribute_value("demand", 1024UL * 1024);
|
2013-08-05 10:16:43 +00:00
|
|
|
|
2011-12-22 15:19:25 +00:00
|
|
|
printf("--- bomb started ---\n");
|
|
|
|
|
|
|
|
/* connect to core's cap service used for creating parent capabilities */
|
|
|
|
Cap_connection cap;
|
|
|
|
|
|
|
|
/* names of services provided by the parent */
|
|
|
|
static const char *names[] = {
|
|
|
|
"CAP", "RAM", "RM", "PD", "CPU", "ROM", "LOG", 0 };
|
|
|
|
|
|
|
|
static Service_registry parent_services;
|
|
|
|
for (unsigned i = 0; names[i]; i++)
|
|
|
|
parent_services.insert(new (env()->heap()) Parent_service(names[i]));
|
|
|
|
|
|
|
|
unsigned long avail = env()->ram_session()->avail();
|
2015-07-02 12:24:51 +00:00
|
|
|
unsigned long amount = (avail - demand) / children;
|
|
|
|
if (amount < (demand * children)) {
|
|
|
|
PLOG("I'm a leaf node - generation %u - not enough memory.",
|
|
|
|
generation);
|
|
|
|
sleep_forever();
|
|
|
|
}
|
|
|
|
if (generation == 0) {
|
|
|
|
PLOG("I'm a leaf node - generation 0");
|
2011-12-22 15:19:25 +00:00
|
|
|
sleep_forever();
|
|
|
|
}
|
|
|
|
|
2015-07-02 12:24:51 +00:00
|
|
|
for (unsigned round = 0; round < rounds ; ++round) {
|
2011-12-22 15:19:25 +00:00
|
|
|
for (unsigned i = children; i; --i)
|
2015-07-02 12:24:51 +00:00
|
|
|
start_child("bomb", &cap, amount, &parent_services, generation - 1);
|
2011-12-22 15:19:25 +00:00
|
|
|
|
|
|
|
/* is init our parent? */
|
|
|
|
if (!timer()) sleep_forever();
|
|
|
|
|
2015-07-15 11:56:31 +00:00
|
|
|
/* don't ask parent for further resources if we ran out of memory */
|
|
|
|
static Signal_receiver sig_rec;
|
|
|
|
static Signal_context sig_ctx_res_avail;
|
|
|
|
if (round == 0) {
|
|
|
|
/* prevent to block for resource upgrades caused by clients */
|
|
|
|
env()->parent()->resource_avail_sigh(sig_rec.manage(&sig_ctx_res_avail));
|
|
|
|
}
|
|
|
|
|
2015-07-02 12:24:51 +00:00
|
|
|
timer()->msleep(sleeptime);
|
2012-11-14 15:36:59 +00:00
|
|
|
PINF("[%03d] It's time to kill all my children...", round);
|
2011-12-22 15:19:25 +00:00
|
|
|
|
|
|
|
while (1) {
|
|
|
|
Bomb_child *c;
|
|
|
|
|
|
|
|
_children_lock.lock();
|
|
|
|
c = _children.first();
|
|
|
|
if (c) _children.remove(c);
|
|
|
|
_children_lock.unlock();
|
|
|
|
|
|
|
|
if (c) exit_child(c);
|
|
|
|
else break;
|
|
|
|
}
|
|
|
|
|
2013-08-05 10:16:43 +00:00
|
|
|
PINF("[%03d] Done.", round);
|
2011-12-22 15:19:25 +00:00
|
|
|
}
|
|
|
|
|
2015-07-15 11:56:31 +00:00
|
|
|
/* master if we have a timer connection */
|
|
|
|
if (timer())
|
2015-07-02 12:24:51 +00:00
|
|
|
PINF("Done. Going to sleep");
|
2013-08-05 10:16:43 +00:00
|
|
|
|
2011-12-22 15:19:25 +00:00
|
|
|
sleep_forever();
|
|
|
|
return 0;
|
|
|
|
}
|