diff options
author | Alexander Bersenev <bay@hackerdom.ru> | 2011-06-10 12:45:13 +0000 |
---|---|---|
committer | Alexander Bersenev <bay@hackerdom.ru> | 2011-06-10 12:45:13 +0000 |
commit | 8b8b0e496ae3676790215f1eb94e233403f06936 (patch) | |
tree | f068bb9646876a987d4dca6bcae44061cd85df67 | |
parent | better logging system. Finalize format of logs (diff) | |
download | autodep-8b8b0e496ae3676790215f1eb94e233403f06936.tar.gz autodep-8b8b0e496ae3676790215f1eb94e233403f06936.tar.bz2 autodep-8b8b0e496ae3676790215f1eb94e233403f06936.zip |
Finalized format of communications. Fiexed a very annoying bug with lost ALLOW packet. Fixed tests
-rw-r--r-- | logger/src/autodep/logfs/fstracer.py | 102 | ||||
-rw-r--r-- | logger/src/autodep/logfs/logger_fusefs.py | 6 | ||||
-rw-r--r-- | logger/src/autodep/logfs/test_fstracer.py | 41 | ||||
-rwxr-xr-x | logger/src/autodep/showfsevents.py | 30 | ||||
-rw-r--r-- | logger/src/hook_fusefs/hookfs.c | 74 |
5 files changed, 210 insertions, 43 deletions
diff --git a/logger/src/autodep/logfs/fstracer.py b/logger/src/autodep/logfs/fstracer.py index cf10e6e..6979b27 100644 --- a/logger/src/autodep/logfs/fstracer.py +++ b/logger/src/autodep/logfs/fstracer.py @@ -30,22 +30,76 @@ def parse_message(message): # check if proccess is finished def checkfinished(pid): if not os.path.exists("/proc/%d/stat" % pid): - return (True,0) + return True try: pid_child,exitcode = os.waitpid(pid, os.WNOHANG) except OSError, e: if e.errno == 10: - return (False,0) + return False else: raise if pid_child==0: - return (False,0) - return (True,exitcode) + return False + return True + +#check if process is zombie +def iszombie(pid): + try: + statfile=open("/proc/%d/stat" % pid,"r") + line=statfile.readline() + statfile.close() + line=line.rsplit(")")[1] # find last ")" char + line=line.strip() + match=re.match(r"(\w)",line) + if match==None: + print "Failed to get check if process is zombie. Format of /proc/<pid>/stat is incorrect. Did you change a kernel?" + return False + + return match.group(1)=="Z" + + except IOError,e: + return True + + +# uses /proc filesystem to get pid of parent +def getparentpid(pid): + try: + statfile=open("/proc/%d/stat" % pid,"r") + line=statfile.readline() + statfile.close() + line=line.rsplit(")")[1] # find last ")" char + line=line.strip() + match=re.match(r"\w\s(\d+)",line) + if match==None: + print "Failed to get parent process. Format of /proc/<pid>/stat is incorrect. Did you change a kernel?" + return 1 + + return int(match.group(1)) + + except IOError,e: + return 1 + +#check if message came from one of a child +def checkparent(parent,child): + #print "Parent %s, child %s"%(parent,child) + if child==1 or getparentpid(child)==1: + return True + + currpid=child +# for(pid=getpid();pid!=0;pid=__getparentpid(pid)) + while getparentpid(currpid)!=1: + currpid=getparentpid(currpid) + if currpid==parent: + return True + + print "External actions with filesystem detected pid of external prog is %d" % child + return False + +# default access filter. Allow acess to all files +def defaultfilter(eventname, filename, pid): -# default access filter. Allow always -def defaultfilter(time, filename, pid): return True # run the program and get file access events @@ -59,7 +113,7 @@ def getfsevents(prog_name,arguments,approach="hooklib",filterproc=defaultfilter) sock_listen=socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) sock_listen.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock_listen.bind(socketname) - sock_listen.listen(1024) + sock_listen.listen(65536*8) except socket.error, e: print "Failed to create a socket for exchange data with the logger: %s" % e return [] @@ -103,7 +157,7 @@ def getfsevents(prog_name,arguments,approach="hooklib",filterproc=defaultfilter) input.append(client) buffers[client]='' else: - data=s.recv(65536) + data=s.recv(4096) buffers[s]+=data @@ -131,26 +185,50 @@ def getfsevents(prog_name,arguments,approach="hooklib",filterproc=defaultfilter) #print "datalen: %d" % len(data) message=parse_message(record) + try: if message[4]=="ASKING": - if filterproc(message[1],message[2],message[3]): + #print "ASKING %s"%message[2] + if message[2]=="/" or ( # always allow acces to "/" because of some processes like ksysguardd + True):#checkparent(pid,int(message[3])) and filterproc(message[1],message[2],message[3])): s.sendall("ALLOW\n"); # TODO: think about flush here + #print "ALLOWING %s"%message[2] + else: print "Blocking an access to %s" % message[2] s.sendall("DENY\n"); # TODO: think about flush here else: - events.append([message[1],message[2]]); + # check previous five messages for possible repeats + for prevevent in events[-5:]: + if prevevent[1:]==message[1:]: + break + else: + pass + #events.append(message) except IndexError: print "IndexError while parsing %s"%record #print "!!"+data+"!!" #print parse_message(data) - if len(input)==1 and connects==0: + + if len(input)==1 and connects==0: #or # seems like there is no connect - print "It seems like a logger module was unable to start." + \ + print "It seems like a logger module was unable to start or failed to finish" + \ "Check that you are not launching a suid program under non-root user." return [] + #if iszombie(pid): + # print "Child finished, but connection remains. Closing a connection" + # break os.wait() + + if len(events)==0: + return [] + + timeofstart=int(events[0][0]) + # make all event times relative to time 0 - time of start task + for event_num in range(0,len(events)): + events[event_num][0]=int(events[event_num][0])-timeofstart return events + diff --git a/logger/src/autodep/logfs/logger_fusefs.py b/logger/src/autodep/logfs/logger_fusefs.py index 11a6f39..ec19b80 100644 --- a/logger/src/autodep/logfs/logger_fusefs.py +++ b/logger/src/autodep/logfs/logger_fusefs.py @@ -93,9 +93,9 @@ class logger: print "Unmounting partitions" self.mountlist.reverse() for mount in self.mountlist: - self.smartcommandlauncher(['umount',self.rootmountpath+mount]) - self.smartcommandlauncher(['fusermount','-u',self.rootmountpath]); - self.smartcommandlauncher(['umount',self.rootmountpath]); + self.smartcommandlauncher(['umount','-l',self.rootmountpath+mount]) + self.smartcommandlauncher(['fusermount','-z','-u',self.rootmountpath]); + self.smartcommandlauncher(['umount','-l',self.rootmountpath]); os.rmdir(self.rootmountpath) except OSError, e: diff --git a/logger/src/autodep/logfs/test_fstracer.py b/logger/src/autodep/logfs/test_fstracer.py index c254bce..a4c4b56 100644 --- a/logger/src/autodep/logfs/test_fstracer.py +++ b/logger/src/autodep/logfs/test_fstracer.py @@ -2,6 +2,13 @@ import unittest import fstracer +def simple_getfsevents(prog,args,approach="hooklib"): + ret=[] + events = fstracer.getfsevents(prog,args,approach) + for event in events: + ret.append([event[1],event[2],event[4]]) + return ret + class hooklib_simple_tests(unittest.TestCase): def test_open_unexists(self): self.assertEqual(fstracer.getfsevents('/bin/cat', @@ -48,17 +55,20 @@ class hooklib_simple_tests(unittest.TestCase): class fusefs_simple_tests(unittest.TestCase): def test_open_unexists(self): - eventslist=fstracer.getfsevents('/bin/cat', ['/bin/cat','/f1','/f2'],approach="fusefs") - self.assertTrue(eventslist.count(['stat', '/f1'])==1) - def test_open_exists(self): - eventslist=fstracer.getfsevents('/bin/cat', ['/bin/cat','/etc/passwd'],approach="fusefs") - self.assertTrue(eventslist.count(['stat', '/etc/passwd'])>=1) + eventslist=simple_getfsevents('/bin/cat', ['/bin/cat','/f1','/f2'],approach="fusefs") + print eventslist + self.assertTrue(eventslist.count(['stat', '/f1',"ERR/2"])==1) + self.assertTrue(eventslist.count(['stat', '/f2',"ERR/2"])==1) + + def test_open_exists(self): + eventslist=simple_getfsevents('/bin/cat', ['/bin/cat','/etc/passwd'],approach="fusefs") + self.assertTrue(eventslist.count(['stat', '/etc/passwd',"OK"])>=1) def test_open_many(self): filesnum=200 - eventslist=fstracer.getfsevents('/bin/cat',['/bin/cat']+ + eventslist=simple_getfsevents('/bin/cat',['/bin/cat']+ map(lambda x: '/file'+str(x),range(0,filesnum)), approach="fusefs") - for f in map(lambda x: ['stat','/file'+str(x)],range(0,filesnum)): + for f in map(lambda x: ['stat','/file'+str(x),"ERR/2"],range(0,filesnum)): self.assertTrue(f in eventslist) def test_parralel(self): @@ -72,21 +82,20 @@ class fusefs_simple_tests(unittest.TestCase): for f in xrange(0,filesnum): command+="/file_%d_%d " % (p,f) command+="& " - command+=" >/dev/null 2>&1" + command+=" 2>/dev/null" #command+=" "+"A"*65536 - resultarray=fstracer.getfsevents('/bin/sh', ['/bin/sh','-c',command],approach="fusefs") - - #self.assertTrue(resultarray.count(['execve', '/bin/cat'])==procnum) - - print resultarray + resultarray=simple_getfsevents('/bin/sh', ['/bin/sh','-c',command],approach="fusefs") for p in xrange(0,procnum): for f in xrange(0,filesnum): - self.assertTrue(resultarray.count(['stat', '/file_%d_%d' % (p,f)])==1) - - + self.assertTrue(resultarray.count(['stat', '/file_%d_%d' % (p,f),"ERR/2"])==1) + def test_open_very_many(self): + resultarray=simple_getfsevents('/bin/sh', ['/bin/sh','-c', + "for i in `seq 1 10`; do cat /testmany;done 2> /dev/null"],approach="fusefs") + print resultarray + self.assertTrue(resultarray.count(['stat','/testmany',"ERR/2"])>=1000) if __name__ == '__main__': #unittest.main() diff --git a/logger/src/autodep/showfsevents.py b/logger/src/autodep/showfsevents.py index 25bf1ff..0fba98a 100755 --- a/logger/src/autodep/showfsevents.py +++ b/logger/src/autodep/showfsevents.py @@ -5,6 +5,10 @@ import sys import logfs.fstracer +def printevents(events): + for event in events: + print "%s %s"%(event[1],event[2]) + #logfs.fstracer.getfsevents("/bin/sh", ["sh" , "-c", "/usr/bin/tac bay_success; /usr/bin/tac bay_god bay_god2"]) #events=logfs.fstracer.getfsevents("/bin/cat", ["cat" , "l l l"]) if len(sys.argv)<2: @@ -12,5 +16,29 @@ if len(sys.argv)<2: exit(1) events=logfs.fstracer.getfsevents(sys.argv[1], sys.argv[1:],approach="fusefs") -print events + +succ_events=[] +err_events=[] +deny_events=[] + +for event in events: + if event[4]=="OK": + succ_events.append(event) + elif event[4]=="DENIED": + deny_events.append(event) + else: + err_events.append(event) + + + +print "Report:" +if len(succ_events)>0: + print "Successful events:" + printevents(succ_events) +if len(err_events)>0: + print "\nNon-successful events:" + printevents(err_events) +if len(deny_events)>0: + print "\nBlocked events:" + printevents(deny_events) #logfs.fstracer.getfsevents("emerge", ["emerge","--info"])
\ No newline at end of file diff --git a/logger/src/hook_fusefs/hookfs.c b/logger/src/hook_fusefs/hookfs.c index 16b9a46..45bcd6b 100644 --- a/logger/src/hook_fusefs/hookfs.c +++ b/logger/src/hook_fusefs/hookfs.c @@ -60,7 +60,7 @@ struct hookfs_config config; * Prints a string escaping spaces and '\' * Does not check input variables */ -void __print_escaped(FILE *fh ,const char *s){ +static void __print_escaped(FILE *fh ,const char *s){ for(;(*s)!=0; s++) { if(*s==' ') fprintf(fh,"\\ "); @@ -78,10 +78,25 @@ void __print_escaped(FILE *fh ,const char *s){ } /* - * Format of log string: time event file flags result parents -*/ -void log_event(const char *event_type, const char *filename, char *result,int err, pid_t pid) { - pthread_mutex_lock( &socketblock ); + * This is here because launching of a task is very slow without it + */ +static int is_file_excluded(const char *filename) { + if(strcmp(filename,"/etc/ld.so.preload")==0) + return 1; + if(strcmp(filename,"/etc/ld.so.cache")==0) + return 1; + if(strcmp(filename,"/usr/lib64/locale/locale-archive")==0) + return 1; + if(strcmp(filename,"/usr/lib64/locale")==0) + return 1; + + return 0; +} + + +static void raw_log_event(const char *event_type, const char *filename, char *result,int err, pid_t pid) { + if(is_file_excluded(filename)) return; + fprintf(log_file,"%lld ",(unsigned long long)time(NULL)); @@ -97,6 +112,14 @@ void log_event(const char *event_type, const char *filename, char *result,int er fprintf(log_file,"\n"); fflush(log_file); +} + +/* + * Format of log string: time event file flags result parents +*/ +static void log_event(const char *event_type, const char *filename, char *result,int err, pid_t pid) { + pthread_mutex_lock( &socketblock ); + raw_log_event(event_type,filename,result,err,pid); pthread_mutex_unlock( &socketblock ); } @@ -104,13 +127,17 @@ void log_event(const char *event_type, const char *filename, char *result,int er * Ack a python part about an event * Returns 1 if access is allowed and 0 if denied */ -int is_event_allowed(const char *event_type,const char *filename, pid_t pid) { +static int is_event_allowed(const char *event_type,const char *filename, pid_t pid) { // sending asking log_event - log_event(event_type,filename,"ASKING",0,pid); + if(is_file_excluded(filename)) return 1; + //return 1; + pthread_mutex_lock( &socketblock ); + + raw_log_event(event_type,filename,"ASKING",0,pid); char answer[8]; - pthread_mutex_lock( &socketblock ); fscanf(log_file,"%7s",answer); + fflush(log_file); // yes, it is here too pthread_mutex_unlock( &socketblock ); if(strcmp(answer,"ALLOW")==0) @@ -122,7 +149,6 @@ int is_event_allowed(const char *event_type,const char *filename, pid_t pid) { return 0; } - static char * malloc_relative_path(const char *path) { int len = strlen(path); char * buf = malloc(1 + len + 1); @@ -149,6 +175,14 @@ static int hookfs_getattr(const char *path, struct stat *stbuf) { struct fuse_context * context = fuse_get_context(); + if(! is_event_allowed("stat",path,context->pid)) { + errno=2; // not found + log_event("stat",path,"DENIED",errno,context->pid); + + return -errno; + } + + char * rel_path = malloc_relative_path(path); if (! rel_path) { return -errno; @@ -172,7 +206,14 @@ static int hookfs_fgetattr(const char *path, struct stat *stbuf, int res; struct fuse_context * context = fuse_get_context(); + if(! is_event_allowed("stat",path,context->pid)) { + errno=2; // not found + log_event("stat",path,"DENIED",errno,context->pid); + + return -errno; + } + res = fstat(fi->fh, stbuf); if (res == -1) { @@ -188,6 +229,14 @@ static int hookfs_access(const char *path, int mask) { struct fuse_context * context = fuse_get_context(); + if(! is_event_allowed("stat",path,context->pid)) { + errno=2; // not found + log_event("stat",path,"DENIED",errno,context->pid); + + return -errno; + } + + char * rel_path = malloc_relative_path(path); if (! rel_path) { return -errno; @@ -348,7 +397,7 @@ static int hookfs_unlink(const char *path) int res = unlink(rel_path); free(rel_path); - //NOTIFY(post_unlink, path, res); + if (res == -1) return -errno; @@ -556,6 +605,8 @@ static int hookfs_create(const char *path, mode_t mode, struct fuse_file_info *f if(! is_event_allowed("create",path,context->pid)) { errno=2; // not found + log_event("create",path,"DENIED",errno,context->pid); + return -errno; } @@ -587,6 +638,8 @@ static int hookfs_open(const char *path, struct fuse_file_info *fi) if(! is_event_allowed("open",path,context->pid)) { errno=2; // not found + log_event("open",path,"DENIED",errno,context->pid); + return -errno; } @@ -895,7 +948,6 @@ static int hookfs_handle_opt(void *data, const char *arg, int key, struct fuse_a "\n" "%s options:\n" " --argv-debug enable argv debugging\n" - " --flush flush log after each write\n" "\n" "general options:\n" " -o opt,[opt...] mount options\n" |