Bug 10591

Summary: mount: fallback to default $PATH for mount helpers
Product: Busybox Reporter: roman
Component: OtherAssignee: unassigned
Status: NEW ---    
Severity: normal CC: busybox-cvs
Priority: P5    
Version: 1.25.x   
Target Milestone: ---   
Hardware: All   
OS: Linux   
Host: Target:
Build:

Description roman 2017-12-15 17:23:11 UTC
I've stumbled upon the fact that busybox mount calls its helper binaries (if configured) by searching them in the user's $PATH. It does:

	args[0] = xasprintf("mount.%s", mp->mnt_type);
	//...
	rc = spawn_and_wait(args);

Unless the helper boils down to an applet, this does execvp() in libbb/vfork_daemon_rexec.c, which looks at $PATH in the environment.

During a bug analysis, I had a user that logged in via Putty's plink and he wondered that mounting some NFS export failed with "invalid argument". As reason it turned out that mount.nfs is located in /sbin in our system and simply wasn't found because plink forced $PATH to default /bin:/usr/bin and no login rc file was executed to change $PATH.

This itself is not the real bug... but I think it's at least a bit suspicious to search for mount.<fstype> along the user's $PATH.

First, if used by root, it might be simply surprising that $PATH must be set correctly to find mount.<fstype>, and if things go bad this could be used to trick a root user to call some crafted binary this way (for example if "." is part of $PATH).

Second, if mount is installed setuid to allow non-root mounts, it could be an attack vector to call an arbitrary binary with root priviledges. NB, I have _not_ checked if that is actually possible in busybox's standard nonroot case (because I don't use that), but nevertheless I would consider it an unnecessary risk.

For my part, it was the easiest solution to simply hardwire the path to /sbin because all helpers have to be located there in my system:

@@ -698,7 +698,7 @@
                if (HELPERS_ALLOWED && rc && mp->mnt_type) {
                        char *args[8];
                        int errno_save = errno;
-                       args[0] = xasprintf("mount.%s", mp->mnt_type);
+                       args[0] = xasprintf("/sbin/mount.%s", mp->mnt_type);
                        rc = 1;
                        if (FAKE_IT)
                                args[rc++] = (char *)"-f";

The directory used could also easily be a configured directory instead /sbin. But you might prefer a more flexible solution, for example hardwiring some $PATH for the helpers by a config var. (That is actually also what mount from util-linux does, BTW: there a function mnt_context_prepare_helper() splits FS_SEARCH_PATH, which is a configure define.) However, that's obviously more effort and I'm not sure if you want to tolerate that additional code.
Comment 1 Mike Frysinger 2018-01-24 04:02:07 UTC
the code already correctly handles the setuid scenario.  look at CONFIG_FEATURE_SUID and sanitize_env_if_suid() which resets PATH.

hardcoding /sbin and ignoring $PATH would be incorrect.

adding a fallback to use the values in bb_default_path if the exec failed would probably be nice.