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

Commit 3b125388 authored by Al Viro's avatar Al Viro
Browse files

[PATCH] sanitize unshare_files/reset_files_struct



* let unshare_files() give caller the displaced files_struct
* don't bother with grabbing reference only to drop it in the
  caller if it hadn't been shared in the first place
* in that form unshare_files() is trivially implemented via
  unshare_fd(), so we eliminate the duplicate logics in fork.c
* reset_files_struct() is not just only called for current;
  it will break the system if somebody ever calls it for anything
  else (we can't modify ->files of somebody else).  Lose the
  task_struct * argument.

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent fd8328be
Loading
Loading
Loading
Loading
+6 −12
Original line number Diff line number Diff line
@@ -1269,19 +1269,13 @@ int do_execve(char * filename,
	struct linux_binprm *bprm;
	struct file *file;
	unsigned long env_p;
	struct files_struct *files;
	struct files_struct *displaced;
	int retval;

	files = current->files;
	retval = unshare_files();
	retval = unshare_files(&displaced);
	if (retval)
		goto out_ret;

	if (files == current->files) {
		put_files_struct(files);
		files = NULL;
	}

	retval = -ENOMEM;
	bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
	if (!bprm)
@@ -1340,8 +1334,8 @@ int do_execve(char * filename,
		security_bprm_free(bprm);
		acct_update_integrals(current);
		kfree(bprm);
		if (files)
			put_files_struct(files);
		if (displaced)
			put_files_struct(displaced);
		return retval;
	}

@@ -1363,8 +1357,8 @@ out_kfree:
	kfree(bprm);

out_files:
	if (files)
		reset_files_struct(current, files);
	if (displaced)
		reset_files_struct(displaced);
out_ret:
	return retval;
}
+2 −1
Original line number Diff line number Diff line
@@ -117,7 +117,8 @@ struct task_struct;

struct files_struct *get_files_struct(struct task_struct *);
void put_files_struct(struct files_struct *fs);
void reset_files_struct(struct task_struct *, struct files_struct *);
void reset_files_struct(struct files_struct *);
int unshare_files(struct files_struct **);

extern struct kmem_cache *files_cachep;

+0 −3
Original line number Diff line number Diff line
@@ -2033,9 +2033,6 @@ static inline ino_t parent_ino(struct dentry *dentry)
	return res;
}

/* kernel/fork.c */
extern int unshare_files(void);

/* Transaction based IO helpers */

/*
+2 −1
Original line number Diff line number Diff line
@@ -507,8 +507,9 @@ void put_files_struct(struct files_struct *files)
	}
}

void reset_files_struct(struct task_struct *tsk, struct files_struct *files)
void reset_files_struct(struct files_struct *files)
{
	struct task_struct *tsk = current;
	struct files_struct *old;

	old = tsk->files;
+24 −30
Original line number Diff line number Diff line
@@ -840,36 +840,6 @@ static int copy_io(unsigned long clone_flags, struct task_struct *tsk)
	return 0;
}

/*
 *	Helper to unshare the files of the current task.
 *	We don't want to expose copy_files internals to
 *	the exec layer of the kernel.
 */

int unshare_files(void)
{
	struct files_struct *files  = current->files;
	struct files_struct *newf;
	int error = 0;

	BUG_ON(!files);

	/* This can race but the race causes us to copy when we don't
	   need to and drop the copy */
	if(atomic_read(&files->count) == 1)
	{
		atomic_inc(&files->count);
		return 0;
	}
	newf = dup_fd(files, &error);
	if (newf) {
		task_lock(current);
		current->files = newf;
		task_unlock(current);
	}
	return error;
}

static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk)
{
	struct sighand_struct *sig;
@@ -1807,3 +1777,27 @@ bad_unshare_cleanup_thread:
bad_unshare_out:
	return err;
}

/*
 *	Helper to unshare the files of the current task.
 *	We don't want to expose copy_files internals to
 *	the exec layer of the kernel.
 */

int unshare_files(struct files_struct **displaced)
{
	struct task_struct *task = current;
	struct files_struct *copy;
	int error;

	error = unshare_fd(CLONE_FILES, &copy);
	if (error || !copy) {
		*displaced = NULL;
		return error;
	}
	*displaced = task->files;
	task_lock(task);
	task->files = copy;
	task_unlock(task);
	return 0;
}