~james/scope

ref: 3cec21766d164acbbd612dabbfa0ad045d6f4cf8 scope/test/native.c -rw-r--r-- 4.2 KiB
3cec2176 — james test(xen): inject native failures and verify watch evidence retention 14 days ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#include <xenctrl.h>
#include <xenforeignmemory.h>
#include <xentoollog.h>
#include <xen/hvm/save.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>

static int references;
static int calls;
static int samples;

static int failing(const char *name) {
  const char *failure = getenv("SCOPE_TEST_FAILURE");
  return failure && strcmp(failure, name) == 0;
}

static void record(const char *name) {
  const char *path = getenv("SCOPE_TEST_LOG");
  if (!path) abort();
  FILE *stream = fopen(path, "a");
  if (!stream) abort();
  fprintf(stream, "%s %d\n", name, references);
  if (fclose(stream)) abort();
}

static void diagnostic(xentoollog_logger *logger, const char *format, ...) {
  va_list arguments;
  va_start(arguments, format);
  if (logger) logger->vmessage(logger, XTL_ERROR, EACCES, "mock", format, arguments);
  else vfprintf(stderr, format, arguments);
  va_end(arguments);
}

xc_interface *xc_interface_open(xentoollog_logger *logger, xentoollog_logger *builder, unsigned flags) {
  (void)logger; (void)builder; (void)flags;
  references = getenv("SCOPE_TEST_PAUSED") ? 1 : 0;
  calls = 0;
  samples++;
  record("open");
  if (failing("logged")) { diagnostic(logger, "mock diagnostic\n"); return NULL; }
  return failing("open") ? NULL : (xc_interface *)1;
}

int xc_interface_close(xc_interface *control) {
  (void)control;
  record("close");
  return 0;
}

int xc_domain_getinfolist(xc_interface *control, uint32_t domain, unsigned count, xc_domaininfo_t *info) {
  (void)control; (void)count;
  calls++;
  if (failing("info")) return -1;
  memset(info, 0, sizeof(*info));
  info->domain = domain;
  info->max_vcpu_id = 3;
  info->flags = XEN_DOMINF_hvm_guest | (references ? XEN_DOMINF_paused : 0);
  if (failing("identity") && calls > 2) info->handle[0] = 1;
  return 1;
}

int xc_domain_pause(xc_interface *control, uint32_t domain) {
  (void)control; (void)domain;
  if (failing("pause")) return -1;
  references++;
  record("pause");
  if (failing("opensignal")) raise(SIGTERM);
  return 0;
}

int xc_domain_unpause(xc_interface *control, uint32_t domain) {
  (void)control; (void)domain;
  if (failing("unpause")) { record("unpausefailed"); return -1; }
  references--;
  record("unpause");
  return references < 0 ? -1 : 0;
}

int xc_domain_hvm_getcontext_partial(xc_interface *control, uint32_t domain, uint16_t type,
                                    uint16_t instance, void *buffer, uint32_t size) {
  (void)control; (void)domain; (void)type; (void)instance;
  record("registers");
  if (failing("signal")) raise(SIGTERM);
  if (failing("registers")) return -1;
  if (size < sizeof(struct hvm_hw_cpu)) abort();
  struct hvm_hw_cpu *cpu = buffer;
  memset(cpu, 0, sizeof(*cpu));
  cpu->cr0 = 0x80010001;
  cpu->cr3 = 0x1000;
  if (getenv("SCOPE_TEST_WATCH") && samples >= 4) cpu->cr3 = 0x6000;
  cpu->cr4 = 0x20;
  cpu->msr_efer = 0xd00;
  cpu->rflags = 2;
  return 0;
}

xenforeignmemory_handle *xenforeignmemory_open(struct xentoollog_logger *logger, unsigned flags) {
  (void)logger; (void)flags;
  record("foreignopen");
  return failing("foreignopen") ? NULL : (xenforeignmemory_handle *)2;
}

int xenforeignmemory_close(xenforeignmemory_handle *memory) {
  (void)memory;
  record("foreignclose");
  return 0;
}

void *xenforeignmemory_map(xenforeignmemory_handle *memory, uint32_t domain, int protection,
                           size_t count, const xen_pfn_t *frames, int *errors) {
  (void)memory; (void)domain; (void)protection;
  record("map");
  if (count != 1) abort();
  if (failing("map")) { errno = EACCES; return NULL; }
  uint64_t *page = calloc(512, sizeof(*page));
  if (!page) abort();
  *errors = failing("page") ? EACCES : 0;
  switch (frames[0]) {
    case 1: case 6: page[0] = 0x2007; break;
    case 2: page[0] = 0x3007; break;
    case 3: page[2] = 0x4001; page[4] = 0x5003; break;
    case 4: page[0] = 0x9003; break;
    case 5: page[0] = getenv("SCOPE_TEST_WATCH") && samples >= 2 ? 0x800000000000a003ull : 0x8000000000009003ull; break;
    default: free(page); errno = ENOENT; return NULL;
  }
  return page;
}

int xenforeignmemory_unmap(xenforeignmemory_handle *memory, void *address, size_t count) {
  (void)memory; (void)count;
  record("unmap");
  if (failing("unmap")) return -1;
  free(address);
  return 0;
}