diff options
author | Alexander Bersenev <bay@hackerdom.ru> | 2011-08-03 23:55:50 +0000 |
---|---|---|
committer | Alexander Bersenev <bay@hackerdom.ru> | 2011-08-03 23:55:50 +0000 |
commit | f04c87bf5470eb417d76e0e97ccf3374da0fa4f3 (patch) | |
tree | 95ba1c3e628b866d0eb51c24eefc821b13d023b3 | |
parent | small docs changes (diff) | |
download | autodep-f04c87bf5470eb417d76e0e97ccf3374da0fa4f3.tar.gz autodep-f04c87bf5470eb417d76e0e97ccf3374da0fa4f3.tar.bz2 autodep-f04c87bf5470eb417d76e0e97ccf3374da0fa4f3.zip |
fusefs: hiding blocked files in directory listings, tests updated
-rwxr-xr-x[-rw-r--r--] | src/autodep/autodep | 192 | ||||
-rw-r--r-- | src/autodep/logfs/fstracer.py | 2 | ||||
-rw-r--r-- | src/autodep/package_utils/portage_misc_functions.py | 6 | ||||
-rw-r--r-- | src/autodep/tests/test_fusefs.py | 33 | ||||
-rw-r--r-- | src/autodep/tests/test_hookfs.py | 30 | ||||
-rw-r--r-- | src/hook_fusefs/hookfs.c | 26 |
6 files changed, 213 insertions, 76 deletions
diff --git a/src/autodep/autodep b/src/autodep/autodep index 518eed8..45f4a5b 100644..100755 --- a/src/autodep/autodep +++ b/src/autodep/autodep @@ -17,14 +17,21 @@ def parse_args(): """ args_parser=optparse.OptionParser("%prog [options] <command>") - args_parser.add_option("-b", "--block",action="store", type="string", + args_parser.add_option("-b","--block",action="store_true", + dest="strict_block", default="", + help="strict mode: deny all access to non-dependency packages") + args_parser.add_option("--blockpkgs",action="store", type="string", dest="packages", default="", help="block an access to files from this packages") args_parser.add_option("-f","--files", action="store_true", dest="show_files", - default=False, help="show accessed files and not founded files") + default=False, help="show all accessed files and not founded files") args_parser.add_option("-v","--verbose", action="store_true", dest="verbose", default=False, help="show non-important packages, " "show unknown package and unknown stage") + args_parser.add_option("-n","--numfiles",action="store", type="string", + dest="numfiles", + default=10, + help="maximum number of files from each package to show(default is 10)") args_parser.add_option("-C","--nocolor",action="store_true", dest="nocolor", default=False, help="don't output color") @@ -43,49 +50,114 @@ def parse_args(): return options,args -portage_api=portage_misc_functions.portage_api() -system_packages = portage_api.get_system_packages_list() - -runtime_vars={} # This is here mainly for grouping. We are trying to - # get as much data about an environment as possible -runtime_vars["starttime"]=int(time.time()) -#print package_utils.portage_log_parser.get_list_of_merged_packages(1244256830) - -#quit(1) +def init_environment(): + portage_api=portage_misc_functions.portage_api() + system_packages = portage_api.get_system_packages_list() + + return portage_api, system_packages + +def init_runtime_vars(options,args): + runtime_vars={} # This is here mainly for grouping. We are trying to + # get as much data about an environment as possible + + runtime_vars["starttime"]=int(time.time()) + + # trivial check for emerge proccess + if args[0]=="emerge": + runtime_vars["is_emerge"]=True + emergeaction ,emergeopts, emergefiles=portage_api.parse_emerge_args(args[1:]) + runtime_vars["raw_emerge_parameters"]=args[1:] + runtime_vars["emerge_parameters"]=(emergeaction ,emergeopts, emergefiles) + if len(emergefiles)>1: + print "Please, install packages one by one to get more accurate reports" + else: + runtime_vars["is_emerge"]=False + + return runtime_vars + +def get_filter_function(options,system_packages,portage_api): + # handling --block + # exits if package name is bad + if not options.packages and not options.strict_block: + return lambda eventname,filename,stage: True + elif not options.strict_block and options.packages: + packages=options.packages.split(",") + files_to_block=[] + for package in packages: + files_in_package=portage_utils.getfilesbypackage(package) + if len(files_in_package)==0: + print "Bad package name: %s. Exiting" % package + exit(1) + files_to_block+=files_in_package + files_to_block={}.fromkeys(files_to_block) + # new filter function + def filter(eventname,filename,stage): + return not filename in files_to_block + return filter + elif options.strict_block and options.packages: + print "You can't use --block and --blockpkgs options togeter\n" + exit(1) + elif options.strict_block: # this option is very strict + # because blocking logic is complex + print "Building a list of files to block. This may take some time" + # we get list of all files and substract list of allowed files from it + allfiles=portage_utils.get_all_packages_files() + allowedpkgs=[] + allowedpkgs+=system_packages + if runtime_vars["is_emerge"]: # blocking logic for emerge + (emergeaction ,emergeopts, emergefiles)=runtime_vars["emerge_parameters"] + if len(emergefiles)>1: + print "You can't install several packages with option -b" + exit(1) + mergelist=portage_api.get_merge_list(runtime_vars["raw_emerge_parameters"]) + if len(mergelist)!=1: + print "You can't install several packages with option -b" + print "Emerge tried to install several packages: %s" % mergelist + print "You can force emerge to merge a package without any other " \ + "packages with emerge --nodeps option or you can install these " \ + "packages first" + + exit(1) + pkg=mergelist[0] + depslist=list(portage_api.get_deps(pkg)) + allowedpkgs+=depslist + else: + pass # TODO: blocking logic for non-emerge proccesses + # always include current python interpreter + #print allowedpkgs + #allowedpkgs+=portage_utils.getpackagesbyfiles(sys.executable) + #print allowedpkgs + + allowedfiles=[] + for pkg in allowedpkgs: + allowedfiles+=portage_utils.getfilesbypackage(pkg) + # manually add all python interpreters to this list + allowedfiles+=portage_utils.getfilesbypackage('python') + # manually add sandbox to this list + allowedfiles+=portage_utils.getfilesbypackage('sandbox') + + allowedfiles=set(allowedfiles) + + deniedfiles=allfiles-allowedfiles + + + print "The list size is about %dM" % (int(sys.getsizeof(deniedfiles))/1024/1024) + def filter(eventname,filename,stage): + if filename in deniedfiles: + return False + return True + return filter + + + +portage_api, system_packages=init_environment() options,args=parse_args() - +runtime_vars=init_runtime_vars(options,args) color_printer=colorize_output.color_printer(not options.nocolor) - -if args[0]=="emerge": - runtime_vars["is_emerge"]=True - emergeaction ,emergeopts, emergefiles=portage_api.parse_emerge_args(args[1:]) - runtime_vars["emerge_parameters"]=(emergeaction ,emergeopts, emergefiles) - if len(emergefiles)>1: - print "Please, install packages one by one to get more accurate reports" -else: - runtime_vars["is_emerge"]=False - - -filter_function=lambda eventname,filename,stage: True - -# handling --block -if options.packages: - packages=options.packages.split(",") - files_to_block=[] - for package in packages: - files_in_package=portage_utils.getfilesbypackage(package) - if len(files_in_package)==0: - print "Bad package name: %s. Exiting" % package - exit(1) - files_to_block+=files_in_package - files_to_block={}.fromkeys(files_to_block) - # new filter function - def filter(eventname,filename,stage): - return not filename in files_to_block - filter_function=filter +filter_function=get_filter_function(options,system_packages,portage_api) # launching program events=logfs.fstracer.getfsevents(args[0], args,approach=options.approach,filterproc=filter_function) @@ -100,15 +172,14 @@ if runtime_vars["is_emerge"]: ) if len(pkgs) > 1: print "Several packages were installed. The report will be inaccurate" + elif len(pkgs)==0: + print "None packages have been installed sucessfully. The report will be inaccurate" runtime_vars["pkgs_installed"]=pkgs runtime_vars["deps_buildtime"]=[] runtime_vars["deps_all"]=[] for pkg in pkgs: runtime_vars["deps_buildtime"]+=portage_api.get_deps(pkg,["DEPEND"]) runtime_vars["deps_all"]+=portage_api.get_deps(pkg,["DEPEND","RDEPEND"]) - - #print runtime_vars["deps_buildtime"] - #print runtime_vars["deps_all"] except: print "Non-critical error while parsing logfile of emerge" runtime_vars["is_emerge"]=False # shutting down all emerge handling logic @@ -170,13 +241,10 @@ for stage in sorted(events): filesinfo[filename]={"found":[],"notfound":[]} filesinfo[filename]["notfound"]=fail_events[filename] -#print events_converted_for_output - # generating output stagesorder={"clean":1,"setup":2,"unpack":3,"prepare":4,"configure":5,"compile":6,"test":7, "install":8,"preinst":9,"postinst":10,"prerm":11,"postrm":12,"unknown":13} - # print information grouped by package for package in sorted(packagesinfo): # not showing special directory package @@ -218,19 +286,27 @@ for package in sorted(packagesinfo): # show information about accessed files print "%-40s: %s"%(package,stages) +# if options.show_files: - if options.show_files: - # this is here for readability - action={ - (False,False):"accessed", - (True,False):"readed", - (False,True):"writed", - (True,True):"readed and writed" - } - - for filename in filenames: - event_info=tuple(filenames[filename]) - print " %-56s %-21s" % (filename,action[event_info]) + # this is here for readability + action={ + (False,False):"accessed", + (True,False):"readed", + (False,True):"writed", + (True,True):"readed and writed" + } + + filescounter=0 + + for filename in filenames: + event_info=tuple(filenames[filename]) + print " %-56s %-21s" % (filename,action[event_info]) + filescounter+=1 + if options.show_files: + continue + elif filescounter>=options.numfiles: + print " ..." + break # print not founded files with stages if options.show_files: diff --git a/src/autodep/logfs/fstracer.py b/src/autodep/logfs/fstracer.py index ef185b8..58507bb 100644 --- a/src/autodep/logfs/fstracer.py +++ b/src/autodep/logfs/fstracer.py @@ -169,7 +169,7 @@ def getfsevents(prog_name,arguments,approach="hooklib",filterproc=defaultfilter) message=record.split("\0") #if message[3]=="compile": #and message[1]=="debug": #print message - + #print message try: if message[4]=="ASKING": diff --git a/src/autodep/package_utils/portage_misc_functions.py b/src/autodep/package_utils/portage_misc_functions.py index ca6d890..6afe2c3 100644 --- a/src/autodep/package_utils/portage_misc_functions.py +++ b/src/autodep/package_utils/portage_misc_functions.py @@ -30,7 +30,9 @@ class portage_api: def get_best_visible_pkg(self,pkg): """ Gets best candidate on installing. Returns empty string if no found - + + :param pkg: package name + """ try: return self.portdb.xmatch("bestmatch-visible", pkg) @@ -43,6 +45,8 @@ class portage_api: This function uses very internal functions of portage so it may be unreliable in various portage versions + :param emergeargs: list of raw args of emerge, for example, ['-1','bash'] + """ try: diff --git a/src/autodep/tests/test_fusefs.py b/src/autodep/tests/test_fusefs.py index 71e2a85..c395ddf 100644 --- a/src/autodep/tests/test_fusefs.py +++ b/src/autodep/tests/test_fusefs.py @@ -3,6 +3,8 @@ import logfs.fstracer import os import sys +# just a copypasted tests for fusefs but with hooklib approach + class null_writer: def __init__(self): pass @@ -10,7 +12,7 @@ class null_writer: pass -def simple_getfsevents(prog,args,approach="fusefs"): +def simple_getfsevents(prog,args,approach="fusefs", filestoblock=set([])): ret=[] null_out=null_writer() nullfile=open("/dev/null") @@ -19,23 +21,28 @@ def simple_getfsevents(prog,args,approach="fusefs"): errfd=os.dup(sys.stderr.fileno()) os.dup2(nullfd,sys.stdout.fileno()) os.dup2(nullfd,sys.stderr.fileno()) - - events = logfs.fstracer.getfsevents(prog,args,approach) + + def filter(eventname,filename,stage): + if filename in filestoblock: + return False + return True + + events = logfs.fstracer.getfsevents(prog,args,approach,filter) os.dup2(outfd,sys.stdout.fileno()) os.dup2(errfd,sys.stderr.fileno()) - + #print events for stage in events: for filename in events[stage][0]: ret.append([filename,'success']) for filename in events[stage][1]: ret.append([filename,'fail']) - + return ret - class fusefs_simple_tests(unittest.TestCase): + """ def test_open_unexists(self): eventslist=simple_getfsevents('/bin/cat', ['/bin/cat','/f1','/f2']) self.assertTrue(eventslist.count(['/f1',"fail"])==1) @@ -84,6 +91,20 @@ class fusefs_simple_tests(unittest.TestCase): for i in range(1,14): self.assertTrue(eventslist.count(['/f'+str(i),"fail"])==1) + def test_block(self): + eventslist=simple_getfsevents('/bin/cat', ['/bin/cat','/etc/passwd'],filestoblock=['/etc/passwd']) + self.assertTrue(eventslist.count(['/etc/passwd',"fail"])==1) + self.assertFalse(eventslist.count(['/etc/passwd',"success"])==1) + """ + def test_ls(self): + # this is a little tricky: check if passwd not showed in /etc/ if blocked + command="import os; print open('/etc/group').read() if 'passwd' in os.listdir('/etc/') else quit(1)" + resultarray=simple_getfsevents('python2', ['python','-c',command]) + self.assertTrue(['/etc/group','success'] in resultarray) + resultarray=simple_getfsevents('python2', ['python','-c',command], filestoblock=['/etc/passwd']) + self.assertFalse(['/etc/group','success'] in resultarray) + + #if __name__ == '__main__': #unittest.main() #suite = unittest.TestLoader().loadTestsFromTestCase(fusefs_simple_tests) diff --git a/src/autodep/tests/test_hookfs.py b/src/autodep/tests/test_hookfs.py index 0dbabed..037f4a9 100644 --- a/src/autodep/tests/test_hookfs.py +++ b/src/autodep/tests/test_hookfs.py @@ -12,7 +12,7 @@ class null_writer: pass -def simple_getfsevents(prog,args,approach="hooklib"): +def simple_getfsevents(prog,args,approach="hooklib", filestoblock=set([])): ret=[] null_out=null_writer() nullfile=open("/dev/null") @@ -21,22 +21,26 @@ def simple_getfsevents(prog,args,approach="hooklib"): errfd=os.dup(sys.stderr.fileno()) os.dup2(nullfd,sys.stdout.fileno()) os.dup2(nullfd,sys.stderr.fileno()) - - events = logfs.fstracer.getfsevents(prog,args,approach) + + def filter(eventname,filename,stage): + if filename in filestoblock: + return False + return True + + events = logfs.fstracer.getfsevents(prog,args,approach,filter) os.dup2(outfd,sys.stdout.fileno()) os.dup2(errfd,sys.stderr.fileno()) - + #print events for stage in events: for filename in events[stage][0]: ret.append([filename,'success']) for filename in events[stage][1]: ret.append([filename,'fail']) - + return ret - class fusefs_simple_tests(unittest.TestCase): def test_open_unexists(self): eventslist=simple_getfsevents('/bin/cat', ['/bin/cat','/f1','/f2']) @@ -86,6 +90,20 @@ class fusefs_simple_tests(unittest.TestCase): for i in range(1,14): self.assertTrue(eventslist.count(['/f'+str(i),"fail"])==1) + def test_block(self): + eventslist=simple_getfsevents('/bin/cat', ['/bin/cat','/etc/passwd'],filestoblock=['/etc/passwd']) + self.assertTrue(eventslist.count(['/etc/passwd',"fail"])==1) + self.assertFalse(eventslist.count(['/etc/passwd',"success"])==1) + + def test_ls(self): + # this is a little tricky: check if passwd not showed in /etc/ if blocked + command="import os; print open('/etc/group').read() if 'passwd' in os.listdir('/etc/') else quit(1)" + resultarray=simple_getfsevents('python2', ['python','-c',command]) + self.assertTrue(['/etc/group','success'] in resultarray) + resultarray=simple_getfsevents('python2', ['python','-c',command], filestoblock=['/etc/passwd']) + self.assertFalse(['/etc/group','success'] in resultarray) + + #if __name__ == '__main__': #unittest.main() #suite = unittest.TestLoader().loadTestsFromTestCase(fusefs_simple_tests) diff --git a/src/hook_fusefs/hookfs.c b/src/hook_fusefs/hookfs.c index 00a27a8..d6371dd 100644 --- a/src/hook_fusefs/hookfs.c +++ b/src/hook_fusefs/hookfs.c @@ -42,7 +42,7 @@ #define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#define MAXPATHLEN 256 +#define MAXPATHLEN PATH_MAX #define MAXSOCKETPATHLEN 108 #define MAXFILEBUFFLEN 2048 @@ -454,7 +454,11 @@ static int hookfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, { struct hookfs_dirp *d = get_dirp(fi); - (void) path; + struct fuse_context * context = fuse_get_context(); + char *stage=getstagebypid(context->pid); + + + //(void) path; if (offset != d->offset) { seekdir(d->dp, offset); d->entry = NULL; @@ -466,17 +470,31 @@ static int hookfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, if (!d->entry) { d->entry = readdir(d->dp); + if (!d->entry) break; } + //log_event("debug",d->entry->d_name,"DENIED",0,stage); memset(&st, 0, sizeof(st)); st.st_ino = d->entry->d_ino; st.st_mode = d->entry->d_type << 12; nextoff = telldir(d->dp); - if (filler(buf, d->entry->d_name, &st, nextoff)) + + // we must ask registrar about should we show the file + char fullpath[MAXPATHLEN]; + snprintf(fullpath,MAXPATHLEN,"%s/%s",path,d->entry->d_name); + + char abspath[MAXPATHLEN]; + realpath(fullpath,abspath); + + if(! is_event_allowed("stat",abspath,context->pid,stage)) { + errno=2; + log_event("stat",abspath,"DENIED",errno,stage); + } else if (filler(buf, d->entry->d_name, &st, nextoff)) { break; - + } + d->entry = NULL; d->offset = nextoff; } |