2011-12-22 16:19:25 +01:00
|
|
|
/*
|
|
|
|
* \brief Utilities for handling server-side session policies
|
|
|
|
* \author Norman Feske
|
|
|
|
* \date 2011-09-13
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2017-02-20 13:23:52 +01:00
|
|
|
* Copyright (C) 2011-2017 Genode Labs GmbH
|
2011-12-22 16:19:25 +01:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
2017-02-20 13:23:52 +01:00
|
|
|
* under the terms of the GNU Affero General Public License version 3.
|
2011-12-22 16:19:25 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _INCLUDE__OS__SESSION_POLICY_H_
|
|
|
|
#define _INCLUDE__OS__SESSION_POLICY_H_
|
|
|
|
|
2016-01-12 14:11:58 +01:00
|
|
|
#include <base/session_label.h>
|
2019-01-22 18:57:22 +01:00
|
|
|
#include <base/log.h>
|
2017-05-29 14:52:24 +02:00
|
|
|
#include <session/session.h>
|
|
|
|
#include <util/arg_string.h>
|
|
|
|
#include <util/xml_node.h>
|
2017-01-30 11:35:12 +01:00
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
namespace Genode {
|
2015-09-17 16:59:09 +02:00
|
|
|
|
2015-11-24 16:53:10 +01:00
|
|
|
struct Xml_node_label_score;
|
2015-09-17 16:59:09 +02:00
|
|
|
class Session_policy;
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
|
2015-11-24 16:53:10 +01:00
|
|
|
/**
|
|
|
|
* Score for matching an Xml_node against a label
|
|
|
|
*
|
|
|
|
* The score is based on the attributes 'label', 'label_prefix', and
|
|
|
|
* 'label_suffix'.
|
|
|
|
*/
|
|
|
|
struct Genode::Xml_node_label_score
|
|
|
|
{
|
2016-03-09 15:06:42 +01:00
|
|
|
bool label_present = true;
|
2015-11-24 16:53:10 +01:00
|
|
|
bool prefix_present = true;
|
|
|
|
bool suffix_present = true;
|
|
|
|
|
|
|
|
bool label_match = false;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The match values contain the number of matching characters + 1.
|
|
|
|
* If 0, there is a conflict. If 1, an empty string matched.
|
|
|
|
*/
|
|
|
|
enum { CONFLICT = 0 };
|
|
|
|
unsigned prefix_match = CONFLICT;
|
|
|
|
unsigned suffix_match = CONFLICT;
|
|
|
|
|
|
|
|
Xml_node_label_score() { }
|
|
|
|
|
|
|
|
template <size_t N>
|
|
|
|
Xml_node_label_score(Xml_node node, String<N> const &label)
|
|
|
|
:
|
|
|
|
label_present (node.has_attribute("label")),
|
|
|
|
prefix_present(node.has_attribute("label_prefix")),
|
|
|
|
suffix_present(node.has_attribute("label_suffix"))
|
|
|
|
{
|
|
|
|
if (label_present)
|
|
|
|
label_match = node.attribute_value("label", String<N>()) == label;
|
|
|
|
|
|
|
|
if (prefix_present) {
|
|
|
|
typedef String<N> Prefix;
|
|
|
|
Prefix const prefix = node.attribute_value("label_prefix", Prefix());
|
|
|
|
|
|
|
|
if (!strcmp(label.string(), prefix.string(), prefix.length() - 1))
|
2017-01-19 17:37:13 +01:00
|
|
|
prefix_match = prefix.length();
|
2015-11-24 16:53:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (suffix_present) {
|
|
|
|
typedef String<N> Suffix;
|
|
|
|
Suffix const suffix = node.attribute_value("label_suffix", Suffix());
|
|
|
|
|
|
|
|
if (label.length() >= suffix.length()) {
|
|
|
|
unsigned const offset = label.length() - suffix.length();
|
|
|
|
|
|
|
|
if (!strcmp(label.string() + offset, suffix.string()))
|
2017-01-19 17:37:13 +01:00
|
|
|
suffix_match = suffix.length();
|
2015-11-24 16:53:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool conflict() const
|
|
|
|
{
|
|
|
|
return (label_present && !label_match)
|
|
|
|
|| (prefix_present && !prefix_match)
|
|
|
|
|| (suffix_present && !suffix_match);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return true if this node's score is higher than 'other'
|
|
|
|
*/
|
|
|
|
bool stronger(Xml_node_label_score const &other) const
|
|
|
|
{
|
2016-03-09 15:06:42 +01:00
|
|
|
/* something must match */
|
|
|
|
if (!(label_present || prefix_present || suffix_present))
|
|
|
|
return false;
|
|
|
|
|
2015-11-24 16:53:10 +01:00
|
|
|
/* if we are in conflict, we have a lower score than any other node */
|
|
|
|
if (conflict())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* there are no conflicts */
|
|
|
|
|
|
|
|
/* we have a higher score than another conflicting node */
|
|
|
|
if (other.conflict())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (label_present && !other.label_present)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (other.label_present)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* labels are equally good */
|
|
|
|
|
|
|
|
if (prefix_present && !other.prefix_present)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (!prefix_present && other.prefix_present)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (prefix_present && other.prefix_present) {
|
|
|
|
|
|
|
|
if (prefix_match > other.prefix_match)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (prefix_match < other.prefix_match)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* prefixes are equally good */
|
|
|
|
|
|
|
|
if (suffix_present && !other.suffix_present)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (!suffix_present && other.suffix_present)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (suffix_present && other.suffix_present) {
|
|
|
|
|
|
|
|
if (suffix_match > other.suffix_match)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (suffix_match < other.suffix_match)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* nodes are equally good */
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-03-04 21:12:14 +01:00
|
|
|
/**
|
|
|
|
* Query server-side policy for a session request
|
|
|
|
*/
|
|
|
|
class Genode::Session_policy : public Xml_node
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Exception type
|
|
|
|
*/
|
Streamline exception types
This patch reduces the number of exception types by facilitating
globally defined exceptions for common usage patterns shared by most
services. In particular, RPC functions that demand a session-resource
upgrade not longer reflect this condition via a session-specific
exception but via the 'Out_of_ram' or 'Out_of_caps' types.
Furthermore, the 'Parent::Service_denied', 'Parent::Unavailable',
'Root::Invalid_args', 'Root::Unavailable', 'Service::Invalid_args',
'Service::Unavailable', and 'Local_service::Factory::Denied' types have
been replaced by the single 'Service_denied' exception type defined in
'session/session.h'.
This consolidation eases the error handling (there are fewer exceptions
to handle), alleviates the need to convert exceptions along the
session-creation call chain, and avoids possible aliasing problems
(catching the wrong type with the same name but living in a different
scope).
2017-05-07 22:03:22 +02:00
|
|
|
class No_policy_defined : public Service_denied { };
|
2015-03-04 21:12:14 +01:00
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Query session policy from session label
|
|
|
|
*/
|
2015-11-24 16:53:10 +01:00
|
|
|
template <size_t N>
|
|
|
|
static Xml_node _query_policy(String<N> const &label, Xml_node config)
|
2015-03-04 21:12:14 +01:00
|
|
|
{
|
2015-09-17 16:59:09 +02:00
|
|
|
/*
|
|
|
|
* Find policy node that matches best
|
|
|
|
*/
|
2015-11-24 16:53:10 +01:00
|
|
|
Xml_node best_match("<none/>");
|
|
|
|
Xml_node_label_score best_score;
|
2015-03-04 21:12:14 +01:00
|
|
|
|
2015-09-17 16:59:09 +02:00
|
|
|
/*
|
|
|
|
* Functor to be applied to each policy node
|
|
|
|
*/
|
|
|
|
auto lambda = [&] (Xml_node policy) {
|
2015-11-24 16:53:10 +01:00
|
|
|
Xml_node_label_score const score(policy, label);
|
|
|
|
if (score.stronger(best_score)) {
|
|
|
|
best_match = policy;
|
|
|
|
best_score = score;
|
|
|
|
}
|
2015-09-17 16:59:09 +02:00
|
|
|
};
|
2015-03-04 21:12:14 +01:00
|
|
|
|
2015-09-17 16:59:09 +02:00
|
|
|
config.for_each_sub_node("policy", lambda);
|
2015-03-04 21:12:14 +01:00
|
|
|
|
2015-09-17 16:59:09 +02:00
|
|
|
if (!best_match.has_type("none"))
|
|
|
|
return best_match;
|
2015-03-04 21:12:14 +01:00
|
|
|
|
2016-03-09 15:06:42 +01:00
|
|
|
try { return config.sub_node("default-policy"); }
|
|
|
|
catch (...) { }
|
|
|
|
|
2019-01-22 18:57:22 +01:00
|
|
|
warning("no policy defined for label '", label, "'");
|
2015-03-04 21:12:14 +01:00
|
|
|
throw No_policy_defined();
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*
|
2015-09-17 16:59:09 +02:00
|
|
|
* \param label label used as the selector of a policy
|
2017-04-04 15:18:06 +02:00
|
|
|
* \param config XML node that contains the policies as sub nodes
|
2015-03-04 21:12:14 +01:00
|
|
|
*
|
2015-09-17 16:59:09 +02:00
|
|
|
* \throw No_policy_defined the server configuration has no
|
|
|
|
* policy defined for the specified label
|
2015-03-04 21:12:14 +01:00
|
|
|
*
|
2015-09-17 16:59:09 +02:00
|
|
|
* On construction, the 'Session_policy' looks up the 'policy' XML node
|
|
|
|
* that matches the label provided as argument. The server-side
|
|
|
|
* policies are defined in one or more policy subnodes of the server's
|
|
|
|
* 'config' node. Each policy node has a label attribute. If the policy
|
|
|
|
* label matches the first part of the label as delivered as session
|
|
|
|
* argument, the policy matches. If multiple policies match, the one
|
|
|
|
* with the longest label is selected.
|
2015-03-04 21:12:14 +01:00
|
|
|
*/
|
2015-09-17 16:59:09 +02:00
|
|
|
template <size_t N>
|
2017-04-04 15:18:06 +02:00
|
|
|
Session_policy(String<N> const &label, Xml_node config)
|
2015-09-17 16:59:09 +02:00
|
|
|
:
|
2015-11-24 16:53:10 +01:00
|
|
|
Xml_node(_query_policy(label, config))
|
2015-09-17 16:59:09 +02:00
|
|
|
{ }
|
2015-03-04 21:12:14 +01:00
|
|
|
};
|
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
#endif /* _INCLUDE__OS__SESSION_POLICY_H_ */
|