From: glider@google.com
To: Jens Axboe <axboe@kernel.dk>, Andy Lutomirski <luto@kernel.org>,
Vegard Nossum <vegard.nossum@oracle.com>,
Dmitry Vyukov <dvyukov@google.com>,
linux-mm@kvack.org
Cc: viro@zeniv.linux.org.uk, akpm@linux-foundation.org,
aryabinin@virtuozzo.com, ard.biesheuvel@linaro.org,
arnd@arndb.de, hch@lst.de, dmitry.torokhov@gmail.com,
edumazet@google.com, ericvh@gmail.com,
gregkh@linuxfoundation.org, harry.wentland@amd.com,
herbert@gondor.apana.org.au, mingo@elte.hu,
martin.petersen@oracle.com, schwidefsky@de.ibm.com,
mst@redhat.com, monstr@monstr.eu, pmladek@suse.com,
sergey.senozhatsky@gmail.com, rostedt@goodmis.org,
tiwai@suse.com, tytso@mit.edu, tglx@linutronix.de,
wsa@the-dreams.de, gor@linux.ibm.com, iii@linux.ibm.com,
mark.rutland@arm.com, willy@infradead.org,
rdunlap@infradead.org, andreyknvl@google.com, elver@google.com,
Alexander Potapenko <glider@google.com>
Subject: [PATCH RFC v2 15/25] kmsan: Changing existing files to enable KMSAN builds
Date: Wed, 30 Oct 2019 15:22:27 +0100 [thread overview]
Message-ID: <20191030142237.249532-16-glider@google.com> (raw)
In-Reply-To: <20191030142237.249532-1-glider@google.com>
Do the following to make KMSAN usable:
- add KMSAN declarations to struct page and struct task_struct;
- add Makefile.kmsan to top-level Makefile;
- call KMSAN initialization from init/main.c
- add asm hooks to arch/x86/entry/entry_64.S;
- increase task stack size under KMSAN;
- disable page merging in block/blk.h;
- disable CONFIG_KMSAN in arch/x86/boot/compressed/misc.h to use
default string functions instead of KMSAN ones.
Signed-off-by: Alexander Potapenko <glider@google.com>
To: Alexander Potapenko <glider@google.com>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Vegard Nossum <vegard.nossum@oracle.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: linux-mm@kvack.org
---
Change-Id: I37e0b7f2d2f2b0aeac5753ff9d6b411485fc374e
---
Makefile | 3 ++-
arch/x86/boot/compressed/misc.h | 1 +
arch/x86/entry/entry_64.S | 18 ++++++++++++++++++
arch/x86/include/asm/page_64_types.h | 12 +++++++-----
block/blk.h | 7 +++++++
include/linux/mm_types.h | 9 +++++++++
include/linux/sched.h | 5 +++++
init/main.c | 3 +++
lib/stackdepot.c | 7 ++++---
mm/Makefile | 1 +
scripts/Makefile.lib | 6 ++++++
11 files changed, 63 insertions(+), 9 deletions(-)
diff --git a/Makefile b/Makefile
index 79be70bf2899..181ae2dac415 100644
--- a/Makefile
+++ b/Makefile
@@ -478,7 +478,7 @@ export KBUILD_HOSTCXXFLAGS KBUILD_HOSTLDFLAGS KBUILD_HOSTLDLIBS LDFLAGS_MODULE
export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS KBUILD_LDFLAGS
export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE
-export CFLAGS_KASAN CFLAGS_KASAN_NOSANITIZE CFLAGS_UBSAN
+export CFLAGS_KASAN CFLAGS_KASAN_NOSANITIZE CFLAGS_UBSAN CFLAGS_KMSAN
export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE
export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE
export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL
@@ -898,6 +898,7 @@ KBUILD_CFLAGS += $(call cc-option,-fcf-protection=none)
endif
include scripts/Makefile.kasan
+include scripts/Makefile.kmsan
include scripts/Makefile.extrawarn
include scripts/Makefile.ubsan
diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h
index c8181392f70d..dd4bd8c5d97a 100644
--- a/arch/x86/boot/compressed/misc.h
+++ b/arch/x86/boot/compressed/misc.h
@@ -12,6 +12,7 @@
#undef CONFIG_PARAVIRT_XXL
#undef CONFIG_PARAVIRT_SPINLOCKS
#undef CONFIG_KASAN
+#undef CONFIG_KMSAN
/* cpu_feature_enabled() cannot be used this early */
#define USE_EARLY_PGTABLE_L5
diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S
index b7c3ea4cb19d..1218672bad85 100644
--- a/arch/x86/entry/entry_64.S
+++ b/arch/x86/entry/entry_64.S
@@ -35,6 +35,7 @@
#include <asm/asm.h>
#include <asm/smap.h>
#include <asm/pgtable_types.h>
+#include <asm/kmsan.h>
#include <asm/export.h>
#include <asm/frame.h>
#include <asm/nospec-branch.h>
@@ -168,12 +169,14 @@ GLOBAL(entry_SYSCALL_64_after_hwframe)
PUSH_AND_CLEAR_REGS rax=$-ENOSYS
TRACE_IRQS_OFF
+ KMSAN_SYSCALL_ENTER
/* IRQs are off. */
movq %rax, %rdi
movq %rsp, %rsi
call do_syscall_64 /* returns with IRQs disabled */
+ KMSAN_SYSCALL_EXIT
TRACE_IRQS_IRETQ /* we're about to change IF */
/*
@@ -575,6 +578,7 @@ ENTRY(interrupt_entry)
1:
ENTER_IRQ_STACK old_rsp=%rdi save_ret=1
+ KMSAN_INTERRUPT_ENTER
/* We entered an interrupt context - irqs are off: */
TRACE_IRQS_OFF
@@ -604,12 +608,14 @@ common_interrupt:
addq $-0x80, (%rsp) /* Adjust vector to [-256, -1] range */
call interrupt_entry
UNWIND_HINT_REGS indirect=1
+ KMSAN_UNPOISON_PT_REGS
call do_IRQ /* rdi points to pt_regs */
/* 0(%rsp): old RSP */
ret_from_intr:
DISABLE_INTERRUPTS(CLBR_ANY)
TRACE_IRQS_OFF
+ KMSAN_INTERRUPT_EXIT
LEAVE_IRQ_STACK
testb $3, CS(%rsp)
@@ -802,6 +808,7 @@ ENTRY(\sym)
.Lcommon_\sym:
call interrupt_entry
UNWIND_HINT_REGS indirect=1
+ KMSAN_UNPOISON_PT_REGS
call \do_sym /* rdi points to pt_regs */
jmp ret_from_intr
END(\sym)
@@ -909,15 +916,18 @@ apicinterrupt IRQ_WORK_VECTOR irq_work_interrupt smp_irq_work_interrupt
.if \shift_ist != -1
subq $\ist_offset, CPU_TSS_IST(\shift_ist)
+ KMSAN_IST_ENTER(\shift_ist)
.endif
.if \read_cr2
movq %r12, %rdx /* Move CR2 into 3rd argument */
.endif
+ KMSAN_UNPOISON_PT_REGS
call \do_sym
.if \shift_ist != -1
+ KMSAN_IST_EXIT(\shift_ist)
addq $\ist_offset, CPU_TSS_IST(\shift_ist)
.endif
@@ -1079,7 +1089,9 @@ ENTRY(do_softirq_own_stack)
pushq %rbp
mov %rsp, %rbp
ENTER_IRQ_STACK regs=0 old_rsp=%r11
+ KMSAN_SOFTIRQ_ENTER
call __do_softirq
+ KMSAN_SOFTIRQ_EXIT
LEAVE_IRQ_STACK regs=0
leaveq
ret
@@ -1466,9 +1478,12 @@ ENTRY(nmi)
* done with the NMI stack.
*/
+ KMSAN_NMI_ENTER
movq %rsp, %rdi
movq $-1, %rsi
+ KMSAN_UNPOISON_PT_REGS
call do_nmi
+ KMSAN_NMI_EXIT
/*
* Return back to user mode. We must *not* do the normal exit
@@ -1678,10 +1693,13 @@ end_repeat_nmi:
call paranoid_entry
UNWIND_HINT_REGS
+ KMSAN_NMI_ENTER
/* paranoidentry do_nmi, 0; without TRACE_IRQS_OFF */
movq %rsp, %rdi
movq $-1, %rsi
+ KMSAN_UNPOISON_PT_REGS
call do_nmi
+ KMSAN_NMI_EXIT
/* Always restore stashed CR3 value (see paranoid_entry) */
RESTORE_CR3 scratch_reg=%r15 save_reg=%r14
diff --git a/arch/x86/include/asm/page_64_types.h b/arch/x86/include/asm/page_64_types.h
index 288b065955b7..ea9fbf09f43b 100644
--- a/arch/x86/include/asm/page_64_types.h
+++ b/arch/x86/include/asm/page_64_types.h
@@ -7,18 +7,20 @@
#endif
#ifdef CONFIG_KASAN
-#define KASAN_STACK_ORDER 1
+#define EXTRA_STACK_ORDER 1
+#elif defined(CONFIG_KMSAN)
+#define EXTRA_STACK_ORDER 2
#else
-#define KASAN_STACK_ORDER 0
+#define EXTRA_STACK_ORDER 0
#endif
-#define THREAD_SIZE_ORDER (2 + KASAN_STACK_ORDER)
+#define THREAD_SIZE_ORDER (2 + EXTRA_STACK_ORDER)
#define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER)
-#define EXCEPTION_STACK_ORDER (0 + KASAN_STACK_ORDER)
+#define EXCEPTION_STACK_ORDER (0 + EXTRA_STACK_ORDER)
#define EXCEPTION_STKSZ (PAGE_SIZE << EXCEPTION_STACK_ORDER)
-#define IRQ_STACK_ORDER (2 + KASAN_STACK_ORDER)
+#define IRQ_STACK_ORDER (2 + EXTRA_STACK_ORDER)
#define IRQ_STACK_SIZE (PAGE_SIZE << IRQ_STACK_ORDER)
/*
diff --git a/block/blk.h b/block/blk.h
index 47fba9362e60..9ee271a22423 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -78,6 +78,13 @@ static inline bool biovec_phys_mergeable(struct request_queue *q,
phys_addr_t addr1 = page_to_phys(vec1->bv_page) + vec1->bv_offset;
phys_addr_t addr2 = page_to_phys(vec2->bv_page) + vec2->bv_offset;
+#ifdef CONFIG_KMSAN
+ /*
+ * Merging consequent physical pages may not work correctly under KMSAN
+ * if their metadata pages aren't consequent. Just disable merging.
+ */
+ return false;
+#endif
if (addr1 + vec1->bv_len != addr2)
return false;
if (xen_domain() && !xen_biovec_phys_mergeable(vec1, vec2->bv_page))
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 2222fa795284..c87c5416a802 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -216,6 +216,15 @@ struct page {
not kmapped, ie. highmem) */
#endif /* WANT_PAGE_VIRTUAL */
+#ifdef CONFIG_KMSAN
+ /*
+ * Bits in struct page are scarce, so the LSB in *shadow is used to
+ * indicate whether the page should be ignored by KMSAN or not.
+ */
+ struct page *shadow;
+ struct page *origin;
+#endif
+
#ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS
int _last_cpupid;
#endif
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 72b20f33c56e..ba705f66f78c 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -15,6 +15,7 @@
#include <linux/sem.h>
#include <linux/shm.h>
#include <linux/kcov.h>
+#include <linux/kmsan.h>
#include <linux/mutex.h>
#include <linux/plist.h>
#include <linux/hrtimer.h>
@@ -1173,6 +1174,10 @@ struct task_struct {
unsigned int kasan_depth;
#endif
+#ifdef CONFIG_KMSAN
+ struct kmsan_task_state kmsan;
+#endif
+
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
/* Index of current stored address in ret_stack: */
int curr_ret_stack;
diff --git a/init/main.c b/init/main.c
index 91f6ebb30ef0..afcca2a38348 100644
--- a/init/main.c
+++ b/init/main.c
@@ -32,6 +32,7 @@
#include <linux/nmi.h>
#include <linux/percpu.h>
#include <linux/kmod.h>
+#include <linux/kmsan.h>
#include <linux/vmalloc.h>
#include <linux/kernel_stat.h>
#include <linux/start_kernel.h>
@@ -554,6 +555,7 @@ static void __init mm_init(void)
*/
page_ext_init_flatmem();
report_meminit();
+ kmsan_initialize_shadow();
mem_init();
kmem_cache_init();
kmemleak_init();
@@ -625,6 +627,7 @@ asmlinkage __visible void __init start_kernel(void)
sort_main_extable();
trap_init();
mm_init();
+ kmsan_initialize();
ftrace_init();
diff --git a/lib/stackdepot.c b/lib/stackdepot.c
index 460efd3ef742..529a86eb1dd1 100644
--- a/lib/stackdepot.c
+++ b/lib/stackdepot.c
@@ -233,8 +233,8 @@ unsigned int stack_depot_fetch(depot_stack_handle_t handle,
if (parts.slabindex > depot_index) {
WARN(1, "slab index %d out of bounds (%d) for stack id %08x\n",
parts.slabindex, depot_index, handle);
- __memset(trace, 0, sizeof(*trace));
- return;
+ *entries = NULL;
+ return 0;
}
slab = stack_slabs[parts.slabindex];
stack = slab + offset;
@@ -299,7 +299,8 @@ depot_stack_handle_t stack_depot_save(unsigned long *entries,
* contexts and I/O.
*/
alloc_flags &= ~GFP_ZONEMASK;
- alloc_flags &= (GFP_ATOMIC | GFP_KERNEL);
+ alloc_flags &= (GFP_ATOMIC | GFP_KERNEL |
+ __GFP_NO_KMSAN_SHADOW);
alloc_flags |= __GFP_NOWARN;
page = alloc_pages(alloc_flags, STACK_ALLOC_ORDER);
if (page)
diff --git a/mm/Makefile b/mm/Makefile
index d996846697ef..419e6e02dfaf 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -71,6 +71,7 @@ obj-$(CONFIG_PAGE_POISONING) += page_poison.o
obj-$(CONFIG_SLAB) += slab.o
obj-$(CONFIG_SLUB) += slub.o
obj-$(CONFIG_KASAN) += kasan/
+obj-$(CONFIG_KMSAN) += kmsan/
obj-$(CONFIG_FAILSLAB) += failslab.o
obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o
obj-$(CONFIG_MEMTEST) += memtest.o
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 179d55af5852..f9f38f7c1cd4 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -140,6 +140,12 @@ _c_flags += $(if $(patsubst n%,, \
$(CFLAGS_KASAN), $(CFLAGS_KASAN_NOSANITIZE))
endif
+ifeq ($(CONFIG_KMSAN),y)
+_c_flags += $(if $(patsubst n%,, \
+ $(KMSAN_SANITIZE_$(basetarget).o)$(KMSAN_SANITIZE)y), \
+ $(CFLAGS_KMSAN))
+endif
+
ifeq ($(CONFIG_UBSAN),y)
_c_flags += $(if $(patsubst n%,, \
$(UBSAN_SANITIZE_$(basetarget).o)$(UBSAN_SANITIZE)$(CONFIG_UBSAN_SANITIZE_ALL)), \
--
2.24.0.rc0.303.g954a862665-goog
next prev parent reply other threads:[~2019-10-30 14:23 UTC|newest]
Thread overview: 61+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-10-30 14:22 [PATCH RFC v2 00/25] Add KernelMemorySanitizer infrastructure glider
2019-10-30 14:22 ` [PATCH RFC v2 01/25] stackdepot: check depot_index before accessing the stack slab glider
2019-10-30 14:22 ` [PATCH RFC v2 02/25] stackdepot: prevent Clang from optimizing away stackdepot_memcmp() glider
2019-11-01 5:50 ` Sergey Senozhatsky
2019-11-06 11:43 ` Alexander Potapenko
2019-11-07 6:08 ` Sergey Senozhatsky
2019-11-07 9:04 ` Arnd Bergmann
2019-11-07 9:22 ` Alexander Potapenko
2019-11-07 9:28 ` Arnd Bergmann
2019-11-07 9:43 ` Alexander Potapenko
[not found] ` <47fdac13-fa2c-2acd-2480-5e6d4db208f8@virtuozzo.com>
2019-11-07 10:00 ` Arnd Bergmann
[not found] ` <6875c6e6-2f1f-f8e6-e5d7-d451c48397ff@virtuozzo.com>
2019-11-07 10:30 ` Alexander Potapenko
2019-10-30 14:22 ` [PATCH RFC v2 03/25] kasan: stackdepot: move filter_irq_stacks() to stackdepot.c glider
2019-10-30 14:22 ` [PATCH RFC v2 04/25] stackdepot: reserve 5 extra bits in depot_stack_handle_t glider
2019-10-30 14:22 ` [PATCH RFC v2 05/25] kmsan: add ReST documentation glider
2019-10-30 14:22 ` [PATCH RFC v2 06/25] kmsan: gfp: introduce __GFP_NO_KMSAN_SHADOW glider
2019-10-30 14:22 ` [PATCH RFC v2 07/25] kmsan: introduce __no_sanitize_memory and __SANITIZE_MEMORY__ glider
2019-10-30 15:50 ` Andrey Konovalov
2019-11-01 12:52 ` Alexander Potapenko
2019-10-30 14:22 ` [PATCH RFC v2 08/25] kmsan: reduce vmalloc space glider
2019-10-30 14:22 ` [PATCH RFC v2 09/25] kmsan: add KMSAN runtime glider
2019-11-08 12:08 ` Dmitry Vyukov
2019-11-08 12:17 ` Dmitry Vyukov
2019-11-21 12:06 ` Alexander Potapenko
2019-11-13 8:13 ` Wolfram Sang
2019-11-21 12:01 ` Alexander Potapenko
2019-10-30 14:22 ` [PATCH RFC v2 10/25] kmsan: define READ_ONCE_NOCHECK() glider
2019-11-05 14:21 ` Mark Rutland
2019-11-21 12:08 ` Alexander Potapenko
2019-10-30 14:22 ` [PATCH RFC v2 11/25] kmsan: x86: sync metadata pages on page fault glider
2019-10-30 14:22 ` [PATCH RFC v2 12/25] kmsan: add tests for KMSAN glider
2019-10-30 14:22 ` [PATCH RFC v2 13/25] kmsan: make READ_ONCE_TASK_STACK() return initialized values glider
2019-10-30 14:22 ` [PATCH RFC v2 14/25] kmsan: Kconfig changes to disable options incompatible with KMSAN glider
2019-10-30 14:34 ` Qian Cai
2019-10-30 14:34 ` Christoph Hellwig
2019-10-30 14:22 ` glider [this message]
2019-10-30 14:36 ` [PATCH RFC v2 15/25] kmsan: Changing existing files to enable KMSAN builds Christoph Hellwig
2019-10-30 14:22 ` [PATCH RFC v2 16/25] kmsan: disable KMSAN instrumentation for certain kernel parts glider
2019-10-30 14:22 ` [PATCH RFC v2 17/25] kmsan: mm: call KMSAN hooks from SLUB code glider
2019-10-30 16:07 ` Andrey Konovalov
2019-10-30 14:22 ` [PATCH RFC v2 18/25] kmsan: call KMSAN hooks where needed glider
2019-10-31 11:49 ` Petr Mladek
2019-11-01 8:26 ` Sergey Senozhatsky
2019-11-05 14:12 ` Alexander Potapenko
2019-11-06 9:04 ` Petr Mladek
2019-11-06 9:07 ` Sergey Senozhatsky
2019-10-30 14:22 ` [PATCH RFC v2 19/25] kmsan: disable instrumentation of certain functions glider
2019-10-30 14:22 ` [PATCH RFC v2 20/25] kmsan: unpoison |tlb| in arch_tlb_gather_mmu() glider
2019-10-30 14:22 ` [PATCH RFC v2 21/25] kmsan: use __msan_memcpy() where possible glider
2019-10-30 14:22 ` [PATCH RFC v2 22/25] kmsan: unpoisoning buffers from devices etc glider
2019-10-30 14:38 ` Christoph Hellwig
2019-11-05 15:02 ` Alexander Potapenko
2019-11-07 13:00 ` Alexander Potapenko
2019-11-13 11:07 ` Alexander Potapenko
2019-11-01 22:25 ` kbuild test robot
2019-11-03 18:16 ` kbuild test robot
2019-10-30 14:22 ` [PATCH RFC v2 23/25] kmsan: hooks for copy_to_user() and friends glider
2019-11-01 23:08 ` kbuild test robot
2019-11-03 22:10 ` kbuild test robot
2019-10-30 14:22 ` [PATCH RFC v2 24/25] kmsan: disable strscpy() optimization under KMSAN glider
2019-10-30 14:22 ` [PATCH RFC v2 25/25] net: kasan: kmsan: support CONFIG_GENERIC_CSUM on x86, enable it for KASAN/KMSAN glider
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20191030142237.249532-16-glider@google.com \
--to=glider@google.com \
--cc=akpm@linux-foundation.org \
--cc=andreyknvl@google.com \
--cc=ard.biesheuvel@linaro.org \
--cc=arnd@arndb.de \
--cc=aryabinin@virtuozzo.com \
--cc=axboe@kernel.dk \
--cc=dmitry.torokhov@gmail.com \
--cc=dvyukov@google.com \
--cc=edumazet@google.com \
--cc=elver@google.com \
--cc=ericvh@gmail.com \
--cc=gor@linux.ibm.com \
--cc=gregkh@linuxfoundation.org \
--cc=harry.wentland@amd.com \
--cc=hch@lst.de \
--cc=herbert@gondor.apana.org.au \
--cc=iii@linux.ibm.com \
--cc=linux-mm@kvack.org \
--cc=luto@kernel.org \
--cc=mark.rutland@arm.com \
--cc=martin.petersen@oracle.com \
--cc=mingo@elte.hu \
--cc=monstr@monstr.eu \
--cc=mst@redhat.com \
--cc=pmladek@suse.com \
--cc=rdunlap@infradead.org \
--cc=rostedt@goodmis.org \
--cc=schwidefsky@de.ibm.com \
--cc=sergey.senozhatsky@gmail.com \
--cc=tglx@linutronix.de \
--cc=tiwai@suse.com \
--cc=tytso@mit.edu \
--cc=vegard.nossum@oracle.com \
--cc=viro@zeniv.linux.org.uk \
--cc=willy@infradead.org \
--cc=wsa@the-dreams.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.