next up previous
Next: Exporting RTLinux-internals via /proc Up: RT-Interfaces via proc Previous: RT-Interfaces via proc

Task control via /proc

Inserting modules requires root privileges. When setting up an embedded system with RTLinux then commonly some way to launch an rt-thread is neded without giving the operator root privileges. Setting the SETUID bit for insmod is a unacceptably insecure way, as this would allow inserting a trivial module to gain full control of the system. A common method used is to insert the rt-modules at system startup and have the application modules loaded in an inactive state. Later on, a unprivileged user starts the rt-thread by sending a start command via real-time FIFO, but this does requires to give the /dev/rtf# write access for unprivileged users, thus also opening some potential problems. An alternative is to use a /proc file and protect these files via kernel capabilities if needed. The advantage of the proc based solution is that the read/ write methods are file specific and not file system specific or tied to the major number of a device with access control restricted to virtual file systems capabilities, which are generally insufficient. These file specific file operations allow very restricted access to kernel space. File operations for proc files not only map to a very specific read/ write method but also have statically, compile time defined, virtual file systems permissions preventing runtime modifications, and allow a very application specific check of passed data.


pthread_t thread;
hrtime_t start_nsec;

static int running=1;
struct proc_dir_entry *proc_th_stat;

This rt-thread is launched on insmod (running is initialised to 1) and stops by exiting the while(running) loop when running is set to 0 via /proc/thread_status, it also allows monitoring the status of this thread by inspecting the /proc/thread_status simply by running cat /proc/thread_status.


void * 
start_routine(void *arg)
{
   int i=0;
   struct sched_param p;
   hrtime_t elapsed_time,now;
   p . sched_priority = 1;
   pthread_setschedparam(pthread_self(), 
      SCHED_FIFO, &p);

   pthread_make_periodic_np(pthread_self(), 
      gethrtime(), 500000000);

   while (running) {
      pthread_wait_np ();
      now = clock_gethrtime(CLOCK_REAL-TIME);
      elapsed_time=now-start_nsec;
      rtl_printf("elapsed_time = %Ld\n",
         (long long)elapsed_time);
      i++;
   }
   return (void *)i;
}

One of the nice things about the proc files being generated on the fly is that the read method can output the values in a nice user-friendly manner while the write method does not need to bother with any parsing as would be required with a configuration file.


int 
get_status(char *page, char **start, 
   off_t off, int count, int *eof,
   void *data)
{
   int size = 0;
    
   MOD_INC_USE_COUNT;
   
   size+=sprintf(page+size,"Thread State:%d\n",
      (int)running);

   MOD_DEC_USE_COUNT;
   return(size);
}

As the proc interface receives character input, one needs to convert input values to the appropriate internal data types. In this example a brute-force atoi is done, which also only takes the first passed character into account. Generally one needs to ensure that ANY write method in proc checks data passed to not open security holes in the kernel.


static int 
set_status(struct file *file,
   const char *user_buffer,
   unsigned long count, 
   void *data)
{
   MOD_INC_USE_COUNT;

   /* brute force atoi */
   running=(int)*user_buffer-'0';

   MOD_DEC_USE_COUNT;
   return count;
}
  
int init_module(void) {
   int retval;
   start_nsec=clock_gethrtime( CLOCK_REAL-TIME);
   retval = pthread_create( &thread, NULL, 
      start_routine, 0);
   if(retval){
      printk("pthread create failed\n");
      return -1;
   }
   proc_th_stat=create_proc_entry( "thread_status",
      S_IFREG | S_IWUSR, &proc_root);

   /* the file specific operations */
   proc_th_stat->read_proc=get_status;
   proc_th_stat->write_proc=set_status;
   return 0;
}

void cleanup_module(void) {
   void * ret_val;
   pthread_cancel(thread);
   pthread_join( thread, &ret_val);
   printk("Thread terminated (%d)\n",
      (int)ret_val);
   remove_proc_entry("thread_status", 
      &proc_root);
}


next up previous
Next: Exporting RTLinux-internals via /proc Up: RT-Interfaces via proc Previous: RT-Interfaces via proc
Der Herr Hofrat
2003-03-26