xorl %eax, %eax

CVE-2017-12762: Linux kernel isdn_net IOCTL memory corruption

leave a comment »

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.

Written by xorl

February 24, 2018 at 02:37

Posted in vulnerabilities

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 )

Google+ photo

You are commenting using your Google+ 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 )

w

Connecting to %s