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'
*/
if (!announce) {
enum { WRITEABLE = true };
PREPARE_WORK(&delayed, ack_packet);
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));
announce = true;
}

View File

@ -41,7 +41,7 @@ struct Main
} 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) {
env.parent().announce(env.ep().manage(root)); }

View File

@ -102,7 +102,7 @@ struct Main
Env &env;
Heap heap { env.ram(), env.rm() };
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) {
env.parent().announce(env.ep().manage(root)); }

View File

@ -105,7 +105,7 @@ append_if $use_ahci config {
</route>
<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 {
</config>
</start>}

View File

@ -76,6 +76,7 @@ class Block::Session_component : public Block::Session_component_base,
bool _ack_queue_full;
Packet_descriptor _p_to_handle;
unsigned _p_in_fly;
bool _writeable;
/**
* Acknowledge a packet already handled
@ -127,6 +128,10 @@ class Block::Session_component : public Block::Session_component_base,
break;
case Block::Packet_descriptor::WRITE:
if (!_writeable) {
_ack_packet(_p_to_handle);
break;
}
if (_driver.dma_enabled())
_driver.write_dma(packet.block_number(),
packet.block_count(),
@ -178,14 +183,16 @@ class Block::Session_component : public Block::Session_component_base,
Session_component(Driver_factory &driver_factory,
Genode::Entrypoint &ep,
Genode::Region_map &rm,
size_t buf_size)
size_t buf_size,
bool writeable)
: Session_component_base(driver_factory, buf_size),
Driver_session(rm, _rq_ds, ep.rpc_ep()),
_rq_phys(Dataspace_client(_rq_ds).phys_addr()),
_sink_ack(ep, *this, &Session_component::_signal),
_sink_submit(ep, *this, &Session_component::_signal),
_req_queue_full(false),
_p_in_fly(0)
_p_in_fly(0),
_writeable(writeable)
{
_tx.sigh_ready_to_ack(_sink_ack);
_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,
Operations *ops)
{
Operations driver_ops = _driver.ops();
*blk_count = _driver.block_count();
*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(); }
@ -252,6 +269,7 @@ class Block::Root : public Genode::Root_component<Block::Session_component,
Driver_factory &_driver_factory;
Genode::Entrypoint &_ep;
Genode::Region_map &_rm;
bool const _writeable;
protected:
@ -283,8 +301,13 @@ class Block::Root : public Genode::Root_component<Block::Session_component,
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,
_ep, _rm, tx_buf_size);
_ep, _rm, tx_buf_size,
writeable);
}
public:
@ -300,10 +323,11 @@ class Block::Root : public Genode::Root_component<Block::Session_component,
Root(Genode::Entrypoint &ep,
Allocator &md_alloc,
Genode::Region_map &rm,
Driver_factory &driver_factory)
Driver_factory &driver_factory,
bool writeable)
:
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" />
<provides><service name="Block" /></provides>
<config>
<policy label_prefix="test-ahci" device="0" />
<policy label_prefix="test-ahci" device="0" writeable="yes" />
</config>
</start>

View File

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

View File

@ -19,15 +19,18 @@ which client can access a certain device:
! </route>
! <config atapi="no">
! <!-- 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 -->
! <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>
!</start>
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
device at port 1. ATAPI support is by default disabled and can be enabled by
a device with certain model and serial numbers, "bench" gains access to
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".
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,
Genode::Entrypoint &ep,
Genode::Region_map &rm,
Genode::size_t buf_size)
: Block::Session_component(driver_factory, ep, rm, buf_size) { }
Genode::size_t buf_size,
bool writeable)
: Block::Session_component(driver_factory, ep, rm, buf_size, writeable) { }
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::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:
::Session_component *_create_session(const char *args)
{
Session_label const label = label_from_args(args);
Session_policy const policy(label, _config);
size_t ram_quota =
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();
}
/* Search for configured device */
char model_buf[64], sn_buf[64];
/* try read device port number attribute */
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 */
if ((model_buf[0] != 0) && (sn_buf[0] != 0))
num = Ahci_driver::device_number(model_buf, sn_buf);
if ((model != "") && (serial != ""))
num = Ahci_driver::device_number(model.string(), serial.string());
if (num < 0) {
error("rejecting session request, no matching policy for '", label, "'",
model_buf[0] == 0 ? ""
: " (model=", Cstring(model_buf), " serial=", Cstring(sn_buf), ")");
model == "" ? ""
: " (model=", model, " serial=", serial, ")");
throw Service_denied();
}
@ -137,10 +124,15 @@ class Block::Root_multiple_clients : public Root_component< ::Session_component>
throw Service_denied();
}
if (writeable)
writeable = Arg_string::find_arg(args, "writeable").bool_value(true);
Block::Factory *factory = new (&_alloc) Block::Factory(num);
::Session_component *session = new (&_alloc)
::Session_component(*factory, _env.ep(), _env.rm(), tx_buf_size);
log("session opened at device ", num, " for '", label, "'");
::Session_component(*factory, _env.ep(), _env.rm(), tx_buf_size, writeable);
log(
writeable ? "writeable " : "read-only ",
"session opened at device ", num, " for '", label, "'");
return session;
}

View File

@ -43,7 +43,7 @@ struct Main
} 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)
{

View File

@ -818,7 +818,7 @@ struct Usb::Main
};
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) { }
};

View File

@ -70,7 +70,7 @@ struct Main
Genode::Env &env;
Genode::Heap heap { env.ram(), env.rm() };
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 {
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.
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
<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"/>
! </partitions>
Clients have read-only access to partitions unless overriden by a 'writeable'
policy attribute.
Usage
-----
@ -65,8 +67,8 @@ Configuration snippet with two clients and an (hypothetical) IDE driver:
! 'test-part2' receives access to primary partition 1 -->
! <config>
! <report partitions="yes"/>
! <policy label_prefix="test-part1" partition="6"/>
! <policy label_prefix="test-part2" partition="1"/>
! <policy label_prefix="test-part1" partition="6" writeable="yes"/>
! <policy label_prefix="test-part2" partition="1" writeable="yes"/>
! </config>
!</start>
!

View File

@ -47,6 +47,7 @@ class Block::Session_component : public Block::Session_rpc_object,
Packet_descriptor _p_to_handle;
unsigned _p_in_fly;
Block::Driver &_driver;
bool _writeable;
/**
* 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;
size_t cnt = _p_to_handle.block_count();
void* addr = tx_sink()->packet_content(_p_to_handle);
if (write && !_writeable) {
_ack_packet(_p_to_handle);
return;
}
try {
_driver.io(write, off, cnt, addr, *this, _p_to_handle);
} catch (Block::Session::Tx::Source::Packet_alloc_failed) {
@ -126,7 +133,8 @@ class Block::Session_component : public Block::Session_rpc_object,
Partition *partition,
Genode::Entrypoint &ep,
Genode::Region_map &rm,
Block::Driver &driver)
Block::Driver &driver,
bool writeable)
: Session_rpc_object(rm, rq_ds, ep.rpc_ep()),
_rq_ds(rq_ds),
_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),
_ack_queue_full(false),
_p_in_fly(0),
_driver(driver)
_driver(driver),
_writeable(writeable)
{
_tx.sigh_ready_to_ack(_sink_ack);
_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,
Operations *ops)
{
Operations driver_ops = _driver.ops();
*blk_count = _partition->sectors;
*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(); }
@ -230,6 +248,7 @@ class Block::Root :
Session_component *_create_session(const char *args) override
{
long num = -1;
bool writeable = false;
Session_label const label = label_from_args(args);
char const *label_str = label.string();
@ -239,6 +258,9 @@ class Block::Root :
/* read partition attribute */
policy.attribute("partition").value(&num);
/* sessions are not writeable by default */
writeable = policy.attribute_value("writeable", false);
} catch (Xml_node::Nonexistent_attribute) {
error("policy does not define partition number for for '",
label_str, "'");
@ -280,11 +302,15 @@ class Block::Root :
throw Insufficient_ram_quota();
}
if (writeable)
writeable = Arg_string::find_arg(args, "writeable").bool_value(true);
Ram_dataspace_capability ds_cap;
ds_cap = _env.ram().alloc(tx_buf_size);
Session_component *session = new (md_alloc())
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, "'");
return session;

View File

@ -194,7 +194,9 @@ struct Main
Genode::destroy(&alloc, driver); }
} 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)
{

View File

@ -117,7 +117,9 @@ struct Main
Genode::destroy(&heap, driver); }
} 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) {
env.parent().announce(env.ep().manage(root)); }

View File

@ -124,7 +124,7 @@ struct Main
void destroy(Block::Driver *driver) { }
} 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 };
Genode::Signal_handler<Driver> dispatcher { env.ep(), *factory.driver,
&Driver::handler };

View File

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

View File

@ -92,7 +92,7 @@ append config {
<resource name="RAM" quantum="10M"/>
<provides><service name="Block"/></provides>
<config>
<policy label_prefix="part_blk" device="0"/>
<policy label_prefix="part_blk" device="0" writeable="yes"/>
</config>
</start>
<start name="part_blk" priority="-1">
@ -103,9 +103,9 @@ append config {
</route>
<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 {
<policy label_prefix="vbox1 -> raw" partition="3"/>}
<policy label_prefix="vbox1 -> raw" partition="3" writeable="yes"/>}
append config {
</config>
</start>}