[linux-cifs-client] [PATCH 17/19] mount.cifs: guard against signals by unprivileged users

Jeff Layton jlayton at samba.org
Sun Mar 28 07:34:10 MDT 2010


On Fri, 26 Mar 2010 10:25:40 -0400
Jeff Layton <jlayton at samba.org> wrote:

> From: Jeff Layton <jlayton at redhat.com>
> 
> If mount.cifs is setuid root, then the unprivileged user who runs the
> program can send the mount.cifs process a signal and kill it. This is
> not a huge problem unless we happen to be updating the mtab at the
> time, in which case the mtab lockfiles might not get cleaned up.
> 
> To remedy this, have the privileged mount.cifs process set its real
> uid to the effective uid (usually, root). This prevents unprivileged
> users from being able to signal the process.
> 
> While we're at it, also mask off signals while we're updating the
> mtab. This leaves a SIGKILL by root as the only way to interrupt the
> mtab update, but there's really nothing we can do about that.
> 
> Signed-off-by: Jeff Layton <jlayton at redhat.com>
> ---
>  mount.cifs.c |   42 +++++++++++++++++++++++++++++++++++-------
>  1 files changed, 35 insertions(+), 7 deletions(-)
> 
> diff --git a/mount.cifs.c b/mount.cifs.c
> index f4aea01..e292e40 100644
> --- a/mount.cifs.c
> +++ b/mount.cifs.c
> @@ -267,10 +267,10 @@ static int set_password(struct parsed_mount_info *parsed_info, const char *src)
>  }
>  
>  /* caller frees username if necessary */
> -static char *getusername(void)
> +static char *getusername(uid_t uid)
>  {
>  	char *username = NULL;
> -	struct passwd *password = getpwuid(getuid());
> +	struct passwd *password = getpwuid(uid);
>  
>  	if (password)
>  		username = password->pw_name;
> @@ -1051,13 +1051,26 @@ static int check_mtab(const char *progname, const char *devname,
>  }
>  
>  static int
> -add_mtab(char *devname, char *mountpoint, unsigned long flags)
> +add_mtab(char *devname, char *mountpoint, unsigned long flags, uid_t uid)
>  {
>  	int rc = 0;
>  	char *mount_user;
>  	struct mntent mountent;
>  	FILE *pmntfile;
> +	sigset_t mask, oldmask;
>  
> +	rc = sigfillset(&mask);
> +	if (rc) {
> +		fprintf(stderr, "Unable to set filled signal mask\n");
> +		return EX_FILEIO;
> +	}
> +
> +	rc = sigprocmask(SIG_SETMASK, &mask, &oldmask);
> +	if (rc) {
> +		fprintf(stderr, "Unable to make process ignore signals\n");
> +		return EX_FILEIO;
> +	}
> +	
>  	atexit(unlock_mtab);
>  	rc = lock_mtab();
>  	if (rc) {
> @@ -1094,9 +1107,9 @@ add_mtab(char *devname, char *mountpoint, unsigned long flags)
>  			strlcat(mountent.mnt_opts, ",nodev", MTAB_OPTIONS_LEN);
>  		if (flags & MS_SYNCHRONOUS)
>  			strlcat(mountent.mnt_opts, ",sync", MTAB_OPTIONS_LEN);
> -		if (getuid() != 0) {
> +		if (uid != 0) {
>  			strlcat(mountent.mnt_opts, ",user=", MTAB_OPTIONS_LEN);
> -			mount_user = getusername();
> +			mount_user = getusername(uid);
>  			if (mount_user)
>  				strlcat(mountent.mnt_opts, mount_user,
>  					MTAB_OPTIONS_LEN);
> @@ -1109,6 +1122,7 @@ add_mtab(char *devname, char *mountpoint, unsigned long flags)
>  	unlock_mtab();
>  	SAFE_FREE(mountent.mnt_opts);
>  add_mtab_exit:
> +	sigprocmask(SIG_SETMASK, &oldmask, NULL);
>  	if (rc) {
>  		fprintf(stderr, "unable to add mount entry to mtab\n");
>  		rc = EX_FILEIO;
> @@ -1204,7 +1218,7 @@ assemble_mountinfo(struct parsed_mount_info *parsed_info,
>  			strlcpy(parsed_info->username, getenv("USER"),
>  				sizeof(parsed_info->username));
>  		else
> -			strlcpy(parsed_info->username, getusername(),
> +			strlcpy(parsed_info->username, getusername(getuid()),
>  				sizeof(parsed_info->username));
>  		parsed_info->got_user = 1;
>  	}
> @@ -1259,6 +1273,7 @@ int main(int argc, char **argv)
>  	size_t dev_len;
>  	struct parsed_mount_info *parsed_info = NULL;
>  	pid_t pid;
> +	uid_t uid;
>  
>  	if (check_setuid())
>  		return EX_USAGE;
> @@ -1390,6 +1405,19 @@ int main(int argc, char **argv)
>  			goto mount_exit;
>  	}
>  
> +	/*
> +	 * Set the real uid to the effective uid. This prevents unprivileged
> +	 * users from sending signals to this process, though ^c on controlling
> +	 * terminal should still work.
> +	 */
> +	uid = getuid();
> +	rc = setreuid(geteuid(), -1);
> +	if (rc != 0) {
> +		fprintf(stderr, "Unable to set real uid to effective uid: %s\n",
> +				strerror(errno));
> +		rc = EX_USAGE;
> +	}
> +
>  	options = calloc(options_size, 1);
>  	if (!options) {
>  		fprintf(stderr, "Unable to allocate memory.\n");
> @@ -1500,7 +1528,7 @@ mount_retry:
>  	}
>  
>  	if (!parsed_info->nomtab)
> -		rc = add_mtab(dev_name, mountpoint, parsed_info->flags);
> +		rc = add_mtab(dev_name, mountpoint, parsed_info->flags, uid);
>  
>  mount_exit:
>  	if (parsed_info) {

A little self-review on this patch...

It's probably better not to change the real uid until the mtab is set
to be updated, so I'm moving that piece into add_mtab. Doing so very
early on like this means that the kernel loses the ability to get the
real uid of the user running the mount command.

Replacement patch attached...
-- 
Jeff Layton <jlayton at samba.org>


More information about the linux-cifs-client mailing list