catalinux / srh (public) (License: GPLv3) (since 2016-02-04) (hash sha1)
srh = Stop Row Hammer
Try to stop the row hammer attacks. It is a work in progress.
List of commits:
Subject Hash Author Date (UTC)
Checkpoint f38914356d8e28188130a3aec2d1a4982979ab88 Catalin(ux) M. BOIE 2015-03-17 20:56:10
Checkpoint 41f58214060ec445e871366111c68ee150412c79 Catalin(ux) M. BOIE 2015-03-16 17:46:50
Checkpoint - I am able to detect attack1! 6d5349c93a2a5412fa4b6382056c2378e8d2ecb4 Catalin(ux) M. BOIE 2015-03-15 22:44:59
Checkpoint before using mmap 91d01917a463f031770ea08cec9a50f6a5ac5708 Catalin(ux) M. BOIE 2015-03-14 22:27:15
First version fe8b5ebc6a823d2045bce201a9638283db2c6ead Catalin(ux) M. BOIE 2015-03-12 17:58:12
Commit f38914356d8e28188130a3aec2d1a4982979ab88 - Checkpoint
Author: Catalin(ux) M. BOIE
Author date (UTC): 2015-03-17 20:56
Committer name: Catalin(ux) M. BOIE
Committer date (UTC): 2015-03-17 20:56
Parent(s): 41f58214060ec445e871366111c68ee150412c79
Signing key:
Tree: 593a7e9f02f3bf5edebc5caf8b20f5b481faf916
File Lines added Lines deleted
Makefile 5 1
attack2.c 25 0
srhd.c 320 48
File Makefile changed (mode: 100644) (index b6e9d5f..3266901)
1 TARGETS := srhd attack1 attack1b
1 TARGETS := srhd attack1 attack1b attack2
2 2
3 3 CFLAGS := -g -Wall -Wextra -pipe CFLAGS := -g -Wall -Wextra -pipe
4 4
 
... ... srhd: srhd.c
9 9
10 10 attack1: attack1.c attack1: attack1.c
11 11 $(CC) $(CFLAGS) -O0 $@.c -o $@ $(CC) $(CFLAGS) -O0 $@.c -o $@
12
12 13 attack1b: attack1b.c attack1b: attack1b.c
13 14 $(CC) $(CFLAGS) -O0 $@.c -o $@ $(CC) $(CFLAGS) -O0 $@.c -o $@
14 15
16 attack2: attack2.c
17 $(CC) $(CFLAGS) -O0 $@.c -o $@
18
15 19
16 20 .PHONY: clean .PHONY: clean
17 21 clean: clean:
File attack2.c added (mode: 100644) (index 0000000..517db29)
1 /*
2 * This one access TWO locations to see what perf counters report to me
3 */
4
5 #include <stdio.h>
6 #include <sys/types.h>
7 #include <unistd.h>
8
9 static int k[4096];
10
11 int main(void)
12 {
13 int i, j;
14
15 fprintf(stderr, "my pid is %d\n", getpid());
16
17 for (i = 0; i < 100 * 1000 * 1000; i++) {
18 asm volatile("clflush (%0)" : : "r" (&k[0]) : "memory");
19 j = k[0];
20 asm volatile("clflush (%0)" : : "r" (&k[4095]) : "memory");
21 j = k[4095];
22 }
23
24 return 0;
25 }
File srhd.c changed (mode: 100644) (index 4af0777..e3414ce)
1 /*
2 * Stop Row Hammer
3 * Copyright: Catalin(ux) M. BOIE
4 * After an idea found on Project Zero Google site
5 * (http://googleprojectzero.blogspot.ro/2015/03/exploiting-dram-rowhammer-bug-to-gain.html)
6 *
7 * TODO: investigate PERF_TYPE_BREAKPOINT
8 */
9
1 10 #include <stdlib.h> #include <stdlib.h>
2 11 #include <stdio.h> #include <stdio.h>
3 12 #include <unistd.h> #include <unistd.h>
 
11 20 #include <asm/unistd.h> #include <asm/unistd.h>
12 21 #include <sys/epoll.h> #include <sys/epoll.h>
13 22 #include <signal.h> #include <signal.h>
23 #include <sys/time.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27
28 #define MISSES_SUSPEND_TRIGGER 20000 /* How many events will trigger a suspend */
29 #define MISS_TRIGGER 10000 /* How many perf counts events will trigger an epoll wakeup */
30 #define PENALTY_TIME 100 /* how much time to suspend the process (in milliseconds) */
31 #define MMAP_BUF_SIZE 1 /* in pages */
32 #define PID_HASH_SIZE 128
14 33
15 34 #define barrier() asm volatile ("" ::: "memory") #define barrier() asm volatile ("" ::: "memory")
16 35
17 #define MMAP_BUF_SIZE 8 /* in pages */
36 /* This tructure will keep track of suspect pids */
37 struct pid_cell
38 {
39 int pid;
40 struct pid_cell *next;
41 struct pid_cell *next_in_queue; /* used for suspend queue */
42 unsigned long misses; /* how many misses this process got */
43 unsigned int suspends; /* how many suspends this pid got */
44 struct timeval start;
45 struct timeval wake;
46 unsigned int uid;
47 char cmd[128];
48 };
49 static struct pid_cell *pid_hash[PID_HASH_SIZE];
50
51 /* Queue that will store the entries that will need unblocking */
52 static struct pid_cell *queue_head, *queue_tail;
53
54 static unsigned long page_size;
55
18 56
19 static unsigned long page_size;
57 /*
58 * Difference in milliseconds between two timeval structures
59 */
60 static long time_diff(const struct timeval *t1, const struct timeval *t2)
61 {
62 return (t1->tv_sec - t2->tv_sec) * 1000
63 + (t1->tv_usec - t2->tv_usec) / 1000;
64 }
20 65
21 66 static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid, static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
22 67 int cpu, int group_fd, unsigned long flags) int cpu, int group_fd, unsigned long flags)
 
... ... static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
24 69 return syscall(__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags); return syscall(__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags);
25 70 } }
26 71
27 // TODO: investigate PERF_TYPE_BREAKPOINT
72 /*
73 * Lookup proc info
74 */
75 static void lookup_proc_info(struct pid_cell *p)
76 {
77 struct stat S;
78 char path[128];
79 int fd;
80 ssize_t n;
81
82 snprintf(path, sizeof(path), "/proc/%d/cmdline", p->pid);
83 if (stat(path, &S) != 0)
84 return;
85
86 fd = open(path, O_RDONLY);
87 if (fd != -1) {
88 n = read(fd, p->cmd, sizeof(p->cmd) - 1);
89 if (n > 0) {
90 int i;
91
92 for (i = 0; i < n; i++) {
93 if (p->cmd[i] == '\0')
94 p->cmd[i] = ' ';
95 }
96 p->cmd[n] = '\0';
97 }
98 close(fd);
99 }
100
101 p->uid = S.st_uid;
102 }
103
104 /*
105 * Suspends a pid
106 */
107 static void pid_suspend(const struct timeval *now, struct pid_cell *p)
108 {
109 int r;
110
111 /* I will not block myself */
112 if (p->pid == getpid())
113 return;
114
115 /* We do not block root processes */
116 if (p->uid == 0)
117 return;
118
119 /* TODO */
120 if (p->uid != 503)
121 return;
122
123 r = kill(p->pid, SIGSTOP);
124 if (r != 0)
125 fprintf(stderr, "Cannot suspend pid: %s!\n", strerror(errno));
126
127 fprintf(stderr, "Suspended pid %d (uid %u) [%s]...\n",
128 p->pid, p->uid, p->cmd);
129
130 p->suspends++;
131 p->wake = *now;
132 if (p->wake.tv_usec > 1000000 - PENALTY_TIME) {
133 p->wake.tv_sec++;
134 p->wake.tv_usec = 1000000 - p->wake.tv_usec + PENALTY_TIME;
135 } else {
136 p->wake.tv_usec += PENALTY_TIME;
137 }
138
139 /* To be able to resume it, add it to the resume queue */
140 if (queue_head == NULL)
141 queue_head = p;
142 else
143 queue_tail->next_in_queue = p;
144 queue_tail = p;
145 }
146
147 /*
148 * Un-suspends a pid
149 */
150 static void pid_unsuspend(struct pid_cell *p)
151 {
152 int r;
153
154 fprintf(stderr, "Un-suspend pid %d (uid %u) [%s]...\n",
155 p->pid, p->uid, p->cmd);
156
157 r = kill(p->pid, SIGCONT);
158 if (r != 0)
159 fprintf(stderr, "Cannot un-suspend pid: %s!\n", strerror(errno));
160
161 p->start.tv_sec = 0;
162 p->start.tv_usec = 0;
163 p->misses = 0;
164 }
165
166 /*
167 * Adds a pid to suspect list, and suspend it if needed
168 */
169 static void pid_hash_add(const int pid)
170 {
171 unsigned int i;
172 struct pid_cell *p, *q;
173 struct timeval now;
174 float misses_per_second;
175 int diff;
176
177 i = pid % PID_HASH_SIZE;
178
179 /* First, search for it */
180 q = pid_hash[i];
181 while (q) {
182 if (q->pid == pid)
183 break;
184
185 q = q->next;
186 }
187
188 gettimeofday(&now, NULL);
189
190 if (q) {
191 /* Found an old entry */
192 q->misses += MISS_TRIGGER;
193
194 if (q->start.tv_sec == 0) {
195 q->start = now;
196 return;
197 }
198
199 /* Compute the number of misses per second */
200 diff = time_diff(&now, &q->start);
201 misses_per_second = q->misses;
202 misses_per_second /= diff;
203 misses_per_second *= 1000; /* ms -> s */
204
205 /* its time to look-up proc info */
206 if (q->uid == 0x0FFFFFFF)
207 lookup_proc_info(q);
208
209 if (strstr(q->cmd, "attack2"))
210 fprintf(stderr, "attack2: [%s] diff=%dms misses=%lu mps=%.3f\n",
211 q->cmd, diff, q->misses, misses_per_second);
212
213 if (misses_per_second > MISSES_SUSPEND_TRIGGER) {
214 fprintf(stderr, "pid %d [%s] has %.3f/s score (diff=%dms misses=%lu\n",
215 q->pid, q->cmd, misses_per_second, diff, q->misses);
216 pid_suspend(&now, q);
217 return;
218 }
219 }
220
221 /* Add it to the hash */
222 p = malloc(sizeof(struct pid_cell));
223 if (!p)
224 return;
225
226 p->pid = pid;
227 p->next = NULL;
228 p->next_in_queue = NULL;
229 p->start = now;
230 p->misses = 0;
231 p->uid = 0x0FFFFFFF;
232 strcpy(p->cmd, "?");
233
234 if (pid_hash[i] == NULL) {
235 pid_hash[i] = p;
236 } else {
237 q = pid_hash[i];
238 while (q->next)
239 q = q->next;
240
241 q->next = p;
242 }
243 }
28 244
29 245 /* /*
30 246 * Registers a counter * Registers a counter
 
... ... static int register_event(const unsigned int cpu, const __u32 type,
42 258 | PERF_SAMPLE_ADDR | PERF_SAMPLE_ADDR
43 259 | PERF_SAMPLE_PERIOD | PERF_SAMPLE_PERIOD
44 260 | PERF_SAMPLE_CPU; | PERF_SAMPLE_CPU;
45 attr.sample_period = 1000;
261 attr.sample_period = MISS_TRIGGER;
46 262 //attr.enable_on_exec = 1; //attr.enable_on_exec = 1;
47 263 attr.disabled = 0; attr.disabled = 0;
48 264 attr.exclude_kernel = 1; attr.exclude_kernel = 1;
 
... ... static int register_event(const unsigned int cpu, const __u32 type,
73 289 return fd; return fd;
74 290 } }
75 291
292 /*
293 * Increments q with @inc, taking in consideration the wrap around
294 */
295 static inline void q_inc(void *m, void **q, const unsigned int inc)
296 {
297 void *old_q = *q;
298 int diff;
299
300 diff = (*q + inc) - (m + (1 + MMAP_BUF_SIZE) * page_size);
301 if (diff >= 0)
302 *q = m + page_size;
303 else
304 *q = *q + inc;
305
306 #if 0
307 fprintf(stderr, "\tm=%p *q=%p -> *q=%p inc=%u\n",
308 m, old_q, *q, inc);
309 #endif
310 }
311
76 312 /* /*
77 313 * Checking if any process is on the wrong side * Checking if any process is on the wrong side
78 314 * Returns the ?TODO * Returns the ?TODO
 
... ... static int check(void *m)
101 337 barrier(); barrier();
102 338 } while (mp->lock != seq); } while (mp->lock != seq);
103 339
104 head %= MMAP_BUF_SIZE * page_size;
105 tail %= MMAP_BUF_SIZE * page_size;
106
340 #if 0
107 341 fprintf(stderr, "version=%u index=%u count=%llu" fprintf(stderr, "version=%u index=%u count=%llu"
108 " head=%llu tail=%llu\n",
109 version, index, count, head, tail);
342 " head=%llu(%llu) tail=%llu(%llu)\n",
343 version, index, count,
344 head, head % (MMAP_BUF_SIZE * page_size),
345 tail, tail % (MMAP_BUF_SIZE * page_size));
346 #endif
110 347
111 348 /* Dump rest of buffers */ /* Dump rest of buffers */
112 p = m + page_size + tail;
113 349 rest = head - tail; rest = head - tail;
114 350 while (rest > 0) { while (rest > 0) {
351 p = m + page_size + tail % (MMAP_BUF_SIZE * page_size);
352 //fprintf(stderr, "\trest=%llu p=%p\n", rest, p);
115 353 q = p; q = p;
116 354 h = q; h = q;
117 fprintf(stderr, "\th: type=%u misc=%hu size=%hu rest=%llu\n",
118 h->type, h->misc, h->size, rest);
355 #if 0
356 fprintf(stderr, "\th: type=%u misc=%hu size=%hu\n",
357 h->type, h->misc, h->size);
358 #endif
119 359 q += sizeof(struct perf_event_header); q += sizeof(struct perf_event_header);
120 360
121 361 switch (h->type) { switch (h->type) {
122 362 case PERF_RECORD_MMAP: case PERF_RECORD_MMAP:
123 p_pid = q; q += 4;
124 p_tid = q; q += 4;
125 p_addr = q; q += 8;
126 p_len = q; q += 8;
127 p_pgoff = q; q += 8;
363 p_pid = q; q_inc(m, &q, 4);
364 p_tid = q; q_inc(m, &q, 4);
365 p_addr = q; q_inc(m, &q, 8);
366 p_len = q; q_inc(m, &q, 8);
367 p_pgoff = q; q_inc(m, &q, 8);
128 368 filename = q; filename = q;
129 369 fprintf(stderr, "\tmmap pid=%u tid=%u addr=%llx" fprintf(stderr, "\tmmap pid=%u tid=%u addr=%llx"
130 370 " len=%llu pgoff=%llx filename=%s.\n", " len=%llu pgoff=%llx filename=%s.\n",
 
... ... static int check(void *m)
133 373 break; break;
134 374
135 375 case PERF_RECORD_SAMPLE: case PERF_RECORD_SAMPLE:
136 p_ip = q; q += 8;
137 p_pid = q; q += 4;
138 p_tid = q; q += 4;
139 p_addr = q; q += 8;
140 p_cpu = q; q += 8;
141 p_period = q; q += 8;
376 p_ip = q; q_inc(m, &q, 8);
377 p_pid = q; q_inc(m, &q, 4);
378 p_tid = q; q_inc(m, &q, 4);
379 p_addr = q; q_inc(m, &q, 8);
380 p_cpu = q; q_inc(m, &q, 8);
381 p_period = q; q_inc(m, &q, 8);
382 #if 0
142 383 fprintf(stderr, "\tsample ip=0x%llx pid=%u" fprintf(stderr, "\tsample ip=0x%llx pid=%u"
143 384 " tid=%u addr=%llx period=%llu cpu=%u\n", " tid=%u addr=%llx period=%llu cpu=%u\n",
144 385 *p_ip, *p_pid, *p_tid, *p_addr, *p_period, *p_cpu); *p_ip, *p_pid, *p_tid, *p_addr, *p_period, *p_cpu);
386 #endif
387 pid_hash_add(*p_pid);
145 388 break; break;
146 389
147 390 case PERF_RECORD_EXIT: case PERF_RECORD_EXIT:
148 p_pid = q; q += 4;
149 p_ppid = q; q += 4;
150 p_tid = q; q += 4;
151 p_ptid = q; q += 4;
152 p_time = q; q += 8;
391 p_pid = q; q_inc(m, &q, 4);
392 p_ppid = q; q_inc(m, &q, 4);
393 p_tid = q; q_inc(m, &q, 4);
394 p_ptid = q; q_inc(m, &q, 4);
395 p_time = q; q_inc(m, &q, 8);
153 396 fprintf(stderr, "\texit pid=%u ppid=%u tid=%u" fprintf(stderr, "\texit pid=%u ppid=%u tid=%u"
154 397 " ptid=%u time=%llu\n", " ptid=%u time=%llu\n",
155 398 *p_pid, *p_ppid, *p_tid, *p_ptid, *p_pid, *p_ppid, *p_tid, *p_ptid,
 
... ... static int check(void *m)
157 400 break; break;
158 401
159 402 case PERF_RECORD_COMM: case PERF_RECORD_COMM:
160 p_pid = q; q += 4;
161 p_tid = q; q += 4;
403 p_pid = q; q_inc(m, &q, 4);
404 p_tid = q; q_inc(m, &q, 4);
162 405 comm = q; comm = q;
163 406 fprintf(stderr, "\tcomm pid=%u tid=%u comm=%s\n", fprintf(stderr, "\tcomm pid=%u tid=%u comm=%s\n",
164 407 *p_pid, *p_tid, comm); *p_pid, *p_tid, comm);
165 408 break; break;
166 409
167 410 case PERF_RECORD_MMAP2: case PERF_RECORD_MMAP2:
168 p_pid = q; q += 4;
169 p_tid = q; q += 4;
170 p_addr = q; q += 8;
171 p_len = q; q += 8;
172 p_pgoff = q; q += 8;
173 q += 4; /* maj */
174 q += 4; /* min */
175 q += 8; /* ino */
176 q += 8; /* ino_generation */
177 q += 4; /* prot */
178 q += 4; /* flags */
411 p_pid = q; q_inc(m, &q, 4);
412 p_tid = q; q_inc(m, &q, 4);
413 p_addr = q; q_inc(m, &q, 8);
414 p_len = q; q_inc(m, &q, 8);
415 p_pgoff = q; q_inc(m, &q, 8);
416 q_inc(m, &q, 4); /* maj */
417 q_inc(m, &q, 4); /* min */
418 q_inc(m, &q, 8); /* ino */
419 q_inc(m, &q, 8); /* ino_generation */
420 q_inc(m, &q, 4); /* prot */
421 q_inc(m, &q, 4); /* flags */
179 422 filename = p; filename = p;
180 423 fprintf(stderr, "\tmmap pid=%u tid=%u addr=%llx" fprintf(stderr, "\tmmap pid=%u tid=%u addr=%llx"
181 424 " len=%llu pgoff=%llx filename=%s.\n", " len=%llu pgoff=%llx filename=%s.\n",
 
... ... static int check(void *m)
184 427 break; break;
185 428
186 429 case PERF_RECORD_FORK: case PERF_RECORD_FORK:
187 p_pid = q; q += 4;
188 p_ppid = q; q += 4;
189 p_tid = q; q += 4;
190 p_ptid = q; q += 4;
191 p_time = q; q += 8;
430 p_pid = q; q_inc(m, &q, 4);
431 p_ppid = q; q_inc(m, &q, 4);
432 p_tid = q; q_inc(m, &q, 4);
433 p_ptid = q; q_inc(m, &q, 4);
434 p_time = q; q_inc(m, &q, 8);
192 435 fprintf(stderr, "\tfork pid=%u ppid=%u tid=%u" fprintf(stderr, "\tfork pid=%u ppid=%u tid=%u"
193 436 " ptid=%u time=%llu\n", " ptid=%u time=%llu\n",
194 437 *p_pid, *p_ppid, *p_tid, *p_ptid, *p_pid, *p_ppid, *p_tid, *p_ptid,
 
... ... static int check(void *m)
199 442 fprintf(stderr, "\tUnknown type %u\n", h->type); fprintf(stderr, "\tUnknown type %u\n", h->type);
200 443 break; break;
201 444 } }
202 p += h->size;
445 tail += h->size;
203 446 rest -= h->size; rest -= h->size;
204 447 } }
205 448 mp->data_tail = head; mp->data_tail = head;
 
... ... int main(void)
213 456 int fd1, fd2[2], nr_cpus, r, efd, i, fd; int fd1, fd2[2], nr_cpus, r, efd, i, fd;
214 457 void *m1, *m2[2]; void *m1, *m2[2];
215 458 struct epoll_event ee; struct epoll_event ee;
459 struct pid_cell *p, *prev;
460 struct timeval now;
461 int next_wake, diff;
216 462
217 463 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
218 464 fprintf(stderr, "%d cpu(s) online.\n", nr_cpus); fprintf(stderr, "%d cpu(s) online.\n", nr_cpus);
 
... ... int main(void)
220 466 page_size = sysconf(_SC_PAGE_SIZE); page_size = sysconf(_SC_PAGE_SIZE);
221 467 fprintf(stderr, "page size is %lu\n", page_size); fprintf(stderr, "page size is %lu\n", page_size);
222 468
469 memset(pid_hash, 0, sizeof(pid_hash));
470
223 471 /* TODO: move to 99? */ /* TODO: move to 99? */
224 472 param.sched_priority = 1; param.sched_priority = 1;
225 473 if (sched_setscheduler(0, SCHED_FIFO, &param)) { if (sched_setscheduler(0, SCHED_FIFO, &param)) {
 
... ... int main(void)
264 512 //ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0); //ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0);
265 513
266 514 while (1) { while (1) {
267 r = epoll_wait(efd, &ee, 1, 1000);
515 next_wake = -1;
516 if (queue_head) {
517 gettimeofday(&now, NULL);
518 next_wake = time_diff(&queue_head->wake, &now);
519 }
520 r = epoll_wait(efd, &ee, 1, next_wake);
268 521 if (r == -1) { if (r == -1) {
269 522 if (errno == EINTR) if (errno == EINTR)
270 523 continue; continue;
 
... ... int main(void)
273 526 return 1; return 1;
274 527 } }
275 528
529 /* Process suspend queue */
530 gettimeofday(&now, NULL);
531 p = queue_head;
532 prev = NULL;
533 while (p) {
534 diff = time_diff(&p->wake, &now);
535 fprintf(stderr, "Q: p=%p diff=%ums\n", p, diff);
536 if (diff <= 0) {
537 pid_unsuspend(p);
538 if (prev)
539 prev->next_in_queue = p->next_in_queue;
540 else
541 queue_head = p->next_in_queue;
542 }
543 prev = p;
544 p = p->next_in_queue;
545 }
546 queue_tail = prev;
547
276 548 if (r == 0) if (r == 0)
277 549 continue; continue;
278 550
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/catalinux/srh

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/catalinux/srh

Clone this repository using git:
git clone git://git.rocketgit.com/user/catalinux/srh

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main