xorl %eax, %eax

CVE-2009-0784: SystemTap Race Condition

leave a comment »

SystemTap is a known utility for system administration on Linux. It is included in numerous popular Linux distributions and it’s being used by a lot of people. This bug was patched by Євгеній Мещеряков but I’m not sure if he is the one who discovered it at first place. The code presented here is from the latest release of SystemTap which is 0.9 (the patch was performed on the snapshot build).

203 /*
204  * Members of the 'stapusr' group can only use "blessed" modules -
205  * ones in the '/lib/modules/KVER/systemtap' directory.  Make sure the
206  * module path is in that directory.
207  *
208  * Returns: -1 on errors, 0 on failure, 1 on success.
209  */
210 static int
211 check_path(void)
212 {
       ...
225         if (sprintf_chk(staplib_dir_path, "/lib/modules/%s/systemtap", utsbuf.release))
       ...
228         /* Validate /lib/modules/KVER/systemtap. */
229         if (stat(staplib_dir_path, &sb) < 0) {
       ...
235         /* Make sure it is a directory. */
236         if (! S_ISDIR(sb.st_mode)) {
       ...
242         /* Make sure it is owned by root. */
243         if (sb.st_uid != 0) {
       ...
249         /* Make sure it isn't world writable. */
250         if (sb.st_mode & S_IWOTH) {
       ...
257         /* Use realpath() to canonicalize the module directory
258          * path. */
259         if (realpath(staplib_dir_path, staplib_dir_realpath) == NULL) {
       ...
266         /* Use realpath() to canonicalize the module path. */
267         if (realpath(modpath, module_realpath) == NULL) {
       ...
272         /* To make sure the user can't specify something like
273          * /lib/modules/`uname -r`/systemtapmod.ko, put a '/' on the
274          * end of staplib_dir_realpath. */
275         if (strlen(staplib_dir_realpath) < (PATH_MAX - 1))
276                 strcat(staplib_dir_realpath, "/");
      ...
282         /* Now we've got two canonicalized paths.  Make sure
283          * module_realpath starts with staplib_dir_realpath. */
284         if (strncmp(staplib_dir_realpath, module_realpath,
285                     strlen(staplib_dir_realpath)) != 0) {
       ...
290                 return 0;
291         }
292         return 1;
293 }

So… this looks like “I’ll anything to avoid a TOCTOU bug” to me. This function which can be found at runtime/staprun/staprun_funcs.c and it checks the module path against various conditions but a race window is still there. This function is being called by check_permissions() which is then invoked by the main() function. The problem of the above code is between lines 267 and 275. modpath after line 267 should contain module_realpath which is later used (line 284) and which is also used to load the module path. These two variables should contain the same pointer but the above code leaves an inconsistent state between them since modpath is not being updated. Here is the patch to avoid this inconsistency:

     }
-   
+
+    /* Overwrite the modpath with the canonicalized one, to defeat
+       a possible race between path checking below and somewhat later
+       module loading. */
+    modpath = strdup (module_realpath);
+    if (modpath == NULL) {
+        _perr("allocating memory failed");
+        exit (1);
+    }
+
     /* To make sure the user can't specify something like

I haven’t checked if this is an exploitable race condition but it is clearly the most interesting bug I’ve studied today (until now of course).

Written by xorl

March 27, 2009 at 16:38

Posted in bugs

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s