xorl %eax, %eax

Linux Kernel Shared Memory DoS

with one comment

It was reported by Jiri Olsa on 29 February 2008 at the Linux Kernel Mailing List. I’m writing for this bug because I read about it at work yesterday and when I came back home I looked at the kernel source I had (2.6.27) and wrote the following analysis.

The bug is located at ipc/shm.c. This is part of the interprocess communication shared memory subsystem provided by the kernel. The problem was at function shm_get_stat(). Here is the interesting part of this routine:

539 /*
540  * Called with shm_ids.rw_mutex held as a reader
541  */
542  static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss,
543                unsigned long *swp)
544 {
      ...
553        for (total = 0, next_id = 0; total < in_use; next_id++) {
554                struct shmid_kernel *shp;
555                struct inode *inode;
556
      ...
560
561                inode = shp->shm_file->f_path.dentry->d_inode;
562
563                if (is_file_hugepages(shp->shm_file)) {
      ...
567                } else {
568                        struct shmem_inode_info *info = SHMEM_I(inode);
569                        spin_lock(&info->lock);
570                        *rss += inode->i_mapping->nrpages;
571                        *swp += info->swapped;
572                        spin_unlock(&info->lock);
573                }
574
575                total++;
576        }
577 }

Here, we can see at line 568 that this function treats the inode as a shmem_inode_info structure. However, if the CONFIG_SHMEM is not enabled during the compile time (it is by default) then the shared memory is managed through RamFS filesystem. Now, a closer look at fs/ramfs/inode.c reveals the following:

52 struct inode *ramfs_get_inode(struct super_block *sb, int mode, dev_t dev)
53 {
54        struct inode * inode = new_inode(sb);
55
56        if (inode) {
    ...
84        }
85        return inode;
86 }

This function uses an inode structure to manage the information where SHMEM uses the structure found at line 568 as we can see at mm/shmem.c:

1500 static struct inode *
1501 shmem_get_inode(struct super_block *sb, int mode, dev_t dev)
1502 {
1503        struct inode *inode;
1504        struct shmem_inode_info *info;
        ...
1519                info = SHMEM_I(inode);
1520                memset(info, 0, (char *)inode - (char *)info);
        ...
1553        return inode;
1554 }

This means, that on a system with a kernel compiled without CONFIG_SHMEM an attempt of accessing shared memory through two or more processes that share memory could lead to an undefined behavior which is most likely a kernel crash. The patch for this bug was simple:

             *rss += pages_per_huge_page(h) * mapping->nrpages;
        } else {
+#ifdef CONFIG_SHMEM
             struct shmem_inode_info *info = SHMEM_I(inode);
             spin_lock(&info->lock);
             *rss += inode->i_mapping->nrpages;
             *swp += info->swapped;
             spin_unlock(&info->lock);
+#else
+            *rss += inode->i_mapping->nrpages;
+#endif
         }

Which disables the shmem_inode_info manipulation if CONFIG_SHMEM is not defined in the kernel configuration.

Written by xorl

March 10, 2009 at 19:17

Posted in bugs, linux

One Response

Subscribe to comments with RSS.

  1. Reported 2009-02-05 (not 2008) and CVE-2009-0859 =)

    Jericho

    April 3, 2009 at 09:50


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