Table of Contents

Basics

Generic list management provides an infrastructure to simply define and register a list or a list of sublists, which can optionally be kept persistent or have a /proc/rsbac-info/backup entry. All management, like SMP locking, on-disk storage etc., is done internally without bothering the registering module.

Keeping and using generic list managment has some advantages:

Examples of list usage can be found in REG sample 3 and in rsbac/data_structures/*_data_structures.c, which have been ported to generic lists and lost much of their source code on the way.

List Registration

All list registration handling is done with abstract handles of type rsbac_list_handle_t, which is just a void pointer. As usual, the NULL value is used for 'undefined' or 'not yet registered'.

List data type and function definitions can be found in include/rsbac/lists.h, other type definitions are in include/rsbac/types.h. These header files should always be included for registration.

Callback Functions

The following help functions can be provided by the registrant:

Note: Non-0 values are only used for list optimization and do not necessarily imply a real order of values.

int rsbac_list_compare_function_t
  (void * desc1, void * desc2);

Note: List optimization is based on descriptors, so data lookup is always linear search from first to last element in list order.

int rsbac_list_data_compare_function_t
  (void * data1, void * data2);

Attention: if old or new data_size is 0, the respective data pointer is NULL!

int rsbac_list_conv_function_t(
        void * old_desc,
        void * old_data,
        void * new_desc,
        void * new_data);

Note: Lists implementation does not assume anything about your version number apart from being of type rsbac_version_t, which is just a 32Bit unsigned integer. Use it as you like.

rsbac_list_conv_function_t *
  rsbac_list_get_conv_t(rsbac_version_t old_version); 

There also is a function useful when using __u32 values as descriptors. It compares two __u32 descriptors and can be used instead of implementing your own rsbac_list_compare_function_t function.

int rsbac_list_compare_u32(void * desc1, void * desc2); 

The following function returns the Generic List registration version

rsbac_version_t rsbac_list_version(void);

The list_info Structures

The rsbac_list_info and rsbac_lists_lol_info structs contain all data that will be stored persistently, i.e. written to disk. They have the following items:

struct rsbac_list_info_t
  {
    rsbac_version_t version;
    rsbac_list_key_t key;
    __u32 desc_size;
    __u32 data_size;
    rsbac_time_t max_age;
  };
 
struct rsbac_list_lol_info_t
  {
    rsbac_version_t version;
    rsbac_list_key_t key;
    __u32 desc_size;
    __u32 data_size;
    __u32 subdesc_size;
    __u32 subdata_size;
    rsbac_time_t max_age;
  };                      

Registration Functions

For list registration, you first have to choose a positive, signed 32 Bit integer as your personal, secret registration key. All registration related actions will later require this key. If your list name happens to be already in use, registration will fail with an error value of -RSBAC_EEXIST.

The list_info structs (s.a.) hold all necessary values. Functions can be left out by setting their pointer to NULL. Your module will later be identified in list messages and proc files by its name, access will require the handle returned by registration. The current maximum name length is 30 characters.

Registration is quite easy. It usually happens in the init_module() function of kernel modules, deregistration in cleanup_module(). Unloading a kernel module without deregistration will keep all registered lists in memory and prevent their next registration until you reboot!

Registration flags are:

Note: only items with 0 ttl (unlimited) get removed, and lol items with default data only get removed, if they have no subitems.

Note: only subitems with 0 ttl (unlimited) get removed.

There are several registration parameters additional to the list_info struct:

int rsbac_list_register(
  rsbac_version_t ds_version,
  rsbac_list_handle_t *handle_p,
  struct rsbac_list_info_t info,
  u_int flags,
  rsbac_list_compare_function_t * compare,
  rsbac_list_get_conv_t * get_conv,
  void * def_data,
  char * name,
  kdev_t device);
 
int rsbac_list_lol_register(
  rsbac_version_t ds_version,
  rsbac_list_handle_t *handle_p,
  struct rsbac_list_lol_info_t info,
  u_int flags,
  rsbac_list_compare_function_t * compare,
  rsbac_list_compare_function_t * subcompare,
  rsbac_list_get_conv_t * get_conv,
  rsbac_list_get_conv_t * get_subconv,
  void * def_data,
  void * def_subdata,
  char * name,
  kdev_t device); 

Once successfully registered, you can use the (possibly restored) lists with the access functions, which are described below.

If the list is no longer needed, you can either destroy it, then the on-disk version is deleted, or detach from it, then the list is stored to disk and removed from memory only. For security, you need both your handle and the key from the list_info struct.

int rsbac_list_destroy(
  rsbac_list_handle_t * handle_p, rsbac_list_key_t key);
 
int rsbac_list_lol_destroy(
  rsbac_list_handle_t * handle_p, rsbac_list_key_t key); 

Finally, you can set or unset your list's no_write flag to temporarily enable or disable on-disk storage. This can e.g. be used for a simple transaction scheme. The no_write value is either TRUE (do not write) or FALSE (do write).

int rsbac_list_no_write(
  rsbac_list_handle_t handle,
  rsbac_list_key_t key,
  boolean no_write);
 
int rsbac_list_lol_no_write(
  rsbac_list_handle_t handle,
  rsbac_list_key_t key,
  boolean no_write);

OK, your list is working. You should now have a look at its status, which is shown in /proc/rsbac-info/gen_lists.

Let me hint at the REG sample module 3 again - in the beginning using it as a base will be a good choice as well as save you a lot of typing.

Using the Lists

Items can be added, modified, removed, looked up, retrieved and counted. For most functions, there is also a wrapper for unsigned 32 bit integer descriptors, so that you can pass values instead of pointers. Also time-to-live property has been added: when specified, the item gets automatically removed after the given amount of seconds.

Add or modify items

If item for desc exists, the data is updated. data can be NULL, if list is registered with data_size 0 (used as set).

int rsbac_list_add(
  rsbac_list_handle_t handle,
  void * desc,
  void * data);
 
int rsbac_list_add_u32
  (rsbac_list_handle_t handle, __u32 desc, void * data);

Add with time-to-live in seconds. Set the value of ttl to 0 for unlimited (default), or to RSBAC_LIST_TTL_KEEP to keep the old ttl value of an existing item.

int rsbac_list_add_ttl(
  rsbac_list_handle_t handle,
  rsbac_time_t ttl,
  void * desc,
  void * data);
 
int rsbac_list_add_ttl_u32(
  rsbac_list_handle_t handle,
  rsbac_time_t ttl,
  __u32 desc,
  void * data);

Add list of lists sublist item. The item for desc must exist, if list has been registered without RSBAC_LIST_DEF_DATA, otherwise it is created on the fly.

int rsbac_list_lol_subadd(
  rsbac_list_handle_t handle,
  void * desc,
  void * subdesc,
  void * subdata);
 
int rsbac_list_lol_subadd_u32(
  rsbac_list_handle_t handle,
  __u32 desc,
  __u32 subdesc,
  void * subdata);

Add list of lists sublist item with ttl. Set the value of ttl to 0 for unlimited (default), or to RSBAC_LIST_TTL_KEEP to keep the old ttl value of an existing item.

int rsbac_list_lol_subadd_ttl(
  rsbac_list_handle_t handle,
  rsbac_time_t ttl,
  void * desc,
  void * subdesc,
  void * subdata);
 
int rsbac_list_lol_subadd_ttl_u32(
  rsbac_list_handle_t handle,
  rsbac_time_t ttl,
  __u32 desc,
  __u32 subdesc,
  void * subdata);

Add list of lists top level item.

int rsbac_list_lol_add(
  rsbac_list_handle_t handle,
  void * desc,
  void * data);
 
int rsbac_list_lol_add_u32(
  rsbac_list_handle_t handle, __u32 desc, void * data);

Add list of lists top level item with ttl. Set the value of ttl to 0 for unlimited (default), or to RSBAC_LIST_TTL_KEEP to keep the old ttl value of an existing item.

int rsbac_list_lol_add_ttl(
  rsbac_list_handle_t handle,
  rsbac_time_t ttl,
  void * desc,
  void * data);
 
int rsbac_list_lol_add_ttl_u32(
  rsbac_list_handle_t handle,
  rsbac_time_t ttl,
  __u32 desc,
  void * data);

Remove items

int rsbac_list_remove
  (rsbac_list_handle_t handle, void * desc);
 
int rsbac_list_remove_u32
  (rsbac_list_handle_t handle, __u32 desc);

Remove all items.

int rsbac_list_remove_all(rsbac_list_handle_t handle);

Remove item from sublist - also succeeds, if item for desc or subdesc does not exist.

int rsbac_list_lol_subremove(
  rsbac_list_handle_t handle,
  void * desc,
  void * subdesc);
 
int rsbac_list_lol_subremove_u32(
  rsbac_list_handle_t handle, __u32 desc, __u32 subdesc);

Remove all subitems from list

int rsbac_list_lol_subremove_all
  (rsbac_list_handle_t handle, void * desc);
 
int rsbac_list_lol_subremove_all_u32
  (rsbac_list_handle_t handle, __u32 desc);

Remove item from the top-level list of a list-of-lists

int rsbac_list_lol_remove(
  rsbac_list_handle_t handle,
  void * desc);
 
int rsbac_list_lol_remove_u32
  (rsbac_list_handle_t handle, __u32 desc);

Remove all items from a list-of-lists

int rsbac_list_lol_remove_all(rsbac_list_handle_t handle);

Retrieve item data

Item data is always copied - we cannot give a pointer, because item could be removed.

int rsbac_list_get_data(
  rsbac_list_handle_t handle,
  void * desc,
  void * data);
 
int rsbac_list_get_data_u32(
  rsbac_list_handle_t handle,
  __u32 desc,
  void * data);

Also get time-to-live. Both ttl_p and data can be NULL, they are then simply not returned

int rsbac_list_get_data_ttl(
  rsbac_list_handle_t handle,
  rsbac_time_t * ttl_p,
  void * desc,
  void * data);
 
int rsbac_list_get_data_ttl_u32(
  rsbac_list_handle_t handle,
  rsbac_time_t * ttl_p,
  __u32 desc,
  void * data);

Get data from a subitem.

int rsbac_list_lol_get_subdata(
  rsbac_list_handle_t handle,
  void * desc,
  void * subdesc,
  void * subdata);
 
int rsbac_list_lol_get_subdata_u32(
  rsbac_list_handle_t handle,
  __u32 desc,
  __u32 subdesc,
  void * data);

Also get time-to-live. Both ttl_p and data can be NULL, they are then simply not returned

int rsbac_list_lol_get_subdata_ttl(
  rsbac_list_handle_t handle,
  rsbac_time_t * ttl_p,
  void * desc,
  void * subdesc,
  void * subdata);
 
int rsbac_list_lol_get_subdata_ttl_u32(
  rsbac_list_handle_t handle,
  rsbac_time_t * ttl_p,
  __u32 desc,
  __u32 subdesc,
  void * data);

Get data from the top-level item.

int rsbac_list_lol_get_data(
  rsbac_list_handle_t handle,
  void * desc,
  void * data);
 
int rsbac_list_lol_get_data_u32(
  rsbac_list_handle_t handle,
  __u32 desc,
  void * data);

Also get time-to-live. Both ttl_p and data can be NULL, they are then simply not returned

int rsbac_list_lol_get_data_ttl(
  rsbac_list_handle_t handle,
  rsbac_time_t * ttl_p,
  void * desc,
  void * data);
 
int rsbac_list_lol_get_data_ttl_u32(
  rsbac_list_handle_t handle,
  rsbac_time_t * ttl_p,
  __u32 desc,
  void * data);

Retrieve item desc by data

Item desc is copied - we cannot give a pointer, because item could be removed. If no compare function is provided (NULL value), memcmp is used. Note: The stored list value is always used as first and the data value given here is always used as second parameter to the compare function, so you can use different types for storage and lookup.

int rsbac_list_get_desc(
  rsbac_list_handle_t handle,
  void * desc,
  void * data,
  rsbac_list_data_compare_function_t compare);
 
 
int rsbac_list_get_desc_u32(
  rsbac_list_handle_t handle,
  void * desc,
  __u32 data);

Get maximum descriptor value in the list (according to its compare function).

int rsbac_list_get_max_desc(
  rsbac_list_handle_t handle,
  void * desc);

Lookup items

Items can be simply checked for existence. All functions return TRUE, if item exists, and FALSE, if not.

int rsbac_list_exist(
  rsbac_list_handle_t handle,
  void * desc);
 
int rsbac_list_exist_u32(
  rsbac_list_handle_t handle,
  __u32 desc);
 
int rsbac_list_lol_subexist(
  rsbac_list_handle_t handle,
  void * desc,
  void * subdesc);
 
int rsbac_list_lol_subexist_u32(
  rsbac_list_handle_t handle,
  __u32 desc,
  __u32 subdesc)
 
int rsbac_list_lol_exist(
  rsbac_list_handle_t handle,
  void * desc);
 
int rsbac_list_lol_exist_u32(
  rsbac_list_handle_t handle,
  __u32 desc);

Count items

All functions return the number of elements or a negative error code.

long rsbac_list_count(
  rsbac_list_handle_t handle);
 
long rsbac_list_lol_subcount(
  rsbac_list_handle_t handle,
  void * desc);
 
long rsbac_list_lol_all_subcount(
  rsbac_list_handle_t handle);
 
long rsbac_list_lol_count(
  rsbac_list_handle_t handle);

Retrieve all items and/or all data

All functions return the number of elements or a negative error code.

Get array of all descriptors. If the return value is positive, *array_p contains a pointer to a vmalloc'd array of descs, otherwise *array_p is set to NULL. If *array_p has been set, caller must call vfree(*array_p) after use!

long rsbac_list_get_all_desc(
  rsbac_list_handle_t handle,
  void ** array_p);
 
long rsbac_list_lol_get_all_subdesc(
  rsbac_list_handle_t handle,
  void * desc,
  void ** array_p);
 
long rsbac_list_lol_get_all_subdesc_ttl(
  rsbac_list_handle_t handle,
  void * desc,
  void ** array_p,
  rsbac_time_t ** ttl_array_p);
 
 
long rsbac_list_lol_get_all_desc(
  rsbac_list_handle_t handle,
  void ** array_p);

Get array of all datas. If the return value is positive, *array_p contains a pointer to a vmalloc'd array of datas, otherwise *array_p is set to NULL. If *array_p has been set, caller must call vfree(*array_p) after use!

long rsbac_list_get_all_data(
  rsbac_list_handle_t handle,
  void ** array_p);
 
long rsbac_list_lol_get_all_subdata(
  rsbac_list_handle_t handle,
  void * desc,
  void ** array_p);
 
long rsbac_list_lol_get_all_data(
  rsbac_list_handle_t handle,
  void ** array_p);

Get item size.

int rsbac_list_get_item_size(
  rsbac_list_handle_t handle);
 
int rsbac_list_lol_get_subitem_size(
  rsbac_list_handle_t handle);
 
int rsbac_list_lol_get_item_size(
  rsbac_list_handle_t handle);

Get array of all items. If the return value is positive, *array_p contains a pointer to a vmalloc'd array of items, where desc and data are placed directly behind each other. If *array_p has been set, caller must call vfree(*array_p) after use!

long rsbac_list_get_all_items(
  rsbac_list_handle_t handle,
  void ** array_p);
 
long rsbac_list_get_all_items_ttl(
  rsbac_list_handle_t handle,
  void ** array_p,
  rsbac_time_t ** ttl_array_p);
 
long rsbac_list_lol_get_all_subitems(
  rsbac_list_handle_t handle,
  void * desc,
  void ** array_p);
 
long rsbac_list_lol_get_all_subitems_ttl(
  rsbac_list_handle_t handle,
  void * desc,
  void ** array_p,
  rsbac_time_t ** ttl_array_p);
 
 
long rsbac_list_lol_get_all_items(
  rsbac_list_handle_t handle,
  void ** array_p);

RSBAC Helper Functions

The RSBAC framework provides a lot of helper functions and variables, which should be used by your module, if appropiate. You can find a list of the most important ones in the REG description.