Viele verschiedene Ordnerinhalte in einen Ordner abbilden mit FUSE



  • Hallo,

    ich habe hier viele verschiedene Ordner innerhalb meines Home-Verzeichnisbaums herumliegen. Diese würde ich gerne auf einen Ordner (sagen wir mal /home/jan/allFiles) abbilden.

    Dass man mit FUSE ein eigenes virtuelles Filesystem erstellen kann, ist mir klar, jedoch ist mir bisher nur bekannt, dass man dort einen rootdir und einen mountdir angeben kann. Ist es irgendwie möglich, beliebig viele Ordner in einen Zielordner zu mounten?

    Mein Codeschnipsel sieht jetzt bisher so aus in der main:

    int main(int argc, char*argv[]) {
    
    	int fuse_stat;
    	int argc2;
    	char* argv2[] = {
    			"/home/jan/Test1",
                            "/home/jan/Test2",
    			"/home/jan/Test3"
    	};
    
    	struct fs_state* fs_data;
    
    	/* Test if root user is logged (security check */
    	if((getuid() == 0) || (geteuid() == 0)) {
    		fprintf(stderr, "Running this FS as root opens unacceptable security holes!");
    		return 1;
    	}
    
    	/* Reserve space */
    	fs_data = calloc(sizeof(struct fs_state), 1);
    	if(fs_data == NULL) {
    		perror("main calloc");
    		abort();
    	}
    
    	/* Open logfile (TODO)*/
    
    	argc2=2;
    
    /* Hier wird je nachdem, auf welches Element ich zeige, ein anderes Stammverzeichnis gewählt und auf argv[1] 
    immer abgebildet (hier also von Test3 nach Test1, ich wuerde aber gerne mehrere verzeichnisse hier angeben */
    	fs_data->rootdir = realpath(argv2[2], NULL); 
    
    	fuse_stat=fuse_main(argc2, argv2, &fs_oper, fs_data);
    	fuse_stat=1;
    	return fuse_stat;
    }
    

    fs_state fs_data sieht so aus:

    struct fs_state {
    	FILE *logfile;
    	char *rootdir;
    };
    

    Und die fs_oper habe ich nicht verändert, es passiert also nichts anderes außer das mounten, was auch für einzelne Ordner funktioniert.

    Danke für die kommende Hilfe!



  • Fabulus schrieb:

    /* Test if root user is logged (security check */
    	if((getuid() == 0) || (geteuid() == 0)) {
    		fprintf(stderr, "Running this FS as root opens unacceptable security holes!");
    		return 1;
    	}
    

    Für diesen Mist möchte ich so manchen Coder an den Eiern aufhängen. root hat alles zu dürfen.



  • Naja, das hlft mir leider immernoch nicht bei meinem Problem... Aber den Teil streiche ich jedenfalls raus 🙂


  • Mod

    Fabulus schrieb:

    Naja, das hlft mir leider immernoch nicht bei meinem Problem... Aber den Teil streiche ich jedenfalls raus 🙂

    Falls das wirklich (bist du sicher?) ein Sicherheitsproblem ist, dann kannst du ja eine Warnung drinlassen.

    Ansonsten ist der Versuch, in einem User-Level Programm dem root etwas zu verbieten nur Kosmetik, da er das Programm einfach ändern könnte. Einen kleinen Binärpatch um eine if-Abfrage rauszunehmen bekomme sogar ich hin.

    Hilft dir leider auch nicht weiter bei deinem konkreten Problem. 😞



  • Also die Sache mit der Prüfung des root-users habe ich aus dem Tutorial so übernommen und mir dabei nichts gedacht, da ich vorerst erst einmal nur testen möchte, wie FUSE funktioniert.



  • Ich glaube, der da http://podgorny.cz/moin/UnionFsFuse hat es schon geschafft.



  • Ah, das sieht mir schon nach dem aus, was ich suche!
    Was ist denn der unterschied zwischen unionfs und unionfsFuse? Und welches ist für meine Nutzung sinnvoller?

    Ich benutze openSuSE im Übrigen (habe bisher über unionfs nur im Zusammenhang mit Ubuntu etwas gelesen, deshalb diese Anmerkung).

    Hat damit jemand schon gearbeitet und weiß, wie ich diese Library nutzen kann? Ich habe jetzt die zip Datei runtergeladen und entpackt und das make-File ausgeführt, würde aber gerne lernen, wie genau ich das benutze.

    Danke für den Hinweis 🙂



  • Warum nutzt du nicht gleich mount bzw. machst entsprechende einträge in der fstab?



  • Hat sich hier irgendwer schon mit dem Code des Programms befasst? Ich editiere grade die main-methode etwas zum Testen, aber plötzlich gibt er keine print-Befehle mehr aus.

    Die main sieht so aus:

    int main(int argc, char *argv[]) {
    	struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
    
    	int res = debug_init();
    	if (res != 0) return res;
    
    	uopt_init();
    
    	if (fuse_opt_parse(&args, NULL, unionfs_opts, unionfs_opt_proc) == -1) return 1;
    
    	if (!uopt.doexit) {
    		if (uopt.nbranches == 0) {
    			printf("You need to specify at least one branch!\n");
    			return 1;
    		}
    
    		if (uopt.stats_enabled) stats_init(&stats);
    	}
    
    	// enable fuse permission checks, we need to set this, even we we are
    	// not root, since we don't have our own access() function
    	if (fuse_opt_add_arg(&args, "-odefault_permissions")) {
    		fprintf(stderr, "Severe failure, can't enable permssion checks, aborting!\n");
    		exit(1);
    	}
    	unionfs_post_opts();
    
    	umask(0);
    	res = fuse_main(args.argc, args.argv, &unionfs_oper, NULL);
    	return uopt.doexit ? uopt.retval : res;
    }
    

    Ich habe jetzt an verschiedenen Stellen ein

    printf("Gib das aus");
    

    hinzugefuegt, aber es wird nichts ausgegeben, wenn der Aufrufcommand korrekt war, also

    unionfs <rootdir>:<rootdir> <mountdir>
    

    Wird aber eine Sache falsch eingegeben, erscheint eine Errormeldung (wie im Code vorgesehen) und auch die Testnachricht.
    Ansonsten aber nicht 😞
    Bis zu einem Neustart war alles in Ordnung, da wurde es ausgegeben, aber als ich einmal neugestartet habe, nicht mehr.

    Ich bin hier echt am verzweifeln, warum das vorher klappte und jetzt nicht.



  • volkard schrieb:

    Fabulus schrieb:

    /* Test if root user is logged (security check */
    	if((getuid() == 0) || (geteuid() == 0)) {
    		fprintf(stderr, "Running this FS as root opens unacceptable security holes!");
    		return 1;
    	}
    

    Für diesen Mist möchte ich so manchen Coder an den Eiern aufhängen. root hat alles zu dürfen.

    Das Problem bei fuse ist etwas subtiler. Es steht nämlich vor einem Zielkonflikt:
    1. Root hat alles zu dürfen.
    2. Ein User darf den root-User nicht in seinen Aktionen blockieren können (oder allgemeiner, Dienste oder andere User des lokalen Systems blockieren).

    Angenommen, ein normaler User mountet mit FUSE ein Dateisystem. Der Code hinter dem Dateisystem ist vom User vorgegeben, das geht mit fuse ja. Jetzt macht root ein
    $ cat /home/foo/fuse_mount_point_of_the_user/some_file

    cat weiß natürlich nicht, dass das ein fuse-Dateisystem ist. Es ruft einfach fopen() auf auf den angegebenen Pfad. fopen() geht erstmal in den Kernel. Der Kernel merkt dann, dass das ein fuse-Dateisystem ist und geht wieder in den user-mode zurück, diesmal im Kontext des users "foo". Der fuse-Code ist aber so programmiert, dass er bei einem open(), das von root kommt, hängt statt irgendwas zurückzugeben.

    Das Ergebnis ist, dass der cat-Prozess, den root gestartet hat, im syscall open() festhängt und nicht mehr so einfach gekillt werden kann. Dasselbe passiert dann natürlich auch bei Backups, die per cronjob laufen. Sobald die aus Versehen ins fuse-Dateisystem gehen, hängt der Backup-Task bis in alle Ewigkeit, bzw. bis der fuse-Prozess des Users gekillt wird.

    Es gibt bestimmt noch andere Angriffsszenarien, die noch größeren Schaden anrichten können, wenn man root erlaubt auf fuse-Dateisysteme zuzugreifen, die von einem User kontrolliert werden. Deswegen sind fuse-mounts soweit ich weiß pauschal für den root-User völlig unzugänglich. Einen fuse-mount, der für den root-User offen ist, kann nur root selber anlegen.

    Unangenehm für den root-User ist es manchmal trotzdem, da stimme ich dir zu.

    Hier ist der Fall etwas anders gelegen, merk ich grad. Da geht es wohl darum, dass root selber dieses fuse-Dateisystem nicht mounten darf. Das kann sinnvoll sein, je nachdem was das fuse-Dateisystem macht. Schöner wär aber ein Verhalten wie bei sshfs (was auch fuse ist): Wenn man als root ein sshfs mountet, dann ist der mountpoint nur für root zugänglich, was es erstmal relativ sicher macht. Wenn man auch anderen Usern Zugang gewähren möchte, kann man sshfs eine entsprechende command line option übergeben.


Anmelden zum Antworten