diff options
author | Paul Moore <pmoore@redhat.com> | 2012-07-17 07:07:47 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-07-18 12:01:12 -0400 |
commit | 89d7ae34cdda4195809a5a987f697a517a2a3177 (patch) | |
tree | 47e00fa639216e6c071db786e9a04028d1db2efd /net/ipv4/cipso_ipv4.c | |
parent | a018540141a931f5299a866907b27886916b4374 (diff) |
cipso: don't follow a NULL pointer when setsockopt() is called
As reported by Alan Cox, and verified by Lin Ming, when a user
attempts to add a CIPSO option to a socket using the CIPSO_V4_TAG_LOCAL
tag the kernel dies a terrible death when it attempts to follow a NULL
pointer (the skb argument to cipso_v4_validate() is NULL when called via
the setsockopt() syscall).
This patch fixes this by first checking to ensure that the skb is
non-NULL before using it to find the incoming network interface. In
the unlikely case where the skb is NULL and the user attempts to add
a CIPSO option with the _TAG_LOCAL tag we return an error as this is
not something we want to allow.
A simple reproducer, kindly supplied by Lin Ming, although you must
have the CIPSO DOI #3 configure on the system first or you will be
caught early in cipso_v4_validate():
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/ip.h>
#include <linux/in.h>
#include <string.h>
struct local_tag {
char type;
char length;
char info[4];
};
struct cipso {
char type;
char length;
char doi[4];
struct local_tag local;
};
int main(int argc, char **argv)
{
int sockfd;
struct cipso cipso = {
.type = IPOPT_CIPSO,
.length = sizeof(struct cipso),
.local = {
.type = 128,
.length = sizeof(struct local_tag),
},
};
memset(cipso.doi, 0, 4);
cipso.doi[3] = 3;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
#define SOL_IP 0
setsockopt(sockfd, SOL_IP, IP_OPTIONS,
&cipso, sizeof(struct cipso));
return 0;
}
CC: Lin Ming <mlin@ss.pku.edu.cn>
Reported-by: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: Paul Moore <pmoore@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/cipso_ipv4.c')
-rw-r--r-- | net/ipv4/cipso_ipv4.c | 6 |
1 files changed, 4 insertions, 2 deletions
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index c48adc565e92..667c1d4ca984 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c | |||
@@ -1725,8 +1725,10 @@ int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option) | |||
1725 | case CIPSO_V4_TAG_LOCAL: | 1725 | case CIPSO_V4_TAG_LOCAL: |
1726 | /* This is a non-standard tag that we only allow for | 1726 | /* This is a non-standard tag that we only allow for |
1727 | * local connections, so if the incoming interface is | 1727 | * local connections, so if the incoming interface is |
1728 | * not the loopback device drop the packet. */ | 1728 | * not the loopback device drop the packet. Further, |
1729 | if (!(skb->dev->flags & IFF_LOOPBACK)) { | 1729 | * there is no legitimate reason for setting this from |
1730 | * userspace so reject it if skb is NULL. */ | ||
1731 | if (skb == NULL || !(skb->dev->flags & IFF_LOOPBACK)) { | ||
1730 | err_offset = opt_iter; | 1732 | err_offset = opt_iter; |
1731 | goto validate_return_locked; | 1733 | goto validate_return_locked; |
1732 | } | 1734 | } |