Commit 7f6afc33 authored by David S. Miller's avatar David S. Miller

Merge branch 'l2tp-fixes'

Guillaume Nault says:

====================
l2tp: pppol2tp_connect() fixes

This series fixes a few remaining issues with pppol2tp_connect().

It doesn't try to prevent invalid configurations that have no effect on
kernel's reliability. That would be work for a future patch set.

Patch 2 is the most important as it avoids an invalid pointer
dereference crashing the kernel. It depends on patch 1 for correctly
identifying L2TP session types.

Patches 3 and 4 avoid creating stale tunnels and sessions.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents aeddb6d5 bda06be2
...@@ -612,6 +612,8 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, ...@@ -612,6 +612,8 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
u32 session_id, peer_session_id; u32 session_id, peer_session_id;
bool drop_refcnt = false; bool drop_refcnt = false;
bool drop_tunnel = false; bool drop_tunnel = false;
bool new_session = false;
bool new_tunnel = false;
int ver = 2; int ver = 2;
int fd; int fd;
...@@ -701,6 +703,15 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, ...@@ -701,6 +703,15 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
.encap = L2TP_ENCAPTYPE_UDP, .encap = L2TP_ENCAPTYPE_UDP,
.debug = 0, .debug = 0,
}; };
/* Prevent l2tp_tunnel_register() from trying to set up
* a kernel socket.
*/
if (fd < 0) {
error = -EBADF;
goto end;
}
error = l2tp_tunnel_create(sock_net(sk), fd, ver, tunnel_id, peer_tunnel_id, &tcfg, &tunnel); error = l2tp_tunnel_create(sock_net(sk), fd, ver, tunnel_id, peer_tunnel_id, &tcfg, &tunnel);
if (error < 0) if (error < 0)
goto end; goto end;
...@@ -713,6 +724,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, ...@@ -713,6 +724,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
goto end; goto end;
} }
drop_tunnel = true; drop_tunnel = true;
new_tunnel = true;
} }
} else { } else {
/* Error if we can't find the tunnel */ /* Error if we can't find the tunnel */
...@@ -734,6 +746,12 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, ...@@ -734,6 +746,12 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
session = l2tp_session_get(sock_net(sk), tunnel, session_id); session = l2tp_session_get(sock_net(sk), tunnel, session_id);
if (session) { if (session) {
drop_refcnt = true; drop_refcnt = true;
if (session->pwtype != L2TP_PWTYPE_PPP) {
error = -EPROTOTYPE;
goto end;
}
ps = l2tp_session_priv(session); ps = l2tp_session_priv(session);
/* Using a pre-existing session is fine as long as it hasn't /* Using a pre-existing session is fine as long as it hasn't
...@@ -751,6 +769,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, ...@@ -751,6 +769,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
/* Default MTU must allow space for UDP/L2TP/PPP headers */ /* Default MTU must allow space for UDP/L2TP/PPP headers */
cfg.mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD; cfg.mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD;
cfg.mru = cfg.mtu; cfg.mru = cfg.mtu;
cfg.pw_type = L2TP_PWTYPE_PPP;
session = l2tp_session_create(sizeof(struct pppol2tp_session), session = l2tp_session_create(sizeof(struct pppol2tp_session),
tunnel, session_id, tunnel, session_id,
...@@ -772,6 +791,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, ...@@ -772,6 +791,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
goto end; goto end;
} }
drop_refcnt = true; drop_refcnt = true;
new_session = true;
} }
/* Special case: if source & dest session_id == 0x0000, this /* Special case: if source & dest session_id == 0x0000, this
...@@ -818,6 +838,12 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, ...@@ -818,6 +838,12 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
session->name); session->name);
end: end:
if (error) {
if (new_session)
l2tp_session_delete(session);
if (new_tunnel)
l2tp_tunnel_delete(tunnel);
}
if (drop_refcnt) if (drop_refcnt)
l2tp_session_dec_refcount(session); l2tp_session_dec_refcount(session);
if (drop_tunnel) if (drop_tunnel)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment