Linux kernel MD Driver NULL Pointer Dereference
I was having a look at 2.6.30.2’s ChangeLog and noticed this one. The bug is easy to understand, here is one of the buggy functions from 2.6.30’s drivers/md/md.c:
static ssize_t suspend_lo_store(mddev_t *mddev, const char *buf, size_t len) { char *e; unsigned long long new = simple_strtoull(buf, &e, 10); if (mddev->pers->quiesce == NULL) return -EINVAL; if (buf == e || (*e && *e != '\n')) return -EINVAL; if (new >= mddev->suspend_hi || (new > mddev->suspend_lo && new < mddev->suspend_hi)) { mddev->suspend_lo = new; mddev->pers->quiesce(mddev, 2); return len; } else return -EINVAL; } static struct md_sysfs_entry md_suspend_lo = __ATTR(suspend_lo, S_IRUGO|S_IWUSR, suspend_lo_show, suspend_lo_store);
As you can easily deduce from the two last lines, this can be reached through /sys/block/mdX/md/suspend_lo sysfs file. Of course as you can see that its default mode is 0644 and that might make this non-exploitable unless some distribution has different mode. Anyhow, the first if condition checks that mddev->pers->quiesce is not NULL. However, if the array is not active, then mddev->pers which is an mdk_personality structure describing the device and it includes numerous function pointers, could be NULL. In this case, the first if will be bypassed since mddev->pers->quiesce will definitely not going to be NULL, it will be NULL + the offset until quiesce which is just a void * if we have a look at the equivalent structure in drivers/md/md.h. This can result in a NULL pointer dereference or if it isn’t triggered by that time, then it will be triggered when mddev function pointer of mddev->pers->quiesce is called.
This was patched by adding the missing check.
unsigned long long new = simple_strtoull(buf, &e, 10); - if (mddev->pers->quiesce == NULL) + if (mddev->pers == NULL || + mddev->pers->quiesce == NULL) return -EINVAL;
And the exact same vulnerability was also present in suspend_hi_store() of the same file.
Leave a Reply