xorl %eax, %eax

CVE-2013-3228: Linux kernel IrDA Information Leak

with 2 comments

This is another simple kernel memory information leak fixed by Mathias Krauss. Here is the exact code where this bug is located in net/irda/af_irda.c code.

/*
 * Function irda_recvmsg_dgram (iocb, sock, msg, size, flags)
 *
 *    Try to receive message and copy it to user. The frame is discarded
 *    after being read, regardless of how much the user actually read
 */
static int irda_recvmsg_dgram(struct kiocb *iocb, struct socket *sock,
			      struct msghdr *msg, size_t size, int flags)
{
	struct sock *sk = sock->sk;
	struct irda_sock *self = irda_sk(sk);
	struct sk_buff *skb;
	size_t copied;
	int err;

	IRDA_DEBUG(4, "%s()\n", __func__);

	skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
				flags & MSG_DONTWAIT, &err);
   ...
	skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);

	skb_free_datagram(sk, skb);
   ...
	return copied;
}

This is a command which is defined as shown below.

static const struct proto_ops irda_seqpacket_ops = {
  ...
	.recvmsg =	irda_recvmsg_dgram,
  ...
};

static const struct proto_ops irda_dgram_ops = {
  ...
	.recvmsg =	irda_recvmsg_dgram,
  ...
};

#ifdef CONFIG_IRDA_ULTRA
static const struct proto_ops irda_ultra_ops = {
  ...
	.recvmsg =	irda_recvmsg_dgram,
  ...
};
#endif /* CONFIG_IRDA_ULTRA */

As Mathias Krausse pointed out, the ‘msg_namelen’ member of the ‘msghdr’ structure remains uninitialized resulting in kernel information leak. Below is how this structure is defined in include/linux/socket.h header file.

/*
 *      As we do 4.4BSD message passing we use a 4.4BSD message passing
 *      system, not 4.3. Thus msg_accrights(len) are now missing. They
 *      belong in an obscure libc emulation or the bin.
 */
  
struct msghdr {
        void    *       msg_name;       /* Socket name                  */
        int             msg_namelen;    /* Length of name               */
        struct iovec *  msg_iov;        /* Data blocks                  */
        __kernel_size_t msg_iovlen;     /* Number of blocks             */
        void    *       msg_control;    /* Per protocol magic (eg BSD file descriptor passing) */
       __kernel_size_t msg_controllen; /* Length of cmsg list */
       unsigned int    msg_flags;
};

And the fix was to add the missing initialization.

 	IRDA_DEBUG(4, "%s()\n", __func__);
 
+	msg->msg_namelen = 0;
+
 	skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
 				flags & MSG_DONTWAIT, &err);
About these ads

Written by xorl

May 26, 2013 at 14:18

Posted in bugs, linux

2 Responses

Subscribe to comments with RSS.

  1. What’s missing in the article IMHO, is the location of the leak itself: the call to move_addr_to_user() in net/socket.c:__sys_recvmsg()/sys_recvfrom(). It takes the user supplied msg_namelen value capped at sizeof(struct sockaddr_storage) as upper bound for the user copy of the (uninitialized) sockaddr_storage stack variable. Therefore the fix for IrDa was only one of many.

    It’s Mathias Krause, btw. But you weren’t the only one that got it wrong. :/

    minipli

    May 29, 2013 at 09:16

  2. Thanks for the info Mathias! :)

    xorl

    May 29, 2013 at 22:12


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

Follow

Get every new post delivered to your Inbox.

Join 62 other followers