Skip to content

Commit c7e664c

Browse files
committed
reduce reproducer size
1 parent df58c5f commit c7e664c

File tree

5 files changed

+92
-230
lines changed

5 files changed

+92
-230
lines changed

Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
CC = gcc
1+
CC = clang
22

3-
CFLAGS = -g -O2 -Wall -fPIC -D_GNU_SOURCE=1
3+
CFLAGS = -g -O1 -Wall -fPIC -D_GNU_SOURCE=1 -fstack-protector-strong
44

55
all: libpreload.so libdlns.so run app app-standalone
66

@@ -11,7 +11,7 @@ libdlns.so: dlns.c
1111
$(CC) -o $@ $< $(CFLAGS) -shared -ldl -lpthread -Wl,-soname=dlns,-as-needed
1212

1313
run: run.c
14-
$(CC) -o $@ $^ $(CFLAGS)
14+
$(CC) -o $@ $^ $(CFLAGS)
1515

1616
app: app.c
1717
$(CC) -o $@ $^ $(CFLAGS) -DWITH_DLNS -pthread

app.c

Lines changed: 16 additions & 195 deletions
Original file line numberDiff line numberDiff line change
@@ -1,213 +1,34 @@
11
#include <sys/types.h>
2-
#include <sys/stat.h>
3-
#include <fcntl.h>
42
#include <unistd.h>
53
#include <stdlib.h>
64
#include <string.h>
75
#include <stdio.h>
8-
#include <errno.h>
96
#include <pthread.h>
10-
#include <elf.h>
117
#include <assert.h>
8+
#include <signal.h>
9+
#include <time.h>
1210

13-
typedef int (*getpid_pfn)(void);
14-
struct thread_params {
15-
long thread_id;
16-
getpid_pfn getpid;
17-
};
18-
19-
#ifdef WITH_DLNS
20-
static int ended_with(const char* s, const char* pattern) {
21-
int n = strlen(pattern);
22-
int m = strlen(s);
23-
24-
if (n > m) return 0;
25-
26-
int j = m - 1;
27-
int k = n - 1;
28-
29-
while (k >= 0) {
30-
if(pattern[k--] != s[j--]) {
31-
return 0;
32-
}
33-
}
34-
return 1;
35-
}
36-
37-
static unsigned long resolve(int fd, unsigned long dlstart, const char* sym_name) {
38-
unsigned long off = 0;
39-
40-
Elf64_Ehdr ehdr;
41-
Elf64_Phdr phdr;
42-
Elf64_Phdr* dynamic = NULL;
43-
44-
assert(pread(fd, &ehdr, sizeof(ehdr), off) == sizeof(ehdr));
45-
46-
off += ehdr.e_phoff;
47-
for (int i = 0; i < ehdr.e_phnum; i++) {
48-
assert(pread(fd, &phdr, sizeof(phdr), off) == sizeof(phdr));
49-
off += sizeof(phdr);
50-
if (phdr.p_type == PT_DYNAMIC) {
51-
dynamic = &phdr;
52-
break;
53-
}
54-
}
55-
56-
if (!dynamic) {
57-
fprintf(stderr, "found no dynamic segment");
58-
return -1;
59-
}
60-
61-
unsigned long dyn[64] = {0,};
62-
unsigned long* ptr = (unsigned long*)(dynamic->p_vaddr + dlstart);
63-
64-
while(*ptr) {
65-
if (ptr[0] < 64)
66-
dyn[ptr[0]] = ptr[1];
67-
ptr += 2;
68-
}
69-
70-
const char* strtab = (const char*)dyn[DT_STRTAB];
71-
if (!strtab) {
72-
fprintf(stderr, "found no strtab");
73-
return -1;
74-
}
75-
76-
Elf64_Sym* symtab = (Elf64_Sym*)dyn[DT_SYMTAB];
77-
if (!symtab) {
78-
fprintf(stderr, "found no symtab");
79-
return -1;
80-
}
81-
82-
unsigned long symtab_nb = 1 + dynamic->p_memsz / sizeof(void*);
83-
84-
for (int i = 0; i < symtab_nb; i++) {
85-
const char* name = (const char*)&strtab[symtab[i].st_name];
86-
if (!strcmp(name, sym_name)) {
87-
return symtab[i].st_value + dlstart;
88-
}
89-
}
90-
91-
return -1;
92-
}
93-
94-
unsigned long symbol_resolve(const char* dso, const char* sym) {
95-
int fd;
96-
char* buffer;
97-
98-
unsigned long sym_addr = -1;
99-
100-
fd = open("/proc/self/maps", O_RDONLY);
101-
assert(fd >= 0);
102-
103-
buffer = calloc(1, 8192);
104-
assert(buffer);
105-
106-
ssize_t n = read(fd, buffer, 8192);
107-
assert(n > 0);
108-
109-
char* next = buffer;
110-
char* dso_fullname = NULL;
111-
int found_dlns_dso = 0;
112-
unsigned long dlstart, dlend;
113-
114-
while(1) {
115-
char* curr = strsep(&next, "\n");
116-
if (!curr) break;
117-
118-
char* words = curr;
119-
char* endptr = NULL;
120-
dlstart = strtoul(curr, &endptr, 16);
121-
dlend = strtoul(1 + endptr, &words, 16);
122-
words += 1;
123-
while(1) {
124-
while(words && (words[0] == ' ' || words[0] == '\t'))
125-
++words;
126-
char* wp = strsep(&words, " \t");
127-
if (!wp) break;
128-
if (ended_with(wp, dso)) {
129-
dso_fullname = wp;
130-
found_dlns_dso = 1;
131-
goto found;
132-
}
133-
}
134-
}
135-
136-
found:
137-
close(fd);
138-
139-
if (found_dlns_dso) {
140-
printf("found %s loaded at %lx-%lx\n", dso_fullname, dlstart, dlend);
141-
fd = open(dso_fullname, O_RDONLY);
142-
assert(fd >= 0);
143-
sym_addr = resolve(fd, dlstart, sym);
144-
}
145-
return sym_addr;
11+
static void handle_sigalrm(int sig) {
14612
}
14713

148-
static getpid_pfn resolved_local_getpid = (getpid_pfn)-1;
149-
static pthread_once_t resolve_getpid_once = PTHREAD_ONCE_INIT;
150-
static void resolve_local_getpid(void) {
151-
resolved_local_getpid = (getpid_pfn)symbol_resolve("libdlns.so", "local_getpid");
152-
}
153-
static int local_getpid_real(void) {
154-
pthread_once(&resolve_getpid_once, resolve_local_getpid);
155-
if (resolved_local_getpid != (getpid_pfn)-1) {
156-
return resolved_local_getpid();
157-
}
158-
return 0;
159-
}
160-
161-
#else
162-
extern int local_getpid(void);
163-
static int local_getpid_real(void) {
164-
return local_getpid();
165-
}
166-
#endif
167-
168-
void* threadfn(void* param) {
169-
170-
struct thread_params* tp = (struct thread_params*)param;
171-
172-
pthread_key_t pkey;
173-
unsigned long *data = malloc(sizeof(unsigned long));
174-
assert(data);
175-
176-
*data = 0x1234;
177-
178-
pthread_key_create(&pkey, free);
179-
pthread_setspecific(pkey, data);
180-
181-
fprintf(stderr, "#%lu local_getpid addr = %p\n", tp->thread_id, tp->getpid);
182-
183-
if (tp->getpid != (getpid_pfn)-1UL) {
184-
printf("#%lu local_getpid: %u\n", tp->thread_id, tp->getpid());
185-
printf("#%lu local_getpid: %u\n", tp->thread_id, tp->getpid());
186-
}
187-
188-
printf("#%lu my own tls: %lx\n", tp->thread_id, *(unsigned long*)pthread_getspecific(pkey));
189-
190-
return 0;
14+
void* thread_fn(void* param) {
15+
signal(SIGALRM, handle_sigalrm);
16+
printf("pause = %d\n", pause());
17+
return NULL;
19118
}
19219

19320
int main(int argc, char* argv[]) {
194-
pthread_t threads[4];
21+
pthread_t thread;
22+
23+
pthread_create(&thread, NULL, thread_fn, NULL);
19524

196-
getpid_pfn getpid = (getpid_pfn)local_getpid_real;
197-
struct thread_params params[] = {
198-
{0, getpid},
199-
{1, getpid},
200-
{2, getpid},
201-
{3, getpid},
202-
};
203-
204-
for (int i = 0; i < 4; i++) {
205-
assert(pthread_create(&threads[i], NULL, threadfn, &params[i]) == 0);
206-
}
25+
struct timespec ts = {1, 0};
26+
// NB: this could be racy because no guarantee
27+
// `thread' called pause already
28+
nanosleep(&ts, NULL);
29+
pthread_kill(thread, SIGALRM);
20730

208-
for (int i = 0; i < 4; i++) {
209-
pthread_join(threads[i], NULL);
210-
}
31+
pthread_join(thread, NULL);
21132

21233
return 0;
21334
}

dlns.c

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,36 +11,33 @@
1111
#include <elf.h>
1212
#include <assert.h>
1313

14-
static pthread_key_t local_pkey = -1;
14+
pthread_key_t local_pkey;
1515

16-
static int gettid(void) {
17-
return syscall(SYS_gettid);
18-
}
19-
20-
static void pkey_destroy(void* p)
21-
{
22-
fprintf(stderr, "%u called %s\n", gettid(), __func__);
16+
static __attribute__((noinline)) void pkey_destroy(void* p) {
17+
fprintf(stderr, "called %s\n", __func__);
2318
free(p);
2419
}
2520

26-
int local_getpid(void) {
21+
int pause(void) {
22+
fprintf(stderr, "called pause from dlns\n");
23+
24+
unsigned long* p = calloc(2, sizeof(long));
25+
26+
printf("calloc symbol resolved to %p\n", calloc);
27+
printf("call calloc returned %p\n", p);
2728

28-
if (pthread_getspecific(local_pkey) == NULL) {
29-
unsigned long* data = malloc(sizeof(unsigned long));
30-
assert(data);
31-
pthread_setspecific(local_pkey, data);
32-
*data = gettid();
33-
}
29+
p[0] = 0x1234;
30+
p[1] = 0x5678;
3431

35-
unsigned long* cached = pthread_getspecific(local_pkey);
36-
assert(cached);
37-
return *cached;
32+
printf("free resolved to %p\n", free);
33+
34+
pthread_key_create(&local_pkey, pkey_destroy);
35+
pthread_setspecific(local_pkey, p);
36+
37+
return syscall(SYS_pause);
3838
}
3939

4040
__attribute__((constructor)) int dlns_init(void) {
4141
fprintf(stderr, "dlns_init\n");
42-
43-
assert(pthread_key_create(&local_pkey, pkey_destroy) == 0);
44-
4542
return 0;
4643
}

preload.c

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
/**
22
* a mini-loader to load dso into new linker namespace
33
*/
4-
4+
#include <sys/types.h>
5+
#include <sys/sysinfo.h>
6+
#include <sys/mman.h>
57
#include <link.h>
68
#include <stdlib.h>
79
#include <dlfcn.h>
810
#include <stdio.h>
911
#include <assert.h>
12+
#include <errno.h>
13+
#include <string.h>
1014

1115
static void dump_link_map(struct link_map* map) {
1216
struct link_map* curr = map;
@@ -18,6 +22,21 @@ static void dump_link_map(struct link_map* map) {
1822
}
1923
}
2024

25+
static void* dlns_handle;
26+
27+
typedef int (*pause_pfn)(void);
28+
29+
// exposed LD_PRELOAD
30+
int pause(void) {
31+
fprintf(stderr, "called pause.\n");
32+
33+
// call pause from new the lmid
34+
pause_pfn dlns_pause = dlsym(dlns_handle, "pause");
35+
assert(dlns_pause);
36+
37+
return dlns_pause();
38+
}
39+
2140
__attribute__((constructor)) int dl_start(void)
2241
{
2342
char* dso = secure_getenv("DLNS");
@@ -27,13 +46,15 @@ __attribute__((constructor)) int dl_start(void)
2746
}
2847

2948
fprintf(stderr, "open %s\n", dso);
30-
void* link_map = dlmopen(LM_ID_NEWLM, dso, RTLD_NOW | RTLD_LOCAL);
49+
void* link_map = dlmopen(LM_ID_NEWLM, dso, RTLD_LAZY | RTLD_LOCAL);
3150
if (!link_map) {
3251
fprintf(stderr, "dlmopen %s failed: %s\n", dso, dlerror());
3352
return -1;
3453
}
3554

3655
dump_link_map(link_map);
3756

57+
dlns_handle = (void*)link_map;
58+
3859
return 0;
3960
}

0 commit comments

Comments
 (0)