kern/73777: linux emulation: root dir special handling useless and harmful

Andriy Gapon avg at icyb.net.ua
Wed Nov 10 07:50:31 PST 2004


>Number:         73777
>Category:       kern
>Synopsis:       linux emulation: root dir special handling useless and harmful
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Nov 10 15:50:29 GMT 2004
>Closed-Date:
>Last-Modified:
>Originator:     Andriy Gapon
>Release:        FreeBSD 5.2.1-RELEASE-p11 i386
>Organization:
>Environment:
System:
FreeBSD 4.X, 5.X
linux_base-7.1_7
	
>Description:
A little background: in linux emulation any access to file system node is first
tried with "/compt/linux" prepended to its path, original path is tried only
if linuxified path is not vaiable. In that fashion linux applications can
access both files under linux emulation root (/compat/linux) and those files
under the real root that are not shadowed by the former files. This behavior
is reverted only for one filesystem node - "/compat/linux" itself. That is,
no application under linux emualtion is able to access linux compatibility
root, real root ("/") is given to it instead.
This seems to be illogical, linux application is probably more ineterested
in linux root directory rather than real root directory. Also, no linux 
application should ever want to "break out" from linux root by "cd ..".

So I think that the special handling for root directories should be removed
and real root directory should be shadowed by /compat/linux.

Existing linux emulation behavior also breaks "mkdir -p" from linux base 7, if
you want to creat a directory with more than one path unexstistant component:
in this case mkdir first performs chdir("/") and then iterativly mkdir()s and
chdir()s to subdirectories. So, the first action, chdir("/") would chdir to
real root and directory created either will be wrong one or will not be
created at all because of permissions.

Please also see my attemps to discuss this issue on mailing lists:
http://docs.freebsd.org/cgi/mid.cgi?4178DBA0.8050605
http://docs.freebsd.org/cgi/mid.cgi?4176A6C0.5070408

I have applied the patch attached on my system and have not seen any
problems with linux emulation, only improvements.
I run oracle 9, ibm websphere 5.1 with mq and wemps.

	
>How-To-Repeat:
1. work as unpriviledged user with shell /compat/linux/bin/bash
2. make sure /var and /compat/linux/var are different directories
3. create /compat/linux/var/foo directory with rwx permission for the user
   mentioned in step 1.
4. make sure there is no /var/foo directory
5. execute "mkdir -p /var/foo/1/2/3" as user from step 1.
6. see the above command fail with permission denied error
7. apply the attached patch
8. recompile kernel and/or linux.ko, reboot
9. try the same again
10. see successful creation of expected directory

	
>Fix:

	

--- rootdir.patch begins here ---
--- sys/compat/linux/linux_util.c.orig	Sun Nov  7 15:34:58 2004
+++ sys/compat/linux/linux_util.c	Sun Nov  7 15:53:20 2004
@@ -95,9 +95,6 @@
 	int		  cflag;
 {
 	struct nameidata	 nd;
-	struct nameidata	 ndroot;
-	struct vattr		 vat;
-	struct vattr		 vatroot;
 	int			 error;
 	const char		*prefix;
 	char			*ptr, *buf, *cp;
@@ -150,55 +147,12 @@
 
 		if ((error = namei(&nd)) != 0)
 			goto keeporig;
-
-		/*
-		 * We now compare the vnode of the linux_root to the one
-		 * vnode asked. If they resolve to be the same, then we
-		 * ignore the match so that the real root gets used.
-		 * This avoids the problem of traversing "../.." to find the
-		 * root directory and never finding it, because "/" resolves
-		 * to the emulation root directory. This is expensive :-(
-		 */
-		NDINIT(&ndroot, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path,
-		       td);
-
-		if ((error = namei(&ndroot)) != 0) {
-			/* Cannot happen! */
-			NDFREE(&nd, NDF_ONLY_PNBUF);
-			vrele(nd.ni_vp);
-			goto keeporig;
-		}
-
-		if ((error = VOP_GETATTR(nd.ni_vp, &vat, td->td_ucred, td)) != 0) {
-			goto bad;
-		}
-
-		if ((error = VOP_GETATTR(ndroot.ni_vp, &vatroot, td->td_ucred, td))
-		    != 0) {
-			goto bad;
-		}
-
-		if (vat.va_fsid == vatroot.va_fsid &&
-		    vat.va_fileid == vatroot.va_fileid) {
-			error = ENOENT;
-			goto bad;
-		}
-
 	}
 
 	NDFREE(&nd, NDF_ONLY_PNBUF);
 	vrele(nd.ni_vp);
-	if (!cflag) {
-		NDFREE(&ndroot, NDF_ONLY_PNBUF);
-		vrele(ndroot.ni_vp);
-	}
 	return error;
 
-bad:
-	NDFREE(&ndroot, NDF_ONLY_PNBUF);
-	vrele(ndroot.ni_vp);
-	NDFREE(&nd, NDF_ONLY_PNBUF);
-	vrele(nd.ni_vp);
 keeporig:
 	/* Keep the original path; copy it back to the start of the buffer. */
 	bcopy(ptr, buf, len);
--- rootdir.patch ends here ---


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list