]> git.ipfire.org Git - thirdparty/zlib-ng.git/commitdiff
IBM zSystems DFLTCC: Extend sanitizer checks
authorIlya Leoshkevich <iii@linux.ibm.com>
Thu, 2 May 2024 15:29:00 +0000 (17:29 +0200)
committerHans Kristian Rosbach <hk-github@circlestorm.org>
Mon, 6 May 2024 20:51:54 +0000 (22:51 +0200)
Currently the DFLTCC sanitizer instrumentation is limited to
MSAN-unpoisoning the parameter block. Add ASAN and MSAN checks;
also MSAN-unpoison the window.

Introduce the generic instrument_read(), instrument_write() and
instrument_read_write() macros, that are modeled after the repsective
functions in the Linux kernel.

arch/s390/dfltcc_detail.h
zbuild.h

index 49779d60c5b34a54ac8c05e163e73fbd2f371387..21417ca8d4ee3bea29d8102fe97354326ec25802 100644 (file)
@@ -162,6 +162,30 @@ typedef enum {
 #define HB_BITS 15
 #define HB_SIZE (1 << HB_BITS)
 
+/* Return lengths of high (starting at param->ho) and low (starting at 0) fragments of the circular history buffer. */
+static inline void get_history_lengths(struct dfltcc_param_v0 *param, size_t *hl_high, size_t *hl_low) {
+    *hl_high = MIN(param->hl, HB_SIZE - param->ho);
+    *hl_low = param->hl - *hl_high;
+}
+
+/* Notify instrumentation about an upcoming read/write access to the circular history buffer. */
+static inline void instrument_read_write_hist(struct dfltcc_param_v0 *param, void *hist) {
+    size_t hl_high, hl_low;
+
+    get_history_lengths(param, &hl_high, &hl_low);
+    instrument_read_write(hist + param->ho, hl_high);
+    instrument_read_write(hist, hl_low);
+}
+
+/* Notify MSan about a completed write to the circular history buffer. */
+static inline void msan_unpoison_hist(struct dfltcc_param_v0 *param, void *hist) {
+    size_t hl_high, hl_low;
+
+    get_history_lengths(param, &hl_high, &hl_low);
+    __msan_unpoison(hist + param->ho, hl_high);
+    __msan_unpoison(hist, hl_low);
+}
+
 static inline dfltcc_cc dfltcc(int fn, void *param,
                                unsigned char **op1, size_t *len1,
                                z_const unsigned char **op2, size_t *len2, void *hist) {
@@ -170,14 +194,33 @@ static inline dfltcc_cc dfltcc(int fn, void *param,
     size_t t3 = len1 ? *len1 : 0;
     z_const unsigned char *t4 = op2 ? *op2 : NULL;
     size_t t5 = len2 ? *len2 : 0;
-    Z_REGISTER int r0 __asm__("r0") = fn;
-    Z_REGISTER void *r1 __asm__("r1") = param;
-    Z_REGISTER unsigned char *r2 __asm__("r2") = t2;
-    Z_REGISTER size_t r3 __asm__("r3") = t3;
-    Z_REGISTER z_const unsigned char *r4 __asm__("r4") = t4;
-    Z_REGISTER size_t r5 __asm__("r5") = t5;
+    Z_REGISTER int r0 __asm__("r0");
+    Z_REGISTER void *r1 __asm__("r1");
+    Z_REGISTER unsigned char *r2 __asm__("r2");
+    Z_REGISTER size_t r3 __asm__("r3");
+    Z_REGISTER z_const unsigned char *r4 __asm__("r4");
+    Z_REGISTER size_t r5 __asm__("r5");
     int cc;
 
+    /* Insert pre-instrumentation for DFLTCC. */
+    switch (fn & DFLTCC_FN_MASK) {
+    case DFLTCC_QAF:
+        instrument_write(param, DFLTCC_SIZEOF_QAF);
+        break;
+    case DFLTCC_GDHT:
+        instrument_read_write(param, DFLTCC_SIZEOF_GDHT_V0);
+        instrument_read(t4, t5);
+        break;
+    case DFLTCC_CMPR:
+    case DFLTCC_XPND:
+        instrument_read_write(param, DFLTCC_SIZEOF_CMPR_XPND_V0);
+        instrument_read(t4, t5);
+        instrument_write(t2, t3);
+        instrument_read_write_hist(param, hist);
+        break;
+    }
+
+    r0 = fn; r1 = param; r2 = t2; r3 = t3; r4 = t4; r5 = t5;
     __asm__ volatile(
 #ifdef HAVE_SYS_SDT_H
                      STAP_PROBE_ASM(zlib, dfltcc_entry, STAP_PROBE_ASM_TEMPLATE(5))
@@ -201,6 +244,7 @@ static inline dfltcc_cc dfltcc(int fn, void *param,
                      : "cc", "memory");
     t2 = r2; t3 = r3; t4 = r4; t5 = r5;
 
+    /* Insert post-instrumentation for DFLTCC. */
     switch (fn & DFLTCC_FN_MASK) {
     case DFLTCC_QAF:
         __msan_unpoison(param, DFLTCC_SIZEOF_QAF);
@@ -211,10 +255,12 @@ static inline dfltcc_cc dfltcc(int fn, void *param,
     case DFLTCC_CMPR:
         __msan_unpoison(param, DFLTCC_SIZEOF_CMPR_XPND_V0);
         __msan_unpoison(orig_t2, t2 - orig_t2 + (((struct dfltcc_param_v0 *)param)->sbb == 0 ? 0 : 1));
+        msan_unpoison_hist(param, hist);
         break;
     case DFLTCC_XPND:
         __msan_unpoison(param, DFLTCC_SIZEOF_CMPR_XPND_V0);
         __msan_unpoison(orig_t2, t2 - orig_t2);
+        msan_unpoison_hist(param, hist);
         break;
     }
 
@@ -297,12 +343,9 @@ static inline void append_history(struct dfltcc_param_v0 *param, unsigned char *
 
 static inline void get_history(struct dfltcc_param_v0 *param, const unsigned char *history,
                                unsigned char *buf) {
-    if (param->ho + param->hl <= HB_SIZE)
-        /* Circular history buffer does not wrap - copy one chunk */
-        memcpy(buf, history + param->ho, param->hl);
-    else {
-        /* Circular history buffer wraps - copy two chunks */
-        memcpy(buf, history + param->ho, HB_SIZE - param->ho);
-        memcpy(buf + HB_SIZE - param->ho, history, param->ho + param->hl - HB_SIZE);
-    }
+    size_t hl_high, hl_low;
+
+    get_history_lengths(param, &hl_high, &hl_low);
+    memcpy(buf, history + param->ho, hl_high);
+    memcpy(buf + hl_high, history, hl_low);
 }
index d550b4c582c33e08ec11976894f9b84dad7dce80..206eed23121f861287c97dab9c032af9ea22a22f 100644 (file)
--- a/zbuild.h
+++ b/zbuild.h
 #  endif
 #endif
 
+#if defined(__has_feature)
+#  if __has_feature(address_sanitizer)
+#    define Z_ADDRESS_SANITIZER 1
+#  endif
+#elif defined(__SANITIZE_ADDRESS__)
+#  define Z_ADDRESS_SANITIZER 1
+#endif
+
+/*
+ * __asan_loadN() and __asan_storeN() calls are inserted by compilers in order to check memory accesses.
+ * They can be called manually too, with the following caveats:
+ * gcc says: "warning: implicit declaration of function ‘...’"
+ * g++ says: "error: new declaration ‘...’ ambiguates built-in declaration ‘...’"
+ * Accommodate both.
+ */
+#ifdef Z_ADDRESS_SANITIZER
+#ifndef __cplusplus
+void __asan_loadN(void *, long);
+void __asan_storeN(void *, long);
+#endif
+#else
+#  define __asan_loadN(a, size) do { Z_UNUSED(a); Z_UNUSED(size); } while (0)
+#  define __asan_storeN(a, size) do { Z_UNUSED(a); Z_UNUSED(size); } while (0)
+#endif
+
 #if defined(__has_feature)
 #  if __has_feature(memory_sanitizer)
 #    define Z_MEMORY_SANITIZER 1
 #endif
 
 #ifndef Z_MEMORY_SANITIZER
+#  define __msan_check_mem_is_initialized(a, size) do { Z_UNUSED(a); Z_UNUSED(size); } while (0)
 #  define __msan_unpoison(a, size) do { Z_UNUSED(a); Z_UNUSED(size); } while (0)
 #endif
 
+/* Notify sanitizer runtime about an upcoming read access. */
+#define instrument_read(a, size) do {             \
+    void *__a = (void *)(a);                      \
+    long __size = size;                           \
+    __asan_loadN(__a, __size);                    \
+    __msan_check_mem_is_initialized(__a, __size); \
+} while (0)
+
+/* Notify sanitizer runtime about an upcoming write access. */
+#define instrument_write(a, size) do { \
+   void *__a = (void *)(a);            \
+   long __size = size;                 \
+   __asan_storeN(__a, __size);         \
+} while (0)
+
+/* Notify sanitizer runtime about an upcoming read/write access. */
+#define instrument_read_write(a, size) do {       \
+    void *__a = (void *)(a);                      \
+    long __size = size;                           \
+    __asan_storeN(__a, __size);                   \
+    __msan_check_mem_is_initialized(__a, __size); \
+} while (0)
+
 #endif