default ahci_drv and part_blk Block sessions to read-only

Add a "writeable" policy option to the ahci_drv and part_blk Block
servers and default from writeable to ready-only. Should a policy
permit write acesss the session request argument "writeable" may still
downgrade a session to ready-only.

Fix #2469
This commit is contained in:
Emery Hemingway 2017-07-31 12:53:34 -05:00 committed by Christian Helmuth
parent cf2886dc8f
commit 1fce8d0d74
19 changed files with 118 additions and 65 deletions

View File

@ -222,9 +222,11 @@ void scsi_add_device(struct scsi_device *sdev)
* XXX move to 'main' * XXX move to 'main'
*/ */
if (!announce) { if (!announce) {
enum { WRITEABLE = true };
PREPARE_WORK(&delayed, ack_packet); PREPARE_WORK(&delayed, ack_packet);
static Block::Root root(_signal->ep(), Lx::Malloc::mem(), static Block::Root root(_signal->ep(), Lx::Malloc::mem(),
_signal->rm(), factory); _signal->rm(), factory, WRITEABLE);
_signal->parent().announce(_signal->ep().rpc_ep().manage(&root)); _signal->parent().announce(_signal->ep().rpc_ep().manage(&root));
announce = true; announce = true;
} }

View File

@ -41,7 +41,7 @@ struct Main
} factory { env, heap }; } factory { env, heap };
Block::Root root { env.ep(), heap, env.rm(), factory }; Block::Root root { env.ep(), heap, env.rm(), factory, true };
Main(Genode::Env &env) : env(env) { Main(Genode::Env &env) : env(env) {
env.parent().announce(env.ep().manage(root)); } env.parent().announce(env.ep().manage(root)); }

View File

@ -102,7 +102,7 @@ struct Main
Env &env; Env &env;
Heap heap { env.ram(), env.rm() }; Heap heap { env.ram(), env.rm() };
Factory factory { env, heap }; Factory factory { env, heap };
Block::Root root { env.ep(), heap, env.rm(), factory }; Block::Root root { env.ep(), heap, env.rm(), factory, true };
Main(Env &env) : env(env) { Main(Env &env) : env(env) {
env.parent().announce(env.ep().manage(root)); } env.parent().announce(env.ep().manage(root)); }

View File

@ -105,7 +105,7 @@ append_if $use_ahci config {
</route> </route>
<config>} <config>}
append_if $use_ahci config " append_if $use_ahci config "
<policy label_prefix=\"test-libc_$filesystem\" device=\"0\" />" <policy label_prefix=\"test-libc_$filesystem\" device=\"0\" writeable=\"yes\"/>"
append_if $use_ahci config { append_if $use_ahci config {
</config> </config>
</start>} </start>}

View File

@ -76,6 +76,7 @@ class Block::Session_component : public Block::Session_component_base,
bool _ack_queue_full; bool _ack_queue_full;
Packet_descriptor _p_to_handle; Packet_descriptor _p_to_handle;
unsigned _p_in_fly; unsigned _p_in_fly;
bool _writeable;
/** /**
* Acknowledge a packet already handled * Acknowledge a packet already handled
@ -127,6 +128,10 @@ class Block::Session_component : public Block::Session_component_base,
break; break;
case Block::Packet_descriptor::WRITE: case Block::Packet_descriptor::WRITE:
if (!_writeable) {
_ack_packet(_p_to_handle);
break;
}
if (_driver.dma_enabled()) if (_driver.dma_enabled())
_driver.write_dma(packet.block_number(), _driver.write_dma(packet.block_number(),
packet.block_count(), packet.block_count(),
@ -178,14 +183,16 @@ class Block::Session_component : public Block::Session_component_base,
Session_component(Driver_factory &driver_factory, Session_component(Driver_factory &driver_factory,
Genode::Entrypoint &ep, Genode::Entrypoint &ep,
Genode::Region_map &rm, Genode::Region_map &rm,
size_t buf_size) size_t buf_size,
bool writeable)
: Session_component_base(driver_factory, buf_size), : Session_component_base(driver_factory, buf_size),
Driver_session(rm, _rq_ds, ep.rpc_ep()), Driver_session(rm, _rq_ds, ep.rpc_ep()),
_rq_phys(Dataspace_client(_rq_ds).phys_addr()), _rq_phys(Dataspace_client(_rq_ds).phys_addr()),
_sink_ack(ep, *this, &Session_component::_signal), _sink_ack(ep, *this, &Session_component::_signal),
_sink_submit(ep, *this, &Session_component::_signal), _sink_submit(ep, *this, &Session_component::_signal),
_req_queue_full(false), _req_queue_full(false),
_p_in_fly(0) _p_in_fly(0),
_writeable(writeable)
{ {
_tx.sigh_ready_to_ack(_sink_ack); _tx.sigh_ready_to_ack(_sink_ack);
_tx.sigh_packet_avail(_sink_submit); _tx.sigh_packet_avail(_sink_submit);
@ -232,9 +239,19 @@ class Block::Session_component : public Block::Session_component_base,
void info(sector_t *blk_count, size_t *blk_size, void info(sector_t *blk_count, size_t *blk_size,
Operations *ops) Operations *ops)
{ {
Operations driver_ops = _driver.ops();
*blk_count = _driver.block_count(); *blk_count = _driver.block_count();
*blk_size = _driver.block_size(); *blk_size = _driver.block_size();
*ops = _driver.ops(); *ops = Operations();
typedef Block::Packet_descriptor::Opcode Opcode;
if (driver_ops.supported(Opcode::READ))
ops->set_operation(Opcode::READ);
if (_writeable && driver_ops.supported(Opcode::WRITE))
ops->set_operation(Opcode::WRITE);
} }
void sync() { _driver.sync(); } void sync() { _driver.sync(); }
@ -252,6 +269,7 @@ class Block::Root : public Genode::Root_component<Block::Session_component,
Driver_factory &_driver_factory; Driver_factory &_driver_factory;
Genode::Entrypoint &_ep; Genode::Entrypoint &_ep;
Genode::Region_map &_rm; Genode::Region_map &_rm;
bool const _writeable;
protected: protected:
@ -283,8 +301,13 @@ class Block::Root : public Genode::Root_component<Block::Session_component,
throw Insufficient_ram_quota(); throw Insufficient_ram_quota();
} }
bool writeable = _writeable
? Arg_string::find_arg(args, "writeable").bool_value(true)
: false;
return new (md_alloc()) Session_component(_driver_factory, return new (md_alloc()) Session_component(_driver_factory,
_ep, _rm, tx_buf_size); _ep, _rm, tx_buf_size,
writeable);
} }
public: public:
@ -300,10 +323,11 @@ class Block::Root : public Genode::Root_component<Block::Session_component,
Root(Genode::Entrypoint &ep, Root(Genode::Entrypoint &ep,
Allocator &md_alloc, Allocator &md_alloc,
Genode::Region_map &rm, Genode::Region_map &rm,
Driver_factory &driver_factory) Driver_factory &driver_factory,
bool writeable)
: :
Root_component(ep, md_alloc), Root_component(ep, md_alloc),
_driver_factory(driver_factory), _ep(ep), _rm(rm) _driver_factory(driver_factory), _ep(ep), _rm(rm), _writeable(writeable)
{ } { }
}; };

View File

@ -57,7 +57,7 @@ append config {
<resource name="RAM" quantum="10M" /> <resource name="RAM" quantum="10M" />
<provides><service name="Block" /></provides> <provides><service name="Block" /></provides>
<config> <config>
<policy label_prefix="test-ahci" device="0" /> <policy label_prefix="test-ahci" device="0" writeable="yes" />
</config> </config>
</start> </start>

View File

@ -64,7 +64,7 @@ append config {
<provides><service name="Block" /></provides> <provides><service name="Block" /></provides>
<config atapi="yes"> <config atapi="yes">
<report ports="yes"/> <report ports="yes"/>
<policy label_prefix="test-ahci" device="0" /> <policy label_prefix="test-ahci" device="0" writeable="yes" />
</config> </config>
<route> <route>
<service name="Report"> <child name="ahci_report_rom"/> </service> <service name="Report"> <child name="ahci_report_rom"/> </service>

View File

@ -19,15 +19,18 @@ which client can access a certain device:
! </route> ! </route>
! <config atapi="no"> ! <config atapi="no">
! <!-- use model and serial number --> ! <!-- use model and serial number -->
! <policy label_prefix="test-ahci" model="QEMU HARDDISK" serial="QM00005" /> ! <policy label_prefix="test-ahci" model="QEMU HARDDISK" serial="QM00005" writeable="yes" />
! <!-- use controller port number --> ! <!-- use controller port number -->
! <policy label_prefix="bench" device="1" /> ! <policy label_prefix="bench" device="1" writeable="yes" />
! <!-- read-only access -->
! <policy label_prefix="boot_fs" device="2"/>
! </config> ! </config>
!</start> !</start>
In the example above, a session request labeled with "test-ahci" gains access to In the example above, a session request labeled with "test-ahci" gains access to
a device with certain model and serial numbers, while "bench" gains access to a device with certain model and serial numbers, "bench" gains access to
device at port 1. ATAPI support is by default disabled and can be enabled by device at port 1, and finally the session "boot_fs" gains read-only access to
port 2. ATAPI support is by default disabled and can be enabled by
setting the config attribute "atapi" to "yes". setting the config attribute "atapi" to "yes".
ahci_drv supports reporting of active ports, which can be enabled via ahci_drv supports reporting of active ports, which can be enabled via

View File

@ -57,8 +57,9 @@ class Session_component : public Block::Session_component
Session_component(Block::Driver_factory &driver_factory, Session_component(Block::Driver_factory &driver_factory,
Genode::Entrypoint &ep, Genode::Entrypoint &ep,
Genode::Region_map &rm, Genode::Region_map &rm,
Genode::size_t buf_size) Genode::size_t buf_size,
: Block::Session_component(driver_factory, ep, rm, buf_size) { } bool writeable)
: Block::Session_component(driver_factory, ep, rm, buf_size, writeable) { }
Block::Driver_factory &factory() { return _driver_factory; } Block::Driver_factory &factory() { return _driver_factory; }
}; };
@ -73,32 +74,12 @@ class Block::Root_multiple_clients : public Root_component< ::Session_component>
Genode::Allocator &_alloc; Genode::Allocator &_alloc;
Genode::Xml_node _config; Genode::Xml_node _config;
long _device_num(Session_label const &label, char *model, char *sn, size_t bufs_len)
{
long num = -1;
try {
Session_policy policy(label, _config);
/* try read device port number attribute */
try { policy.attribute("device").value(&num); }
catch (...) { }
/* try read device model and serial number attributes */
model[0] = sn[0] = 0;
policy.attribute("model").value(model, bufs_len);
policy.attribute("serial").value(sn, bufs_len);
} catch (...) { }
return num;
}
protected: protected:
::Session_component *_create_session(const char *args) ::Session_component *_create_session(const char *args)
{ {
Session_label const label = label_from_args(args); Session_label const label = label_from_args(args);
Session_policy const policy(label, _config);
size_t ram_quota = size_t ram_quota =
Arg_string::find_arg(args, "ram_quota").ulong_value(0); Arg_string::find_arg(args, "ram_quota").ulong_value(0);
@ -117,18 +98,24 @@ class Block::Root_multiple_clients : public Root_component< ::Session_component>
throw Insufficient_ram_quota(); throw Insufficient_ram_quota();
} }
/* Search for configured device */ /* try read device port number attribute */
char model_buf[64], sn_buf[64]; long num = policy.attribute_value("device", -1L);
/* try read device model and serial number attributes */
auto const model = policy.attribute_value("model", String<64>());
auto const serial = policy.attribute_value("serial", String<64>());
/* sessions are not writeable by default */
bool writeable = policy.attribute_value("writeable", false);
long num = _device_num(label, model_buf, sn_buf, sizeof(model_buf));
/* prefer model/serial routing */ /* prefer model/serial routing */
if ((model_buf[0] != 0) && (sn_buf[0] != 0)) if ((model != "") && (serial != ""))
num = Ahci_driver::device_number(model_buf, sn_buf); num = Ahci_driver::device_number(model.string(), serial.string());
if (num < 0) { if (num < 0) {
error("rejecting session request, no matching policy for '", label, "'", error("rejecting session request, no matching policy for '", label, "'",
model_buf[0] == 0 ? "" model == "" ? ""
: " (model=", Cstring(model_buf), " serial=", Cstring(sn_buf), ")"); : " (model=", model, " serial=", serial, ")");
throw Service_denied(); throw Service_denied();
} }
@ -137,10 +124,15 @@ class Block::Root_multiple_clients : public Root_component< ::Session_component>
throw Service_denied(); throw Service_denied();
} }
if (writeable)
writeable = Arg_string::find_arg(args, "writeable").bool_value(true);
Block::Factory *factory = new (&_alloc) Block::Factory(num); Block::Factory *factory = new (&_alloc) Block::Factory(num);
::Session_component *session = new (&_alloc) ::Session_component *session = new (&_alloc)
::Session_component(*factory, _env.ep(), _env.rm(), tx_buf_size); ::Session_component(*factory, _env.ep(), _env.rm(), tx_buf_size, writeable);
log("session opened at device ", num, " for '", label, "'"); log(
writeable ? "writeable " : "read-only ",
"session opened at device ", num, " for '", label, "'");
return session; return session;
} }

View File

@ -43,7 +43,7 @@ struct Main
} factory { env, heap }; } factory { env, heap };
Block::Root root { env.ep(), heap, env.rm(), factory }; Block::Root root { env.ep(), heap, env.rm(), factory, true };
Main(Genode::Env &env) : env(env) Main(Genode::Env &env) : env(env)
{ {

View File

@ -818,7 +818,7 @@ struct Usb::Main
}; };
Factory factory { env, heap, announce_dispatcher }; Factory factory { env, heap, announce_dispatcher };
Block::Root root { env.ep(), heap, env.rm(), factory }; Block::Root root { env.ep(), heap, env.rm(), factory, true };
Main(Env &env) : env(env) { } Main(Env &env) : env(env) { }
}; };

View File

@ -70,7 +70,7 @@ struct Main
Genode::Env &env; Genode::Env &env;
Genode::Heap heap { env.ram(), env.rm() }; Genode::Heap heap { env.ram(), env.rm() };
Factory<Lru_policy> factory { env, heap }; Factory<Lru_policy> factory { env, heap };
Block::Root root { env.ep(), heap, env.rm(), factory }; Block::Root root { env.ep(), heap, env.rm(), factory, true };
Genode::Signal_handler<Main> resource_dispatcher { Genode::Signal_handler<Main> resource_dispatcher {
env.ep(), *this, &Main::resource_handler }; env.ep(), *this, &Main::resource_handler };

View File

@ -22,7 +22,7 @@ In order to route a client to the right partition, the server parses its
configuration section looking for 'policy' tags. configuration section looking for 'policy' tags.
XML Syntax: XML Syntax:
! <policy labal="<program name>" parition="<partition number>" /> ! <policy label="<program name>" partition="<partition number>" writeable="<boolean>"/>
part_blk supports partition reporting, which can be enabled via the part_blk supports partition reporting, which can be enabled via the
<report> configuration node. See below for an example. The report <report> configuration node. See below for an example. The report
@ -41,6 +41,8 @@ looks like follows (for MBR resp. GPT).
! guid="87199a83-d0f4-4a01-b9e3-6516a8579d61" start="4096" length="16351"/> ! guid="87199a83-d0f4-4a01-b9e3-6516a8579d61" start="4096" length="16351"/>
! </partitions> ! </partitions>
Clients have read-only access to partitions unless overriden by a 'writeable'
policy attribute.
Usage Usage
----- -----
@ -65,8 +67,8 @@ Configuration snippet with two clients and an (hypothetical) IDE driver:
! 'test-part2' receives access to primary partition 1 --> ! 'test-part2' receives access to primary partition 1 -->
! <config> ! <config>
! <report partitions="yes"/> ! <report partitions="yes"/>
! <policy label_prefix="test-part1" partition="6"/> ! <policy label_prefix="test-part1" partition="6" writeable="yes"/>
! <policy label_prefix="test-part2" partition="1"/> ! <policy label_prefix="test-part2" partition="1" writeable="yes"/>
! </config> ! </config>
!</start> !</start>
! !

View File

@ -47,6 +47,7 @@ class Block::Session_component : public Block::Session_rpc_object,
Packet_descriptor _p_to_handle; Packet_descriptor _p_to_handle;
unsigned _p_in_fly; unsigned _p_in_fly;
Block::Driver &_driver; Block::Driver &_driver;
bool _writeable;
/** /**
* Acknowledge a packet already handled * Acknowledge a packet already handled
@ -84,6 +85,12 @@ class Block::Session_component : public Block::Session_rpc_object,
sector_t off = _p_to_handle.block_number() + _partition->lba; sector_t off = _p_to_handle.block_number() + _partition->lba;
size_t cnt = _p_to_handle.block_count(); size_t cnt = _p_to_handle.block_count();
void* addr = tx_sink()->packet_content(_p_to_handle); void* addr = tx_sink()->packet_content(_p_to_handle);
if (write && !_writeable) {
_ack_packet(_p_to_handle);
return;
}
try { try {
_driver.io(write, off, cnt, addr, *this, _p_to_handle); _driver.io(write, off, cnt, addr, *this, _p_to_handle);
} catch (Block::Session::Tx::Source::Packet_alloc_failed) { } catch (Block::Session::Tx::Source::Packet_alloc_failed) {
@ -126,7 +133,8 @@ class Block::Session_component : public Block::Session_rpc_object,
Partition *partition, Partition *partition,
Genode::Entrypoint &ep, Genode::Entrypoint &ep,
Genode::Region_map &rm, Genode::Region_map &rm,
Block::Driver &driver) Block::Driver &driver,
bool writeable)
: Session_rpc_object(rm, rq_ds, ep.rpc_ep()), : Session_rpc_object(rm, rq_ds, ep.rpc_ep()),
_rq_ds(rq_ds), _rq_ds(rq_ds),
_rq_phys(Dataspace_client(_rq_ds).phys_addr()), _rq_phys(Dataspace_client(_rq_ds).phys_addr()),
@ -136,7 +144,8 @@ class Block::Session_component : public Block::Session_rpc_object,
_req_queue_full(false), _req_queue_full(false),
_ack_queue_full(false), _ack_queue_full(false),
_p_in_fly(0), _p_in_fly(0),
_driver(driver) _driver(driver),
_writeable(writeable)
{ {
_tx.sigh_ready_to_ack(_sink_ack); _tx.sigh_ready_to_ack(_sink_ack);
_tx.sigh_packet_avail(_sink_submit); _tx.sigh_packet_avail(_sink_submit);
@ -193,9 +202,18 @@ class Block::Session_component : public Block::Session_rpc_object,
void info(sector_t *blk_count, size_t *blk_size, void info(sector_t *blk_count, size_t *blk_size,
Operations *ops) Operations *ops)
{ {
Operations driver_ops = _driver.ops();
*blk_count = _partition->sectors; *blk_count = _partition->sectors;
*blk_size = _driver.blk_size(); *blk_size = _driver.blk_size();
*ops = _driver.ops(); *ops = Operations();
typedef Block::Packet_descriptor::Opcode Opcode;
if (driver_ops.supported(Opcode::READ))
ops->set_operation(Opcode::READ);
if (_writeable && driver_ops.supported(Opcode::WRITE))
ops->set_operation(Opcode::WRITE);
} }
void sync() { _driver.session().sync(); } void sync() { _driver.session().sync(); }
@ -230,6 +248,7 @@ class Block::Root :
Session_component *_create_session(const char *args) override Session_component *_create_session(const char *args) override
{ {
long num = -1; long num = -1;
bool writeable = false;
Session_label const label = label_from_args(args); Session_label const label = label_from_args(args);
char const *label_str = label.string(); char const *label_str = label.string();
@ -239,6 +258,9 @@ class Block::Root :
/* read partition attribute */ /* read partition attribute */
policy.attribute("partition").value(&num); policy.attribute("partition").value(&num);
/* sessions are not writeable by default */
writeable = policy.attribute_value("writeable", false);
} catch (Xml_node::Nonexistent_attribute) { } catch (Xml_node::Nonexistent_attribute) {
error("policy does not define partition number for for '", error("policy does not define partition number for for '",
label_str, "'"); label_str, "'");
@ -280,11 +302,15 @@ class Block::Root :
throw Insufficient_ram_quota(); throw Insufficient_ram_quota();
} }
if (writeable)
writeable = Arg_string::find_arg(args, "writeable").bool_value(true);
Ram_dataspace_capability ds_cap; Ram_dataspace_capability ds_cap;
ds_cap = _env.ram().alloc(tx_buf_size); ds_cap = _env.ram().alloc(tx_buf_size);
Session_component *session = new (md_alloc()) Session_component *session = new (md_alloc())
Session_component(ds_cap, _table.partition(num), Session_component(ds_cap, _table.partition(num),
_env.ep(), _env.rm(), _driver); _env.ep(), _env.rm(), _driver,
writeable);
log("session opened at partition ", num, " for '", label_str, "'"); log("session opened at partition ", num, " for '", label_str, "'");
return session; return session;

View File

@ -194,7 +194,9 @@ struct Main
Genode::destroy(&alloc, driver); } Genode::destroy(&alloc, driver); }
} factory { env, heap, config_rom.xml() }; } factory { env, heap, config_rom.xml() };
Block::Root root { env.ep(), heap, env.rm(), factory }; enum { WRITEABLE = true };
Block::Root root { env.ep(), heap, env.rm(), factory, WRITEABLE };
Main(Env &env) : env(env) Main(Env &env) : env(env)
{ {

View File

@ -117,7 +117,9 @@ struct Main
Genode::destroy(&heap, driver); } Genode::destroy(&heap, driver); }
} factory { env, heap }; } factory { env, heap };
Block::Root root { env.ep(), heap, env.rm(), factory }; enum { WRITEABLE = false };
Block::Root root { env.ep(), heap, env.rm(), factory, WRITEABLE };
Main(Env &env) : env(env) { Main(Env &env) : env(env) {
env.parent().announce(env.ep().manage(root)); } env.parent().announce(env.ep().manage(root)); }

View File

@ -124,7 +124,7 @@ struct Main
void destroy(Block::Driver *driver) { } void destroy(Block::Driver *driver) { }
} factory { env, heap }; } factory { env, heap };
Block::Root root { env.ep(), heap, env.rm(), factory }; Block::Root root { env.ep(), heap, env.rm(), factory, true };
Timer::Connection timer { env }; Timer::Connection timer { env };
Genode::Signal_handler<Driver> dispatcher { env.ep(), *factory.driver, Genode::Signal_handler<Driver> dispatcher { env.ep(), *factory.driver,
&Driver::handler }; &Driver::handler };

View File

@ -181,7 +181,7 @@ append_if $use_block_sata config {
<resource name="RAM" quantum="1M" /> <resource name="RAM" quantum="1M" />
<provides><service name="Block"/></provides> <provides><service name="Block"/></provides>
<config> <config>
<policy label="seoul -> VirtualDisk 0" device="0" /> <policy label="seoul -> VirtualDisk 0" device="0" writeable="yes"/>
</config> </config>
</start>} </start>}

View File

@ -92,7 +92,7 @@ append config {
<resource name="RAM" quantum="10M"/> <resource name="RAM" quantum="10M"/>
<provides><service name="Block"/></provides> <provides><service name="Block"/></provides>
<config> <config>
<policy label_prefix="part_blk" device="0"/> <policy label_prefix="part_blk" device="0" writeable="yes"/>
</config> </config>
</start> </start>
<start name="part_blk" priority="-1"> <start name="part_blk" priority="-1">
@ -103,9 +103,9 @@ append config {
</route> </route>
<config>} <config>}
append_if [expr $use_rumpfs] config { append_if [expr $use_rumpfs] config {
<policy label_prefix="rump_fs" partition="4"/>} <policy label_prefix="rump_fs" partition="4" writeable="yes"/>}
append_if [expr !$use_rumpfs] config { append_if [expr !$use_rumpfs] config {
<policy label_prefix="vbox1 -> raw" partition="3"/>} <policy label_prefix="vbox1 -> raw" partition="3" writeable="yes"/>}
append config { append config {
</config> </config>
</start>} </start>}