@@ -91,6 +91,7 @@ struct inet_protosw {
#define INET_PROTOSW_REUSE 0x01 /* Are ports automatically reusable? */
#define INET_PROTOSW_PERMANENT 0x02 /* Permanent protocols are unremovable. */
#define INET_PROTOSW_ICSK 0x04 /* Is this an inet_connection_sock? */
+#define INET_PROTOSW_AFNETNS_OK 0x08 /* Is this proto afnetns compatible? */
extern const struct net_protocol __rcu *inet_protos[MAX_INET_PROTOS];
extern const struct net_offload __rcu *inet_offloads[MAX_INET_PROTOS];
@@ -302,14 +302,22 @@ static int inet_create(struct net *net, struct socket *sock, int protocol,
goto out_rcu_unlock;
}
+ sock->ops = answer->ops;
+ answer_prot = answer->prot;
+ answer_flags = answer->flags;
+
err = -EPERM;
if (sock->type == SOCK_RAW && !kern &&
!ns_capable(net->user_ns, CAP_NET_RAW))
goto out_rcu_unlock;
- sock->ops = answer->ops;
- answer_prot = answer->prot;
- answer_flags = answer->flags;
+#if IS_ENABLED(CONFIG_AFNETNS)
+ if (unlikely(!kern &&
+ current->nsproxy->afnet_ns != net->afnet_ns &&
+ !(answer_flags & INET_PROTOSW_AFNETNS_OK)))
+ goto out_rcu_unlock;
+#endif
+
rcu_read_unlock();
WARN_ON(!answer_prot->slab);
@@ -1060,7 +1068,8 @@ static struct inet_protosw inetsw_array[] =
.prot = &tcp_prot,
.ops = &inet_stream_ops,
.flags = INET_PROTOSW_PERMANENT |
- INET_PROTOSW_ICSK,
+ INET_PROTOSW_ICSK |
+ INET_PROTOSW_AFNETNS_OK,
},
{
@@ -1068,7 +1077,8 @@ static struct inet_protosw inetsw_array[] =
.protocol = IPPROTO_UDP,
.prot = &udp_prot,
.ops = &inet_dgram_ops,
- .flags = INET_PROTOSW_PERMANENT,
+ .flags = INET_PROTOSW_PERMANENT |
+ INET_PROTOSW_AFNETNS_OK,
},
{
@@ -69,7 +69,8 @@ static struct inet_protosw udplite4_protosw = {
.protocol = IPPROTO_UDPLITE,
.prot = &udplite_prot,
.ops = &inet_dgram_ops,
- .flags = INET_PROTOSW_PERMANENT,
+ .flags = INET_PROTOSW_PERMANENT |
+ INET_PROTOSW_AFNETNS_OK,
};
#ifdef CONFIG_PROC_FS
@@ -167,14 +167,22 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol,
goto out_rcu_unlock;
}
+ sock->ops = answer->ops;
+ answer_prot = answer->prot;
+ answer_flags = answer->flags;
+
err = -EPERM;
if (sock->type == SOCK_RAW && !kern &&
!ns_capable(net->user_ns, CAP_NET_RAW))
goto out_rcu_unlock;
- sock->ops = answer->ops;
- answer_prot = answer->prot;
- answer_flags = answer->flags;
+#if IS_ENABLED(CONFIG_AFNETNS)
+ if (unlikely(!kern &&
+ current->nsproxy->afnet_ns != net->afnet_ns &&
+ !(answer_flags & INET_PROTOSW_AFNETNS_OK)))
+ goto out_rcu_unlock;
+#endif
+
rcu_read_unlock();
WARN_ON(!answer_prot->slab);
@@ -1944,7 +1944,8 @@ static struct inet_protosw tcpv6_protosw = {
.prot = &tcpv6_prot,
.ops = &inet6_stream_ops,
.flags = INET_PROTOSW_PERMANENT |
- INET_PROTOSW_ICSK,
+ INET_PROTOSW_ICSK |
+ INET_PROTOSW_AFNETNS_OK,
};
static int __net_init tcpv6_net_init(struct net *net)
@@ -1475,7 +1475,8 @@ static struct inet_protosw udpv6_protosw = {
.protocol = IPPROTO_UDP,
.prot = &udpv6_prot,
.ops = &inet6_dgram_ops,
- .flags = INET_PROTOSW_PERMANENT,
+ .flags = INET_PROTOSW_PERMANENT |
+ INET_PROTOSW_AFNETNS_OK,
};
int __init udpv6_init(void)
@@ -63,7 +63,8 @@ static struct inet_protosw udplite6_protosw = {
.protocol = IPPROTO_UDPLITE,
.prot = &udplitev6_prot,
.ops = &inet6_dgram_ops,
- .flags = INET_PROTOSW_PERMANENT,
+ .flags = INET_PROTOSW_PERMANENT |
+ INET_PROTOSW_AFNETNS_OK,
};
int __init udplitev6_init(void)
We only care about inet protocols (which is IPv4 and IPv6). Other protocols, like netlink are not under control of afnetns and thus must be hardened with capabilities. Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org> --- include/net/protocol.h | 1 + net/ipv4/af_inet.c | 20 +++++++++++++++----- net/ipv4/udplite.c | 3 ++- net/ipv6/af_inet6.c | 14 +++++++++++--- net/ipv6/tcp_ipv6.c | 3 ++- net/ipv6/udp.c | 3 ++- net/ipv6/udplite.c | 3 ++- 7 files changed, 35 insertions(+), 12 deletions(-)