This enables the run-time checking of dynamic memcpy() and memmove()
lengths, issuing a WARN when a write would exceed the size of the
target field.

Signed-off-by: Kees Cook <keesc...@chromium.org>
---
 include/linux/fortify-string.h | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/include/linux/fortify-string.h b/include/linux/fortify-string.h
index 4afd42079d3b..0d0acd959ba0 100644
--- a/include/linux/fortify-string.h
+++ b/include/linux/fortify-string.h
@@ -260,7 +260,7 @@ __FORTIFY_INLINE void fortify_memset_chk(__kernel_size_t 
size,
  * V = vulnerable to run-time overflow
  *
  */
-__FORTIFY_INLINE void fortify_memcpy_chk(__kernel_size_t size,
+__FORTIFY_INLINE bool fortify_memcpy_chk(__kernel_size_t size,
                                         const size_t p_size,
                                         const size_t q_size,
                                         const size_t p_size_field,
@@ -309,13 +309,25 @@ __FORTIFY_INLINE void fortify_memcpy_chk(__kernel_size_t 
size,
        if ((p_size != (size_t)(-1) && p_size < size) ||
            (q_size != (size_t)(-1) && q_size < size))
                fortify_panic(func);
+
+       /*
+        * Warn when writing beyond destination field size. Since
+        * flexible-arrays are considered 0 bytes, we must ignore 0 sizes
+        * at runtime for now.
+        */
+       if (p_size_field && p_size != p_size_field && p_size_field < size)
+               return true;
+
+       return false;
 }
 
 #define __fortify_memcpy_chk(p, q, size, p_size, q_size,               \
                             p_size_field, q_size_field, op) ({         \
        size_t __fortify_size = (size_t)(size);                         \
-       fortify_memcpy_chk(__fortify_size, p_size, q_size,              \
-                          p_size_field, q_size_field, #op);            \
+       WARN_ONCE(fortify_memcpy_chk(__fortify_size, p_size, q_size,    \
+                                    p_size_field, q_size_field, #op),  \
+                 #op ": detected field-spanning write (size %zu) of single 
field (size %zu)\n", \
+                 __fortify_size, p_size_field);                        \
        __underlying_##op(p, q, __fortify_size);                        \
 })
 
-- 
2.30.2

Reply via email to