[OpenAFS] Reduce mount point/symlink name space abuse

Rainer Toebbicke rtb@pclella.cern.ch
Wed, 28 May 2008 16:29:33 +0200


--------------050908080104060902070905
Content-Type: text/plain; charset="ISO-8859-15"; format=flowed
Content-Transfer-Encoding: 7bit

As people ever trying to create a symlink to a file starting with '%' 
or '#' (either by finger trouble, using Gnome, or on purpose) have 
certainly already experienced: this does not work as expected. The 
target is assumed to be a volume name in those cases, and is normally 
useless and difficult to get rid of unless it happens to correspond to 
a valid volumme name.

However, since eons "fs mkmount" (the official way) creates mount 
points not only starting with a '%' or a '#', but also ending with in 
a '.' (dot)!

Worse, on 'input' a mount is only recognized if it corresponds to the 
strict format imposed by fs mkmount, hence every now and then we end 
up with mount points which are not recognized as such by the cache 
manager, and become, de facto, unusable and unremovable.

With the attached patch symlinks to targets starting with '%' or '#' 
are henceforth only interpreted as mount points when they also end in 
a '.' (dot). Still ugly, but this reduces the part of the name space 
carved out for "fs mkmount". 'ln -s %hash percent' now works and the 
link works normally afterwards. (sigh, linking to '%hash.'remains 
problematic - the correct solution would involve a special "create 
mount" system call).

(remark: I'm speaking Unix here, I don't know about symlinks in 
Windows nor how the cache manager handles them there).

The patch also updates the salvager so that it deals correctly with 
the dead bodies created over the years by this discrepancy.


-- 
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Rainer Toebbicke
European Laboratory for Particle Physics(CERN) - Geneva, Switzerland
Phone: +41 22 767 8985       Fax: +41 22 767 7155

--------------050908080104060902070905
Content-Type: text/plain; name="p_mp_symlink"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="p_mp_symlink"
Content-Description: p_mp_symlink

--- openafs/src/afs/VNOPS/afs_vnop_symlink.c.o1	2005-10-15 04:33:12.000000000 +0200
+++ openafs/src/afs/VNOPS/afs_vnop_symlink.c	2008-03-27 14:44:58.000000000 +0100
@@ -107,7 +107,7 @@
     InStatus.Mask = AFS_SETMODTIME | AFS_SETMODE;
     InStatus.ClientModTime = osi_Time();
     alen = strlen(atargetName);	/* we want it to include the null */
-    if (*atargetName == '#' || *atargetName == '%') {
+    if ( (*atargetName == '#' || *atargetName == '%') && alen > 1 && atargetName[alen-1] == '.') {
 	InStatus.UnixModeBits = 0644;	/* mt pt: null from "." at end */
 	if (alen == 1)
 	    alen++;		/* Empty string */
--- openafs/src/vol/vol-salvage.c.o1	2008-01-07 10:01:37.000000000 +0100
+++ openafs/src/vol/vol-salvage.c	2008-03-27 13:53:28.000000000 +0100
@@ -3035,27 +3035,47 @@
     } else {
 	if (ShowSuid && (vnodeEssence->modeBits & 06000))
 	    Log("FOUND suid/sgid file: %s/%s (%u.%u %05o) author %u (vnode %u dir %u)\n", dir->name ? dir->name : "??", name, vnodeEssence->owner, vnodeEssence->group, vnodeEssence->modeBits, vnodeEssence->author, vnodeNumber, dir->vnodeNumber);
-	if (ShowMounts && (vnodeEssence->type == vSymlink)
+	if (/* ShowMounts && */ (vnodeEssence->type == vSymlink)
 	    && !(vnodeEssence->modeBits & 0111)) {
 	    int code, size;
-	    char buf[1024];
+	    char buf[1025];
 	    IHandle_t *ihP;
 	    FdHandle_t *fdP;
 
 	    IH_INIT(ihP, fileSysDevice, dir->dirHandle.dirh_handle->ih_vid,
 		    vnodeEssence->InodeNumber);
 	    fdP = IH_OPEN(ihP);
-	    assert(fdP != NULL);
+	    if (fdP == NULL) {
+		Log("ERROR %s could not open mount point vnode %u\n", dir->vname, vnodeNumber);
+		IH_RELEASE(ihP);
+		return;
+	    }
 	    size = FDH_SIZE(fdP);
-	    assert(size != -1);
-	    memset(buf, 0, 1024);
+	    if (size < 0) {
+		Log("ERROR %s mount point has invalid size %d, vnode %u\n", dir->vname, size, vnodeNumber);
+		FDH_REALLYCLOSE(fdP);
+		IH_RELEASE(ihP);
+		return;
+	    }
+	
 	    if (size > 1024)
 		size = 1024;
 	    code = FDH_READ(fdP, buf, size);
-	    assert(code == size);
-	    Log("In volume %u (%s) found mountpoint %s/%s to '%s'\n",
-		dir->dirHandle.dirh_handle->ih_vid, dir->vname,
-		dir->name ? dir->name : "??", name, buf);
+	    if (code == size) {
+		buf[size] = '\0';
+		if ( (*buf != '#' && *buf != '%') || buf[strlen(buf)-1] != '.' ) {
+		    Log("Volume %u (%s) mount point %s/%s to '%s' invalid, %s to symbolic link\n",
+			dir->dirHandle.dirh_handle->ih_vid, dir->vname, dir->name ? dir->name : "??", name, buf,
+			Testing ? "would convert" : "converted");
+		    vnodeEssence->modeBits |= 0111;
+		    vnodeEssence->changed = 1;
+		} else if (ShowMounts) Log("In volume %u (%s) found mountpoint %s/%s to '%s'\n",
+		    dir->dirHandle.dirh_handle->ih_vid, dir->vname,
+		    dir->name ? dir->name : "??", name, buf);
+	    } else {
+		Log("Volume %s cound not read mount point vnode %u size %d code %d\n",
+		    dir->vname, vnodeNumber, size, code);
+	    }
 	    FDH_REALLYCLOSE(fdP);
 	    IH_RELEASE(ihP);
 	}
@@ -3531,6 +3551,8 @@
 		    if (!Showmode) {
 			Log("Vnode %u: link count incorrect (was %d, %s %d)\n", vnodeNumber, oldCount, (Testing ? "would have changed to" : "now"), vnode.linkCount);
 		    }
+		} else {
+		    vnode.modeBits = vnp->modeBits;
 		}
 
 		vnode.dataVersion++;

--------------050908080104060902070905--