Channels ▼
RSS

Design

Kernel-Mode Databases

Source Code Accompanies This Article. Download It Now.


Sample Application

To illustrate, the sample application we present here implements a basic access-control system, using eXtremeDB-KM to create and maintain the access-control database in the kernel space. The database maintains file-access rules, and the runtime provides drivers and user-level applications with high-performance access to the storage. The example code uses UNIX-like notations.

The application in Figure 2 contains three major components:

  • The database kernel module, responsible for storage, maintains database access logic.
  • A user-mode application that utilizes a user-mode database API.
  • The "filter" or kernel module that intercepts filesystem calls and provides a file access authorization mechanism to the system.

The database kernel module implements kernel-mode data storage and provides the API to manipulate the data. The module is integrated with the eXtremeDB database runtime, which is responsible for providing "standard" database functionality such as transaction control, data access coordination and locking, lookup algorithms, and the like. Example 1 presents the data layout using eXtremeDB Data Definition Language syntax.

Figure 2: Sample app components.

The class File describes a file object that is identified by the file's name, and the inode and device on which it is located. The rest of the fields (owner, defaccess, and acl vector) define file-access rules. The database maintains two hash-based indices that facilitate fast data access.

struct ACL
{
  uint4   uid;       // user id
  uint4   access;    // access allowed for some user id
};
class File
{
  char<100> name;   // file name
  uint4  inode;     // file inode
  uint4  device;    // device    
  uint4  owner;     // owner of the File
  uint4  defaccess;  
  vector< ACL > acls; // access control lists

  hash < name >          hname[4096];
  hash < inode ,device > hfile[4096];
};

Example 1: Database schema.

Because the database could grow large, the database pool is allocated in virtual memory. To use the allocated memory pool, it is mapped to the physical page (Examples 2 and 3). Once memory is allocated, the in-memory database is created and supports connections using standard database runtime functions.

/* allocate the database memory pool */
mem_ua_ptr = (char*)vmalloc( arg+PAGE_SIZE*2 );
if ( mem_ua_ptr == 0 ) {
     return -ENOMEM; /* error allocating memory */
}

Example 2: Allocating virtual memory for the database pool.

/* calculate page aligned address */
mem_ptr = (char*) ( ((unsigned long)mem_ua_ptr+PAGE_SIZE-1) & PAGE_MASK );
    /* lock pages */
    for ( va=(unsigned long)mem_ptr;
           va<(unsigned long)(&(mem_ptr[mem_size/sizeof(int)]));
           va+=PAGE_SIZE) {
     SetPageReserved(vmalloc_to_page((void *)(((unsigned long)va))));
    }

Example 3: Locking virtual memory pages.

The module exports two types of interface: the "direct" API available to other kernel modules and drivers, and the "indirect" API that implements eXtremeDB-KM's ioctl interface to the database module. The direct API is not available for user-mode processes, but is efficient because it maintains only kernel-space references and eliminates expensive (in performance terms) translations from kernel-address space to user-address space. The ioctl interface provides user-mode applications with access to the kernel-mode database.

The user-level application creates a user-level database access API exposed by the database module via the ioctl interface. This API lets user-mode processes (such as administrative applications) interact with eXtremeDB-KM.

To facilitate the implementation of the "indirect" system call API, eXtremeDB-KM provides a simple "interface compiler" utility. This utility is similar to that of a standard remote procedure call compiler, except it generates the user/kernel mode interface files instead of remote access stubs. Developers define the API for C functions that the user-mode applications use to access the kernel-mode database. The eXtremeDB-KM interface compiler generates interface files that implement the user-to-kernel-mode interface through the generic ioctl function. In particular, the interface compiler generates stub files that should be linked with the user-mode applications and the kernel-mode stubs that are included into the kernel module (Figure 3). The generated files encapsulate the user-to-kernel-mode transition and hide ioctl-based implementation details from kernel modules and user-mode applications.

Figure 3: eXtremeDB-KM interface compiler.

In contrast to other IDL implementations, the eXtremeDB-KM interface compiler accepts standard C header files to declare user-mode database access interfaces. The compiler recognizes a number of keywords in the form of comments to declare string, union, and array data types used as a part of the interface declaration. The IDL in Example 4 illustrates the concept.

#ifndef __EX_DB_API_H
#define __EX_DB_API_H

typedef struct tagFile {
        unsigned char result;
        char     name[100];
        unsigned int  inode;
        unsigned int  device;
        unsigned int  owner;
        unsigned int  defaccess;
}File_t, *File_h;

typedef char* zstring    /*sero-terminated string*/;
typedef unsigned int* pint;
int exdb_init_database ( unsigned long mem_size );
int exdb_shutdown_database( );
int exdb_add_file
        (zstring file_name, unsigned int inode,
         unsigned int device, unsigned int owner,
         unsigned int defaccess );

int exdb_remove_file( zstring file_name );
int exdb_find_file( zstring file_name,
                   /*out*/ pint pinode,
                   /*out*/ pint pdevice,
                   /*out*/ pint powner,
                   /*out*/ pint pdefaccess );
int exdb_authorize_file( zstring file_name, unsigned int uid, unsigned int access );
#endif /* __EX_DB_API_H */

Example 4: Interface definition header file.

The interface compiler approach simplifies access to databases created in the context of a kernel module. The user-mode application code that implements database access is almost undistinguishable from that used by the kernel-mode application, with the exception of a simple initialization step (Example 5). There is no need for the user-mode application to serialize/deserialize function parameters, and similar technicalities. The application only needs to define and implement its database access interface, regardless of whether the interface is used inside or outside the kernel.

(a)
if ( 0 != (i = exdb_find_file( name, &inode, &device, &owner, &access ))) {
         printf("exdb_find_file(\"%s\")==%d\n", name, i );
         return (0);
 };

(b)
if ( 0 != (i = exdb_find_file( name,&inode,&device,&owner,&access ))) {
         pr_info(DEV_NAME" exdb_find_file(\"%s\")==%d\n", name, i );
         return (0);
 };

Example 5: Initialization. (a) User mode; (b) Kernel mode.

The third component of our sample application—the filter module—intercepts calls to the filesystem and replaces standard file-access functions with its own, providing the user application with authorization to obtain the sought-after system resource. The implementation involves registering the custom module's file-access functions upon module initialization (Examples 6 and 7). In turn, these custom functions provide authentication. This is a standard technique used in numerous applications. However, the filter we present here benefits from using the database access API exposed by the eXtremeDB-KM-based database module to authenticate file access; see Example 8.

static int __init eACmod_init( void )
{
  if (!sys_call_table)
  {
    return -1;
  }
  if ( (major = register_chrdev( 0, DEV_NAME, &eACmod_fops )) < 0 )
  {
    return -EIO;
  };
  eACm_api_Init();
  intercept_syscalls();
  return 0;
};

Example 6: Registering file access.

extern void *sys_call_table[];
typedef int (*syscall_t)();

extern int my_open();
extern int my_creat();
extern int my_chmod();
extern int my_chown();
extern int my_unlink();
extern int my_execve();

struct replace_syscall replace_syscall[]={
     {INDEX_NR_open,     __NR_open,     (int(*)())0,   my_open},
     {INDEX_NR_creat,    __NR_creat,    (int(*)())0,   my_creat},
     {INDEX_NR_chmod,    __NR_chmod,    (int(*)())0,   my_chmod},
     {INDEX_NR_chown,    __NR_chown,    (int(*)())0,   my_chown},
     {INDEX_NR_unlink,   __NR_unlink,   (int(*)())0,   my_unlink},
     {INDEX_NR_execve,   __NR_execve,   (int(*)())0,   my_execve},
     {-1,           -1,       (int(*)())0,   (int(*)())0}
};
int nreplace_syscall = sizeof(replace_syscall)/sizeof(*replace_syscall)-1; 
void intercept_syscalls()
{
  int i, f;
  for(i = 0; i < nreplace_syscall; i++)
  {
    f = replace_syscall[i].index;
    replace_syscall[i].original = sys_call_table[f];
    sys_call_table[f] = replace_syscall[i].seos_syscall;
  }
}

Example 7: intercept_syscalls.

asmlinkage int my_open(const char* fname, int fmode, int mode)
{
  int access, rv;
  /* some processing */
  rv = replace_syscall[INDEX_NR_open].original(fname, fmode, mode);
  return rv;
}

Example 8: my_open() example.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video