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>
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 *
5356 * called intercept.
5457 */
5558static __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)
99106int
100107syscall_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}
0 commit comments