diff options
author | Alexander Bersenev <bay@hackerdom.ru> | 2011-06-27 03:41:57 +0000 |
---|---|---|
committer | Alexander Bersenev <bay@hackerdom.ru> | 2011-06-27 03:41:57 +0000 |
commit | d8d0c8f39f95af3647f73b5781199899e9b9529d (patch) | |
tree | 73691538b09cd6a3e12236a7b95fbb4495cdbc4b | |
parent | using epoll instead of select (diff) | |
download | autodep-d8d0c8f39f95af3647f73b5781199899e9b9529d.tar.gz autodep-d8d0c8f39f95af3647f73b5781199899e9b9529d.tar.bz2 autodep-d8d0c8f39f95af3647f73b5781199899e9b9529d.zip |
hooklib approach has been rewritten
-rw-r--r-- | logger/src/autodep/logfs/fstracer.py | 36 | ||||
-rw-r--r-- | logger/src/autodep/logfs/logger_hooklib.py | 1 | ||||
-rw-r--r-- | logger/src/autodep/logfs/test_fstracer.py | 51 | ||||
-rw-r--r-- | logger/src/hook_lib/file_hook.c | 354 |
4 files changed, 249 insertions, 193 deletions
diff --git a/logger/src/autodep/logfs/fstracer.py b/logger/src/autodep/logfs/fstracer.py index a4a5b49..7ceb36e 100644 --- a/logger/src/autodep/logfs/fstracer.py +++ b/logger/src/autodep/logfs/fstracer.py @@ -5,6 +5,7 @@ This module is a bridge between low-level logging services and high level handli import os import sys +import stat import time import tempfile import socket @@ -132,6 +133,10 @@ def getfsevents(prog_name,arguments,approach="hooklib",filterproc=defaultfilter) sock_listen.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock_listen.bind(socketname) sock_listen.listen(1024) + # enable connect a socket for anyone + os.chmod(tmpdir,stat.S_IRUSR|stat.S_IWUSR|stat.S_IXUSR|stat.S_IROTH|stat.S_IWOTH|stat.S_IXOTH) + os.chmod(socketname,stat.S_IRUSR|stat.S_IWUSR|stat.S_IROTH|stat.S_IWOTH) + except socket.error, e: print "Failed to create a socket for exchange data with the logger: %s" % e return [] @@ -161,6 +166,7 @@ def getfsevents(prog_name,arguments,approach="hooklib",filterproc=defaultfilter) connects = 0; clients={} stop=0 + was_first_connect=False while stop==0: sock_events = epoll.poll(3) @@ -172,21 +178,27 @@ def getfsevents(prog_name,arguments,approach="hooklib",filterproc=defaultfilter) else: (client,addr)=ret connects+=1; # client accepted + was_first_connect=True epoll.register(client.fileno(), select.EPOLLIN) clients[client.fileno()]=client - elif sock_event & select.EPOLLHUP: - epoll.unregister(fileno) - clients[fileno].close() - del clients[fileno] - connects-=1 + #elif sock_event & select.EPOLLHUP: + #epoll.unregister(fileno) + #clients[fileno].close() + #del clients[fileno] + #connects-=1 - if connects==0: - stop=1 - break elif sock_event & select.EPOLLIN: s=clients[fileno] record=s.recv(8192) + if not record: # if connection was closed + epoll.unregister(fileno) + clients[fileno].close() + del clients[fileno] + connects-=1 + #print "closing!!" + continue + message=record.split("\0") #print message @@ -194,11 +206,11 @@ def getfsevents(prog_name,arguments,approach="hooklib",filterproc=defaultfilter) if message[4]=="ASKING": if filterproc(message[1],message[2],message[3]): #print "Allowing an access to %s" % message[2] - s.sendall("ALLOW"); # TODO: think about flush here + s.sendall("ALLOW\0"); # TODO: think about flush here else: print "Blocking an access to %s" % message[2] - s.sendall("DENY"); # TODO: think about flush here + s.sendall("DENY\0"); # TODO: think about flush here else: eventname,filename,stage,result=message[1:5] @@ -236,7 +248,9 @@ def getfsevents(prog_name,arguments,approach="hooklib",filterproc=defaultfilter) except IndexError: print "IndexError while parsing %s"%record - + if was_first_connect and connects==0: + break + if len(sock_events)==0 and len(clients)==0: # # seems like there is no connect print "It seems like a logger module was unable to start or failed to finish\n" + \ diff --git a/logger/src/autodep/logfs/logger_hooklib.py b/logger/src/autodep/logfs/logger_hooklib.py index cf677f4..cda22b6 100644 --- a/logger/src/autodep/logfs/logger_hooklib.py +++ b/logger/src/autodep/logfs/logger_hooklib.py @@ -1,6 +1,7 @@ #!/usr/bin/env python2 import os +import sys class logger: socketname='' diff --git a/logger/src/autodep/logfs/test_fstracer.py b/logger/src/autodep/logfs/test_fstracer.py index db61486..15d4c27 100644 --- a/logger/src/autodep/logfs/test_fstracer.py +++ b/logger/src/autodep/logfs/test_fstracer.py @@ -16,47 +16,49 @@ def simple_getfsevents(prog,args,approach="hooklib"): class hooklib_simple_tests(unittest.TestCase): def test_open_unexists(self): - self.assertEqual(fstracer.getfsevents('/bin/cat', - ['/bin/cat','f1','f2']), - [['open', 'f1'], ['open', 'f2']]) + eventslist=simple_getfsevents('/bin/cat', ['/bin/cat','/f1','/f2'],approach="hooklib") + print eventslist + self.assertTrue(eventslist.count(['/f1',"fail"])==1) + self.assertTrue(eventslist.count(['/f2',"fail"])==1) def test_open_exists(self): - self.assertEqual(fstracer.getfsevents('/bin/cat', - ['/bin/cat','/etc/passwd']), - [['open', '/etc/passwd']]) + eventslist=simple_getfsevents('/bin/cat', ['/bin/cat','/etc/passwd'],approach="hooklib") + self.assertTrue(eventslist.count(['/etc/passwd','success'])>=1) - def test_open_many(self): filesnum=200 - self.assertEqual(fstracer.getfsevents('/bin/cat', - ['/bin/cat']+map(lambda x: 'file'+str(x),range(0,filesnum))), - map(lambda x: ['open','file'+str(x)],range(0,filesnum))) - + eventslist=simple_getfsevents('/bin/cat',['/bin/cat']+ + map(lambda x: '/file'+str(x),range(0,filesnum)), approach="hooklib") + for f in map(lambda x: ['/file'+str(x),'fail'],range(0,filesnum)): + self.assertTrue(f in eventslist) def test_parralel(self): - filesnum=200 - procnum=6 + filesnum=400 + procnum=8 # create command command="" for p in xrange(0,procnum): command+="/bin/cat " for f in xrange(0,filesnum): - command+="file_%d_%d " % (p,f) + command+="/file_%d_%d " % (p,f) command+="& " - command+=" >/dev/null 2>&1" - command+=" "+"A"*65536 - + command+=" 2>/dev/null" + #command+=" "+"A"*65536 - resultarray=fstracer.getfsevents('/bin/sh', ['/bin/sh','-c',command]) - - self.assertTrue(resultarray.count(['execve', '/bin/cat'])==procnum) - - print resultarray + resultarray=simple_getfsevents('/bin/sh', ['/bin/sh','-c',command],approach="hooklib") for p in xrange(0,procnum): for f in xrange(0,filesnum): - self.assertTrue(resultarray.count(['open', 'file_%d_%d' % (p,f)])==1) + self.assertTrue(resultarray.count(['/file_%d_%d' % (p,f),"fail"])==1) + + def test_open_very_many(self): + resultarray=simple_getfsevents('/bin/sh', ['/bin/sh','-c', + "for i in `seq 1 1000`; do cat /testmany$i;done 2> /dev/null"],approach="hooklib") + #print resultarray + for i in range(1,1000): + self.assertTrue(resultarray.count(['/testmany'+str(i),'fail'])==1) + class fusefs_simple_tests(unittest.TestCase): def test_open_unexists(self): @@ -105,5 +107,6 @@ class fusefs_simple_tests(unittest.TestCase): if __name__ == '__main__': #unittest.main() - suite = unittest.TestLoader().loadTestsFromTestCase(fusefs_simple_tests) + #suite = unittest.TestLoader().loadTestsFromTestCase(fusefs_simple_tests) + suite = unittest.TestLoader().loadTestsFromTestCase(hooklib_simple_tests) unittest.TextTestRunner(verbosity=2).run(suite)
\ No newline at end of file diff --git a/logger/src/hook_lib/file_hook.c b/logger/src/hook_lib/file_hook.c index d17becc..7c846e2 100644 --- a/logger/src/hook_lib/file_hook.c +++ b/logger/src/hook_lib/file_hook.c @@ -8,6 +8,7 @@ #include <time.h> #include <dlfcn.h> +#include <pthread.h> #define _FCNTL_H #include <bits/fcntl.h> @@ -16,36 +17,48 @@ #include <sys/socket.h> #include <sys/un.h> -#define MAXPATHLEN 256 +#define MAXPATHLEN 1024 #define MAXSOCKETPATHLEN 108 #define MAXFILEBUFFLEN 2048 +#define MAXSOCKETMSGLEN 8192 + //extern int errorno; +pthread_mutex_t socketblock = PTHREAD_MUTEX_INITIALIZER; + int (*_open)(const char * pathname, int flags, ...); int (*_open64)(const char * pathname, int flags, ...); FILE * (*_fopen)(const char *path, const char *mode); FILE * (*_fopen64)(const char *path, const char *mode); int (*_execve)(const char *filename, char *const argv[],char *const envp[]); -pid_t (*_fork)(); +ssize_t (*_read)(int fd, void *buf, size_t count); +ssize_t (*_write)(int fd, const void *buf, size_t count); +size_t (*_fread)(void *ptr, size_t size, size_t nmemb, FILE *stream); +size_t (*_fwrite)(const void *ptr, size_t size, size_t nmemb, FILE *stream); -FILE *log_file; // one of these two vars will be used for logging -int log_socket=-1; +int (*_close)(int fd); // we hooking this, because some programs closes our socket -int is_log_into_socket=0; +int log_socket=-1; void __doinit(){ - //stat(NULL,NULL); _open = (int (*)(const char * pathname, int flags, ...)) dlsym(RTLD_NEXT, "open"); _open64 = (int (*)(const char * pathname, int flags, ...)) dlsym(RTLD_NEXT, "open64"); + _fopen = (FILE * (*)(const char *path, const char *mode)) dlsym(RTLD_NEXT, "fopen"); _fopen64 = (FILE * (*)(const char *path, const char *mode)) dlsym(RTLD_NEXT, "fopen64"); + + _read= (ssize_t (*)(int fd, void *buf, size_t count)) dlsym(RTLD_NEXT, "read"); + _write= (ssize_t (*)(int fd, const void *buf, size_t count)) dlsym(RTLD_NEXT, "write"); + _execve = (int (*)(const char *filename, char *const argv[],char *const envp[])) dlsym(RTLD_NEXT, "execve"); - _fork = (pid_t (*)()) dlsym(RTLD_NEXT, "fork"); + _close= (int (*)(int fd)) dlsym(RTLD_NEXT, "close"); + + if(_open==NULL || _open64==NULL || _fopen==NULL || _fopen64==NULL || - execve==NULL || _fork==NULL) { + execve==NULL || _read==NULL || _write==NULL || close==NULL) { fprintf(stderr,"Failed to load original functions of hook\n"); exit(1); } @@ -53,19 +66,17 @@ void __doinit(){ char *log_socket_name=getenv("LOG_SOCKET"); if(log_socket_name==NULL) { - fprintf(stderr,"Using stderr as output for logs " - "because the LOG_SOCKET environment variable isn't defined.\n"); + fprintf(stderr,"LOG_SOCKET environment variable isn't defined." + "Are this library launched by server?\n"); - log_file=stderr; + exit(1); } else { - is_log_into_socket=1; - if(strlen(log_socket_name)>=MAXSOCKETPATHLEN) { fprintf(stderr,"Unable to create a unix-socket %s: socket name is too long,exiting\n", log_socket_name); exit(1); } - log_socket=socket(AF_UNIX, SOCK_STREAM, 0); + log_socket=socket(AF_UNIX, SOCK_SEQPACKET, 0); if(log_socket==-1) { fprintf(stderr,"Unable to create a unix-socket %s: %s\n", log_socket_name, strerror(errno)); exit(1); @@ -81,24 +92,11 @@ void __doinit(){ fprintf(stderr,"Unable to connect a unix-socket: %s\n", strerror(errno)); exit(1); } - - log_file=fdopen(log_socket,"r+"); - - if(log_file==NULL) { - fprintf(stderr,"Unable to open a socket for a steam writing: %s\n", strerror(errno)); - exit(1); - } } } void __dofini() { - fflush(log_file); - fclose(log_file); - - if(is_log_into_socket) - close(log_socket); - - //fprintf(stderr,"All sockets closed\n"); + //close(log_socket); } void _init() { @@ -110,188 +108,228 @@ void _fini() { } /* - * Prints a string escaping spaces and '\' - * Does not check input variables -*/ -void __print_escaped(FILE *fh ,const char *s){ - for(;(*s)!=0; s++) { - if(*s==' ') - fprintf(fh,"\\ "); - else if(*s==',') - fprintf(fh,"\\,"); - else if(*s=='\r') - fprintf(fh,"\\r"); - else if(*s=='\n') - fprintf(fh,"\\n"); - else if(*s=='\\') - fprintf(fh,"\\\\"); - else - fprintf(fh,"%c", *s); - } -} - -/* - * Get a pid of the parent proccess - * Parse the /proc/pid/stat - * We need a first number after last ')' character + * Format of log string: time event filename stage result/err */ -pid_t __getparentpid(pid_t pid){ - char filename[MAXPATHLEN]; - snprintf(filename,MAXPATHLEN, "/proc/%d/stat",pid); - FILE *stat_file_handle=fopen(filename,"r"); - if(stat_file_handle==NULL) { - fprintf(log_file,"NULL"); - return 0; - } - - char filedata[MAXFILEBUFFLEN]; - size_t bytes_readed=fread(filedata,sizeof(char),MAXFILEBUFFLEN,stat_file_handle); - if(bytes_readed==0 || bytes_readed>=MAXFILEBUFFLEN) { - fprintf(log_file,"NULL"); - fclose(stat_file_handle); - return 0; - } - - filedata[bytes_readed]=0; - - char *beg_scan_offset=rindex(filedata,')'); - if(beg_scan_offset==NULL) { - fprintf(log_file,"NULL"); - fclose(stat_file_handle); - return 0; +static void __raw_log_event(const char *event_type, const char *filename, char *result,int err, char* stage) { + //printf("lololo:%s %s %s\n",event_type,filename,stage); + + char msg_buff[MAXSOCKETMSGLEN]; + int bytes_to_send; + if(strcmp(result,"ERR")==0) { + bytes_to_send=snprintf(msg_buff,MAXSOCKETMSGLEN,"%lld%c%s%c%s%c%s%c%s/%d", + (unsigned long long)time(NULL),0,event_type,0,filename,0,stage,0,result,err); + } else { + bytes_to_send=snprintf(msg_buff,MAXSOCKETMSGLEN,"%lld%c%s%c%s%c%s%c%s", + (unsigned long long)time(NULL),0,event_type,0,filename,0,stage,0,result); } - pid_t parent_pid; - int tokens_readed=sscanf(beg_scan_offset,") %*c %d",&parent_pid); - if(tokens_readed!=1) { - fprintf(log_file,"NULL"); - fclose(stat_file_handle); - return 0; + if(bytes_to_send>=MAXSOCKETMSGLEN) return; + if(send(log_socket,msg_buff,bytes_to_send,0)==-1) { + printf("BAYBAY!!!11 %d %d\n",log_socket, getpid()); + sleep(100500); } - fclose(stat_file_handle); - if(pid==1) - return 0; // set this explicitly. - // I am not sure that ppid of init proccess is always 0 - - return parent_pid; } /* - * Print cmdline of proccess(escaped) + * Log an event */ -void __print_cmdline(pid_t pid) { - char filename[MAXPATHLEN]; - snprintf(filename,MAXPATHLEN, "/proc/%d/cmdline",pid); - FILE *cmdline_file_handle=fopen(filename,"r"); - if(cmdline_file_handle==NULL) { - fprintf(log_file,"UNKNOWN"); - return; - } - - char read_buffer[MAXFILEBUFFLEN+1]={0}; - int readed; - do { - readed=fread(read_buffer,sizeof(char),MAXFILEBUFFLEN,cmdline_file_handle); - char *last_printed=read_buffer; - int i; - for(i=0; i<readed; i++) { - if(read_buffer[i]==0) { - __print_escaped(log_file,last_printed); - fprintf(log_file,"\\0"); - last_printed=read_buffer+i+1; - } - } - read_buffer[readed]=0; - if(last_printed<read_buffer+readed) - __print_escaped(log_file,last_printed); // print rest of buffer +static void __log_event(const char *event_type, const char *filename, char *result,int err, char* stage) { + __raw_log_event(event_type,filename,result,err,stage); +} - } while(readed==MAXFILEBUFFLEN); - fclose(cmdline_file_handle); +/* + * Get a stage. Stage is from environment +*/ +static char * __get_stage(){ + char *ret=getenv("EBUILD_PHASE"); + if(ret==NULL) + return "unknown"; + return ret; } /* - * Format of log string: time event file flags result parents + * Get full path by fd */ -void __hook_log(const char *event_type, const char *filename, int result, int err) { - - fprintf(log_file,"%lld ",(unsigned long long)time(NULL)); - - __print_escaped(log_file, event_type); - fprintf(log_file," "); - __print_escaped(log_file, filename); - fprintf(log_file," %d %d %d", result, err, getpid()); - // TODO: add a parent processes in output -// pid_t pid; -// __getparentpid(getpid()); -// for(pid=getpid();pid!=0;pid=__getparentpid(pid)){ -// __print_cmdline(pid); -// if(pid!=1) -// fprintf(log_file,","); - -// } +ssize_t __get_path_by_fd(int fd, char *output, int output_len) { + char path_to_fd_link[MAXPATHLEN]; + + snprintf(path_to_fd_link,MAXPATHLEN,"/proc/self/fd/%d",fd); + ssize_t bytes_num=readlink(path_to_fd_link,output,output_len-1); + output[bytes_num]=0; // because readlink don't do this + if(output[0]!='/') return -1; // some odd string like pipe: + return bytes_num; +} + +/* + * Ask for event "alloweness" +*/ +static int __is_event_allowed(const char *event_type,const char *filename, char* stage) { + char answer[8]; + int bytes_recieved; + + + pthread_mutex_lock( &socketblock ); + + __raw_log_event(event_type,filename,"ASKING",0,stage); + bytes_recieved=recv(log_socket,answer,8,0); + + pthread_mutex_unlock( &socketblock ); - fprintf(log_file,"\n"); - fflush(log_file); + if(strcmp(answer,"ALLOW")==0) + return 1; + else if(strcmp(answer,"DENY")==0) + return 0; + else + fprintf(stderr,"Protocol error, text should be ALLOW or DENY, got: %s",answer); + return 0; } -int open(const char * pathname, int flags, mode_t mode) { + +int open(const char * path, int flags, mode_t mode) { int ret; + char fullpath[MAXPATHLEN]; + realpath(path,fullpath); + char *stage=__get_stage(); + if(! __is_event_allowed("open",fullpath,stage)) { + errno=2; // not found + __log_event("open",fullpath,"DENIED",errno,stage); + return -1; + } + + if(flags & O_CREAT) - ret=_open(pathname, flags, mode); + ret=_open(path, flags, mode); else - ret=_open(pathname, flags, 0); - - __hook_log("open",pathname,ret,errno); + ret=_open(path, flags, 0); + if(ret==-1) + __log_event("open",fullpath,"ERR",errno,stage); + else + __log_event("open",fullpath,"OK",0,stage); + + return ret; } -int open64(const char * pathname, int flags, mode_t mode) { +int open64(const char * path, int flags, mode_t mode) { int ret; + char fullpath[MAXPATHLEN]; + realpath(path,fullpath); + char *stage=__get_stage(); + if(! __is_event_allowed("open",fullpath,stage)) { + errno=2; // not found + __log_event("open",path,"DENIED",errno,stage); + return -1; + } if(flags & O_CREAT) - ret=_open64(pathname, flags, mode); + ret=_open64(path, flags, mode); else - ret=_open64(pathname, flags, 0); + ret=_open64(path, flags, 0); - __hook_log("open",pathname,ret,errno); + if(ret==-1) + __log_event("open",fullpath,"ERR",errno,stage); + else + __log_event("open",fullpath,"OK",0,stage); return ret; } FILE *fopen(const char *path, const char *mode) { FILE *ret; + char fullpath[MAXPATHLEN]; + realpath(path,fullpath); + + char *stage=__get_stage(); + if(! __is_event_allowed("open",fullpath,stage)) { + errno=2; // not found + __log_event("open",path,"DENIED",errno,stage); + return NULL; + } + ret=_fopen(path,mode); - __hook_log("open",path,0,errno); + if(ret==NULL) + __log_event("open",fullpath,"ERR",errno,stage); + else + __log_event("open",fullpath,"OK",0,stage); return ret; } FILE *fopen64(const char *path, const char *mode) { FILE *ret; + char fullpath[MAXPATHLEN]; + realpath(path,fullpath); + + char *stage=__get_stage(); + if(! __is_event_allowed("open",fullpath,stage)) { + errno=2; // not found + __log_event("open",fullpath,"DENIED",errno,stage); + return NULL; + } + ret=_fopen64(path,mode); - __hook_log("open",path,0,errno); + + if(ret==NULL) + __log_event("open",fullpath,"ERR",errno,stage); + else + __log_event("open",fullpath,"OK",0,stage); + return ret; } +ssize_t read(int fd, void *buf, size_t count){ + ssize_t ret=_read(fd,buf,count); + char *stage=__get_stage(); -int execve(const char *filename, char *const argv[], - char *const envp[]) { - __hook_log("execve",filename,0,0); + char fullpath[MAXPATHLEN]; + ssize_t path_size=__get_path_by_fd(fd,fullpath,MAXPATHLEN); + if(path_size==-1) + return ret; + + if(ret==-1) + __log_event("read",fullpath,"ERR",errno,stage); + else + __log_event("read",fullpath,"OK",0,stage); - int ret=_execve(filename, argv, envp); + return ret; +} + +ssize_t write(int fd,const void *buf, size_t count){ + ssize_t ret=_write(fd,buf,count); + char *stage=__get_stage(); + char fullpath[MAXPATHLEN]; + ssize_t path_size=__get_path_by_fd(fd,fullpath,MAXPATHLEN); + if(path_size==-1) + return ret; + if(ret==-1) + __log_event("write",fullpath,"ERR",errno,stage); + else + __log_event("write",fullpath,"OK",0,stage); + return ret; } -pid_t fork(void) { - int ret=_fork(); - // we must to handle fork for reconnect a socket - if(ret==0) { - __dofini(); // reinit connection for clildren - __doinit(); // because now it is different processes - } + +int execve(const char *filename, char *const argv[], + char *const envp[]) { + if(access(filename, F_OK)!=-1) + __log_event("open",filename,"OK",0,__get_stage()); + else + __log_event("open",filename,"ERR",2,__get_stage()); + + + int ret=_execve(filename, argv, envp); return ret; } + +int close(int fd) { + if(fd!=log_socket) { + return _close(fd); + } + return -1; +} + |