Commit 1442f6f7 authored by Paolo Abeni's avatar Paolo Abeni Committed by Simon Horman

ipvs: explicitly forbid ipv6 service/dest creation if ipv6 mod is disabled

When creating a new ipvs service, ipv6 addresses are always accepted
if CONFIG_IP_VS_IPV6 is enabled. On dest creation the address family
is not explicitly checked.

This allows the user-space to configure ipvs services even if the
system is booted with ipv6.disable=1. On specific configuration, ipvs
can try to call ipv6 routing code at setup time, causing the kernel to
oops due to fib6_rules_ops being NULL.

This change addresses the issue adding a check for the ipv6
module being enabled while validating ipv6 service operations and
adding the same validation for dest operations.

According to git history, this issue is apparently present since
the introduction of ipv6 support, and the oops can be triggered
since commit 09571c7a ("IPVS: Add function to determine
if IPv6 address is local")

Fixes: 09571c7a ("IPVS: Add function to determine if IPv6 address is local")
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
Acked-by: default avatarJulian Anastasov <ja@ssi.bg>
Signed-off-by: default avatarSimon Horman <horms@verge.net.au>
parent 9dd2ab60
...@@ -3078,6 +3078,17 @@ static int ip_vs_genl_dump_services(struct sk_buff *skb, ...@@ -3078,6 +3078,17 @@ static int ip_vs_genl_dump_services(struct sk_buff *skb,
return skb->len; return skb->len;
} }
static bool ip_vs_is_af_valid(int af)
{
if (af == AF_INET)
return true;
#ifdef CONFIG_IP_VS_IPV6
if (af == AF_INET6 && ipv6_mod_enabled())
return true;
#endif
return false;
}
static int ip_vs_genl_parse_service(struct netns_ipvs *ipvs, static int ip_vs_genl_parse_service(struct netns_ipvs *ipvs,
struct ip_vs_service_user_kern *usvc, struct ip_vs_service_user_kern *usvc,
struct nlattr *nla, int full_entry, struct nlattr *nla, int full_entry,
...@@ -3104,11 +3115,7 @@ static int ip_vs_genl_parse_service(struct netns_ipvs *ipvs, ...@@ -3104,11 +3115,7 @@ static int ip_vs_genl_parse_service(struct netns_ipvs *ipvs,
memset(usvc, 0, sizeof(*usvc)); memset(usvc, 0, sizeof(*usvc));
usvc->af = nla_get_u16(nla_af); usvc->af = nla_get_u16(nla_af);
#ifdef CONFIG_IP_VS_IPV6 if (!ip_vs_is_af_valid(usvc->af))
if (usvc->af != AF_INET && usvc->af != AF_INET6)
#else
if (usvc->af != AF_INET)
#endif
return -EAFNOSUPPORT; return -EAFNOSUPPORT;
if (nla_fwmark) { if (nla_fwmark) {
...@@ -3610,6 +3617,11 @@ static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info) ...@@ -3610,6 +3617,11 @@ static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)
if (udest.af == 0) if (udest.af == 0)
udest.af = svc->af; udest.af = svc->af;
if (!ip_vs_is_af_valid(udest.af)) {
ret = -EAFNOSUPPORT;
goto out;
}
if (udest.af != svc->af && cmd != IPVS_CMD_DEL_DEST) { if (udest.af != svc->af && cmd != IPVS_CMD_DEL_DEST) {
/* The synchronization protocol is incompatible /* The synchronization protocol is incompatible
* with mixed family services * with mixed family services
......
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