trinity.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* a perf_event_open() update
@ 2013-05-17 15:18 Vince Weaver
  2013-05-17 21:20 ` [patch] " Vince Weaver
  2013-05-18  1:01 ` Dave Jones
  0 siblings, 2 replies; 5+ messages in thread
From: Vince Weaver @ 2013-05-17 15:18 UTC (permalink / raw)
  To: trinity


Here's a patch that improves slightly the coverage in perf_event_open().

It handles cache events and breakpoint events.

perf_event_open() is such a complicated syscall it's fairly unlikely to 
generate a valid event randomly, even with these changes.

Also a question: is there a way to easily generate a 64-bit random number?
From what I can tell rand() only generates a 32-bit one?

I plan to improve this some more, based on the work I've done writing the 
perf_event_open manpage.

Signed-off-by: Vince Weaver <vincent.weaver@maine.edu>

diff --git a/syscalls/perf_event_open.c b/syscalls/perf_event_open.c
index 0c87cf1..769e137 100644
--- a/syscalls/perf_event_open.c
+++ b/syscalls/perf_event_open.c
@@ -7,11 +7,59 @@
 #include <stdlib.h>
 #include <string.h>
 #include <linux/perf_event.h>
+#include <linux/hw_breakpoint.h>
 #include "sanitise.h"
 #include "compat.h"
 #include "maps.h"
 #include "shm.h"
 
+static long long random_cache_config(void) {
+
+	int cache_id,hw_cache_op_id,hw_cache_op_result_id;
+
+	switch(rand()%8) {
+		case 0: cache_id=PERF_COUNT_HW_CACHE_L1D;
+			break;
+		case 1: cache_id=PERF_COUNT_HW_CACHE_L1I;
+			break;
+		case 2: cache_id=PERF_COUNT_HW_CACHE_LL;
+			break;
+		case 3: cache_id=PERF_COUNT_HW_CACHE_DTLB;
+			break;
+		case 4: cache_id=PERF_COUNT_HW_CACHE_ITLB;
+			break;
+		case 5: cache_id=PERF_COUNT_HW_CACHE_BPU;
+			break;
+		case 6: cache_id=PERF_COUNT_HW_CACHE_NODE;
+			break;
+		default: cache_id=rand();
+			break;
+	}
+
+	switch(rand()%4) {
+		case 0: hw_cache_op_id=PERF_COUNT_HW_CACHE_OP_READ;
+			break;
+		case 1: hw_cache_op_id=PERF_COUNT_HW_CACHE_OP_WRITE;
+			break;
+		case 2: hw_cache_op_id=PERF_COUNT_HW_CACHE_OP_PREFETCH;
+			break;
+		default: hw_cache_op_id=rand();
+			break;
+	}
+
+	switch(rand()%3) {
+		case 0:	hw_cache_op_result_id=PERF_COUNT_HW_CACHE_RESULT_ACCESS;
+			break;
+		case 1: hw_cache_op_result_id=PERF_COUNT_HW_CACHE_RESULT_MISS;
+			break;
+		default: hw_cache_op_result_id=rand();
+			break;
+	}
+
+	return (cache_id) | (hw_cache_op_id << 8) |
+               (hw_cache_op_result_id << 16);
+}
+
 static void sanitise_perf_event_open(int childno)
 {
 	struct perf_event_attr *attr;
@@ -24,26 +72,28 @@ static void sanitise_perf_event_open(int childno)
 
 	switch(rand() % 6) {
 		case 0:	attr->type = PERF_TYPE_HARDWARE;
-			switch(rand() % 10) {
+			switch(rand() % 11) {
 				case 0: attr->config=PERF_COUNT_HW_CPU_CYCLES;
 					break;
 				case 1: attr->config=PERF_COUNT_HW_INSTRUCTIONS;
 					break;
 				case 2: attr->config=PERF_COUNT_HW_CACHE_REFERENCES;
 					break;
-				case 3: attr->config=PERF_COUNT_HW_BRANCH_INSTRUCTIONS;
+				case 3: attr->config=PERF_COUNT_HW_CACHE_MISSES;
+					break;
+				case 4: attr->config=PERF_COUNT_HW_BRANCH_INSTRUCTIONS;
 					break;
-				case 4: attr->config=PERF_COUNT_HW_BRANCH_MISSES;
+				case 5: attr->config=PERF_COUNT_HW_BRANCH_MISSES;
 					break;
-				case 5: attr->config=PERF_COUNT_HW_BUS_CYCLES;
+				case 6: attr->config=PERF_COUNT_HW_BUS_CYCLES;
 					break;
-				case 6: attr->config=PERF_COUNT_HW_STALLED_CYCLES_FRONTEND;
+				case 7: attr->config=PERF_COUNT_HW_STALLED_CYCLES_FRONTEND;
 					break;
-				case 7: attr->config=PERF_COUNT_HW_STALLED_CYCLES_BACKEND;
+				case 8: attr->config=PERF_COUNT_HW_STALLED_CYCLES_BACKEND;
 					break;
-				case 8: attr->config=PERF_COUNT_HW_REF_CPU_CYCLES;
+				case 9: attr->config=PERF_COUNT_HW_REF_CPU_CYCLES;
 					break;
-				case 9: attr->config = rand();
+				case 10: attr->config = rand();
 					break;
 				default: break;
 			}
@@ -73,8 +123,12 @@ static void sanitise_perf_event_open(int childno)
 			}
 			break;
 		case 2: attr->type = PERF_TYPE_TRACEPOINT;
+			/* Actual values to use can be found under */
+			/* debugfs tracing/events//*//*/id         */
+			attr->config=rand();
 			break;
 		case 3: attr->type = PERF_TYPE_HW_CACHE;
+			attr->config = random_cache_config();
 			break;
 		case 4: attr->type = PERF_TYPE_RAW;
 			/* can be arbitrary 64-bit value */
@@ -84,6 +138,44 @@ static void sanitise_perf_event_open(int childno)
 
 			break;
 		case 5: attr->type = PERF_TYPE_BREAKPOINT;
+			/* Breakpoint type only valid if config==0 */
+			/* Set it to something else too anyway     */
+			if (rand()%2) attr->config = rand();
+			else attr->config = 0;
+
+			switch (rand()%6) {
+				case 0: attr->bp_type=HW_BREAKPOINT_EMPTY;
+					break;
+				case 1: attr->bp_type=HW_BREAKPOINT_R;
+					break;
+				case 2: attr->bp_type=HW_BREAKPOINT_W;
+					break;
+				case 3: attr->bp_type=HW_BREAKPOINT_RW;
+					break;
+				case 4: attr->bp_type=HW_BREAKPOINT_X;
+					break;
+				default: attr->bp_type=rand();
+					break;
+			}
+
+			/* This might be more interesting if this were    */
+			/* a valid executable address for HW_BREAKPOINT_X */
+			/* or a valid mem location for R/W/RW             */
+			attr->bp_addr = rand();
+
+			switch(rand()%5) {
+				case 0: attr->bp_len=HW_BREAKPOINT_LEN_1;
+					break;
+				case 1: attr->bp_len=HW_BREAKPOINT_LEN_2;
+					break;
+				case 2: attr->bp_len=HW_BREAKPOINT_LEN_4;
+					break;
+				case 3: attr->bp_len=HW_BREAKPOINT_LEN_8;
+					break;
+				default: attr->bp_len=rand();
+					break;
+			}
+
 			break;
 		default: break;
 	}

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [patch] a perf_event_open() update
  2013-05-17 15:18 a perf_event_open() update Vince Weaver
@ 2013-05-17 21:20 ` Vince Weaver
  2013-05-18  1:01 ` Dave Jones
  1 sibling, 0 replies; 5+ messages in thread
From: Vince Weaver @ 2013-05-17 21:20 UTC (permalink / raw)
  To: trinity


And below is an even more complex perf_event_open() update.
This applies on top of the patch from my previous e-mail.

This attempts to create mostly valid perf_event_open calls at least 2/3
of the time.

One problem: it quickly opens all available fds and then fails out with no 
more filedescriptors.  I notice that "trinity -copen" does not have this 
issue... but I can't find out how it gets around it.

I already managed to generate this warning on a debian-unstable 3.8 kernel 
sometime during my testing, but didn't notice until too late to replicate.
I should be running a more recent kernel I guess.


[11982.189962] ------------[ cut here ]------------
[11982.189970] WARNING: at /build/buildd-linux_3.8.12-1-amd64-RaG_7r/linux-3.8.12/arch/x86/kernel/hw_breakpoint.c:121 arch_install_hw_breakpoint+0xad/0xcb()
[11982.189972] Hardware name:  DE7000
[11982.189973] Can't find any breakpoint slot
[11982.190046] Pid: 6495, comm: trinity-child1 Not tainted 3.8-1-amd64 #1 Debian 3.8.12-1
[11982.190047] Call Trace:
[11982.190052]  [<ffffffff8103ce54>] ? warn_slowpath_common+0x76/0x8a
[11982.190055]  [<ffffffff8103cf00>] ? warn_slowpath_fmt+0x45/0x4a
[11982.190059]  [<ffffffff81065bc2>] ? local_clock+0x2c/0x37
[11982.190062]  [<ffffffff810133a0>] ? arch_install_hw_breakpoint+0xad/0xcb
[11982.190066]  [<ffffffff810bc22c>] ? event_sched_in+0x6a/0x11f
[11982.190069]  [<ffffffff810bc327>] ? group_sched_in+0x46/0x124
[11982.190071]  [<ffffffff810136a1>] ? paravirt_read_tsc+0x5/0x8
[11982.190074]  [<ffffffff81013b37>] ? native_sched_clock+0x27/0x2f
[11982.190076]  [<ffffffff810136a9>] ? paravirt_sched_clock+0x5/0x8
[11982.190079]  [<ffffffff81065a0d>] ? sched_clock_local+0xd/0x6f
[11982.190082]  [<ffffffff810bc52a>] ? ctx_sched_in+0x125/0x145
[11982.190085]  [<ffffffff810bcaa2>] ? __perf_install_in_context+0xcb/0xea
[11982.190087]  [<ffffffff810b93bb>] ? perf_exclude_event+0x42/0x42
[11982.190090]  [<ffffffff810b93ce>] ? remote_function+0x13/0x3b
[11982.190093]  [<ffffffff8107f391>] ? smp_call_function_single+0x8a/0x106
[11982.190096]  [<ffffffff810b8bd4>] ? task_function_call+0x42/0x4c
[11982.190098]  [<ffffffff810bc9d7>] ? perf_event_sched_in+0x69/0x69
[11982.190101]  [<ffffffff810baf1d>] ? perf_install_in_context+0x5e/0x9e
[11982.190104]  [<ffffffff810bf98e>] ? sys_perf_event_open+0x66e/0x7e6
[11982.190109]  [<ffffffff81388929>] ? system_call_fastpath+0x16/0x1b
[11982.190111] ---[ end trace 3e45a276025d4240 ]---



Signed-off-by: Vince Weaver <vincent.weaver@maine.edu>

diff --git a/syscalls/perf_event_open.c b/syscalls/perf_event_open.c
index 769e137..0f6eda3 100644
--- a/syscalls/perf_event_open.c
+++ b/syscalls/perf_event_open.c
@@ -60,125 +60,228 @@ static long long random_cache_config(void) {
                (hw_cache_op_result_id << 16);
 }
 
-static void sanitise_perf_event_open(int childno)
-{
-	struct perf_event_attr *attr;
+static long long random_event_type(void) {
 
-	shm->a1[childno] = (unsigned long) page_rand;
-	attr = (struct perf_event_attr *) shm->a1[childno];
-
-	/* this makes sure we clear out the reserved fields. */
-	memset(page_rand, 0, sizeof(struct perf_event_attr));
+	long long type;
 
 	switch(rand() % 6) {
-		case 0:	attr->type = PERF_TYPE_HARDWARE;
+		case 0:	type = PERF_TYPE_HARDWARE;
+			break;
+		case 1: type = PERF_TYPE_SOFTWARE;
+			break;
+		case 2: type = PERF_TYPE_TRACEPOINT;
+			break;
+		case 3: type = PERF_TYPE_HW_CACHE;
+			break;
+		case 4: type = PERF_TYPE_RAW;
+			break;
+		case 5: type = PERF_TYPE_BREAKPOINT;
+			break;
+		default: type=rand();
+			break;
+	}
+	return type;
+}
+
+
+static long long random_event_config(long long event_type) {
+
+	unsigned long long config;
+
+	switch(event_type) {
+		case PERF_TYPE_HARDWARE:
 			switch(rand() % 11) {
-				case 0: attr->config=PERF_COUNT_HW_CPU_CYCLES;
+				case 0: config=PERF_COUNT_HW_CPU_CYCLES;
 					break;
-				case 1: attr->config=PERF_COUNT_HW_INSTRUCTIONS;
+				case 1: config=PERF_COUNT_HW_INSTRUCTIONS;
 					break;
-				case 2: attr->config=PERF_COUNT_HW_CACHE_REFERENCES;
+				case 2: config=PERF_COUNT_HW_CACHE_REFERENCES;
 					break;
-				case 3: attr->config=PERF_COUNT_HW_CACHE_MISSES;
+				case 3: config=PERF_COUNT_HW_CACHE_MISSES;
 					break;
-				case 4: attr->config=PERF_COUNT_HW_BRANCH_INSTRUCTIONS;
+				case 4: config=PERF_COUNT_HW_BRANCH_INSTRUCTIONS;
 					break;
-				case 5: attr->config=PERF_COUNT_HW_BRANCH_MISSES;
+				case 5: config=PERF_COUNT_HW_BRANCH_MISSES;
 					break;
-				case 6: attr->config=PERF_COUNT_HW_BUS_CYCLES;
+				case 6: config=PERF_COUNT_HW_BUS_CYCLES;
 					break;
-				case 7: attr->config=PERF_COUNT_HW_STALLED_CYCLES_FRONTEND;
+				case 7: config=PERF_COUNT_HW_STALLED_CYCLES_FRONTEND;
 					break;
-				case 8: attr->config=PERF_COUNT_HW_STALLED_CYCLES_BACKEND;
+				case 8: config=PERF_COUNT_HW_STALLED_CYCLES_BACKEND;
 					break;
-				case 9: attr->config=PERF_COUNT_HW_REF_CPU_CYCLES;
+				case 9: config=PERF_COUNT_HW_REF_CPU_CYCLES;
 					break;
-				case 10: attr->config = rand();
+				default: config = rand();
 					break;
-				default: break;
 			}
 			break;
-		case 1: attr->type = PERF_TYPE_SOFTWARE;
+		case PERF_TYPE_SOFTWARE:
 			switch(rand() % 10) {
-				case 0: attr->config=PERF_COUNT_SW_CPU_CLOCK;
+				case 0: config=PERF_COUNT_SW_CPU_CLOCK;
+					break;
+				case 1: config=PERF_COUNT_SW_TASK_CLOCK;
 					break;
-				case 1: attr->config=PERF_COUNT_SW_TASK_CLOCK;
+				case 2: config=PERF_COUNT_SW_PAGE_FAULTS;
 					break;
-				case 2: attr->config=PERF_COUNT_SW_PAGE_FAULTS;
+				case 3: config=PERF_COUNT_SW_CONTEXT_SWITCHES;
 					break;
-				case 3: attr->config=PERF_COUNT_SW_CONTEXT_SWITCHES;
+				case 4: config=PERF_COUNT_SW_CPU_MIGRATIONS;
 					break;
-				case 4: attr->config=PERF_COUNT_SW_CPU_MIGRATIONS;
+				case 5: config=PERF_COUNT_SW_PAGE_FAULTS_MIN;
 					break;
-				case 5: attr->config=PERF_COUNT_SW_PAGE_FAULTS_MIN;
+				case 6: config=PERF_COUNT_SW_PAGE_FAULTS_MAJ;
 					break;
-				case 6: attr->config=PERF_COUNT_SW_PAGE_FAULTS_MAJ;
+				case 7: config=PERF_COUNT_SW_ALIGNMENT_FAULTS;
 					break;
-				case 7: attr->config=PERF_COUNT_SW_ALIGNMENT_FAULTS;
+				case 8: config=PERF_COUNT_SW_EMULATION_FAULTS;
 					break;
-				case 8: attr->config=PERF_COUNT_SW_EMULATION_FAULTS;
+				default: config=rand();
 					break;
-				case 9: attr->config=rand();
-				default: break;
 			}
 			break;
-		case 2: attr->type = PERF_TYPE_TRACEPOINT;
+		case PERF_TYPE_TRACEPOINT:
 			/* Actual values to use can be found under */
 			/* debugfs tracing/events//*//*/id         */
-			attr->config=rand();
+			config=rand();
 			break;
-		case 3: attr->type = PERF_TYPE_HW_CACHE;
-			attr->config = random_cache_config();
+		case PERF_TYPE_HW_CACHE:
+			config = random_cache_config();
 			break;
-		case 4: attr->type = PERF_TYPE_RAW;
+		case PERF_TYPE_RAW:
 			/* can be arbitrary 64-bit value */
 			/* there are some constraints we can add */
 			/* to make it more likely to be a valid event */
-			attr->config = rand();
-
+			config = rand();
 			break;
-		case 5: attr->type = PERF_TYPE_BREAKPOINT;
+		case PERF_TYPE_BREAKPOINT:
 			/* Breakpoint type only valid if config==0 */
 			/* Set it to something else too anyway     */
-			if (rand()%2) attr->config = rand();
-			else attr->config = 0;
+			if (rand()%2) config = rand();
+			else config = 0;
+			break;
+		default: config=rand();
+			break;
+	}
+	return config;
+}
 
-			switch (rand()%6) {
-				case 0: attr->bp_type=HW_BREAKPOINT_EMPTY;
-					break;
-				case 1: attr->bp_type=HW_BREAKPOINT_R;
-					break;
-				case 2: attr->bp_type=HW_BREAKPOINT_W;
-					break;
-				case 3: attr->bp_type=HW_BREAKPOINT_RW;
-					break;
-				case 4: attr->bp_type=HW_BREAKPOINT_X;
-					break;
-				default: attr->bp_type=rand();
-					break;
-			}
+static void setup_breakpoints(struct perf_event_attr *attr) {
 
-			/* This might be more interesting if this were    */
-			/* a valid executable address for HW_BREAKPOINT_X */
-			/* or a valid mem location for R/W/RW             */
-			attr->bp_addr = rand();
+	switch (rand()%6) {
+		case 0: attr->bp_type=HW_BREAKPOINT_EMPTY;
+			break;
+		case 1: attr->bp_type=HW_BREAKPOINT_R;
+			break;
+		case 2: attr->bp_type=HW_BREAKPOINT_W;
+			break;
+		case 3: attr->bp_type=HW_BREAKPOINT_RW;
+			break;
+		case 4: attr->bp_type=HW_BREAKPOINT_X;
+			break;
+		default: attr->bp_type=rand();
+			break;
+	}
 
-			switch(rand()%5) {
-				case 0: attr->bp_len=HW_BREAKPOINT_LEN_1;
-					break;
-				case 1: attr->bp_len=HW_BREAKPOINT_LEN_2;
-					break;
-				case 2: attr->bp_len=HW_BREAKPOINT_LEN_4;
-					break;
-				case 3: attr->bp_len=HW_BREAKPOINT_LEN_8;
-					break;
-				default: attr->bp_len=rand();
-					break;
-			}
+	/* This might be more interesting if this were    */
+	/* a valid executable address for HW_BREAKPOINT_X */
+	/* or a valid mem location for R/W/RW             */
+	attr->bp_addr = rand();
 
+	switch(rand()%5) {
+		case 0: attr->bp_len=HW_BREAKPOINT_LEN_1;
+			break;
+		case 1: attr->bp_len=HW_BREAKPOINT_LEN_2;
+			break;
+		case 2: attr->bp_len=HW_BREAKPOINT_LEN_4;
+			break;
+		case 3: attr->bp_len=HW_BREAKPOINT_LEN_8;
+			break;
+		default: attr->bp_len=rand();
 			break;
-		default: break;
 	}
+}
+
+static long long random_sample_type(void) {
+
+	long long sample_type=0;
+
+	if (rand()%2) return rand();
+
+	if (rand()%2) sample_type|=PERF_SAMPLE_IP;
+	if (rand()%2) sample_type|=PERF_SAMPLE_TID;
+	if (rand()%2) sample_type|=PERF_SAMPLE_TIME;
+	if (rand()%2) sample_type|=PERF_SAMPLE_ADDR;
+	if (rand()%2) sample_type|=PERF_SAMPLE_READ;
+	if (rand()%2) sample_type|=PERF_SAMPLE_CALLCHAIN;
+	if (rand()%2) sample_type|=PERF_SAMPLE_ID;
+	if (rand()%2) sample_type|=PERF_SAMPLE_CPU;
+	if (rand()%2) sample_type|=PERF_SAMPLE_PERIOD;
+	if (rand()%2) sample_type|=PERF_SAMPLE_STREAM_ID;
+	if (rand()%2) sample_type|=PERF_SAMPLE_RAW;
+
+	return sample_type;
+}
+
+static long long random_read_format(void) {
+
+	long long read_format=0;
+
+	if (rand()%2) return rand();
+
+	if (rand()%2) read_format|=PERF_FORMAT_GROUP;
+	if (rand()%2) read_format|=PERF_FORMAT_ID;
+	if (rand()%2) read_format|=PERF_FORMAT_TOTAL_TIME_ENABLED;
+	if (rand()%2) read_format|=PERF_FORMAT_TOTAL_TIME_RUNNING;
+
+	return read_format;
+}
+
+static void create_mostly_valid_counting_event(struct perf_event_attr *attr) {
+
+	attr->type=random_event_type();
+	attr->size=sizeof(struct perf_event_attr);
+	attr->config=random_event_config(attr->type);
+	if (attr->type==PERF_TYPE_BREAKPOINT) {
+		setup_breakpoints(attr);
+	}
+	attr->read_format=random_read_format();
+
+	/* Boolean parameters */
+	attr->disabled=rand()%2;
+	attr->pinned=rand()%2;
+	attr->exclude_user=rand()%2;
+	attr->exclude_kernel=rand()%2;
+	attr->exclude_hv=rand()%2;
+
+}
+
+static void create_mostly_valid_sampling_event(struct perf_event_attr *attr) {
+
+	attr->type=random_event_type();
+	attr->size=sizeof(struct perf_event_attr);
+	attr->config=random_event_config(attr->type);
+	if (attr->type==PERF_TYPE_BREAKPOINT) {
+		setup_breakpoints(attr);
+	}
+	attr->sample_period=rand(); /* low values more likely to have "interesting" results */
+	attr->sample_type=random_sample_type();
+	attr->read_format=random_read_format();
+
+	/* booleans */
+	attr->disabled=rand()%2;
+	attr->pinned=rand()%2;
+	attr->exclude_user=rand()%2;
+	attr->exclude_kernel=rand()%2;
+	attr->exclude_hv=rand()%2;
+	attr->wakeup_events=rand()%2;
+
+}
+
+static void create_random_event(struct perf_event_attr *attr) {
+
+	attr->type=random_event_type();
+	attr->config=random_event_config(attr->type);
+	setup_breakpoints(attr);
 
 	switch(rand() % 2) {
 		case 0: attr->size = sizeof(struct perf_event_attr);
@@ -187,9 +290,52 @@ static void sanitise_perf_event_open(int childno)
 		default: break;
 	}
 
-	attr->sample_type = rand() % PERF_SAMPLE_MAX;
-	attr->read_format = rand() % PERF_FORMAT_MAX;
-	attr->exclude_kernel = TRUE;	// FIXME: root-mode
+	attr->sample_type = random_sample_type();
+	attr->read_format = random_read_format();
+
+	/* booleans */
+	attr->exclude_user=rand()%2;
+	attr->exclude_kernel = rand()%2;	/* does't require root unless paranoid set to 2 */
+	attr->exclude_hv = rand()%2;
+}
+
+static void sanitise_perf_event_open(int childno)
+{
+	struct perf_event_attr *attr;
+
+	shm->a1[childno] = (unsigned long) page_rand;
+	attr = (struct perf_event_attr *) shm->a1[childno];
+
+	/* this makes sure we clear out the reserved fields. */
+	memset(page_rand, 0, sizeof(struct perf_event_attr));
+
+	/* pid */
+	/* requires ROOT to select pid that doesn't belong to us */
+	/* pid of 0 means current process */
+	shm->a2[childno]=0;
+
+	/* cpu */
+	/* requires ROOT to select CPU if paranoid level not 0 */
+	shm->a3[childno]=-1;
+
+	/* groupfd */
+	/* should usually be -1 or another perf_event fd         */
+	/* Anything but -1 unlikely to work unless the other pid */
+	/* was properly set up to be a group master		 */
+	shm->a4[childno]=-1;
+
+	/* flags */
+	/* You almost never set these unless you're playing with cgroups */
+	shm->a5[childno]=0;
+
+	switch(rand()%3) {
+		case 0:	create_mostly_valid_counting_event(attr);
+			break;
+		case 1: create_mostly_valid_sampling_event(attr);
+			break;
+		default: create_random_event(attr);
+			break;
+	}
 }
 
 struct syscall syscall_perf_event_open = {
@@ -204,11 +350,10 @@ struct syscall syscall_perf_event_open = {
 	.arg4name = "group_fd",
 	.arg4type = ARG_FD,
 	.arg5name = "flags",
-	.arg5type = ARG_LIST,
-	.arg5list = {
-		.num = 3,
-		.values = { PERF_FLAG_FD_NO_GROUP, PERF_FLAG_FD_OUTPUT, PERF_FLAG_PID_CGROUP },
-	},
-	.sanitise = sanitise_perf_event_open,
+        .arg5list = {
+                .num = 3,
+                .values = { PERF_FLAG_FD_NO_GROUP, PERF_FLAG_FD_OUTPUT, PERF_FLAG_PID_CGROUP },
+        },
+        .sanitise = sanitise_perf_event_open,
 	.flags = NEED_ALARM,
 };

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: a perf_event_open() update
  2013-05-17 15:18 a perf_event_open() update Vince Weaver
  2013-05-17 21:20 ` [patch] " Vince Weaver
@ 2013-05-18  1:01 ` Dave Jones
  2013-05-20  3:34   ` [patch] " Vince Weaver
  1 sibling, 1 reply; 5+ messages in thread
From: Dave Jones @ 2013-05-18  1:01 UTC (permalink / raw)
  To: Vince Weaver; +Cc: trinity

On Fri, May 17, 2013 at 11:18:39AM -0400, Vince Weaver wrote:
 > 
 > Here's a patch that improves slightly the coverage in perf_event_open().
 > 
 > It handles cache events and breakpoint events.
 > 
 > perf_event_open() is such a complicated syscall it's fairly unlikely to 
 > generate a valid event randomly, even with these changes.
 > 
 > Also a question: is there a way to easily generate a 64-bit random number?
 > >From what I can tell rand() only generates a 32-bit one?

I was going to wait until I get back from vacation, but
your comment persuaded me to push out what's in my
current tree.  check out rand64.

totally untested so far beyond compile testing.
more when I get back on Tuesday.

	Dave


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [patch] Re: a perf_event_open() update
  2013-05-18  1:01 ` Dave Jones
@ 2013-05-20  3:34   ` Vince Weaver
  2013-05-21 16:54     ` Dave Jones
  0 siblings, 1 reply; 5+ messages in thread
From: Vince Weaver @ 2013-05-20  3:34 UTC (permalink / raw)
  To: Dave Jones; +Cc: trinity


Here's an updated patch that more or less exercises all of the 
perf_event_open() bits, up to around the 3.6 kernel or so.

The patch is standalone against current trinity git.

It could definitely use some review and tuning.

I haven't turned up any issues with it, but that's partly because in my 
experience (the recent exploit being an exception) perf_event bugs rarely 
manifest with just an open call; they usually involve 
reads/writes/ioctls/mmaps/signals on the fd that is opened, as well as 
problems after fork/exec or else on complex events made of multiple 
perf_event_open() calls chained together (the call can take a previously 
opened fd as an argument).  Testing things like this will be more 
difficult.

Signed-off-by: Vince Weaver <vincent.weaver@maine.edu>

diff --git a/syscalls/perf_event_open.c b/syscalls/perf_event_open.c
index 0c87cf1..072c0f8 100644
--- a/syscalls/perf_event_open.c
+++ b/syscalls/perf_event_open.c
@@ -7,86 +7,366 @@
 #include <stdlib.h>
 #include <string.h>
 #include <linux/perf_event.h>
+#include <linux/hw_breakpoint.h>
 #include "sanitise.h"
 #include "compat.h"
 #include "maps.h"
 #include "shm.h"
 
-static void sanitise_perf_event_open(int childno)
-{
-	struct perf_event_attr *attr;
+static long long random_cache_config(void) {
 
-	shm->a1[childno] = (unsigned long) page_rand;
-	attr = (struct perf_event_attr *) shm->a1[childno];
+	int cache_id,hw_cache_op_id,hw_cache_op_result_id;
 
-	/* this makes sure we clear out the reserved fields. */
-	memset(page_rand, 0, sizeof(struct perf_event_attr));
+	switch(rand()%8) {
+		case 0: cache_id=PERF_COUNT_HW_CACHE_L1D;
+			break;
+		case 1: cache_id=PERF_COUNT_HW_CACHE_L1I;
+			break;
+		case 2: cache_id=PERF_COUNT_HW_CACHE_LL;
+			break;
+		case 3: cache_id=PERF_COUNT_HW_CACHE_DTLB;
+			break;
+		case 4: cache_id=PERF_COUNT_HW_CACHE_ITLB;
+			break;
+		case 5: cache_id=PERF_COUNT_HW_CACHE_BPU;
+			break;
+#ifdef PERF_COUNT_HW_CACHE_NODE /* 3.0 */
+		case 6: cache_id=PERF_COUNT_HW_CACHE_NODE;
+			break;
+#endif
+		default: cache_id=rand();
+			break;
+	}
+
+	switch(rand()%4) {
+		case 0: hw_cache_op_id=PERF_COUNT_HW_CACHE_OP_READ;
+			break;
+		case 1: hw_cache_op_id=PERF_COUNT_HW_CACHE_OP_WRITE;
+			break;
+		case 2: hw_cache_op_id=PERF_COUNT_HW_CACHE_OP_PREFETCH;
+			break;
+		default: hw_cache_op_id=rand();
+			break;
+	}
+
+	switch(rand()%3) {
+		case 0:	hw_cache_op_result_id=PERF_COUNT_HW_CACHE_RESULT_ACCESS;
+			break;
+		case 1: hw_cache_op_result_id=PERF_COUNT_HW_CACHE_RESULT_MISS;
+			break;
+		default: hw_cache_op_result_id=rand();
+			break;
+	}
+
+	return (cache_id) | (hw_cache_op_id << 8) |
+               (hw_cache_op_result_id << 16);
+}
+
+static int random_event_type(void) {
+
+	int type;
 
 	switch(rand() % 6) {
-		case 0:	attr->type = PERF_TYPE_HARDWARE;
-			switch(rand() % 10) {
-				case 0: attr->config=PERF_COUNT_HW_CPU_CYCLES;
+		case 0:	type = PERF_TYPE_HARDWARE;
+			break;
+		case 1: type = PERF_TYPE_SOFTWARE;
+			break;
+		case 2: type = PERF_TYPE_TRACEPOINT;
+			break;
+		case 3: type = PERF_TYPE_HW_CACHE;
+			break;
+		case 4: type = PERF_TYPE_RAW;
+			break;
+		case 5: type = PERF_TYPE_BREAKPOINT;
+			break;
+		default: type=rand();
+			break;
+	}
+	return type;
+}
+
+
+static long long random_event_config(long long event_type) {
+
+	unsigned long long config;
+
+	switch(event_type) {
+		case PERF_TYPE_HARDWARE:
+			switch(rand() % 11) {
+				case 0: config=PERF_COUNT_HW_CPU_CYCLES;
+					break;
+				case 1: config=PERF_COUNT_HW_INSTRUCTIONS;
 					break;
-				case 1: attr->config=PERF_COUNT_HW_INSTRUCTIONS;
+				case 2: config=PERF_COUNT_HW_CACHE_REFERENCES;
 					break;
-				case 2: attr->config=PERF_COUNT_HW_CACHE_REFERENCES;
+				case 3: config=PERF_COUNT_HW_CACHE_MISSES;
 					break;
-				case 3: attr->config=PERF_COUNT_HW_BRANCH_INSTRUCTIONS;
+				case 4: config=PERF_COUNT_HW_BRANCH_INSTRUCTIONS;
 					break;
-				case 4: attr->config=PERF_COUNT_HW_BRANCH_MISSES;
+				case 5: config=PERF_COUNT_HW_BRANCH_MISSES;
 					break;
-				case 5: attr->config=PERF_COUNT_HW_BUS_CYCLES;
+				case 6: config=PERF_COUNT_HW_BUS_CYCLES;
 					break;
-				case 6: attr->config=PERF_COUNT_HW_STALLED_CYCLES_FRONTEND;
+#ifdef PERF_COUNT_HW_STALLED_CYCLES_FRONTEND /* added 3.0 */
+				case 7: config=PERF_COUNT_HW_STALLED_CYCLES_FRONTEND;
 					break;
-				case 7: attr->config=PERF_COUNT_HW_STALLED_CYCLES_BACKEND;
+#endif
+#ifdef PERF_COUNT_HW_STALLED_CYCLES_BACKEND /* added 3.0 */
+				case 8: config=PERF_COUNT_HW_STALLED_CYCLES_BACKEND;
 					break;
-				case 8: attr->config=PERF_COUNT_HW_REF_CPU_CYCLES;
+#endif
+#ifdef PERF_COUNT_HW_REF_CPU_CYCLES /* added 3.3 */
+				case 9: config=PERF_COUNT_HW_REF_CPU_CYCLES;
 					break;
-				case 9: attr->config = rand();
+#endif
+				default: config = rand64();
 					break;
-				default: break;
 			}
 			break;
-		case 1: attr->type = PERF_TYPE_SOFTWARE;
+		case PERF_TYPE_SOFTWARE:
 			switch(rand() % 10) {
-				case 0: attr->config=PERF_COUNT_SW_CPU_CLOCK;
+				case 0: config=PERF_COUNT_SW_CPU_CLOCK;
 					break;
-				case 1: attr->config=PERF_COUNT_SW_TASK_CLOCK;
+				case 1: config=PERF_COUNT_SW_TASK_CLOCK;
 					break;
-				case 2: attr->config=PERF_COUNT_SW_PAGE_FAULTS;
+				case 2: config=PERF_COUNT_SW_PAGE_FAULTS;
 					break;
-				case 3: attr->config=PERF_COUNT_SW_CONTEXT_SWITCHES;
+				case 3: config=PERF_COUNT_SW_CONTEXT_SWITCHES;
 					break;
-				case 4: attr->config=PERF_COUNT_SW_CPU_MIGRATIONS;
+				case 4: config=PERF_COUNT_SW_CPU_MIGRATIONS;
 					break;
-				case 5: attr->config=PERF_COUNT_SW_PAGE_FAULTS_MIN;
+				case 5: config=PERF_COUNT_SW_PAGE_FAULTS_MIN;
 					break;
-				case 6: attr->config=PERF_COUNT_SW_PAGE_FAULTS_MAJ;
+				case 6: config=PERF_COUNT_SW_PAGE_FAULTS_MAJ;
 					break;
-				case 7: attr->config=PERF_COUNT_SW_ALIGNMENT_FAULTS;
+#ifdef PERF_COUNT_SW_ALIGNMENT_FAULTS /* since 2.6.33 */
+				case 7: config=PERF_COUNT_SW_ALIGNMENT_FAULTS;
 					break;
-				case 8: attr->config=PERF_COUNT_SW_EMULATION_FAULTS;
+#endif
+#ifdef PERF_COUNT_SW_EMULTATION_FAULTS /* since 2.6.33 */
+				case 8: config=PERF_COUNT_SW_EMULATION_FAULTS;
+					break;
+#endif
+				default: config=rand64();
 					break;
-				case 9: attr->config=rand();
-				default: break;
 			}
 			break;
-		case 2: attr->type = PERF_TYPE_TRACEPOINT;
+		case PERF_TYPE_TRACEPOINT:
+			/* Actual values to use can be found under */
+			/* debugfs tracing/events//*//*/id         */
+			config=rand64();
 			break;
-		case 3: attr->type = PERF_TYPE_HW_CACHE;
+		case PERF_TYPE_HW_CACHE:
+			config = random_cache_config();
 			break;
-		case 4: attr->type = PERF_TYPE_RAW;
+		case PERF_TYPE_RAW:
 			/* can be arbitrary 64-bit value */
 			/* there are some constraints we can add */
 			/* to make it more likely to be a valid event */
-			attr->config = rand();
+			config = rand64();
+			break;
+#ifdef PERF_TYPE_BREAKPOINT /* introduced 2.6.33 */
+		case PERF_TYPE_BREAKPOINT:
+			/* Breakpoint type only valid if config==0 */
+			/* Set it to something else too anyway     */
+			if (rand()%2) config = rand64();
+			else config = 0;
+			break;
+#endif
+
+/* FIXME: value can also be one of the ones found in */
+/* /sys/bus/event_source/devices                     */
 
+		default: config=rand64();
 			break;
-		case 5: attr->type = PERF_TYPE_BREAKPOINT;
+	}
+	return config;
+}
+
+static void setup_breakpoints(struct perf_event_attr *attr) {
+
+	switch (rand()%6) {
+		case 0: attr->bp_type=HW_BREAKPOINT_EMPTY;
+			break;
+		case 1: attr->bp_type=HW_BREAKPOINT_R;
+			break;
+		case 2: attr->bp_type=HW_BREAKPOINT_W;
+			break;
+		case 3: attr->bp_type=HW_BREAKPOINT_RW;
+			break;
+		case 4: attr->bp_type=HW_BREAKPOINT_X;
+			break;
+		default: attr->bp_type=rand();
+			break;
+	}
+
+	/* This might be more interesting if this were    */
+	/* a valid executable address for HW_BREAKPOINT_X */
+	/* or a valid mem location for R/W/RW             */
+	attr->bp_addr = rand();
+
+	switch(rand()%5) {
+		case 0: attr->bp_len=HW_BREAKPOINT_LEN_1;
+			break;
+		case 1: attr->bp_len=HW_BREAKPOINT_LEN_2;
+			break;
+		case 2: attr->bp_len=HW_BREAKPOINT_LEN_4;
+			break;
+		case 3: attr->bp_len=HW_BREAKPOINT_LEN_8;
+			break;
+		default: attr->bp_len=rand();
 			break;
-		default: break;
 	}
+}
+
+static long long random_sample_type(void) {
+
+	long long sample_type=0;
+
+	if (rand()%2) return rand();
+
+	if (rand()%2) sample_type|=PERF_SAMPLE_IP;
+	if (rand()%2) sample_type|=PERF_SAMPLE_TID;
+	if (rand()%2) sample_type|=PERF_SAMPLE_TIME;
+	if (rand()%2) sample_type|=PERF_SAMPLE_ADDR;
+	if (rand()%2) sample_type|=PERF_SAMPLE_READ;
+	if (rand()%2) sample_type|=PERF_SAMPLE_CALLCHAIN;
+	if (rand()%2) sample_type|=PERF_SAMPLE_ID;
+	if (rand()%2) sample_type|=PERF_SAMPLE_CPU;
+	if (rand()%2) sample_type|=PERF_SAMPLE_PERIOD;
+	if (rand()%2) sample_type|=PERF_SAMPLE_STREAM_ID;
+	if (rand()%2) sample_type|=PERF_SAMPLE_RAW;
+#ifdef PERF_SAMPLE_BRANCH_STACK
+	if (rand()%2) sample_type|=PERF_SAMPLE_BRANCH_STACK;
+#endif
+#ifdef PERF_SAMPLE_REGS_USER
+	if (rand()%2) sample_type|=PERF_SAMPLE_REGS_USER;
+#endif
+#ifdef PERF_SAMPLE_STACK_USER
+	if (rand()%2) sample_type|=PERF_SAMPLE_STACK_USER;
+#endif
+
+	return sample_type;
+}
+
+static long long random_read_format(void) {
+
+	long long read_format=0;
+
+	if (rand()%2) return rand();
+
+	if (rand()%2) read_format|=PERF_FORMAT_GROUP;
+	if (rand()%2) read_format|=PERF_FORMAT_ID;
+	if (rand()%2) read_format|=PERF_FORMAT_TOTAL_TIME_ENABLED;
+	if (rand()%2) read_format|=PERF_FORMAT_TOTAL_TIME_RUNNING;
+
+	return read_format;
+}
+
+static void create_mostly_valid_counting_event(struct perf_event_attr *attr) {
+
+	attr->type=random_event_type();
+
+	attr->size=sizeof(struct perf_event_attr);
+	/* FIXME: can typically be 64,72,80,96 depending on kernel */
+	/* Other values will likely not create a valid event       */
+
+	attr->config=random_event_config(attr->type);
+	if (attr->type==PERF_TYPE_BREAKPOINT) {
+		setup_breakpoints(attr);
+	}
+	attr->read_format=random_read_format();
+
+	/* Boolean parameters */
+	attr->disabled=rand()%2;
+	attr->inherit=rand()%2;
+	attr->pinned=rand()%2;
+	attr->exclusive=rand()%2;
+	attr->exclude_user=rand()%2;
+	attr->exclude_kernel=rand()%2;
+	attr->exclude_hv=rand()%2;
+	attr->exclude_idle=rand()%2;
+	attr->mmap=rand()%2;
+	attr->comm=rand()%2;
+	// freq not relevant
+	attr->inherit_stat=rand()%2;
+	attr->enable_on_exec=rand()%2;
+	attr->task=rand()%2;
+	attr->watermark=rand()%2;
+	attr->precise_ip=rand()%4;	// two bits
+	attr->mmap_data=rand()%2;
+	attr->sample_id_all=rand()%2;
+	attr->exclude_host=rand()%2;
+	attr->exclude_guest=rand()%2;
+	attr->exclude_callchain_kernel=rand()%2;
+	attr->exclude_callchain_user=rand()%2;
+
+	attr->wakeup_events=rand();	// also wakeup_watermark
+
+	//attr->config1=rand64();
+	//attr->config2=rand64();
+	// only valid with certain event combinations
+
+	//attr->branch_sample_type=rand64();
+	//attr->sample_regs_user=rand64();
+	//attr->saple_stack_user=rand();
+
+
+}
+
+static void create_mostly_valid_sampling_event(struct perf_event_attr *attr) {
+
+	attr->type=random_event_type();
+	attr->size=sizeof(struct perf_event_attr);
+	attr->config=random_event_config(attr->type);
+	if (attr->type==PERF_TYPE_BREAKPOINT) {
+		setup_breakpoints(attr);
+	}
+	attr->sample_period=rand(); /* low values more likely to have "interesting" results */
+	attr->sample_type=random_sample_type();
+	attr->read_format=random_read_format();
+
+	/* Boolean parameters */
+	attr->disabled=rand()%2;
+	attr->inherit=rand()%2;
+	attr->pinned=rand()%2;
+	attr->exclusive=rand()%2;
+	attr->exclude_user=rand()%2;
+	attr->exclude_kernel=rand()%2;
+	attr->exclude_hv=rand()%2;
+	attr->exclude_idle=rand()%2;
+	attr->mmap=rand()%2;
+	attr->comm=rand()%2;
+
+	attr->inherit_stat=rand()%2;
+	attr->enable_on_exec=rand()%2;
+	attr->task=rand()%2;
+	attr->watermark=rand()%2;
+	attr->precise_ip=rand()%4;	// two bits
+	attr->mmap_data=rand()%2;
+	attr->sample_id_all=rand()%2;
+	attr->exclude_host=rand()%2;
+	attr->exclude_guest=rand()%2;
+	attr->exclude_callchain_kernel=rand()%2;
+	attr->exclude_callchain_user=rand()%2;
+
+	attr->wakeup_events=rand();	// also wakeup_watermark
+
+	//attr->config1=rand64();
+	//attr->config2=rand64();
+	// only valid with certain event combinations
+
+	//attr->branch_sample_type=rand64();
+	//attr->sample_regs_user=rand64();
+	//attr->saple_stack_user=rand();
+
+}
+
+static void create_random_event(struct perf_event_attr *attr) {
+
+	attr->type=random_event_type();
+	attr->config=random_event_config(attr->type);
+	setup_breakpoints(attr);
 
 	switch(rand() % 2) {
 		case 0: attr->size = sizeof(struct perf_event_attr);
@@ -95,9 +375,86 @@ static void sanitise_perf_event_open(int childno)
 		default: break;
 	}
 
-	attr->sample_type = rand() % PERF_SAMPLE_MAX;
-	attr->read_format = rand() % PERF_FORMAT_MAX;
-	attr->exclude_kernel = TRUE;	// FIXME: root-mode
+	attr->sample_type = random_sample_type();
+	attr->read_format = random_read_format();
+
+	/* booleans */
+	attr->exclude_user=rand()%2;
+	attr->exclude_kernel = rand()%2;	/* does't require root unless paranoid set to 2 */
+	attr->exclude_hv = rand()%2;
+}
+
+static void sanitise_perf_event_open(int childno)
+{
+	struct perf_event_attr *attr;
+	unsigned long flags;
+	pid_t pid;
+	int group_fd;
+
+	shm->a1[childno] = (unsigned long) page_rand;
+	attr = (struct perf_event_attr *) shm->a1[childno];
+
+	/* this makes sure we clear out the reserved fields. */
+	memset(page_rand, 0, sizeof(struct perf_event_attr));
+
+	/* cpu */
+	/* requires ROOT to select CPU if paranoid level not 0 */
+	/* -1 means all CPUs */
+	//shm->a3[childno]=cpu;
+	// the default get_cpu() is good enough here
+
+	/* group_fd */
+	/* should usually be -1 or another perf_event fd         */
+	/* Anything but -1 unlikely to work unless the other pid */
+	/* was properly set up to be a group master		 */
+	if (rand()%2) {
+		group_fd=-1;
+	}
+	else {
+		group_fd=get_pid();
+	}
+	shm->a4[childno]=group_fd;
+
+	/* flags */
+	/* You almost never set these unless you're playing with cgroups */
+	flags=0;
+	if (rand()%2) {
+		flags=rand64();
+	} else {
+		if (rand()%2) flags|=PERF_FLAG_FD_NO_GROUP;
+		if (rand()%2) flags|=PERF_FLAG_FD_OUTPUT;
+		if (rand()%2) flags|=PERF_FLAG_PID_CGROUP;
+        }
+	shm->a5[childno]=flags;
+
+	/* pid */
+	/* requires ROOT to select pid that doesn't belong to us */
+	/* pid of 0 means current process */
+	/* pid of -1 means all processes  */
+	pid=0;
+	if (flags&PERF_FLAG_PID_CGROUP) {
+		/* In theory in this case we should pass in */
+		/* a file descriptor from /dev/cgroup       */
+		pid=get_random_fd();
+	}
+	else if (rand()%2) {
+		pid=0;
+	}
+	else {
+		pid=get_pid();
+	}
+	shm->a2[childno]=pid;
+
+
+	/* set up attr structure */
+	switch(rand()%3) {
+		case 0:	create_mostly_valid_counting_event(attr);
+			break;
+		case 1: create_mostly_valid_sampling_event(attr);
+			break;
+		default: create_random_event(attr);
+			break;
+	}
 }
 
 struct syscall syscall_perf_event_open = {

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [patch] Re: a perf_event_open() update
  2013-05-20  3:34   ` [patch] " Vince Weaver
@ 2013-05-21 16:54     ` Dave Jones
  0 siblings, 0 replies; 5+ messages in thread
From: Dave Jones @ 2013-05-21 16:54 UTC (permalink / raw)
  To: Vince Weaver; +Cc: trinity

On Sun, May 19, 2013 at 11:34:53PM -0400, Vince Weaver wrote:
 > 
 > Here's an updated patch that more or less exercises all of the 
 > perf_event_open() bits, up to around the 3.6 kernel or so.
 > 
 > The patch is standalone against current trinity git.
 > 
 > It could definitely use some review and tuning.
 > 
 > I haven't turned up any issues with it, but that's partly because in my 
 > experience (the recent exploit being an exception) perf_event bugs rarely 
 > manifest with just an open call; they usually involve 
 > reads/writes/ioctls/mmaps/signals on the fd that is opened, as well as 
 > problems after fork/exec or else on complex events made of multiple 
 > perf_event_open() calls chained together (the call can take a previously 
 > opened fd as an argument).  Testing things like this will be more 
 > difficult.

Looks ok to me. I applied it after making some whitespace changes.

thanks,

	Dave

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2013-05-21 16:54 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-05-17 15:18 a perf_event_open() update Vince Weaver
2013-05-17 21:20 ` [patch] " Vince Weaver
2013-05-18  1:01 ` Dave Jones
2013-05-20  3:34   ` [patch] " Vince Weaver
2013-05-21 16:54     ` Dave Jones

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).