Right now, I plan to implement this feature with two steps. The first one is to fix up engine framework to solve the matter which I pointed out at the previous message. The later one is to implement access control feature on the modified engine framework.
I think what I should do on the next is to submit a proof of the concept patch to modify the existing engine framework. Is there any comment? (2010/03/05 16:02), KaiGai Kohei wrote: > Now I'm under working on access control feature with engine framework. > The git repository is at: > http://github.com/kaigai/memcached-selinux > > Under the development, I could find some matters to implement such kind > of features on the engine framework. > > (1). We have no server API to obtain socket file descriptor. > > SELinux provides an API to get security context of the peer process which > connects to the server process. This API takes an argument to inform socket > file descriptor. > However, memcached encapsulates conn->sfd, and we have no official interface > to translate the given cookie pointer to the socket file descriptor. > As a workaround, I cast the cookie into conn, and refer the socket. > > I need a server API to obtain a socket file for the given cookie. > > > (2). Order of the invocation of callback functions. > > The SELinux module wants to use engine specific data region in the conn > structure, it defines the following data structure which also provide > a capability to sore engine specific data of the secondary module. > > typedef struct selinux_connect > { > security_id_t sid; /* security context of the client process */ > void *data; /* private data for the secondary engine */ > } selinux_connect_t; > > The selinux_connect_t object is allocated and initialized at ON_CONNECT > callback, and it allows secondary module to register its engine specific > data. Then, it is released at ON_DISCONNECT callback. > > It means ON_CONNECT callback of SELinux must be invoked earlier than any > other modules, and ON_DISCONNECT callback of SELinux must be invoked last. > But we have no way to ensure the order of callback invocations. > > Now, I did a hack depending on internals of memcached. > The memcached calls a callback function earlier registered later, so > I registered ON_DISCONNECT callback prior to initialization of the secondary > engine, then I registered ON_CONNECT callback after the initialization. > > > http://github.com/kaigai/memcached-selinux/blob/selinux/selinux_engine.c#L310 > > As long as the secondary engine registers its callbacks in the initialize() > handler, it will work well. > > > (3). ENGINE_HANDLE is not delivered to a few engine handlers. > > The engine framework does not deliver ENGINE_HANDLE pointer to the following > handlers. > - item_get_cas() > - item_set_cas() > - item_get_key() > - item_get_data() > - item_get_clsid() > > If we use the first dozens bytes of the item data field to store security > context of the item, we have to specify how many first bytes will be used > to store the security attribute. > The ENGINE_HANDLE can contain some of meaningful information, and here is > no reason why we cannot deliver it. > > > (4). The way to store per item security attribute. > > It is the most headache matter for me. > > A straightforward idea is to store security context of the item as a part > of data field. > For example, when we receive a pair of key="aaaa" and value="xyzxyz", > selinux engine can modify the given data field, then it delivers the modified > key/value pair. If the default security context is "classified", it may be > modified to "classified\0xyzxyz", for instance. > The secondary module will store the given key / modified value pair as is, > even if it has backing storage system. > > User -----+ > | key = "aaaa", value="xyzxyz" > V > Memcached > |<-- nbytes --> > | | aaaa | xyzxyz | > | |________|______________| > | key value > | > V > selinux engine > |<--- nbytes + 11 ------> > | | aaaa | classified\0 | xyzxyz | > | |________|________________________| > | key value > V > secondary engine (such as default_engine) > > However, here is a headache. > The secondary engine assumes the data field of the item is numeric on > CAS operations, although the primary engine modified the data field to > store its security attribute. > > One idea is to add "offset" as an argument of the engine handlers. > In above example, the value has 17 bytes in total. 11 bytes of them are used > to selinux engine, and rest of them are used to the secondary engine. > > If item_set_cas() handler has an offset argument to inform secondary engine > how many bytes are already consumed by the primary engine, we can store the > modified value correctly, even if selinux engine modified it. > > In addition, the core memcached should not refer it->nbytes directly, > because it->nbytes is the total length of the item with value and security > context. The item_get_data() should return both of data pointer and nbytes > that engine modules want to show the core memcached. In this case, it should > return 6, not 17. > > > (5). The remove() method > > When its definition is modified to deliver the key, not item itself? > The memcached calls ->get() method prior to ->remove() invocations, although > the given request never wants to read contents of the item. > > Thanks, -- KaiGai Kohei <kai...@ak.jp.nec.com>