aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar netblue30 <netblue30@yahoo.com>2018-08-21 07:55:03 -0400
committerLibravatar netblue30 <netblue30@yahoo.com>2018-08-21 07:55:03 -0400
commit6d0e800ded1e4275c98b3295f51aab65312a7f70 (patch)
tree1ad164ffb19ff6ceca14b450384773c9e478de4e /src
parentmerge 0.9.56-rc1 (diff)
downloadfirejail-6d0e800ded1e4275c98b3295f51aab65312a7f70.tar.gz
firejail-6d0e800ded1e4275c98b3295f51aab65312a7f70.tar.zst
firejail-6d0e800ded1e4275c98b3295f51aab65312a7f70.zip
removed --output, --trace, --tracelog
Diffstat (limited to 'src')
-rw-r--r--src/firejail/fs_trace.c2
-rw-r--r--src/firejail/main.c9
-rw-r--r--src/firejail/output.c109
-rw-r--r--src/firejail/profile.c2
-rw-r--r--src/firejail/sandbox.c5
-rw-r--r--src/ftee/Makefile.in14
-rw-r--r--src/ftee/ftee.h24
-rw-r--r--src/ftee/main.c245
-rw-r--r--src/libtrace/Makefile.in26
-rw-r--r--src/libtrace/libtrace.c692
-rw-r--r--src/libtracelog/Makefile.in26
-rw-r--r--src/libtracelog/libtracelog.c704
12 files changed, 15 insertions, 1843 deletions
diff --git a/src/firejail/fs_trace.c b/src/firejail/fs_trace.c
index 38ab7e2f8..e1320433c 100644
--- a/src/firejail/fs_trace.c
+++ b/src/firejail/fs_trace.c
@@ -53,6 +53,7 @@ void fs_trace(void) {
53 errExit("fopen"); 53 errExit("fopen");
54 const char *prefix = LIBDIR "/firejail"; 54 const char *prefix = LIBDIR "/firejail";
55 55
56#ifndef LTS
56 if (arg_trace) { 57 if (arg_trace) {
57 fprintf(fp, "%s/libtrace.so\n", prefix); 58 fprintf(fp, "%s/libtrace.so\n", prefix);
58 } 59 }
@@ -60,6 +61,7 @@ void fs_trace(void) {
60 fprintf(fp, "%s/libtracelog.so\n", prefix); 61 fprintf(fp, "%s/libtracelog.so\n", prefix);
61 fmessage("Blacklist violations are logged to syslog\n"); 62 fmessage("Blacklist violations are logged to syslog\n");
62 } 63 }
64#endif
63 if (arg_seccomp_postexec) { 65 if (arg_seccomp_postexec) {
64 fprintf(fp, "%s/libpostexecseccomp.so\n", prefix); 66 fprintf(fp, "%s/libpostexecseccomp.so\n", prefix);
65 fmessage("Post-exec seccomp protector enabled\n"); 67 fmessage("Post-exec seccomp protector enabled\n");
diff --git a/src/firejail/main.c b/src/firejail/main.c
index d1f3c47c2..9b406b4b9 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -66,8 +66,10 @@ int arg_caps_drop_all = 0; // drop all capabilities
66int arg_caps_keep = 0; // keep list 66int arg_caps_keep = 0; // keep list
67char *arg_caps_list = NULL; // optional caps list 67char *arg_caps_list = NULL; // optional caps list
68 68
69#ifndef LTS
69int arg_trace = 0; // syscall tracing support 70int arg_trace = 0; // syscall tracing support
70int arg_tracelog = 0; // blacklist tracing support 71int arg_tracelog = 0; // blacklist tracing support
72#endif
71int arg_rlimit_cpu = 0; // rlimit max cpu time 73int arg_rlimit_cpu = 0; // rlimit max cpu time
72int arg_rlimit_nofile = 0; // rlimit nofile 74int arg_rlimit_nofile = 0; // rlimit nofile
73int arg_rlimit_nproc = 0; // rlimit nproc 75int arg_rlimit_nproc = 0; // rlimit nproc
@@ -1062,10 +1064,12 @@ int main(int argc, char **argv) {
1062#endif 1064#endif
1063 } 1065 }
1064 } 1066 }
1067#ifndef LTS
1065 else { 1068 else {
1066 // check --output option and execute it; 1069 // check --output option and execute it;
1067 check_output(argc, argv); // the function will not return if --output or --output-stderr option was found 1070 check_output(argc, argv); // the function will not return if --output or --output-stderr option was found
1068 } 1071 }
1072#endif
1069 EUID_ASSERT(); 1073 EUID_ASSERT();
1070 1074
1071 1075
@@ -1212,11 +1216,11 @@ int main(int argc, char **argv) {
1212 } 1216 }
1213 1217
1214 1218
1219#ifndef LTS
1215 else if (strcmp(argv[i], "--trace") == 0) 1220 else if (strcmp(argv[i], "--trace") == 0)
1216 arg_trace = 1; 1221 arg_trace = 1;
1217 else if (strcmp(argv[i], "--tracelog") == 0) 1222 else if (strcmp(argv[i], "--tracelog") == 0)
1218 arg_tracelog = 1; 1223 arg_tracelog = 1;
1219#ifndef LTS
1220 else if (strncmp(argv[i], "--rlimit-cpu=", 13) == 0) { 1224 else if (strncmp(argv[i], "--rlimit-cpu=", 13) == 0) {
1221 check_unsigned(argv[i] + 13, "Error: invalid rlimit"); 1225 check_unsigned(argv[i] + 13, "Error: invalid rlimit");
1222 sscanf(argv[i] + 13, "%llu", &cfg.rlimit_cpu); 1226 sscanf(argv[i] + 13, "%llu", &cfg.rlimit_cpu);
@@ -2243,11 +2247,12 @@ int main(int argc, char **argv) {
2243 exit(1); 2247 exit(1);
2244 } 2248 }
2245 2249
2250#ifndef LTS
2246 // check trace configuration 2251 // check trace configuration
2247 if (arg_trace && arg_tracelog) { 2252 if (arg_trace && arg_tracelog) {
2248 fwarning("--trace and --tracelog are mutually exclusive; --tracelog disabled\n"); 2253 fwarning("--trace and --tracelog are mutually exclusive; --tracelog disabled\n");
2249 } 2254 }
2250 2255#endif
2251 // check user namespace (--noroot) options 2256 // check user namespace (--noroot) options
2252 if (arg_noroot) { 2257 if (arg_noroot) {
2253 if (arg_overlay) { 2258 if (arg_overlay) {
diff --git a/src/firejail/output.c b/src/firejail/output.c
deleted file mode 100644
index 61c89992d..000000000
--- a/src/firejail/output.c
+++ /dev/null
@@ -1,109 +0,0 @@
1/*
2 * Copyright (C) 2014-2018 Firejail Authors
3 *
4 * This file is part of firejail project
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20#include "firejail.h"
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <unistd.h>
24
25void check_output(int argc, char **argv) {
26 EUID_ASSERT();
27
28 int i;
29 int outindex = 0;
30 int enable_stderr = 0;
31
32 for (i = 1; i < argc; i++) {
33 if (strncmp(argv[i], "--output=", 9) == 0) {
34 outindex = i;
35 break;
36 }
37 if (strncmp(argv[i], "--output-stderr=", 16) == 0) {
38 outindex = i;
39 enable_stderr = 1;
40 break;
41 }
42 }
43 if (!outindex)
44 return;
45
46
47 // check filename
48 drop_privs(0);
49 char *outfile = argv[outindex];
50 outfile += (enable_stderr)? 16:9;
51 invalid_filename(outfile, 0); // no globbing
52
53 // do not accept directories, links, and files with ".."
54 if (strstr(outfile, "..") || is_link(outfile) || is_dir(outfile)) {
55 fprintf(stderr, "Error: invalid output file. Links, directories and files with \"..\" are not allowed.\n");
56 exit(1);
57 }
58
59 struct stat s;
60 if (stat(outfile, &s) == 0) {
61 // check permissions
62 if (s.st_uid != getuid() || s.st_gid != getgid()) {
63 fprintf(stderr, "Error: the output file needs to be owned by the current user.\n");
64 exit(1);
65 }
66
67 // check hard links
68 if (s.st_nlink != 1) {
69 fprintf(stderr, "Error: no hard links allowed.\n");
70 exit(1);
71 }
72 }
73
74 // build the new command line
75 int len = 0;
76 for (i = 0; i < argc; i++) {
77 len += strlen(argv[i]) + 1; // + ' '
78 }
79 len += 100 + strlen(LIBDIR) + strlen(outfile); // tee command
80
81 char *cmd = malloc(len + 1); // + '\0'
82 if (!cmd)
83 errExit("malloc");
84
85 char *ptr = cmd;
86 for (i = 0; i < argc; i++) {
87 if (strncmp(argv[i], "--output=", 9) == 0)
88 continue;
89 if (strncmp(argv[i], "--output-stderr=", 16) == 0)
90 continue;
91 ptr += sprintf(ptr, "%s ", argv[i]);
92 }
93
94 if (enable_stderr)
95 sprintf(ptr, "2>&1 | %s/firejail/ftee %s", LIBDIR, outfile);
96 else
97 sprintf(ptr, " | %s/firejail/ftee %s", LIBDIR, outfile);
98
99 // run command
100 char *a[4];
101 a[0] = "/bin/bash";
102 a[1] = "-c";
103 a[2] = cmd;
104 a[3] = NULL;
105 execvp(a[0], a);
106
107 perror("execvp");
108 exit(1);
109}
diff --git a/src/firejail/profile.c b/src/firejail/profile.c
index fb1beacd5..79fc36fb5 100644
--- a/src/firejail/profile.c
+++ b/src/firejail/profile.c
@@ -197,10 +197,12 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
197 arg_shell_none = 1; 197 arg_shell_none = 1;
198 return 0; 198 return 0;
199 } 199 }
200#ifndef LTS
200 else if (strcmp(ptr, "tracelog") == 0) { 201 else if (strcmp(ptr, "tracelog") == 0) {
201 arg_tracelog = 1; 202 arg_tracelog = 1;
202 return 0; 203 return 0;
203 } 204 }
205#endif
204 else if (strcmp(ptr, "private") == 0) { 206 else if (strcmp(ptr, "private") == 0) {
205 arg_private = 1; 207 arg_private = 1;
206 return 0; 208 return 0;
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c
index deb37d700..b0a792277 100644
--- a/src/firejail/sandbox.c
+++ b/src/firejail/sandbox.c
@@ -719,8 +719,11 @@ int sandbox(void* sandbox_arg) {
719#endif 719#endif
720 720
721 // need ld.so.preload if tracing or seccomp with any non-default lists 721 // need ld.so.preload if tracing or seccomp with any non-default lists
722#ifndef LTS
722 bool need_preload = arg_trace || arg_tracelog || arg_seccomp_postexec; 723 bool need_preload = arg_trace || arg_tracelog || arg_seccomp_postexec;
723 724#else
725 bool need_preload = arg_seccomp_postexec;
726#endif
724 // trace pre-install 727 // trace pre-install
725 if (need_preload) 728 if (need_preload)
726 fs_trace_preload(); 729 fs_trace_preload();
diff --git a/src/ftee/Makefile.in b/src/ftee/Makefile.in
deleted file mode 100644
index d3b92362c..000000000
--- a/src/ftee/Makefile.in
+++ /dev/null
@@ -1,14 +0,0 @@
1all: ftee
2
3include ../common.mk
4
5%.o : %.c $(H_FILE_LIST)
6 $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -c $< -o $@
7
8ftee: $(OBJS)
9 $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) $(EXTRA_LDFLAGS)
10
11clean:; rm -f *.o ftee *.gcov *.gcda *.gcno
12
13distclean: clean
14 rm -fr Makefile
diff --git a/src/ftee/ftee.h b/src/ftee/ftee.h
deleted file mode 100644
index 68c4201c7..000000000
--- a/src/ftee/ftee.h
+++ /dev/null
@@ -1,24 +0,0 @@
1/*
2 * Copyright (C) 2014-2018 Firejail Authors
3 *
4 * This file is part of firejail project
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19*/
20#ifndef FTEE_H
21#define FTEE_H
22#include "../include/common.h"
23
24#endif
diff --git a/src/ftee/main.c b/src/ftee/main.c
deleted file mode 100644
index 0e37f0b72..000000000
--- a/src/ftee/main.c
+++ /dev/null
@@ -1,245 +0,0 @@
1/*
2 * Copyright (C) 2014-2018 Firejail Authors
3 *
4 * This file is part of firejail project
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19*/
20#include "ftee.h"
21#include <errno.h>
22#include <sys/types.h>
23#include <sys/stat.h>
24#include <unistd.h>
25#define MAXBUF 512
26
27static unsigned char buf[MAXBUF];
28
29static FILE *out_fp = NULL;
30static int out_cnt = 0;
31static int out_max = 500 * 1024;
32
33static void log_close(void) {
34 if (out_fp) {
35 fclose(out_fp);
36 out_fp = NULL;
37 }
38}
39
40static void log_rotate(const char *fname) {
41 struct stat s;
42 int index = strlen(fname);
43 char *name1 = malloc(index + 2 + 1);
44 char *name2 = malloc(index + 2 + 1);
45 if (!name1 || !name2)
46 errExit("malloc");
47 strcpy(name1, fname);
48 strcpy(name2, fname);
49 fflush(0);
50
51 // delete filename.5
52 sprintf(name1 + index, ".5");
53 if (stat(name1, &s) == 0) {
54 int rv = unlink(name1);
55 if (rv == -1)
56 perror("unlink");
57 }
58
59 // move files 1 to 4 down one position
60 sprintf(name2 + index, ".4");
61 if (stat(name2, &s) == 0) {
62 int rv = rename(name2, name1);
63 if (rv == -1)
64 perror("rename");
65 }
66
67 sprintf(name1 + index, ".3");
68 if (stat(name1, &s) == 0) {
69 int rv = rename(name1, name2);
70 if (rv == -1)
71 perror("rename");
72 }
73
74 sprintf(name2 + index, ".2");
75 if (stat(name2, &s) == 0) {
76 /* coverity[toctou] */
77 int rv = rename(name2, name1);
78 if (rv == -1)
79 perror("rename");
80 }
81
82 sprintf(name1 + index, ".1");
83 if (stat(name1, &s) == 0) {
84 int rv = rename(name1, name2);
85 if (rv == -1)
86 perror("rename");
87 }
88
89 // move the first file
90 if (out_fp)
91 fclose(out_fp);
92
93 out_fp = NULL;
94 if (stat(fname, &s) == 0) {
95 int rv = rename(fname, name1);
96 if (rv == -1)
97 perror("rename");
98 }
99
100 free(name1);
101 free(name2);
102}
103
104static void log_write(const unsigned char *str, int len, const char *fname) {
105 assert(fname);
106
107 if (out_fp == NULL) {
108 out_fp = fopen(fname, "w");
109 if (!out_fp) {
110 fprintf(stderr, "Error: cannot open log file %s\n", fname);
111 exit(1);
112 }
113 out_cnt = 0;
114 }
115
116 // rotate files
117 out_cnt += len;
118 if (out_cnt >= out_max) {
119 log_rotate(fname);
120
121 // reopen the first file
122 if (out_fp)
123 fclose(out_fp);
124 out_fp = fopen(fname, "w");
125 if (!out_fp) {
126 fprintf(stderr, "Error: cannot open log file %s\n", fname);
127 exit(1);
128 }
129 out_cnt = len;
130 }
131
132 int rv = fwrite(str, len, 1, out_fp);
133 (void) rv;
134 fflush(0);
135}
136
137
138// return 1 if the file is a directory
139static int is_dir(const char *fname) {
140 assert(fname);
141 if (*fname == '\0')
142 return 0;
143
144 // if fname doesn't end in '/', add one
145 int rv;
146 struct stat s;
147 if (fname[strlen(fname) - 1] == '/')
148 rv = stat(fname, &s);
149 else {
150 char *tmp;
151 if (asprintf(&tmp, "%s/", fname) == -1) {
152 fprintf(stderr, "Error: cannot allocate memory, %s:%d\n", __FILE__, __LINE__);
153 exit(1);
154 }
155 rv = stat(tmp, &s);
156 free(tmp);
157 }
158
159 if (rv == -1)
160 return 0;
161
162 if (S_ISDIR(s.st_mode))
163 return 1;
164
165 return 0;
166}
167
168// return 1 if the file is a link
169static int is_link(const char *fname) {
170 assert(fname);
171 if (*fname == '\0')
172 return 0;
173
174 struct stat s;
175 if (lstat(fname, &s) == 0) {
176 if (S_ISLNK(s.st_mode))
177 return 1;
178 }
179
180 return 0;
181}
182
183static void usage(void) {
184 printf("Usage: ftee filename\n");
185}
186
187int main(int argc, char **argv) {
188 if (argc < 2) {
189 fprintf(stderr, "Error: please provide a filename to store the program output\n");
190 usage();
191 exit(1);
192 }
193 if (strcmp(argv[1], "--help") == 0) {
194 usage();
195 return 0;
196 }
197 char *fname = argv[1];
198
199
200 // do not accept directories, links, and files with ".."
201 if (strstr(fname, "..") || is_link(fname) || is_dir(fname))
202 goto errexit;
203
204 struct stat s;
205 if (stat(fname, &s) == 0) {
206 // check permissions
207 if (s.st_uid != getuid() || s.st_gid != getgid())
208 goto errexit;
209
210 // check hard links
211 if (s.st_nlink != 1)
212 goto errexit;
213 }
214
215 // check if we can append to this file
216 /* coverity[toctou] */
217 FILE *fp = fopen(fname, "a");
218 if (!fp)
219 goto errexit;
220 fclose(fp);
221
222
223 // preserve the last log file
224 log_rotate(fname);
225
226 setvbuf (stdout, NULL, _IONBF, 0);
227 while(1) {
228 int n = read(0, buf, sizeof(buf));
229 if (n < 0 && errno == EINTR)
230 continue;
231 if (n <= 0)
232 break;
233
234 int rv = fwrite(buf, n, 1, stdout);
235 (void) rv;
236 log_write(buf, n, fname);
237 }
238
239 log_close();
240 return 0;
241
242errexit:
243 fprintf(stderr, "Error ftee: invalid output file.\n");
244 return 1;
245}
diff --git a/src/libtrace/Makefile.in b/src/libtrace/Makefile.in
deleted file mode 100644
index 6ae078f46..000000000
--- a/src/libtrace/Makefile.in
+++ /dev/null
@@ -1,26 +0,0 @@
1CC=@CC@
2PREFIX=@prefix@
3VERSION=@PACKAGE_VERSION@
4NAME=@PACKAGE_NAME@
5HAVE_FATAL_WARNINGS=@HAVE_FATAL_WARNINGS@
6
7H_FILE_LIST = $(sort $(wildcard *.[h]))
8C_FILE_LIST = $(sort $(wildcard *.c))
9OBJS = $(C_FILE_LIST:.c=.o)
10BINOBJS = $(foreach file, $(OBJS), $file)
11CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIC -Wformat -Wformat-security
12LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now
13
14all: libtrace.so
15
16%.o : %.c $(H_FILE_LIST)
17 $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
18
19libtrace.so: $(OBJS)
20 $(CC) $(LDFLAGS) -shared -fPIC -z relro -o $@ $(OBJS) -ldl
21
22
23clean:; rm -f $(OBJS) libtrace.so
24
25distclean: clean
26 rm -fr Makefile
diff --git a/src/libtrace/libtrace.c b/src/libtrace/libtrace.c
deleted file mode 100644
index c41bafb68..000000000
--- a/src/libtrace/libtrace.c
+++ /dev/null
@@ -1,692 +0,0 @@
1/*
2 * Copyright (C) 2014-2018 Firejail Authors
3 *
4 * This file is part of firejail project
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19*/
20#define _GNU_SOURCE
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <dlfcn.h>
25#include <sys/types.h>
26#include <limits.h>
27#include <unistd.h>
28#include <sys/socket.h>
29#include <netinet/in.h>
30#include <arpa/inet.h>
31#include <sys/un.h>
32#include <sys/stat.h>
33#include <syslog.h>
34#include <dirent.h>
35#include <limits.h>
36
37// break recursivity on fopen call
38typedef FILE *(*orig_fopen_t)(const char *pathname, const char *mode);
39static orig_fopen_t orig_fopen = NULL;
40typedef FILE *(*orig_fopen64_t)(const char *pathname, const char *mode);
41static orig_fopen64_t orig_fopen64 = NULL;
42
43//
44// pid
45//
46static pid_t mypid = 0;
47static inline pid_t pid(void) {
48 if (!mypid)
49 mypid = getpid();
50 return mypid;
51}
52
53//
54// process name
55//
56#define MAXNAME 16
57static char myname[MAXNAME];
58static int nameinit = 0;
59static char *name(void) {
60 if (!nameinit) {
61 // initialize the name of the process based on /proc/PID/comm
62 memset(myname, 0, MAXNAME);
63
64 pid_t p = pid();
65 char *fname;
66 if (asprintf(&fname, "/proc/%u/comm", p) == -1)
67 return "unknown";
68
69 // read file
70 if (!orig_fopen)
71 orig_fopen = (orig_fopen_t)dlsym(RTLD_NEXT, "fopen");
72 FILE *fp = orig_fopen(fname, "r");
73 if (!fp)
74 return "unknown";
75 if (fgets(myname, MAXNAME, fp) == NULL) {
76 fclose(fp);
77 free(fname);
78 return "unknown";
79 }
80
81 // clean '\n'
82 char *ptr = strchr(myname, '\n');
83 if (ptr)
84 *ptr = '\0';
85
86 fclose(fp);
87 free(fname);
88 nameinit = 1;
89 }
90
91 return myname;
92}
93
94//
95// network
96//
97typedef struct {
98 int val;
99 char *name;
100} XTable;
101
102static XTable socket_type[] = {
103#ifdef SOCK_STREAM
104 { SOCK_STREAM, "SOCK_STREAM" },
105#endif
106#ifdef SOCK_DGRAM
107 { SOCK_DGRAM, "SOCK_DGRAM" },
108#endif
109#ifdef SOCK_RAW
110 { SOCK_RAW, "SOCK_RAW" },
111#endif
112#ifdef SOCK_RDM
113 { SOCK_RDM, "SOCK_RDM" },
114#endif
115#ifdef SOCK_SEQPACKET
116 { SOCK_SEQPACKET, "SOCK_SEQPACKET" },
117#endif
118#ifdef SOCK_DCCP
119 { SOCK_DCCP, "SOCK_DCCP" },
120#endif
121 { 0, NULL} // NULL terminated
122};
123
124static XTable socket_domain[] = {
125#ifdef AF_INET
126 { AF_INET, "AF_INET" },
127#endif
128#ifdef AF_INET6
129 { AF_INET6, "AF_INET6" },
130#endif
131#ifdef AF_LOCAL
132 { AF_LOCAL, "AF_LOCAL" },
133#endif
134#ifdef AF_PACKET
135 { AF_PACKET, "AF_PACKET" },
136#endif
137#ifdef AF_IPX
138 { AF_IPX, "AF_IPX" },
139#endif
140#ifdef AF_NETLINK
141 { AF_NETLINK, "AF_NETLINK" },
142#endif
143#ifdef AF_X25
144 { AF_X25, "AF_X25" },
145#endif
146#ifdef AF_AX25
147 { AF_AX25, "AF_AX25" },
148#endif
149#ifdef AF_ATMPVC
150 { AF_ATMPVC, "AF_ATMPVC" },
151#endif
152#ifdef AF_APPLETALK
153 { AF_APPLETALK, "AF_APPLETALK" },
154#endif
155 { 0, NULL} // NULL terminated
156};
157
158static XTable socket_protocol[] = {
159#ifdef IPPROTO_IP
160 { IPPROTO_IP, "IPPROTO_IP" },
161#endif
162#ifdef IPPROTO_ICMP
163 { IPPROTO_ICMP, "IPPROTO_ICMP" },
164#endif
165#ifdef IPPROTO_IGMP
166 { IPPROTO_IGMP, "IPPROTO_IGMP" },
167#endif
168#ifdef IPPROTO_IPIP
169 { IPPROTO_IPIP, "IPPROTO_IPIP" },
170#endif
171#ifdef IPPROTO_TCP
172 { IPPROTO_TCP, "IPPROTO_TCP" },
173#endif
174#ifdef IPPROTO_EGP
175 { IPPROTO_EGP, "IPPROTO_EGP" },
176#endif
177#ifdef IPPROTO_PUP
178 { IPPROTO_PUP, "IPPROTO_PUP" },
179#endif
180#ifdef IPPROTO_UDP
181 { IPPROTO_UDP, "IPPROTO_UDP" },
182#endif
183#ifdef IPPROTO_IDP
184 { IPPROTO_IDP, "IPPROTO_IDP" },
185#endif
186#ifdef IPPROTO_DCCP
187 { IPPROTO_DCCP, "IPPROTO_DCCP" },
188#endif
189#ifdef IPPROTO_RSVP
190 { IPPROTO_RSVP, "IPPROTO_RSVP" },
191#endif
192#ifdef IPPROTO_GRE
193 { IPPROTO_GRE, "IPPROTO_GRE" },
194#endif
195#ifdef IPPROTO_IPV6
196 { IPPROTO_IPV6, "IPPROTO_IPV6" },
197#endif
198#ifdef IPPROTO_ESP
199 { IPPROTO_ESP, "IPPROTO_ESP" },
200#endif
201#ifdef IPPROTO_AH
202 { IPPROTO_AH, "IPPROTO_AH" },
203#endif
204#ifdef IPPROTO_BEETPH
205 { IPPROTO_BEETPH, "IPPROTO_BEETPH" },
206#endif
207#ifdef IPPROTO_PIM
208 { IPPROTO_PIM, "IPPROTO_PIM" },
209#endif
210#ifdef IPPROTO_COMP
211 { IPPROTO_COMP, "IPPROTO_COMP" },
212#endif
213#ifdef IPPROTO_SCTP
214 { IPPROTO_SCTP, "IPPROTO_SCTP" },
215#endif
216#ifdef IPPROTO_UDPLITE
217 { IPPROTO_UDPLITE, "IPPROTO_UDPLITE" },
218#endif
219#ifdef IPPROTO_RAW
220 { IPPROTO_RAW, "IPPROTO_RAW" },
221#endif
222 { 0, NULL} // NULL terminated
223};
224
225static char *translate(XTable *table, int val) {
226 while (table->name != NULL) {
227 if (val == table->val)
228 return table->name;
229 table++;
230 }
231
232 return NULL;
233}
234
235static void print_sockaddr(int sockfd, const char *call, const struct sockaddr *addr, int rv) {
236 if (addr->sa_family == AF_INET) {
237 struct sockaddr_in *a = (struct sockaddr_in *) addr;
238 printf("%u:%s:%s %d %s port %u:%d\n", pid(), name(), call, sockfd, inet_ntoa(a->sin_addr), ntohs(a->sin_port), rv);
239 }
240 else if (addr->sa_family == AF_INET6) {
241 struct sockaddr_in6 *a = (struct sockaddr_in6 *) addr;
242 char str[INET6_ADDRSTRLEN];
243 inet_ntop(AF_INET6, &(a->sin6_addr), str, INET6_ADDRSTRLEN);
244 printf("%u:%s:%s %d %s:%d\n", pid(), name(), call, sockfd, str, rv);
245 }
246 else if (addr->sa_family == AF_UNIX) {
247 struct sockaddr_un *a = (struct sockaddr_un *) addr;
248 if (a->sun_path[0])
249 printf("%u:%s:%s %d %s:%d\n", pid(), name(), call, sockfd, a->sun_path, rv);
250 else
251 printf("%u:%s:%s %d @%s:%d\n", pid(), name(), call, sockfd, a->sun_path + 1, rv);
252 }
253 else {
254 printf("%u:%s:%s %d family %d:%d\n", pid(), name(), call, sockfd, addr->sa_family, rv);
255 }
256}
257
258//
259// syscalls
260//
261
262// open
263typedef int (*orig_open_t)(const char *pathname, int flags, mode_t mode);
264static orig_open_t orig_open = NULL;
265int open(const char *pathname, int flags, mode_t mode) {
266 if (!orig_open)
267 orig_open = (orig_open_t)dlsym(RTLD_NEXT, "open");
268
269 int rv = orig_open(pathname, flags, mode);
270 printf("%u:%s:open %s:%d\n", pid(), name(), pathname, rv);
271 return rv;
272}
273
274typedef int (*orig_open64_t)(const char *pathname, int flags, mode_t mode);
275static orig_open64_t orig_open64 = NULL;
276int open64(const char *pathname, int flags, mode_t mode) {
277 if (!orig_open64)
278 orig_open64 = (orig_open64_t)dlsym(RTLD_NEXT, "open64");
279
280 int rv = orig_open64(pathname, flags, mode);
281 printf("%u:%s:open64 %s:%d\n", pid(), name(), pathname, rv);
282 return rv;
283}
284
285// openat
286typedef int (*orig_openat_t)(int dirfd, const char *pathname, int flags, mode_t mode);
287static orig_openat_t orig_openat = NULL;
288int openat(int dirfd, const char *pathname, int flags, mode_t mode) {
289 if (!orig_openat)
290 orig_openat = (orig_openat_t)dlsym(RTLD_NEXT, "openat");
291
292 int rv = orig_openat(dirfd, pathname, flags, mode);
293 printf("%u:%s:openat %s:%d\n", pid(), name(), pathname, rv);
294 return rv;
295}
296
297typedef int (*orig_openat64_t)(int dirfd, const char *pathname, int flags, mode_t mode);
298static orig_openat64_t orig_openat64 = NULL;
299int openat64(int dirfd, const char *pathname, int flags, mode_t mode) {
300 if (!orig_openat64)
301 orig_openat64 = (orig_openat64_t)dlsym(RTLD_NEXT, "openat64");
302
303 int rv = orig_openat64(dirfd, pathname, flags, mode);
304 printf("%u:%s:openat64 %s:%d\n", pid(), name(), pathname, rv);
305 return rv;
306}
307
308
309// fopen
310FILE *fopen(const char *pathname, const char *mode) {
311 if (!orig_fopen)
312 orig_fopen = (orig_fopen_t)dlsym(RTLD_NEXT, "fopen");
313
314 FILE *rv = orig_fopen(pathname, mode);
315 printf("%u:%s:fopen %s:%p\n", pid(), name(), pathname, rv);
316 return rv;
317}
318
319#ifdef __GLIBC__
320FILE *fopen64(const char *pathname, const char *mode) {
321 if (!orig_fopen64)
322 orig_fopen64 = (orig_fopen_t)dlsym(RTLD_NEXT, "fopen64");
323
324 FILE *rv = orig_fopen64(pathname, mode);
325 printf("%u:%s:fopen64 %s:%p\n", pid(), name(), pathname, rv);
326 return rv;
327}
328#endif /* __GLIBC__ */
329
330
331// freopen
332typedef FILE *(*orig_freopen_t)(const char *pathname, const char *mode, FILE *stream);
333static orig_freopen_t orig_freopen = NULL;
334FILE *freopen(const char *pathname, const char *mode, FILE *stream) {
335 if (!orig_freopen)
336 orig_freopen = (orig_freopen_t)dlsym(RTLD_NEXT, "freopen");
337
338 FILE *rv = orig_freopen(pathname, mode, stream);
339 printf("%u:%s:freopen %s:%p\n", pid(), name(), pathname, rv);
340 return rv;
341}
342
343#ifdef __GLIBC__
344typedef FILE *(*orig_freopen64_t)(const char *pathname, const char *mode, FILE *stream);
345static orig_freopen64_t orig_freopen64 = NULL;
346FILE *freopen64(const char *pathname, const char *mode, FILE *stream) {
347 if (!orig_freopen64)
348 orig_freopen64 = (orig_freopen64_t)dlsym(RTLD_NEXT, "freopen64");
349
350 FILE *rv = orig_freopen64(pathname, mode, stream);
351 printf("%u:%s:freopen64 %s:%p\n", pid(), name(), pathname, rv);
352 return rv;
353}
354#endif /* __GLIBC__ */
355
356// unlink
357typedef int (*orig_unlink_t)(const char *pathname);
358static orig_unlink_t orig_unlink = NULL;
359int unlink(const char *pathname) {
360 if (!orig_unlink)
361 orig_unlink = (orig_unlink_t)dlsym(RTLD_NEXT, "unlink");
362
363 int rv = orig_unlink(pathname);
364 printf("%u:%s:unlink %s:%d\n", pid(), name(), pathname, rv);
365 return rv;
366}
367
368typedef int (*orig_unlinkat_t)(int dirfd, const char *pathname, int flags);
369static orig_unlinkat_t orig_unlinkat = NULL;
370int unlinkat(int dirfd, const char *pathname, int flags) {
371 if (!orig_unlinkat)
372 orig_unlinkat = (orig_unlinkat_t)dlsym(RTLD_NEXT, "unlinkat");
373
374 int rv = orig_unlinkat(dirfd, pathname, flags);
375 printf("%u:%s:unlinkat %s:%d\n", pid(), name(), pathname, rv);
376 return rv;
377}
378
379// mkdir/mkdirat/rmdir
380typedef int (*orig_mkdir_t)(const char *pathname, mode_t mode);
381static orig_mkdir_t orig_mkdir = NULL;
382int mkdir(const char *pathname, mode_t mode) {
383 if (!orig_mkdir)
384 orig_mkdir = (orig_mkdir_t)dlsym(RTLD_NEXT, "mkdir");
385
386 int rv = orig_mkdir(pathname, mode);
387 printf("%u:%s:mkdir %s:%d\n", pid(), name(), pathname, rv);
388 return rv;
389}
390
391typedef int (*orig_mkdirat_t)(int dirfd, const char *pathname, mode_t mode);
392static orig_mkdirat_t orig_mkdirat = NULL;
393int mkdirat(int dirfd, const char *pathname, mode_t mode) {
394 if (!orig_mkdirat)
395 orig_mkdirat = (orig_mkdirat_t)dlsym(RTLD_NEXT, "mkdirat");
396
397 int rv = orig_mkdirat(dirfd, pathname, mode);
398 printf("%u:%s:mkdirat %s:%d\n", pid(), name(), pathname, rv);
399 return rv;
400}
401
402typedef int (*orig_rmdir_t)(const char *pathname);
403static orig_rmdir_t orig_rmdir = NULL;
404int rmdir(const char *pathname) {
405 if (!orig_rmdir)
406 orig_rmdir = (orig_rmdir_t)dlsym(RTLD_NEXT, "rmdir");
407
408 int rv = orig_rmdir(pathname);
409 printf("%u:%s:rmdir %s:%d\n", pid(), name(), pathname, rv);
410 return rv;
411}
412
413// stat
414typedef int (*orig_stat_t)(const char *pathname, struct stat *buf);
415static orig_stat_t orig_stat = NULL;
416int stat(const char *pathname, struct stat *buf) {
417 if (!orig_stat)
418 orig_stat = (orig_stat_t)dlsym(RTLD_NEXT, "stat");
419
420 int rv = orig_stat(pathname, buf);
421 printf("%u:%s:stat %s:%d\n", pid(), name(), pathname, rv);
422 return rv;
423}
424
425#ifdef __GLIBC__
426typedef int (*orig_stat64_t)(const char *pathname, struct stat64 *buf);
427static orig_stat64_t orig_stat64 = NULL;
428int stat64(const char *pathname, struct stat64 *buf) {
429 if (!orig_stat64)
430 orig_stat64 = (orig_stat64_t)dlsym(RTLD_NEXT, "stat64");
431
432 int rv = orig_stat64(pathname, buf);
433 printf("%u:%s:stat64 %s:%d\n", pid(), name(), pathname, rv);
434 return rv;
435}
436#endif /* __GLIBC__ */
437
438// lstat
439typedef int (*orig_lstat_t)(const char *pathname, struct stat *buf);
440static orig_lstat_t orig_lstat = NULL;
441int lstat(const char *pathname, struct stat *buf) {
442 if (!orig_lstat)
443 orig_lstat = (orig_lstat_t)dlsym(RTLD_NEXT, "lstat");
444
445 int rv = orig_lstat(pathname, buf);
446 printf("%u:%s:lstat %s:%d\n", pid(), name(), pathname, rv);
447 return rv;
448}
449
450#ifdef __GLIBC__
451typedef int (*orig_lstat64_t)(const char *pathname, struct stat64 *buf);
452static orig_lstat64_t orig_lstat64 = NULL;
453int lstat64(const char *pathname, struct stat64 *buf) {
454 if (!orig_lstat64)
455 orig_lstat64 = (orig_lstat64_t)dlsym(RTLD_NEXT, "lstat64");
456
457 int rv = orig_lstat64(pathname, buf);
458 printf("%u:%s:lstat64 %s:%d\n", pid(), name(), pathname, rv);
459 return rv;
460}
461#endif /* __GLIBC__ */
462
463// opendir
464typedef DIR *(*orig_opendir_t)(const char *pathname);
465static orig_opendir_t orig_opendir = NULL;
466DIR *opendir(const char *pathname) {
467 if (!orig_opendir)
468 orig_opendir = (orig_opendir_t)dlsym(RTLD_NEXT, "opendir");
469
470 DIR *rv = orig_opendir(pathname);
471 printf("%u:%s:opendir %s:%p\n", pid(), name(), pathname, rv);
472 return rv;
473}
474
475// access
476typedef int (*orig_access_t)(const char *pathname, int mode);
477static orig_access_t orig_access = NULL;
478int access(const char *pathname, int mode) {
479 if (!orig_access)
480 orig_access = (orig_access_t)dlsym(RTLD_NEXT, "access");
481
482 int rv = orig_access(pathname, mode);
483 printf("%u:%s:access %s:%d\n", pid(), name(), pathname, rv);
484 return rv;
485}
486
487
488// connect
489typedef int (*orig_connect_t)(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
490static orig_connect_t orig_connect = NULL;
491int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
492 if (!orig_connect)
493 orig_connect = (orig_connect_t)dlsym(RTLD_NEXT, "connect");
494
495 int rv = orig_connect(sockfd, addr, addrlen);
496 print_sockaddr(sockfd, "connect", addr, rv);
497
498 return rv;
499}
500
501// socket
502typedef int (*orig_socket_t)(int domain, int type, int protocol);
503static orig_socket_t orig_socket = NULL;
504static char buf[1024];
505int socket(int domain, int type, int protocol) {
506 if (!orig_socket)
507 orig_socket = (orig_socket_t)dlsym(RTLD_NEXT, "socket");
508
509 int rv = orig_socket(domain, type, protocol);
510 char *ptr = buf;
511 ptr += sprintf(ptr, "%u:%s:socket ", pid(), name());
512 char *str = translate(socket_domain, domain);
513 if (str == NULL)
514 ptr += sprintf(ptr, "%d ", domain);
515 else
516 ptr += sprintf(ptr, "%s ", str);
517
518 int t = type; // glibc uses higher bits for various other purposes
519#ifdef SOCK_CLOEXEC
520 t &= ~SOCK_CLOEXEC;
521#endif
522#ifdef SOCK_NONBLOCK
523 t &= ~SOCK_NONBLOCK;
524#endif
525 str = translate(socket_type, t);
526 if (str == NULL)
527 ptr += sprintf(ptr, "%d ", type);
528 else
529 ptr += sprintf(ptr, "%s ", str);
530
531 if (domain == AF_LOCAL)
532 sprintf(ptr, "0");
533 else {
534 str = translate(socket_protocol, protocol);
535 if (str == NULL)
536 sprintf(ptr, "%d", protocol);
537 else
538 sprintf(ptr, "%s", str);
539 }
540
541 printf("%s:%d\n", buf, rv);
542 return rv;
543}
544
545// bind
546typedef int (*orig_bind_t)(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
547static orig_bind_t orig_bind = NULL;
548int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
549 if (!orig_bind)
550 orig_bind = (orig_bind_t)dlsym(RTLD_NEXT, "bind");
551
552 int rv = orig_bind(sockfd, addr, addrlen);
553 print_sockaddr(sockfd, "bind", addr, rv);
554
555 return rv;
556}
557
558#if 0
559typedef int (*orig_accept_t)(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
560static orig_accept_t orig_accept = NULL;
561int accept(int sockfd, struct sockaddr *addr, socklen_t addrlen) {
562 if (!orig_accept)
563 orig_accept = (orig_accept_t)dlsym(RTLD_NEXT, "accept");
564
565 int rv = orig_accept(sockfd, addr, addrlen);
566 print_sockaddr(sockfd, "accept", addr, rv);
567
568 return rv;
569}
570#endif
571
572typedef int (*orig_system_t)(const char *command);
573static orig_system_t orig_system = NULL;
574int system(const char *command) {
575 if (!orig_system)
576 orig_system = (orig_system_t)dlsym(RTLD_NEXT, "system");
577
578 int rv = orig_system(command);
579 printf("%u:%s:system %s:%d\n", pid(), name(), command, rv);
580
581 return rv;
582}
583
584typedef int (*orig_setuid_t)(uid_t uid);
585static orig_setuid_t orig_setuid = NULL;
586int setuid(uid_t uid) {
587 if (!orig_setuid)
588 orig_setuid = (orig_setuid_t)dlsym(RTLD_NEXT, "setuid");
589
590 int rv = orig_setuid(uid);
591 printf("%u:%s:setuid %d:%d\n", pid(), name(), uid, rv);
592
593 return rv;
594}
595
596typedef int (*orig_setgid_t)(gid_t gid);
597static orig_setgid_t orig_setgid = NULL;
598int setgid(gid_t gid) {
599 if (!orig_setgid)
600 orig_setgid = (orig_setgid_t)dlsym(RTLD_NEXT, "setgid");
601
602 int rv = orig_setgid(gid);
603 printf("%u:%s:setgid %d:%d\n", pid(), name(), gid, rv);
604
605 return rv;
606}
607
608typedef int (*orig_setfsuid_t)(uid_t uid);
609static orig_setfsuid_t orig_setfsuid = NULL;
610int setfsuid(uid_t uid) {
611 if (!orig_setfsuid)
612 orig_setfsuid = (orig_setfsuid_t)dlsym(RTLD_NEXT, "setfsuid");
613
614 int rv = orig_setfsuid(uid);
615 printf("%u:%s:setfsuid %d:%d\n", pid(), name(), uid, rv);
616
617 return rv;
618}
619
620typedef int (*orig_setfsgid_t)(gid_t gid);
621static orig_setfsgid_t orig_setfsgid = NULL;
622int setfsgid(gid_t gid) {
623 if (!orig_setfsgid)
624 orig_setfsgid = (orig_setfsgid_t)dlsym(RTLD_NEXT, "setfsgid");
625
626 int rv = orig_setfsgid(gid);
627 printf("%u:%s:setfsgid %d:%d\n", pid(), name(), gid, rv);
628
629 return rv;
630}
631
632typedef int (*orig_setreuid_t)(uid_t ruid, uid_t euid);
633static orig_setreuid_t orig_setreuid = NULL;
634int setreuid(uid_t ruid, uid_t euid) {
635 if (!orig_setreuid)
636 orig_setreuid = (orig_setreuid_t)dlsym(RTLD_NEXT, "setreuid");
637
638 int rv = orig_setreuid(ruid, euid);
639 printf("%u:%s:setreuid %d %d:%d\n", pid(), name(), ruid, euid, rv);
640
641 return rv;
642}
643
644typedef int (*orig_setregid_t)(gid_t rgid, gid_t egid);
645static orig_setregid_t orig_setregid = NULL;
646int setregid(gid_t rgid, gid_t egid) {
647 if (!orig_setregid)
648 orig_setregid = (orig_setregid_t)dlsym(RTLD_NEXT, "setregid");
649
650 int rv = orig_setregid(rgid, egid);
651 printf("%u:%s:setregid %d %d:%d\n", pid(), name(), rgid, egid, rv);
652
653 return rv;
654}
655
656typedef int (*orig_setresuid_t)(uid_t ruid, uid_t euid, uid_t suid);
657static orig_setresuid_t orig_setresuid = NULL;
658int setresuid(uid_t ruid, uid_t euid, uid_t suid) {
659 if (!orig_setresuid)
660 orig_setresuid = (orig_setresuid_t)dlsym(RTLD_NEXT, "setresuid");
661
662 int rv = orig_setresuid(ruid, euid, suid);
663 printf("%u:%s:setresuid %d %d %d:%d\n", pid(), name(), ruid, euid, suid, rv);
664
665 return rv;
666}
667
668typedef int (*orig_setresgid_t)(gid_t rgid, gid_t egid, gid_t sgid);
669static orig_setresgid_t orig_setresgid = NULL;
670int setresgid(gid_t rgid, gid_t egid, gid_t sgid) {
671 if (!orig_setresgid)
672 orig_setresgid = (orig_setresgid_t)dlsym(RTLD_NEXT, "setresgid");
673
674 int rv = orig_setresgid(rgid, egid, sgid);
675 printf("%u:%s:setresgid %d %d %d:%d\n", pid(), name(), rgid, egid, sgid, rv);
676
677 return rv;
678}
679
680// every time a new process is started, this gets called
681// it can be used to build things like private-bin
682__attribute__((constructor))
683static void log_exec(int argc, char** argv) {
684 (void) argc;
685 (void) argv;
686 static char buf[PATH_MAX + 1];
687 int rv = readlink("/proc/self/exe", buf, PATH_MAX);
688 if (rv != -1) {
689 buf[rv] = '\0'; // readlink does not add a '\0' at the end
690 printf("%u:%s:exec %s:0\n", pid(), name(), buf);
691 }
692}
diff --git a/src/libtracelog/Makefile.in b/src/libtracelog/Makefile.in
deleted file mode 100644
index 3927c762a..000000000
--- a/src/libtracelog/Makefile.in
+++ /dev/null
@@ -1,26 +0,0 @@
1CC=@CC@
2PREFIX=@prefix@
3VERSION=@PACKAGE_VERSION@
4NAME=@PACKAGE_NAME@
5HAVE_FATAL_WARNINGS=@HAVE_FATAL_WARNINGS@
6
7H_FILE_LIST = $(sort $(wildcard *.[h]))
8C_FILE_LIST = $(sort $(wildcard *.c))
9OBJS = $(C_FILE_LIST:.c=.o)
10BINOBJS = $(foreach file, $(OBJS), $file)
11CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIC -Wformat -Wformat-security
12LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now
13
14all: libtracelog.so
15
16%.o : %.c $(H_FILE_LIST)
17 $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
18
19libtracelog.so: $(OBJS)
20 $(CC) $(LDFLAGS) -shared -fPIC -z relro -o $@ $(OBJS) -ldl
21
22
23clean:; rm -f $(OBJS) libtracelog.so
24
25distclean: clean
26 rm -fr Makefile
diff --git a/src/libtracelog/libtracelog.c b/src/libtracelog/libtracelog.c
deleted file mode 100644
index 0f8d5a00d..000000000
--- a/src/libtracelog/libtracelog.c
+++ /dev/null
@@ -1,704 +0,0 @@
1/*
2 * Copyright (C) 2014-2018 Firejail Authors
3 *
4 * This file is part of firejail project
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19*/
20#define _GNU_SOURCE
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <dlfcn.h>
25#include <sys/types.h>
26#include <unistd.h>
27#include <sys/socket.h>
28#include <netinet/in.h>
29#include <arpa/inet.h>
30#include <sys/un.h>
31#include <sys/stat.h>
32#include <syslog.h>
33#include <dirent.h>
34#include <limits.h>
35
36//#define DEBUG
37
38// break recursivity on fopen call
39typedef FILE *(*orig_fopen_t)(const char *pathname, const char *mode);
40static orig_fopen_t orig_fopen = NULL;
41typedef FILE *(*orig_fopen64_t)(const char *pathname, const char *mode);
42static orig_fopen64_t orig_fopen64 = NULL;
43
44//
45// blacklist storage
46//
47typedef struct list_elem_t {
48 struct list_elem_t *next;
49 char *path;
50} ListElem;
51
52#define HMASK 0x0ff
53ListElem *storage[HMASK + 1];
54
55// djb2
56static inline uint32_t hash(const char *str) {
57 uint32_t hash = 5381;
58 int c;
59
60 while ((c = *str++) != '\0')
61 hash = ((hash << 5) + hash) + c; // hash * 33 + c; another variant would be hash * 33 ^ c
62
63 return hash & HMASK;
64}
65
66static void storage_add(const char *str) {
67 if (!str) {
68#ifdef DEBUG
69 printf("null pointer passed to storage_add\n");
70#endif
71 return;
72 }
73
74#ifdef DEBUG
75 printf("add %s\n", str);
76#endif
77
78 ListElem *ptr = malloc(sizeof(ListElem));
79 if (!ptr) {
80 fprintf(stderr, "Error: cannot allocate memory\n");
81 return;
82 }
83 ptr->path = strdup(str);
84 if (!ptr->path) {
85 fprintf(stderr, "Error: cannot allocate memory\n");
86 free(ptr);
87 return;
88 }
89
90 // insert it into the hash table
91 uint32_t h = hash(ptr->path);
92 ptr->next = storage[h];
93 storage[h] = ptr;
94}
95
96// global variable to keep current working directory
97static char* cwd = NULL;
98
99static char *storage_find(const char *str) {
100 if (!str) {
101#ifdef DEBUG
102 printf("null pointer passed to storage_find\n");
103#endif
104 return NULL;
105 }
106
107#ifdef DEBUG
108 printf("storage find %s\n", str);
109#endif
110
111 const char *tofind = str;
112 int allocated = 0;
113
114 if (strstr(str, "..") || strstr(str, "/./") || strstr(str, "//") || str[0] != '/') {
115 if (cwd != NULL && str[0] != '/') {
116 char *fullpath=malloc(PATH_MAX);
117 if (!fullpath) {
118 fprintf(stderr, "Error: cannot allocate memory\n");
119 return NULL;
120 }
121 if (snprintf(fullpath, PATH_MAX, "%s/%s", cwd, str)<3) {
122 fprintf(stderr, "Error: snprintf failed\n");
123 free(fullpath);
124 return NULL;
125 }
126 tofind = realpath(fullpath, NULL);
127 free(fullpath);
128 } else {
129 tofind = realpath(str, NULL);
130 }
131 if (!tofind) {
132#ifdef DEBUG
133 printf("realpath failed\n");
134#endif
135 return NULL;
136 }
137 allocated = 1;
138 }
139
140 uint32_t h = hash(tofind);
141 ListElem *ptr = storage[h];
142 while (ptr) {
143 if (strcmp(tofind, ptr->path) == 0) {
144 if (allocated)
145 free((char *) tofind);
146#ifdef DEBUG
147 printf("storage found\n");
148#endif
149 return ptr->path;
150 }
151 ptr = ptr->next;
152 }
153
154 if (allocated)
155 free((char *) tofind);
156#ifdef DEBUG
157 printf("storage not found\n");
158#endif
159 return NULL;
160}
161
162
163//
164// load blacklist form /run/firejail/mnt/fslogger
165//
166#define RUN_FSLOGGER_FILE "/run/firejail/mnt/fslogger"
167#define MAXBUF 4096
168static int blacklist_loaded = 0;
169static char *sandbox_pid_str = NULL;
170static char *sandbox_name_str = NULL;
171static void load_blacklist(void) {
172 if (blacklist_loaded)
173 return;
174
175 // open filesystem log
176 if (!orig_fopen)
177 orig_fopen = (orig_fopen_t)dlsym(RTLD_NEXT, "fopen");
178 FILE *fp = orig_fopen(RUN_FSLOGGER_FILE, "r");
179 if (!fp)
180 return;
181
182 // extract blacklists
183 char buf[MAXBUF];
184 int cnt = 0;
185 while (fgets(buf, MAXBUF, fp)) {
186 if (strncmp(buf, "sandbox pid: ", 13) == 0) {
187 char *ptr = strchr(buf, '\n');
188 if (ptr)
189 *ptr = '\0';
190 if (sandbox_pid_str == NULL)
191 sandbox_pid_str = strdup(buf + 13);
192 }
193 else if (strncmp(buf, "sandbox name: ", 14) == 0) {
194 char *ptr = strchr(buf, '\n');
195 if (ptr)
196 *ptr = '\0';
197 if (sandbox_name_str == NULL)
198 sandbox_name_str = strdup(buf + 14);
199 }
200 else if (strncmp(buf, "blacklist ", 10) == 0) {
201 char *ptr = strchr(buf, '\n');
202 if (ptr)
203 *ptr = '\0';
204 storage_add(buf + 10);
205 cnt++;
206 }
207 }
208 fclose(fp);
209 blacklist_loaded = 1;
210#ifdef DEBUG
211 printf("Monitoring %d blacklists\n", cnt);
212 {
213 int i;
214 for (i = 0; i <= HMASK; i++) {
215 int cnt = 0;
216 ListElem *ptr = storage[i];
217 while (ptr) {
218 cnt++;
219 ptr = ptr->next;
220 }
221
222 if ((i % 16) == 0)
223 printf("\n");
224 printf("%02d ", cnt);
225 }
226 printf("\n");
227 }
228#endif
229}
230
231
232static void sendlog(const char *name, const char *call, const char *path) {
233 if (!name || !call || !path) {
234#ifdef DEBUG
235 printf("null pointer passed to sendlog\n");
236#endif
237 return;
238 }
239
240 openlog ("firejail", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);
241 if (sandbox_pid_str && sandbox_name_str)
242 syslog (LOG_INFO, "blacklist violation - sandbox %s, name %s, exe %s, syscall %s, path %s",
243 sandbox_pid_str, sandbox_name_str, name, call, path);
244 else if (sandbox_pid_str)
245 syslog (LOG_INFO, "blacklist violation - sandbox %s, exe %s, syscall %s, path %s",
246 sandbox_pid_str, name, call, path);
247 else
248 syslog (LOG_INFO, "blacklist violation - exe %s, syscall %s, path %s",
249 name, call, path);
250 closelog ();
251}
252
253
254//
255// pid
256//
257static pid_t mypid = 0;
258static inline pid_t pid(void) {
259 if (!mypid)
260 mypid = getpid();
261 return mypid;
262}
263
264//
265// process name
266//
267#define MAXNAME 16
268static char myname[MAXNAME];
269static int nameinit = 0;
270static char *name(void) {
271 if (!nameinit) {
272
273 // initialize the name of the process based on /proc/PID/comm
274 memset(myname, 0, MAXNAME);
275
276 pid_t p = pid();
277 char *fname;
278 if (asprintf(&fname, "/proc/%u/comm", p) == -1)
279 return "unknown";
280
281 // read file
282 if (!orig_fopen)
283 orig_fopen = (orig_fopen_t)dlsym(RTLD_NEXT, "fopen");
284 FILE *fp = orig_fopen(fname, "r");
285 if (!fp)
286 return "unknown";
287 if (fgets(myname, MAXNAME, fp) == NULL) {
288 fclose(fp);
289 free(fname);
290 return "unknown";
291 }
292
293 // clean '\n'
294 char *ptr = strchr(myname, '\n');
295 if (ptr)
296 *ptr = '\0';
297
298 fclose(fp);
299 free(fname);
300 nameinit = 1;
301 }
302
303 return myname;
304}
305
306//
307// syscalls
308//
309
310// open
311typedef int (*orig_open_t)(const char *pathname, int flags, mode_t mode);
312static orig_open_t orig_open = NULL;
313int open(const char *pathname, int flags, mode_t mode) {
314#ifdef DEBUG
315 printf("%s %s\n", __FUNCTION__, pathname);
316#endif
317 if (!orig_open)
318 orig_open = (orig_open_t)dlsym(RTLD_NEXT, "open");
319
320 if (!blacklist_loaded)
321 load_blacklist();
322
323 if (storage_find(pathname))
324 sendlog(name(), __FUNCTION__, pathname);
325 int rv = orig_open(pathname, flags, mode);
326 return rv;
327}
328
329
330
331
332//#if 0 - todo: fix problems on google-chrome and opera - seems to be crashing when open64 is called
333typedef int (*orig_open64_t)(const char *pathname, int flags, mode_t mode);
334static orig_open64_t orig_open64 = NULL;
335int open64(const char *pathname, int flags, mode_t mode) {
336#ifdef DEBUG
337 printf("%s %s\n", __FUNCTION__, pathname);
338#endif
339 if (!orig_open64)
340 orig_open64 = (orig_open64_t)dlsym(RTLD_NEXT, "open64");
341 if (!blacklist_loaded)
342 load_blacklist();
343
344 if (storage_find(pathname))
345 sendlog(name(), __FUNCTION__, pathname);
346 int rv = orig_open64(pathname, flags, mode);
347 return rv;
348}
349//#endif
350
351
352// openat
353typedef int (*orig_openat_t)(int dirfd, const char *pathname, int flags, mode_t mode);
354static orig_openat_t orig_openat = NULL;
355int openat(int dirfd, const char *pathname, int flags, mode_t mode) {
356#ifdef DEBUG
357 printf("%s %s\n", __FUNCTION__, pathname);
358#endif
359 if (!orig_openat)
360 orig_openat = (orig_openat_t)dlsym(RTLD_NEXT, "openat");
361 if (!blacklist_loaded)
362 load_blacklist();
363
364 if (storage_find(pathname))
365 sendlog(name(), __FUNCTION__, pathname);
366 int rv = orig_openat(dirfd, pathname, flags, mode);
367 return rv;
368}
369
370typedef int (*orig_openat64_t)(int dirfd, const char *pathname, int flags, mode_t mode);
371static orig_openat64_t orig_openat64 = NULL;
372int openat64(int dirfd, const char *pathname, int flags, mode_t mode) {
373#ifdef DEBUG
374 printf("%s %s\n", __FUNCTION__, pathname);
375#endif
376 if (!orig_openat64)
377 orig_openat64 = (orig_openat64_t)dlsym(RTLD_NEXT, "openat64");
378 if (!blacklist_loaded)
379 load_blacklist();
380
381 if (storage_find(pathname))
382 sendlog(name(), __FUNCTION__, pathname);
383 int rv = orig_openat64(dirfd, pathname, flags, mode);
384 return rv;
385}
386
387
388// fopen
389FILE *fopen(const char *pathname, const char *mode) {
390#ifdef DEBUG
391 printf("%s %s\n", __FUNCTION__, pathname);
392#endif
393 if (!orig_fopen)
394 orig_fopen = (orig_fopen_t)dlsym(RTLD_NEXT, "fopen");
395 if (!blacklist_loaded)
396 load_blacklist();
397
398 if (storage_find(pathname))
399 sendlog(name(), __FUNCTION__, pathname);
400 FILE *rv = orig_fopen(pathname, mode);
401 return rv;
402}
403
404#ifdef __GLIBC__
405FILE *fopen64(const char *pathname, const char *mode) {
406#ifdef DEBUG
407 printf("%s %s\n", __FUNCTION__, pathname);
408#endif
409 if (!orig_fopen64)
410 orig_fopen64 = (orig_fopen_t)dlsym(RTLD_NEXT, "fopen64");
411 if (!blacklist_loaded)
412 load_blacklist();
413
414 if (storage_find(pathname))
415 sendlog(name(), __FUNCTION__, pathname);
416 FILE *rv = orig_fopen64(pathname, mode);
417 return rv;
418}
419#endif /* __GLIBC__ */
420
421
422// freopen
423typedef FILE *(*orig_freopen_t)(const char *pathname, const char *mode, FILE *stream);
424static orig_freopen_t orig_freopen = NULL;
425FILE *freopen(const char *pathname, const char *mode, FILE *stream) {
426#ifdef DEBUG
427 printf("%s %s\n", __FUNCTION__, pathname);
428#endif
429 if (!orig_freopen)
430 orig_freopen = (orig_freopen_t)dlsym(RTLD_NEXT, "freopen");
431 if (!blacklist_loaded)
432 load_blacklist();
433
434 if (storage_find(pathname))
435 sendlog(name(), __FUNCTION__, pathname);
436 FILE *rv = orig_freopen(pathname, mode, stream);
437 return rv;
438}
439
440#ifdef __GLIBC__
441typedef FILE *(*orig_freopen64_t)(const char *pathname, const char *mode, FILE *stream);
442static orig_freopen64_t orig_freopen64 = NULL;
443FILE *freopen64(const char *pathname, const char *mode, FILE *stream) {
444#ifdef DEBUG
445 printf("%s %s\n", __FUNCTION__, pathname);
446#endif
447 if (!orig_freopen64)
448 orig_freopen64 = (orig_freopen64_t)dlsym(RTLD_NEXT, "freopen64");
449 if (!blacklist_loaded)
450 load_blacklist();
451
452 if (storage_find(pathname))
453 sendlog(name(), __FUNCTION__, pathname);
454 FILE *rv = orig_freopen64(pathname, mode, stream);
455 return rv;
456}
457#endif /* __GLIBC__ */
458
459// unlink
460typedef int (*orig_unlink_t)(const char *pathname);
461static orig_unlink_t orig_unlink = NULL;
462int unlink(const char *pathname) {
463#ifdef DEBUG
464 printf("%s %s\n", __FUNCTION__, pathname);
465#endif
466 if (!orig_unlink)
467 orig_unlink = (orig_unlink_t)dlsym(RTLD_NEXT, "unlink");
468 if (!blacklist_loaded)
469 load_blacklist();
470
471 if (storage_find(pathname))
472 sendlog(name(), __FUNCTION__, pathname);
473 int rv = orig_unlink(pathname);
474 return rv;
475}
476
477typedef int (*orig_unlinkat_t)(int dirfd, const char *pathname, int flags);
478static orig_unlinkat_t orig_unlinkat = NULL;
479int unlinkat(int dirfd, const char *pathname, int flags) {
480#ifdef DEBUG
481 printf("%s %s\n", __FUNCTION__, pathname);
482#endif
483 if (!orig_unlinkat)
484 orig_unlinkat = (orig_unlinkat_t)dlsym(RTLD_NEXT, "unlinkat");
485 if (!blacklist_loaded)
486 load_blacklist();
487
488 if (storage_find(pathname))
489 sendlog(name(), __FUNCTION__, pathname);
490 int rv = orig_unlinkat(dirfd, pathname, flags);
491 return rv;
492}
493
494// mkdir/mkdirat/rmdir
495typedef int (*orig_mkdir_t)(const char *pathname, mode_t mode);
496static orig_mkdir_t orig_mkdir = NULL;
497int mkdir(const char *pathname, mode_t mode) {
498#ifdef DEBUG
499 printf("%s %s\n", __FUNCTION__, pathname);
500#endif
501 if (!orig_mkdir)
502 orig_mkdir = (orig_mkdir_t)dlsym(RTLD_NEXT, "mkdir");
503 if (!blacklist_loaded)
504 load_blacklist();
505
506 if (storage_find(pathname))
507 sendlog(name(), __FUNCTION__, pathname);
508 int rv = orig_mkdir(pathname, mode);
509 return rv;
510}
511
512typedef int (*orig_mkdirat_t)(int dirfd, const char *pathname, mode_t mode);
513static orig_mkdirat_t orig_mkdirat = NULL;
514int mkdirat(int dirfd, const char *pathname, mode_t mode) {
515#ifdef DEBUG
516 printf("%s %s\n", __FUNCTION__, pathname);
517#endif
518 if (!orig_mkdirat)
519 orig_mkdirat = (orig_mkdirat_t)dlsym(RTLD_NEXT, "mkdirat");
520 if (!blacklist_loaded)
521 load_blacklist();
522
523 if (storage_find(pathname))
524 sendlog(name(), __FUNCTION__, pathname);
525 int rv = orig_mkdirat(dirfd, pathname, mode);
526 return rv;
527}
528
529typedef int (*orig_rmdir_t)(const char *pathname);
530static orig_rmdir_t orig_rmdir = NULL;
531int rmdir(const char *pathname) {
532#ifdef DEBUG
533 printf("%s %s\n", __FUNCTION__, pathname);
534#endif
535 if (!orig_rmdir)
536 orig_rmdir = (orig_rmdir_t)dlsym(RTLD_NEXT, "rmdir");
537 if (!blacklist_loaded)
538 load_blacklist();
539
540 if (storage_find(pathname))
541 sendlog(name(), __FUNCTION__, pathname);
542 int rv = orig_rmdir(pathname);
543 return rv;
544}
545
546// stat
547typedef int (*orig_stat_t)(const char *pathname, struct stat *buf);
548static orig_stat_t orig_stat = NULL;
549int stat(const char *pathname, struct stat *buf) {
550#ifdef DEBUG
551 printf("%s %s\n", __FUNCTION__, pathname);
552#endif
553 if (!orig_stat)
554 orig_stat = (orig_stat_t)dlsym(RTLD_NEXT, "stat");
555 if (!blacklist_loaded)
556 load_blacklist();
557
558 if (storage_find(pathname))
559 sendlog(name(), __FUNCTION__, pathname);
560 int rv = orig_stat(pathname, buf);
561 return rv;
562}
563
564#ifdef __GLIBC__
565typedef int (*orig_stat64_t)(const char *pathname, struct stat64 *buf);
566static orig_stat64_t orig_stat64 = NULL;
567int stat64(const char *pathname, struct stat64 *buf) {
568#ifdef DEBUG
569 printf("%s %s\n", __FUNCTION__, pathname);
570#endif
571 if (!orig_stat64)
572 orig_stat64 = (orig_stat64_t)dlsym(RTLD_NEXT, "stat64");
573 if (!blacklist_loaded)
574 load_blacklist();
575
576 if (storage_find(pathname))
577 sendlog(name(), __FUNCTION__, pathname);
578 int rv = orig_stat64(pathname, buf);
579 return rv;
580}
581#endif /* __GLIBC__ */
582
583typedef int (*orig_lstat_t)(const char *pathname, struct stat *buf);
584static orig_lstat_t orig_lstat = NULL;
585int lstat(const char *pathname, struct stat *buf) {
586#ifdef DEBUG
587 printf("%s %s\n", __FUNCTION__, pathname);
588#endif
589 if (!orig_lstat)
590 orig_lstat = (orig_lstat_t)dlsym(RTLD_NEXT, "lstat");
591 if (!blacklist_loaded)
592 load_blacklist();
593
594 if (storage_find(pathname))
595 sendlog(name(), __FUNCTION__, pathname);
596 int rv = orig_lstat(pathname, buf);
597 return rv;
598}
599
600#ifdef __GLIBC__
601typedef int (*orig_lstat64_t)(const char *pathname, struct stat64 *buf);
602static orig_lstat64_t orig_lstat64 = NULL;
603int lstat64(const char *pathname, struct stat64 *buf) {
604#ifdef DEBUG
605 printf("%s %s\n", __FUNCTION__, pathname);
606#endif
607 if (!orig_lstat64)
608 orig_lstat64 = (orig_lstat64_t)dlsym(RTLD_NEXT, "lstat64");
609 if (!blacklist_loaded)
610 load_blacklist();
611
612 if (storage_find(pathname))
613 sendlog(name(), __FUNCTION__, pathname);
614 int rv = orig_lstat64(pathname, buf);
615 return rv;
616}
617#endif /* __GLIBC__ */
618
619// access
620typedef int (*orig_access_t)(const char *pathname, int mode);
621static orig_access_t orig_access = NULL;
622int access(const char *pathname, int mode) {
623#ifdef DEBUG
624 printf("%s, %s\n", __FUNCTION__, pathname);
625#endif
626 if (!orig_access)
627 orig_access = (orig_access_t)dlsym(RTLD_NEXT, "access");
628 if (!blacklist_loaded)
629 load_blacklist();
630
631 if (storage_find(pathname))
632 sendlog(name(), __FUNCTION__, pathname);
633 int rv = orig_access(pathname, mode);
634 return rv;
635}
636
637// opendir
638typedef DIR *(*orig_opendir_t)(const char *pathname);
639static orig_opendir_t orig_opendir = NULL;
640DIR *opendir(const char *pathname) {
641#ifdef DEBUG
642 printf("%s %s\n", __FUNCTION__, pathname);
643#endif
644 if (!orig_opendir)
645 orig_opendir = (orig_opendir_t)dlsym(RTLD_NEXT, "opendir");
646 if (!blacklist_loaded)
647 load_blacklist();
648
649 if (storage_find(pathname))
650 sendlog(name(), __FUNCTION__, pathname);
651 DIR *rv = orig_opendir(pathname);
652 return rv;
653}
654
655// chdir
656typedef int (*orig_chdir_t)(const char *pathname);
657static orig_chdir_t orig_chdir = NULL;
658int chdir(const char *pathname) {
659#ifdef DEBUG
660 printf("%s %s\n", __FUNCTION__, pathname);
661#endif
662 if (!orig_chdir)
663 orig_chdir = (orig_chdir_t)dlsym(RTLD_NEXT, "chdir");
664 if (!blacklist_loaded)
665 load_blacklist();
666
667 if (storage_find(pathname))
668 sendlog(name(), __FUNCTION__, pathname);
669
670 free(cwd);
671 cwd = strdup(pathname);
672
673 int rv = orig_chdir(pathname);
674 return rv;
675}
676
677// fchdir
678typedef int (*orig_fchdir_t)(int fd);
679static orig_fchdir_t orig_fchdir = NULL;
680int fchdir(int fd) {
681#ifdef DEBUG
682 printf("%s %d\n", __FUNCTION__, fd);
683#endif
684 if (!orig_fchdir)
685 orig_fchdir = (orig_fchdir_t)dlsym(RTLD_NEXT, "fchdir");
686
687 free(cwd);
688 char *pathname=malloc(PATH_MAX);
689 if (pathname) {
690 if (snprintf(pathname,PATH_MAX,"/proc/self/fd/%d", fd)>0) {
691 cwd = realpath(pathname, NULL);
692 } else {
693 cwd = NULL;
694 fprintf(stderr, "Error: snprintf failed\n");
695 }
696 free(pathname);
697 } else {
698 fprintf(stderr, "Error: cannot allocate memory\n");
699 cwd = NULL;
700 }
701
702 int rv = orig_fchdir(fd);
703 return rv;
704}