Skip to content
This repository was archived by the owner on Jan 6, 2025. It is now read-only.

Commit d263de2

Browse files
author
Sarah Jelinek
authored
Merge pull request #41 from GBuella/no_proc_self_cmdline
Remove usage of /proc/self/cmdline
2 parents 67d2cf0 + bdb31e3 commit d263de2

File tree

4 files changed

+69
-49
lines changed

4 files changed

+69
-49
lines changed

README.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,11 @@ intercept.log-123.
103103
is not truncated.
104104
105105
*INTERCEPT_HOOK_CMDLINE_FILTER* -- when set, the library
106-
checks the contents of the /proc/self/cmdline file.
106+
checks the command line used to start the program.
107107
Hotpatching, and syscall intercepting is only done, if the
108-
last component of the first zero terminated string in
109-
/proc/self/cmdline matches the string provided
110-
in the environment variable. This can also be queried
111-
by the user of the library:
108+
last component of the command used to start the program
109+
is the same as the string provided in the environment variable.
110+
This can also be queried by the user of the library:
112111
```c
113112
int syscall_hook_in_process_allowed(void);
114113
```

src/entry.c

Lines changed: 38 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
* expected to be executed by the loader while using LD_PRELOAD
3636
*/
3737

38+
#include <stdbool.h>
3839
#include <stdlib.h>
3940
#include <string.h>
4041
#include <syscall.h>
@@ -44,6 +45,8 @@
4445
#include "libsyscall_intercept_hook_point.h"
4546
#include "intercept.h"
4647

48+
static const char *cmdline;
49+
4750
/*
4851
* entry_point - the main entry point for syscall_intercept
4952
*
@@ -53,41 +56,45 @@
5356
* called intercept.
5457
*/
5558
static __attribute__((constructor)) void
56-
entry_point(void)
59+
entry_point(int argc, char **argv)
5760
{
61+
if (argc < 1)
62+
return;
63+
64+
cmdline = argv[0];
65+
5866
if (syscall_hook_in_process_allowed())
5967
intercept();
6068
}
6169

6270
/*
63-
* match_with_file_end
64-
* Compare a string with the end of a file's contents.
65-
* Reads only char by char, but it is expected to be used only for a dozen or so
66-
* chars at a time. See syscall_hook_in_process_allowed below.
71+
* cmdline_match - match the last component of the path in cmdline
6772
*/
68-
static bool
69-
match_with_file_end(const char *expected, int fd)
73+
static int
74+
cmdline_match(const char *filter)
7075
{
71-
char file_c; /* next character from file */
72-
const char *c; /* next character from the expected string */
73-
74-
if (expected[0] == '\0')
75-
return false;
76-
77-
c = expected;
78-
79-
while (syscall_no_intercept(SYS_read, fd, &file_c, (size_t)1)
80-
== (ssize_t)1) {
81-
if (file_c == '\0') /* this probably never happens */
82-
break;
76+
if (filter == NULL)
77+
return 1;
8378

84-
if (file_c != *c)
85-
c = expected; /* start from the beginning */
86-
else
87-
++c; /* match next char */
88-
}
79+
size_t flen = strlen(filter);
80+
size_t clen = strlen(cmdline);
81+
82+
if (flen > clen)
83+
return 0; /* cmdline can't contain filter */
84+
85+
/*
86+
* If cmdline is longer, it must end with a slash + filter:
87+
* "./somewhere/a.out" matches "a.out"
88+
* "./a.out" matches "a.out"
89+
* "./xa.out" does not match "a.out"
90+
*
91+
* Of course if cmdline is not longer, the slash is not needed:
92+
* "a.out" matches "a.out"
93+
*/
94+
if (clen > flen && cmdline[clen - flen - 1] != '/')
95+
return 0;
8996

90-
return *c == '\0';
97+
return strcmp(cmdline + clen - flen, filter) == 0;
9198
}
9299

93100
/*
@@ -99,23 +106,14 @@ match_with_file_end(const char *expected, int fd)
99106
int
100107
syscall_hook_in_process_allowed(void)
101108
{
102-
int fd;
103-
bool result;
104-
const char *filter;
105-
106-
filter = getenv("INTERCEPT_HOOK_CMDLINE_FILTER");
107-
if (filter == NULL)
108-
return 1;
109-
110-
fd = (int)syscall_no_intercept(SYS_open,
111-
"/proc/self/cmdline", O_RDONLY, (mode_t)0);
112-
113-
if (fd < 0)
114-
return 0;
109+
static bool is_decided;
110+
static int result;
115111

116-
result = match_with_file_end(filter, fd);
112+
if (is_decided)
113+
return result;
117114

118-
(void) syscall_no_intercept(SYS_close, fd);
115+
result = cmdline_match(getenv("INTERCEPT_HOOK_CMDLINE_FILTER"));
116+
is_decided = true;
119117

120118
return result;
121119
}

test/CMakeLists.txt

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,12 +165,10 @@ add_test(NAME "filter_none"
165165
set_tests_properties("filter_none"
166166
PROPERTIES PASS_REGULAR_EXPRESSION "hooked - allowed")
167167

168-
get_filename_component(filter_test_filename $<TARGET_FILE:filter_test> NAME)
169-
170168
add_test(NAME "filter_positive"
171169
COMMAND ${CMAKE_COMMAND}
172170
-DTEST_EXTRA_PRELOAD=${TEST_EXTRA_PRELOAD}
173-
-DFILTER=${filter_test_filename}
171+
-DFILTER=$<TARGET_FILE_NAME:filter_test>
174172
-DTEST_PROG=$<TARGET_FILE:filter_test>
175173
-P ${CMAKE_CURRENT_SOURCE_DIR}/check.cmake)
176174
set_tests_properties("filter_positive"
@@ -185,6 +183,26 @@ add_test(NAME "filter_negative"
185183
set_tests_properties("filter_negative"
186184
PROPERTIES PASS_REGULAR_EXPRESSION "disallowed")
187185

186+
# the filter is a substring of the executable name
187+
add_test(NAME "filter_negative_substring0"
188+
COMMAND ${CMAKE_COMMAND}
189+
-DTEST_EXTRA_PRELOAD=${TEST_EXTRA_PRELOAD}
190+
-DFILTER_PLUS_ONECHAR=$<TARGET_FILE_NAME:filter_test>
191+
-DTEST_PROG=$<TARGET_FILE:filter_test>
192+
-P ${CMAKE_CURRENT_SOURCE_DIR}/check.cmake)
193+
set_tests_properties("filter_negative_substring0"
194+
PROPERTIES PASS_REGULAR_EXPRESSION "disallowed")
195+
196+
# the executable name is a substring of the filter
197+
add_test(NAME "filter_negative_substring1"
198+
COMMAND ${CMAKE_COMMAND}
199+
-DTEST_EXTRA_PRELOAD=${TEST_EXTRA_PRELOAD}
200+
-DFILTER=A$<TARGET_FILE_NAME:filter_test>
201+
-DTEST_PROG=$<TARGET_FILE:filter_test>
202+
-P ${CMAKE_CURRENT_SOURCE_DIR}/check.cmake)
203+
set_tests_properties("filter_negative_substring1"
204+
PROPERTIES PASS_REGULAR_EXPRESSION "disallowed")
205+
188206
add_executable(test_clone_thread test_clone_thread.c)
189207
target_link_libraries(test_clone_thread PRIVATE ${CMAKE_THREAD_LIBS_INIT})
190208
add_library(test_clone_thread_preload SHARED test_clone_thread_preload.c)

test/check.cmake

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,13 @@
3030
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3131

3232

33+
if(FILTER_PLUS_ONECHAR)
34+
string(SUBSTRING "${FILTER_PLUS_ONECHAR}" 1 -1 FILTER)
35+
endif()
36+
3337
if(FILTER)
34-
set(ENV{INTERCEPT_HOOK_CMDLINE_FILTER} ${FILTER})
38+
set(ENV{INTERCEPT_HOOK_CMDLINE_FILTER} ${FILTER})
39+
message("FILTER: ${FILTER}")
3540
endif()
3641

3742
if(LIB_FILE)

0 commit comments

Comments
 (0)