Skip to content

Commit 3605857

Browse files
committed
improve: companion handler fd closing; fix: PIPE signal handling (#103)
This commit improves how we decide to close the fd that connects the injected module with the companion, avoiding both double close and fd leaks.
1 parent b0a296f commit 3605857

6 files changed

Lines changed: 90 additions & 93 deletions

File tree

zygiskd/src/.gitignore

Lines changed: 0 additions & 2 deletions
This file was deleted.

zygiskd/src/companion.c

Lines changed: 47 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <dlfcn.h>
88
#include <errno.h>
99
#include <fcntl.h>
10+
#include <signal.h>
1011

1112
#include <unistd.h>
1213
#include <linux/limits.h>
@@ -17,6 +18,9 @@
1718
#include "dl.h"
1819
#include "utils.h"
1920

21+
#undef LOG_TAG
22+
#define LOG_TAG lp_select("zygiskd-companion32", "zygiskd-companion64")
23+
2024
typedef void (*zygisk_companion_entry)(int);
2125

2226
struct companion_module_thread_args {
@@ -28,12 +32,23 @@ zygisk_companion_entry load_module(int fd) {
2832
char path[PATH_MAX];
2933
snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
3034

31-
void *handle = android_dlopen(path, RTLD_NOW);
35+
void *handle = dlopen_ext(path, RTLD_NOW);
36+
37+
if (!handle) return NULL;
38+
3239
void *entry = dlsym(handle, "zygisk_companion_entry");
40+
if (!entry) {
41+
LOGE("Failed to dlsym zygisk_companion_entry: %s\n", dlerror());
42+
43+
dlclose(handle);
44+
45+
return NULL;
46+
}
3347

3448
return (zygisk_companion_entry)entry;
3549
}
3650

51+
/* WARNING: Dynamic memory based */
3752
void *entry_thread(void *arg) {
3853
struct companion_module_thread_args *args = (struct companion_module_thread_args *)arg;
3954

@@ -42,7 +57,7 @@ void *entry_thread(void *arg) {
4257

4358
struct stat st0 = { 0 };
4459
if (fstat(fd, &st0) == -1) {
45-
LOGE("Failed to get initial client fd stats: %s\n", strerror(errno));
60+
LOGE(" - Failed to get initial client fd stats: %s\n", strerror(errno));
4661

4762
free(args);
4863

@@ -56,14 +71,10 @@ void *entry_thread(void *arg) {
5671
if the module companion already closed the fd.
5772
*/
5873
struct stat st1;
59-
if (fstat(fd, &st1) == 0) {
60-
if (st0.st_dev == st1.st_dev && st0.st_ino == st1.st_ino) {
61-
LOGI("Client fd stats unchanged. Closing.\n");
74+
if (fstat(fd, &st1) != -1 || st0.st_ino == st1.st_ino) {
75+
LOGI(" - Client fd changed after module entry\n");
6276

63-
close(fd);
64-
} else {
65-
LOGI("Client fd stats changed, assuming module handled closing.\n");
66-
}
77+
close(fd);
6778
}
6879

6980
free(args);
@@ -80,10 +91,7 @@ void companion_entry(int fd) {
8091
if (ret == -1) {
8192
LOGE("Failed to read module name\n");
8293

83-
/* TODO: Is that appropriate? */
84-
close(fd);
85-
86-
exit(0);
94+
goto cleanup;
8795
}
8896

8997
LOGI(" - Module name: \"%s\"\n", name);
@@ -92,10 +100,7 @@ void companion_entry(int fd) {
92100
if (library_fd == -1) {
93101
LOGE("Failed to receive library fd\n");
94102

95-
/* TODO: Is that appropriate? */
96-
close(fd);
97-
98-
exit(0);
103+
goto cleanup;
99104
}
100105

101106
LOGI(" - Library fd: %d\n", library_fd);
@@ -109,26 +114,33 @@ void companion_entry(int fd) {
109114
ret = write_uint8_t(fd, 0);
110115
ASSURE_SIZE_WRITE("ZygiskdCompanion", "module_entry", ret, sizeof(uint8_t));
111116

112-
exit(0);
117+
goto cleanup;
113118
} else {
114119
LOGI(" - Module entry found\n");
115120

116121
ret = write_uint8_t(fd, 1);
117122
ASSURE_SIZE_WRITE("ZygiskdCompanion", "module_entry", ret, sizeof(uint8_t));
118123
}
119124

125+
struct sigaction sa;
126+
memset(&sa, 0, sizeof(sa));
127+
128+
sigemptyset(&sa.sa_mask);
129+
sa.sa_handler = SIG_IGN;
130+
sigaction(SIGPIPE, &sa, NULL);
131+
120132
while (1) {
121133
if (!check_unix_socket(fd, true)) {
122134
LOGE("Something went wrong in companion. Bye!\n");
123135

124-
exit(0);
136+
break;
125137
}
126138

127139
int client_fd = read_fd(fd);
128140
if (client_fd == -1) {
129141
LOGE("Failed to receive client fd\n");
130142

131-
exit(0);
143+
break;
132144
}
133145

134146
struct companion_module_thread_args *args = malloc(sizeof(struct companion_module_thread_args));
@@ -137,7 +149,7 @@ void companion_entry(int fd) {
137149

138150
close(client_fd);
139151

140-
exit(0);
152+
break;
141153
}
142154

143155
args->fd = client_fd;
@@ -149,9 +161,20 @@ void companion_entry(int fd) {
149161
ASSURE_SIZE_WRITE("ZygiskdCompanion", "client_fd", ret, sizeof(uint8_t));
150162

151163
pthread_t thread;
152-
pthread_create(&thread, NULL, entry_thread, args);
153-
pthread_detach(thread);
164+
if (pthread_create(&thread, NULL, entry_thread, (void *)args) == 0)
165+
continue;
166+
167+
LOGE(" - Failed to create thread for companion module\n");
154168

155-
LOGI(" - Spawned companion thread for client fd: %d\n", client_fd);
169+
close(client_fd);
170+
free(args);
171+
172+
break;
156173
}
174+
175+
cleanup:
176+
close(fd);
177+
LOGE("Companion thread exited\n");
178+
179+
exit(0);
157180
}

zygiskd/src/dl.c

Lines changed: 27 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -11,77 +11,47 @@
1111
#include <stdint.h>
1212

1313
#include <android/log.h>
14+
#include <android/dlext.h>
1415

1516
#include "companion.h"
1617
#include "utils.h"
1718

18-
#define ANDROID_NAMESPACE_TYPE_SHARED 0x2
19-
#define ANDROID_DLEXT_USE_NAMESPACE 0x200
20-
21-
typedef struct AndroidNamespace {
22-
uint8_t _unused[0];
23-
} AndroidNamespace;
24-
25-
typedef struct AndroidDlextinfo {
26-
uint64_t flags;
27-
void *reserved_addr;
28-
size_t reserved_size;
29-
int relro_fd;
30-
int library_fd;
31-
off64_t library_fd_offset;
32-
AndroidNamespace *library_namespace;
33-
} AndroidDlextinfo;
34-
35-
extern void *android_dlopen_ext(const char *filename, int flags, const AndroidDlextinfo *extinfo);
36-
37-
typedef AndroidNamespace *(*AndroidCreateNamespaceFn)(
38-
const char *name,
39-
const char *ld_library_path,
40-
const char *default_library_path,
41-
uint64_t type,
42-
const char *permitted_when_isolated_path,
43-
AndroidNamespace *parent,
44-
const void *caller_addr
45-
);
46-
47-
void *android_dlopen(char *path, int flags) {
19+
#define __LOADER_ANDROID_CREATE_NAMESPACE_TYPE(name) struct android_namespace_t *(*name)( \
20+
const char *name, \
21+
const char *ld_library_path, \
22+
const char *default_library_path, \
23+
uint64_t type, \
24+
const char *permitted_when_isolated_path, \
25+
struct android_namespace_t *parent, \
26+
const void *caller_addr)
27+
28+
void *dlopen_ext(const char* path, int flags) {
29+
android_dlextinfo info = { 0 };
4830
char *dir = dirname(path);
49-
struct AndroidDlextinfo info = {
50-
.flags = 0,
51-
.reserved_addr = NULL,
52-
.reserved_size = 0,
53-
.relro_fd = 0,
54-
.library_fd = 0,
55-
.library_fd_offset = 0,
56-
.library_namespace = NULL,
57-
};
5831

59-
void *handle = dlsym(RTLD_DEFAULT, "__loader_android_create_namespace");
60-
AndroidCreateNamespaceFn android_create_namespace_fn = (AndroidCreateNamespaceFn)handle;
32+
__LOADER_ANDROID_CREATE_NAMESPACE_TYPE(__loader_android_create_namespace) = (__LOADER_ANDROID_CREATE_NAMESPACE_TYPE( ))dlsym(RTLD_DEFAULT, "__loader_android_create_namespace");
6133

62-
AndroidNamespace *ns = android_create_namespace_fn(
63-
path,
64-
dir,
65-
NULL,
66-
ANDROID_NAMESPACE_TYPE_SHARED,
67-
NULL,
68-
NULL,
69-
(const void *)&android_dlopen
70-
);
34+
struct android_namespace_t *ns = __loader_android_create_namespace == NULL ? NULL :
35+
__loader_android_create_namespace(path, dir, NULL,
36+
2, /* ANDROID_NAMESPACE_TYPE_SHARED */
37+
NULL, NULL,
38+
(void *)&dlopen_ext);
7139

72-
if (ns != NULL) {
40+
if (ns) {
7341
info.flags = ANDROID_DLEXT_USE_NAMESPACE;
7442
info.library_namespace = ns;
7543

76-
LOGI("Open %s with namespace %p\n", path, (void *)ns);
44+
LOGI("Open %s with namespace %p", path, (void *)ns);
7745
} else {
78-
LOGI("Cannot create namespace for %s\n", path);
46+
LOGW("Cannot create namespace for %s", path);
7947
}
8048

81-
void *result = android_dlopen_ext(path, flags, &info);
82-
if (result == NULL) {
83-
LOGE("Failed to dlopen %s: %s\n", path, dlerror());
49+
void *handle = android_dlopen_ext(path, flags, &info);
50+
if (handle) {
51+
LOGI("dlopen %s: %p", path, handle);
52+
} else {
53+
LOGE("dlopen %s: %s", path, dlerror());
8454
}
8555

86-
return result;
56+
return handle;
8757
}

zygiskd/src/dl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#ifndef DL_H
22
#define DL_H
33

4-
void *android_dlopen(char *path, int flags);
4+
void *dlopen_ext(char *path, int flags);
55

66
#endif /* DL_H */

zygiskd/src/utils.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -228,11 +228,11 @@ ssize_t write_fd(int fd, int sendfd) {
228228

229229
int read_fd(int fd) {
230230
char cmsgbuf[CMSG_SPACE(sizeof(int))];
231-
char buf[1] = { 0 };
232-
231+
232+
int cnt = 1;
233233
struct iovec iov = {
234-
.iov_base = buf,
235-
.iov_len = 1
234+
.iov_base = &cnt,
235+
.iov_len = sizeof(cnt)
236236
};
237237

238238
struct msghdr msg = {
@@ -242,7 +242,7 @@ int read_fd(int fd) {
242242
.msg_controllen = sizeof(cmsgbuf)
243243
};
244244

245-
ssize_t ret = recvmsg(fd, &msg, 0);
245+
ssize_t ret = recvmsg(fd, &msg, MSG_WAITALL);
246246
if (ret == -1) {
247247
LOGE("recvmsg: %s\n", strerror(errno));
248248

zygiskd/src/utils.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,18 @@
99
#define CONCAT_(x,y) x##y
1010
#define CONCAT(x,y) CONCAT_(x,y)
1111

12-
#define LOGI(...) \
13-
__android_log_print(ANDROID_LOG_INFO, lp_select("zygiskd32", "zygiskd64"), __VA_ARGS__); \
12+
#define LOG_TAG lp_select("zygiskd32", "zygiskd64")
13+
14+
#define LOGI(...) \
15+
__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__); \
16+
printf(__VA_ARGS__);
17+
18+
#define LOGW(...) \
19+
__android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__); \
1420
printf(__VA_ARGS__);
1521

16-
#define LOGE(...) \
17-
__android_log_print(ANDROID_LOG_ERROR , lp_select("zygiskd32", "zygiskd64"), __VA_ARGS__); \
22+
#define LOGE(...) \
23+
__android_log_print(ANDROID_LOG_ERROR , LOG_TAG, __VA_ARGS__); \
1824
printf(__VA_ARGS__);
1925

2026
#define ASSURE_SIZE_WRITE(area_name, subarea_name, sent_size, expected_size) \

0 commit comments

Comments
 (0)