Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a0e881b7 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull second vfs pile from Al Viro:
 "The stuff in there: fsfreeze deadlock fixes by Jan (essentially, the
  deadlock reproduced by xfstests 068), symlink and hardlink restriction
  patches, plus assorted cleanups and fixes.

  Note that another fsfreeze deadlock (emergency thaw one) is *not*
  dealt with - the series by Fernando conflicts a lot with Jan's, breaks
  userland ABI (FIFREEZE semantics gets changed) and trades the deadlock
  for massive vfsmount leak; this is going to be handled next cycle.
  There probably will be another pull request, but that stuff won't be
  in it."

Fix up trivial conflicts due to unrelated changes next to each other in
drivers/{staging/gdm72xx/usb_boot.c, usb/gadget/storage_common.c}

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (54 commits)
  delousing target_core_file a bit
  Documentation: Correct s_umount state for freeze_fs/unfreeze_fs
  fs: Remove old freezing mechanism
  ext2: Implement freezing
  btrfs: Convert to new freezing mechanism
  nilfs2: Convert to new freezing mechanism
  ntfs: Convert to new freezing mechanism
  fuse: Convert to new freezing mechanism
  gfs2: Convert to new freezing mechanism
  ocfs2: Convert to new freezing mechanism
  xfs: Convert to new freezing code
  ext4: Convert to new freezing mechanism
  fs: Protect write paths by sb_start_write - sb_end_write
  fs: Skip atime update on frozen filesystem
  fs: Add freezing handling to mnt_want_write() / mnt_drop_write()
  fs: Improve filesystem freezing handling
  switch the protection of percpu_counter list to spinlock
  nfsd: Push mnt_want_write() outside of i_mutex
  btrfs: Push mnt_want_write() outside of i_mutex
  fat: Push mnt_want_write() outside of i_mutex
  ...
parents eff0d13f dbc6e022
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -138,8 +138,8 @@ evict_inode:
put_super:		write
put_super:		write
write_super:		read
write_super:		read
sync_fs:		read
sync_fs:		read
freeze_fs:		read
freeze_fs:		write
unfreeze_fs:		read
unfreeze_fs:		write
statfs:			maybe(read)	(see below)
statfs:			maybe(read)	(see below)
remount_fs:		write
remount_fs:		write
umount_begin:		no
umount_begin:		no
+42 −0
Original line number Original line Diff line number Diff line
@@ -32,6 +32,8 @@ Currently, these files are in /proc/sys/fs:
- nr_open
- nr_open
- overflowuid
- overflowuid
- overflowgid
- overflowgid
- protected_hardlinks
- protected_symlinks
- suid_dumpable
- suid_dumpable
- super-max
- super-max
- super-nr
- super-nr
@@ -157,6 +159,46 @@ The default is 65534.


==============================================================
==============================================================


protected_hardlinks:

A long-standing class of security issues is the hardlink-based
time-of-check-time-of-use race, most commonly seen in world-writable
directories like /tmp. The common method of exploitation of this flaw
is to cross privilege boundaries when following a given hardlink (i.e. a
root process follows a hardlink created by another user). Additionally,
on systems without separated partitions, this stops unauthorized users
from "pinning" vulnerable setuid/setgid files against being upgraded by
the administrator, or linking to special files.

When set to "0", hardlink creation behavior is unrestricted.

When set to "1" hardlinks cannot be created by users if they do not
already own the source file, or do not have read/write access to it.

This protection is based on the restrictions in Openwall and grsecurity.

==============================================================

protected_symlinks:

A long-standing class of security issues is the symlink-based
time-of-check-time-of-use race, most commonly seen in world-writable
directories like /tmp. The common method of exploitation of this flaw
is to cross privilege boundaries when following a given symlink (i.e. a
root process follows a symlink belonging to another user). For a likely
incomplete list of hundreds of examples across the years, please see:
http://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=/tmp

When set to "0", symlink following behavior is unrestricted.

When set to "1" symlinks are permitted to be followed only when outside
a sticky world-writable directory, or when the uid of the symlink and
follower match, or when the directory owner matches the symlink's owner.

This protection is based on the restrictions in Openwall and grsecurity.

==============================================================

suid_dumpable:
suid_dumpable:


This value can be used to query and set the core dump mode for setuid
This value can be used to query and set the core dump mode for setuid
+25 −52
Original line number Original line Diff line number Diff line
@@ -186,10 +186,13 @@ static void spufs_prune_dir(struct dentry *dir)
static int spufs_rmdir(struct inode *parent, struct dentry *dir)
static int spufs_rmdir(struct inode *parent, struct dentry *dir)
{
{
	/* remove all entries */
	/* remove all entries */
	int res;
	spufs_prune_dir(dir);
	spufs_prune_dir(dir);
	d_drop(dir);
	d_drop(dir);

	res = simple_rmdir(parent, dir);
	return simple_rmdir(parent, dir);
	/* We have to give up the mm_struct */
	spu_forget(SPUFS_I(dir->d_inode)->i_ctx);
	return res;
}
}


static int spufs_fill_dir(struct dentry *dir,
static int spufs_fill_dir(struct dentry *dir,
@@ -245,9 +248,6 @@ static int spufs_dir_close(struct inode *inode, struct file *file)
	mutex_unlock(&parent->i_mutex);
	mutex_unlock(&parent->i_mutex);
	WARN_ON(ret);
	WARN_ON(ret);


	/* We have to give up the mm_struct */
	spu_forget(ctx);

	return dcache_dir_close(inode, file);
	return dcache_dir_close(inode, file);
}
}


@@ -450,28 +450,24 @@ spufs_create_context(struct inode *inode, struct dentry *dentry,
	struct spu_context *neighbor;
	struct spu_context *neighbor;
	struct path path = {.mnt = mnt, .dentry = dentry};
	struct path path = {.mnt = mnt, .dentry = dentry};


	ret = -EPERM;
	if ((flags & SPU_CREATE_NOSCHED) &&
	if ((flags & SPU_CREATE_NOSCHED) &&
	    !capable(CAP_SYS_NICE))
	    !capable(CAP_SYS_NICE))
		goto out_unlock;
		return -EPERM;


	ret = -EINVAL;
	if ((flags & (SPU_CREATE_NOSCHED | SPU_CREATE_ISOLATE))
	if ((flags & (SPU_CREATE_NOSCHED | SPU_CREATE_ISOLATE))
	    == SPU_CREATE_ISOLATE)
	    == SPU_CREATE_ISOLATE)
		goto out_unlock;
		return -EINVAL;


	ret = -ENODEV;
	if ((flags & SPU_CREATE_ISOLATE) && !isolated_loader)
	if ((flags & SPU_CREATE_ISOLATE) && !isolated_loader)
		goto out_unlock;
		return -ENODEV;


	gang = NULL;
	gang = NULL;
	neighbor = NULL;
	neighbor = NULL;
	affinity = flags & (SPU_CREATE_AFFINITY_MEM | SPU_CREATE_AFFINITY_SPU);
	affinity = flags & (SPU_CREATE_AFFINITY_MEM | SPU_CREATE_AFFINITY_SPU);
	if (affinity) {
	if (affinity) {
		gang = SPUFS_I(inode)->i_gang;
		gang = SPUFS_I(inode)->i_gang;
		ret = -EINVAL;
		if (!gang)
		if (!gang)
			goto out_unlock;
			return -EINVAL;
		mutex_lock(&gang->aff_mutex);
		mutex_lock(&gang->aff_mutex);
		neighbor = spufs_assert_affinity(flags, gang, aff_filp);
		neighbor = spufs_assert_affinity(flags, gang, aff_filp);
		if (IS_ERR(neighbor)) {
		if (IS_ERR(neighbor)) {
@@ -492,22 +488,12 @@ spufs_create_context(struct inode *inode, struct dentry *dentry,
	}
	}


	ret = spufs_context_open(&path);
	ret = spufs_context_open(&path);
	if (ret < 0) {
	if (ret < 0)
		WARN_ON(spufs_rmdir(inode, dentry));
		WARN_ON(spufs_rmdir(inode, dentry));
		if (affinity)
			mutex_unlock(&gang->aff_mutex);
		mutex_unlock(&inode->i_mutex);
		spu_forget(SPUFS_I(dentry->d_inode)->i_ctx);
		goto out;
	}


out_aff_unlock:
out_aff_unlock:
	if (affinity)
	if (affinity)
		mutex_unlock(&gang->aff_mutex);
		mutex_unlock(&gang->aff_mutex);
out_unlock:
	mutex_unlock(&inode->i_mutex);
out:
	dput(dentry);
	return ret;
	return ret;
}
}


@@ -580,18 +566,13 @@ static int spufs_create_gang(struct inode *inode,
	int ret;
	int ret;


	ret = spufs_mkgang(inode, dentry, mode & S_IRWXUGO);
	ret = spufs_mkgang(inode, dentry, mode & S_IRWXUGO);
	if (ret)
	if (!ret) {
		goto out;

		ret = spufs_gang_open(&path);
		ret = spufs_gang_open(&path);
		if (ret < 0) {
		if (ret < 0) {
			int err = simple_rmdir(inode, dentry);
			int err = simple_rmdir(inode, dentry);
			WARN_ON(err);
			WARN_ON(err);
		}
		}

	}
out:
	mutex_unlock(&inode->i_mutex);
	dput(dentry);
	return ret;
	return ret;
}
}


@@ -601,40 +582,32 @@ static struct file_system_type spufs_type;
long spufs_create(struct path *path, struct dentry *dentry,
long spufs_create(struct path *path, struct dentry *dentry,
		unsigned int flags, umode_t mode, struct file *filp)
		unsigned int flags, umode_t mode, struct file *filp)
{
{
	struct inode *dir = path->dentry->d_inode;
	int ret;
	int ret;


	ret = -EINVAL;
	/* check if we are on spufs */
	/* check if we are on spufs */
	if (path->dentry->d_sb->s_type != &spufs_type)
	if (path->dentry->d_sb->s_type != &spufs_type)
		goto out;
		return -EINVAL;


	/* don't accept undefined flags */
	/* don't accept undefined flags */
	if (flags & (~SPU_CREATE_FLAG_ALL))
	if (flags & (~SPU_CREATE_FLAG_ALL))
		goto out;
		return -EINVAL;


	/* only threads can be underneath a gang */
	/* only threads can be underneath a gang */
	if (path->dentry != path->dentry->d_sb->s_root) {
	if (path->dentry != path->dentry->d_sb->s_root)
		if ((flags & SPU_CREATE_GANG) ||
		if ((flags & SPU_CREATE_GANG) || !SPUFS_I(dir)->i_gang)
		    !SPUFS_I(path->dentry->d_inode)->i_gang)
			return -EINVAL;
			goto out;
	}


	mode &= ~current_umask();
	mode &= ~current_umask();


	if (flags & SPU_CREATE_GANG)
	if (flags & SPU_CREATE_GANG)
		ret = spufs_create_gang(path->dentry->d_inode,
		ret = spufs_create_gang(dir, dentry, path->mnt, mode);
					 dentry, path->mnt, mode);
	else
	else
		ret = spufs_create_context(path->dentry->d_inode,
		ret = spufs_create_context(dir, dentry, path->mnt, flags, mode,
					    dentry, path->mnt, flags, mode,
					    filp);
					    filp);
	if (ret >= 0)
	if (ret >= 0)
		fsnotify_mkdir(path->dentry->d_inode, dentry);
		fsnotify_mkdir(dir, dentry);
	return ret;


out:
	mutex_unlock(&path->dentry->d_inode->i_mutex);
	dput(dentry);
	return ret;
	return ret;
}
}


+1 −1
Original line number Original line Diff line number Diff line
@@ -70,7 +70,7 @@ static long do_spu_create(const char __user *pathname, unsigned int flags,
	ret = PTR_ERR(dentry);
	ret = PTR_ERR(dentry);
	if (!IS_ERR(dentry)) {
	if (!IS_ERR(dentry)) {
		ret = spufs_create(&path, dentry, flags, mode, neighbor);
		ret = spufs_create(&path, dentry, flags, mode, neighbor);
		path_put(&path);
		done_path_create(&path, dentry);
	}
	}


	return ret;
	return ret;
+2 −7
Original line number Original line Diff line number Diff line
@@ -156,9 +156,7 @@ static int dev_mkdir(const char *name, umode_t mode)
	if (!err)
	if (!err)
		/* mark as kernel-created inode */
		/* mark as kernel-created inode */
		dentry->d_inode->i_private = &thread;
		dentry->d_inode->i_private = &thread;
	dput(dentry);
	done_path_create(&path, dentry);
	mutex_unlock(&path.dentry->d_inode->i_mutex);
	path_put(&path);
	return err;
	return err;
}
}


@@ -218,10 +216,7 @@ static int handle_create(const char *nodename, umode_t mode, struct device *dev)
		/* mark as kernel-created inode */
		/* mark as kernel-created inode */
		dentry->d_inode->i_private = &thread;
		dentry->d_inode->i_private = &thread;
	}
	}
	dput(dentry);
	done_path_create(&path, dentry);

	mutex_unlock(&path.dentry->d_inode->i_mutex);
	path_put(&path);
	return err;
	return err;
}
}


Loading