openvswitch: Prevent kernel-infoleak in ovs_ct_put_key()
authorPeilin Ye <yepeilin.cs@gmail.com>
Fri, 31 Jul 2020 04:48:38 +0000 (00:48 -0400)
committerDavid S. Miller <davem@davemloft.net>
Mon, 3 Aug 2020 22:09:44 +0000 (15:09 -0700)
ovs_ct_put_key() is potentially copying uninitialized kernel stack memory
into socket buffers, since the compiler may leave a 3-byte hole at the end
of `struct ovs_key_ct_tuple_ipv4` and `struct ovs_key_ct_tuple_ipv6`. Fix
it by initializing `orig` with memset().

Fixes: 9dd7f8907c37 ("openvswitch: Add original direction conntrack tuple to sw_flow_key.")
Suggested-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Peilin Ye <yepeilin.cs@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/openvswitch/conntrack.c

index 4340f25fe390f5baac7d0602e67803f2dc05ae57..98d393e70de327d95e6c9548c0b2b1f6b6101ed5 100644 (file)
@@ -276,10 +276,6 @@ void ovs_ct_fill_key(const struct sk_buff *skb, struct sw_flow_key *key)
        ovs_ct_update_key(skb, NULL, key, false, false);
 }
 
-#define IN6_ADDR_INITIALIZER(ADDR) \
-       { (ADDR).s6_addr32[0], (ADDR).s6_addr32[1], \
-         (ADDR).s6_addr32[2], (ADDR).s6_addr32[3] }
-
 int ovs_ct_put_key(const struct sw_flow_key *swkey,
                   const struct sw_flow_key *output, struct sk_buff *skb)
 {
@@ -301,24 +297,30 @@ int ovs_ct_put_key(const struct sw_flow_key *swkey,
 
        if (swkey->ct_orig_proto) {
                if (swkey->eth.type == htons(ETH_P_IP)) {
-                       struct ovs_key_ct_tuple_ipv4 orig = {
-                               output->ipv4.ct_orig.src,
-                               output->ipv4.ct_orig.dst,
-                               output->ct.orig_tp.src,
-                               output->ct.orig_tp.dst,
-                               output->ct_orig_proto,
-                       };
+                       struct ovs_key_ct_tuple_ipv4 orig;
+
+                       memset(&orig, 0, sizeof(orig));
+                       orig.ipv4_src = output->ipv4.ct_orig.src;
+                       orig.ipv4_dst = output->ipv4.ct_orig.dst;
+                       orig.src_port = output->ct.orig_tp.src;
+                       orig.dst_port = output->ct.orig_tp.dst;
+                       orig.ipv4_proto = output->ct_orig_proto;
+
                        if (nla_put(skb, OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4,
                                    sizeof(orig), &orig))
                                return -EMSGSIZE;
                } else if (swkey->eth.type == htons(ETH_P_IPV6)) {
-                       struct ovs_key_ct_tuple_ipv6 orig = {
-                               IN6_ADDR_INITIALIZER(output->ipv6.ct_orig.src),
-                               IN6_ADDR_INITIALIZER(output->ipv6.ct_orig.dst),
-                               output->ct.orig_tp.src,
-                               output->ct.orig_tp.dst,
-                               output->ct_orig_proto,
-                       };
+                       struct ovs_key_ct_tuple_ipv6 orig;
+
+                       memset(&orig, 0, sizeof(orig));
+                       memcpy(orig.ipv6_src, output->ipv6.ct_orig.src.s6_addr32,
+                              sizeof(orig.ipv6_src));
+                       memcpy(orig.ipv6_dst, output->ipv6.ct_orig.dst.s6_addr32,
+                              sizeof(orig.ipv6_dst));
+                       orig.src_port = output->ct.orig_tp.src;
+                       orig.dst_port = output->ct.orig_tp.dst;
+                       orig.ipv6_proto = output->ct_orig_proto;
+
                        if (nla_put(skb, OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6,
                                    sizeof(orig), &orig))
                                return -EMSGSIZE;