CVE-2017-12762: Linux kernel isdn_net IOCTL memory corruption
Recently I came across this report which is kind of sad since this was one nice and funny 0day that had been around for very long time. However, in this post I will only talk about the vulnerability since no exploit has been publicly disclosed yet. The vulnerability is in I4L (ISDN 4 Linux) and starts with the IIOCNETASL (Create slave interface) IOCTL command which is in drivers/isdn/i4l/isdn_common.c as shown below.
static int isdn_ioctl(struct file *file, uint cmd, ulong arg) { ... switch (cmd) { ... case IIOCNETASL: /* Add a slave to a network-interface */ if (arg) { if (copy_from_user(bname, argp, sizeof(bname) - 1)) return -EFAULT; } else return -EINVAL; ret = mutex_lock_interruptible(&dev->mtx); if (ret) return ret; if ((s = isdn_net_newslave(bname))) { if (copy_to_user(argp, s, strlen(s) + 1)) { ... }
Basically this is accessible via /dev/isdnctrl ISDN control device and ioctl(2) system call using IIOCNETASL command. As you can see in the above snippet, it uses copy_from_user() to get the user controlled buffer and store it in “bname” which is a stack allocated buffer that you can see how it was defined below.
union iocpar { char name[10]; char bname[22]; isdn_ioctl_struct iocts; isdn_net_ioctl_phone phone; isdn_net_ioctl_cfg cfg; } iocpar; void __user *argp = (void __user *)arg; #define name iocpar.name #define bname iocpar.bname
Later on we see that the user derived “bname” buffer is passed to isdn_net_newslave() which is a function defined in drivers/isdn/i4l/isdn_net.c. Here is this function.
char * isdn_net_newslave(char *parm) { char *p = strchr(parm, ','); isdn_net_dev *n; char newname[10]; if (p) { /* Slave-Name MUST not be empty */ if (!strlen(p + 1)) return NULL; strcpy(newname, p + 1); *p = 0; ... }
Here we can see that the only check on the user derived “p” pointer is that it is not empty. Then it uses strcpy() to copy the contents of it to “newname” which is a stack buffer with size of 10 Bytes. This is like a 90s textbook stack buffer overflow. In August 2017 it was reported and patched by Annie Cherkaev by replacing strcpy() with strscpy() which ensures that the copy will not exceed “newname” buffer’s limits. The patch is the following.
--- a/drivers/isdn/i4l/isdn_common.c +++ b/drivers/isdn/i4l/isdn_common.c @@ -1379,6 +1379,7 @@ isdn_ioctl(struct file *file, uint cmd, if (arg) { if (copy_from_user(bname, argp, sizeof(bname) - 1)) return -EFAULT; + bname[sizeof(bname)-1] = 0; } else return -EINVAL; ret = mutex_lock_interruptible(&dev->mtx); --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -2611,10 +2611,9 @@ isdn_net_newslave(char *parm) char newname[10]; if (p) { - /* Slave-Name MUST not be empty */ - if (!strlen(p + 1)) + /* Slave-Name MUST not be empty or overflow 'newname' */ + if (strscpy(newname, p + 1, sizeof(newname)) <= 0) return NULL; - strcpy(newname, p + 1); *p = 0; /* Master must already exist */ if (!(n = isdn_net_findif(parm)))
This is kind of sad, not because this is a useful 0day but because it had been around for years. Me and some friends had this 0day literally from 2007 so it is kind of sad seeing it dying quietly like this. In any case, I will not go into how to exploit it but it is a nice trivial vulnerability if you want to play around and practice your Linux kernel stack memory corruption exploitation techniques.
Leave a Reply