net: switch to storing KCOV handle directly in sk_buff
authorMarco Elver <elver@google.com>
Wed, 25 Nov 2020 22:48:40 +0000 (23:48 +0100)
committerJakub Kicinski <kuba@kernel.org>
Tue, 1 Dec 2020 19:26:19 +0000 (11:26 -0800)
It turns out that usage of skb extensions can cause memory leaks. Ido
Schimmel reported: "[...] there are instances that blindly overwrite
'skb->extensions' by invoking skb_copy_header() after __alloc_skb()."

Therefore, give up on using skb extensions for KCOV handle, and instead
directly store kcov_handle in sk_buff.

Fixes: 6370cc3bbd8a ("net: add kcov handle to skb extensions")
Fixes: 85ce50d337d1 ("net: kcov: don't select SKB_EXTENSIONS when there is no NET")
Fixes: 97f53a08cba1 ("net: linux/skbuff.h: combine SKB_EXTENSIONS + KCOV handling")
Link: https://lore.kernel.org/linux-wireless/20201121160941.GA485907@shredder.lan/
Reported-by: Ido Schimmel <idosch@idosch.org>
Signed-off-by: Marco Elver <elver@google.com>
Link: https://lore.kernel.org/r/20201125224840.2014773-1-elver@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/linux/skbuff.h
lib/Kconfig.debug
net/core/skbuff.c

index 0a12398..333bcdc 100644 (file)
@@ -701,6 +701,7 @@ typedef unsigned char *sk_buff_data_t;
  *     @transport_header: Transport layer header
  *     @network_header: Network layer header
  *     @mac_header: Link layer header
+ *     @kcov_handle: KCOV remote handle for remote coverage collection
  *     @tail: Tail pointer
  *     @end: End pointer
  *     @head: Head of buffer
@@ -904,6 +905,10 @@ struct sk_buff {
        __u16                   network_header;
        __u16                   mac_header;
 
+#ifdef CONFIG_KCOV
+       u64                     kcov_handle;
+#endif
+
        /* private: */
        __u32                   headers_end[0];
        /* public: */
@@ -4151,9 +4156,6 @@ enum skb_ext_id {
 #if IS_ENABLED(CONFIG_MPTCP)
        SKB_EXT_MPTCP,
 #endif
-#if IS_ENABLED(CONFIG_KCOV)
-       SKB_EXT_KCOV_HANDLE,
-#endif
        SKB_EXT_NUM, /* must be last */
 };
 
@@ -4608,35 +4610,22 @@ static inline void skb_reset_redirect(struct sk_buff *skb)
 #endif
 }
 
-#if IS_ENABLED(CONFIG_KCOV) && IS_ENABLED(CONFIG_SKB_EXTENSIONS)
 static inline void skb_set_kcov_handle(struct sk_buff *skb,
                                       const u64 kcov_handle)
 {
-       /* Do not allocate skb extensions only to set kcov_handle to zero
-        * (as it is zero by default). However, if the extensions are
-        * already allocated, update kcov_handle anyway since
-        * skb_set_kcov_handle can be called to zero a previously set
-        * value.
-        */
-       if (skb_has_extensions(skb) || kcov_handle) {
-               u64 *kcov_handle_ptr = skb_ext_add(skb, SKB_EXT_KCOV_HANDLE);
-
-               if (kcov_handle_ptr)
-                       *kcov_handle_ptr = kcov_handle;
-       }
+#ifdef CONFIG_KCOV
+       skb->kcov_handle = kcov_handle;
+#endif
 }
 
 static inline u64 skb_get_kcov_handle(struct sk_buff *skb)
 {
-       u64 *kcov_handle = skb_ext_find(skb, SKB_EXT_KCOV_HANDLE);
-
-       return kcov_handle ? *kcov_handle : 0;
-}
+#ifdef CONFIG_KCOV
+       return skb->kcov_handle;
 #else
-static inline void skb_set_kcov_handle(struct sk_buff *skb,
-                                      const u64 kcov_handle) { }
-static inline u64 skb_get_kcov_handle(struct sk_buff *skb) { return 0; }
-#endif /* CONFIG_KCOV && CONFIG_SKB_EXTENSIONS */
+       return 0;
+#endif
+}
 
 #endif /* __KERNEL__ */
 #endif /* _LINUX_SKBUFF_H */
index 826a205..1d15cda 100644 (file)
@@ -1879,7 +1879,6 @@ config KCOV
        depends on CC_HAS_SANCOV_TRACE_PC || GCC_PLUGINS
        select DEBUG_FS
        select GCC_PLUGIN_SANCOV if !CC_HAS_SANCOV_TRACE_PC
-       select SKB_EXTENSIONS if NET
        help
          KCOV exposes kernel code coverage information in a form suitable
          for coverage-guided fuzzing (randomized testing).
index ad98265..90d3423 100644 (file)
@@ -4210,9 +4210,6 @@ static const u8 skb_ext_type_len[] = {
 #if IS_ENABLED(CONFIG_MPTCP)
        [SKB_EXT_MPTCP] = SKB_EXT_CHUNKSIZEOF(struct mptcp_ext),
 #endif
-#if IS_ENABLED(CONFIG_KCOV)
-       [SKB_EXT_KCOV_HANDLE] = SKB_EXT_CHUNKSIZEOF(u64),
-#endif
 };
 
 static __always_inline unsigned int skb_ext_total_length(void)
@@ -4230,9 +4227,6 @@ static __always_inline unsigned int skb_ext_total_length(void)
 #if IS_ENABLED(CONFIG_MPTCP)
                skb_ext_type_len[SKB_EXT_MPTCP] +
 #endif
-#if IS_ENABLED(CONFIG_KCOV)
-               skb_ext_type_len[SKB_EXT_KCOV_HANDLE] +
-#endif
                0;
 }