diff options
author | Richard Alpe <richard.alpe@ericsson.com> | 2016-03-03 08:20:42 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-03-06 22:54:57 -0500 |
commit | ddb3712552c8807c75576fb4fbdbb16f0d48b161 (patch) | |
tree | d412f143ca686dc52c2acf5380d0d45af916eb38 /net/tipc | |
parent | 2837f39c7cdbd209ab04d1c1f4eca015a40d5cd6 (diff) |
tipc: safely copy UDP netlink data from user
The netlink policy for TIPC_NLA_UDP_LOCAL and TIPC_NLA_UDP_REMOTE
is of type binary with a defined length. This causes the policy
framework to threat the defined length as maximum length.
There is however no protection against a user sending a smaller
amount of data. Prior to this patch this wasn't handled which could
result in a partially incomplete sockaddr_storage struct containing
uninitialized data.
In this patch we use nla_memcpy() when copying the user data. This
ensures a potential gap at the end is cleared out properly.
This was found by Julia with Coccinelle tool.
Reported-by: Daniel Borkmann <daniel@iogearbox.net>
Reported-by: Julia Lawall <julia.lawall@lip6.fr>
Signed-off-by: Richard Alpe <richard.alpe@ericsson.com>
Acked-by: Jon Maloy <jon.maloy@ericsson.com>
Reviewed-by: Erik Hugne <erik.hugne@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc')
-rw-r--r-- | net/tipc/udp_media.c | 24 |
1 files changed, 13 insertions, 11 deletions
diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c index f22a5bb169c9..6fe8740a226f 100644 --- a/net/tipc/udp_media.c +++ b/net/tipc/udp_media.c | |||
@@ -276,7 +276,7 @@ static int parse_options(struct nlattr *attrs[], struct udp_bearer *ub, | |||
276 | struct udp_media_addr *remote) | 276 | struct udp_media_addr *remote) |
277 | { | 277 | { |
278 | struct nlattr *opts[TIPC_NLA_UDP_MAX + 1]; | 278 | struct nlattr *opts[TIPC_NLA_UDP_MAX + 1]; |
279 | struct sockaddr_storage *sa_local, *sa_remote; | 279 | struct sockaddr_storage sa_local, sa_remote; |
280 | 280 | ||
281 | if (!attrs[TIPC_NLA_BEARER_UDP_OPTS]) | 281 | if (!attrs[TIPC_NLA_BEARER_UDP_OPTS]) |
282 | goto err; | 282 | goto err; |
@@ -285,41 +285,43 @@ static int parse_options(struct nlattr *attrs[], struct udp_bearer *ub, | |||
285 | tipc_nl_udp_policy)) | 285 | tipc_nl_udp_policy)) |
286 | goto err; | 286 | goto err; |
287 | if (opts[TIPC_NLA_UDP_LOCAL] && opts[TIPC_NLA_UDP_REMOTE]) { | 287 | if (opts[TIPC_NLA_UDP_LOCAL] && opts[TIPC_NLA_UDP_REMOTE]) { |
288 | sa_local = nla_data(opts[TIPC_NLA_UDP_LOCAL]); | 288 | nla_memcpy(&sa_local, opts[TIPC_NLA_UDP_LOCAL], |
289 | sa_remote = nla_data(opts[TIPC_NLA_UDP_REMOTE]); | 289 | sizeof(sa_local)); |
290 | nla_memcpy(&sa_remote, opts[TIPC_NLA_UDP_REMOTE], | ||
291 | sizeof(sa_remote)); | ||
290 | } else { | 292 | } else { |
291 | err: | 293 | err: |
292 | pr_err("Invalid UDP bearer configuration"); | 294 | pr_err("Invalid UDP bearer configuration"); |
293 | return -EINVAL; | 295 | return -EINVAL; |
294 | } | 296 | } |
295 | if ((sa_local->ss_family & sa_remote->ss_family) == AF_INET) { | 297 | if ((sa_local.ss_family & sa_remote.ss_family) == AF_INET) { |
296 | struct sockaddr_in *ip4; | 298 | struct sockaddr_in *ip4; |
297 | 299 | ||
298 | ip4 = (struct sockaddr_in *)sa_local; | 300 | ip4 = (struct sockaddr_in *)&sa_local; |
299 | local->proto = htons(ETH_P_IP); | 301 | local->proto = htons(ETH_P_IP); |
300 | local->udp_port = ip4->sin_port; | 302 | local->udp_port = ip4->sin_port; |
301 | local->ipv4.s_addr = ip4->sin_addr.s_addr; | 303 | local->ipv4.s_addr = ip4->sin_addr.s_addr; |
302 | 304 | ||
303 | ip4 = (struct sockaddr_in *)sa_remote; | 305 | ip4 = (struct sockaddr_in *)&sa_remote; |
304 | remote->proto = htons(ETH_P_IP); | 306 | remote->proto = htons(ETH_P_IP); |
305 | remote->udp_port = ip4->sin_port; | 307 | remote->udp_port = ip4->sin_port; |
306 | remote->ipv4.s_addr = ip4->sin_addr.s_addr; | 308 | remote->ipv4.s_addr = ip4->sin_addr.s_addr; |
307 | return 0; | 309 | return 0; |
308 | 310 | ||
309 | #if IS_ENABLED(CONFIG_IPV6) | 311 | #if IS_ENABLED(CONFIG_IPV6) |
310 | } else if ((sa_local->ss_family & sa_remote->ss_family) == AF_INET6) { | 312 | } else if ((sa_local.ss_family & sa_remote.ss_family) == AF_INET6) { |
311 | struct sockaddr_in6 *ip6; | 313 | struct sockaddr_in6 *ip6; |
312 | 314 | ||
313 | ip6 = (struct sockaddr_in6 *)sa_local; | 315 | ip6 = (struct sockaddr_in6 *)&sa_local; |
314 | local->proto = htons(ETH_P_IPV6); | 316 | local->proto = htons(ETH_P_IPV6); |
315 | local->udp_port = ip6->sin6_port; | 317 | local->udp_port = ip6->sin6_port; |
316 | local->ipv6 = ip6->sin6_addr; | 318 | memcpy(&local->ipv6, &ip6->sin6_addr, sizeof(struct in6_addr)); |
317 | ub->ifindex = ip6->sin6_scope_id; | 319 | ub->ifindex = ip6->sin6_scope_id; |
318 | 320 | ||
319 | ip6 = (struct sockaddr_in6 *)sa_remote; | 321 | ip6 = (struct sockaddr_in6 *)&sa_remote; |
320 | remote->proto = htons(ETH_P_IPV6); | 322 | remote->proto = htons(ETH_P_IPV6); |
321 | remote->udp_port = ip6->sin6_port; | 323 | remote->udp_port = ip6->sin6_port; |
322 | remote->ipv6 = ip6->sin6_addr; | 324 | memcpy(&remote->ipv6, &ip6->sin6_addr, sizeof(struct in6_addr)); |
323 | return 0; | 325 | return 0; |
324 | #endif | 326 | #endif |
325 | } | 327 | } |