Unverified Commit aa8466e7 authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!13903 Script execution control

Merge Pull Request from: @ci-robot 
 
PR sync from: Gu Bowen <gubowen5@huawei.com>
https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/ISONU36A6PNG66PIBPKSX5XMP63VWTAZ/ 
Ensure that direct file execution (e.g. ./script.sh) and indirect file 
execution (e.g. sh script.sh) lead to the same result to support script 
protection.

Gu Bowen (2):
  IMA support script execution check
  fix kabi breakage due to exec is_check

Kees Cook (1):
  exec: Check __FMODE_EXEC instead of in_execve for LSMs

Linus Torvalds (2):
  execve: open the executable file before doing anything else
  uselib: remove use of __FMODE_EXEC

Mickaël Salaün (1):
  exec: Add a new AT_CHECK flag to execveat(2)


-- 
2.25.1
 
https://gitee.com/openeuler/kernel/issues/IAZ996 
 
Link:https://gitee.com/openeuler/kernel/pulls/13903

 

Reviewed-by: default avatarzhangyi (F) <yi.zhang@huawei.com>
Reviewed-by: default avatarLi Nan <linan122@huawei.com>
Reviewed-by: default avatarZucheng Zheng <zhengzucheng@huawei.com>
Signed-off-by: default avatarLi Nan <linan122@huawei.com>
parents d5e3f33f 9b22326d
Loading
Loading
Loading
Loading
+52 −37
Original line number Diff line number Diff line
@@ -132,7 +132,7 @@ SYSCALL_DEFINE1(uselib, const char __user *, library)
	struct filename *tmp = getname(library);
	int error = PTR_ERR(tmp);
	static const struct open_flags uselib_flags = {
		.open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC,
		.open_flag = O_LARGEFILE | O_RDONLY,
		.acc_mode = MAY_READ | MAY_EXEC,
		.intent = LOOKUP_OPEN,
		.lookup_flags = LOOKUP_FOLLOW,
@@ -913,7 +913,7 @@ static struct file *do_open_execat(int fd, struct filename *name, int flags)
		.lookup_flags = LOOKUP_FOLLOW,
	};

	if ((flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0)
	if ((flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH | AT_CHECK)) != 0)
		return ERR_PTR(-EINVAL);
	if (flags & AT_SYMLINK_NOFOLLOW)
		open_exec_flags.lookup_flags &= ~LOOKUP_FOLLOW;
@@ -1496,12 +1496,24 @@ static void free_bprm(struct linux_binprm *bprm)
	kfree(bprm);
}

static struct linux_binprm *alloc_bprm(int fd, struct filename *filename)
static struct linux_binprm *alloc_bprm(int fd, struct filename *filename, int flags)
{
	struct linux_binprm *bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
	struct linux_binprm *bprm;
	struct file *file;
	int retval = -ENOMEM;
	if (!bprm)
		goto out;

	file = do_open_execat(fd, filename, flags);
	if (IS_ERR(file))
		return ERR_CAST(file);

	bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
	if (!bprm) {
		allow_write_access(file);
		fput(file);
		return ERR_PTR(-ENOMEM);
	}

	bprm->file = file;

	if (fd == AT_FDCWD || filename->name[0] == '/') {
		bprm->filename = filename->name;
@@ -1514,18 +1526,42 @@ static struct linux_binprm *alloc_bprm(int fd, struct filename *filename)
		if (!bprm->fdpath)
			goto out_free;

		/*
		 * Record that a name derived from an O_CLOEXEC fd will be
		 * inaccessible after exec.  This allows the code in exec to
		 * choose to fail when the executable is not mmaped into the
		 * interpreter and an open file descriptor is not passed to
		 * the interpreter.  This makes for a better user experience
		 * than having the interpreter start and then immediately fail
		 * when it finds the executable is inaccessible.
		 */
		if (get_close_on_exec(fd))
			bprm->interp_flags |= BINPRM_FLAGS_PATH_INACCESSIBLE;

		bprm->filename = bprm->fdpath;
	}
	bprm->interp = bprm->filename;

	/*
	 * At this point, security_file_open() has already been called (with
	 * __FMODE_EXEC) and access control checks for AT_CHECK will stop just
	 * after the security_bprm_creds_for_exec() call in bprm_execve().
	 * Indeed, the kernel should not try to parse the content of the file
	 * with exec_binprm() nor change the calling thread, which means that
	 * the following security functions will be not called:
	 * - security_bprm_check()
	 * - security_bprm_creds_from_file()
	 * - security_bprm_committing_creds()
	 * - security_bprm_committed_creds()
	 */
	bprm->is_check = !!(flags & AT_CHECK);

	retval = bprm_mm_init(bprm);
	if (retval)
		goto out_free;
	if (!retval)
		return bprm;

out_free:
	free_bprm(bprm);
out:
	return ERR_PTR(retval);
}

@@ -1793,10 +1829,8 @@ static int exec_binprm(struct linux_binprm *bprm)
/*
 * sys_execve() executes a new program.
 */
static int bprm_execve(struct linux_binprm *bprm,
		       int fd, struct filename *filename, int flags)
static int bprm_execve(struct linux_binprm *bprm)
{
	struct file *file;
	int retval;

	/*
@@ -1811,29 +1845,11 @@ static int bprm_execve(struct linux_binprm *bprm,
	check_unsafe_exec(bprm);
	current->in_execve = 1;

	file = do_open_execat(fd, filename, flags);
	retval = PTR_ERR(file);
	if (IS_ERR(file))
		goto out_unmark;

	sched_exec();

	bprm->file = file;
	/*
	 * Record that a name derived from an O_CLOEXEC fd will be
	 * inaccessible after exec.  This allows the code in exec to
	 * choose to fail when the executable is not mmaped into the
	 * interpreter and an open file descriptor is not passed to
	 * the interpreter.  This makes for a better user experience
	 * than having the interpreter start and then immediately fail
	 * when it finds the executable is inaccessible.
	 */
	if (bprm->fdpath && get_close_on_exec(fd))
		bprm->interp_flags |= BINPRM_FLAGS_PATH_INACCESSIBLE;

	/* Set the unchanging part of bprm->cred */
	retval = security_bprm_creds_for_exec(bprm);
	if (retval)
	if (retval || bprm->is_check)
		goto out;

	retval = exec_binprm(bprm);
@@ -1859,7 +1875,6 @@ static int bprm_execve(struct linux_binprm *bprm,
	if (bprm->point_of_no_return && !fatal_signal_pending(current))
		force_sigsegv(SIGSEGV);

out_unmark:
	current->fs->in_exec = 0;
	current->in_execve = 0;

@@ -1893,7 +1908,7 @@ static int do_execveat_common(int fd, struct filename *filename,
	 * further execve() calls fail. */
	current->flags &= ~PF_NPROC_EXCEEDED;

	bprm = alloc_bprm(fd, filename);
	bprm = alloc_bprm(fd, filename, flags);
	if (IS_ERR(bprm)) {
		retval = PTR_ERR(bprm);
		goto out_ret;
@@ -1942,7 +1957,7 @@ static int do_execveat_common(int fd, struct filename *filename,
		bprm->argc = 1;
	}

	retval = bprm_execve(bprm, fd, filename, flags);
	retval = bprm_execve(bprm);
out_free:
	free_bprm(bprm);

@@ -1963,7 +1978,7 @@ int kernel_execve(const char *kernel_filename,
	if (IS_ERR(filename))
		return PTR_ERR(filename);

	bprm = alloc_bprm(fd, filename);
	bprm = alloc_bprm(fd, filename, 0);
	if (IS_ERR(bprm)) {
		retval = PTR_ERR(bprm);
		goto out_ret;
@@ -1998,7 +2013,7 @@ int kernel_execve(const char *kernel_filename,
	if (retval < 0)
		goto out_free;

	retval = bprm_execve(bprm, fd, filename, 0);
	retval = bprm_execve(bprm);
out_free:
	free_bprm(bprm);
out_ret:
+5 −0
Original line number Diff line number Diff line
@@ -42,6 +42,11 @@ struct linux_binprm {
		 * original userspace.
		 */
		point_of_no_return:1;
	/*
	 * Set by user space to check executability according to the
	 * caller's environment.
	 */
	KABI_FILL_HOLE(unsigned int is_check:1)
#ifdef __alpha__
	unsigned int taso:1;
#endif
+6 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@ struct linux_binprm;

#ifdef CONFIG_IMA
extern int ima_bprm_check(struct linux_binprm *bprm);
extern int ima_bprm_creds_for_exec(struct linux_binprm *bprm);
extern int ima_file_check(struct file *file, int mask);
extern void ima_post_create_tmpfile(struct inode *inode);
extern void ima_file_free(struct file *file);
@@ -57,6 +58,11 @@ static inline int ima_bprm_check(struct linux_binprm *bprm)
	return 0;
}

static inline int ima_bprm_creds_for_exec(struct linux_binprm *bprm)
{
	return 0;
}

static inline int ima_file_check(struct file *file, int mask)
{
	return 0;
+31 −0
Original line number Diff line number Diff line
@@ -111,4 +111,35 @@

#define AT_RECURSIVE		0x8000	/* Apply to the entire subtree */

/*
 * AT_CHECK only performs a check on a regular file and returns 0 if execution
 * of this file would be allowed, ignoring the file format and then the related
 * interpreter dependencies (e.g. ELF libraries, script's shebang).
 *
 * Programs should always perform this check to apply kernel-level checks
 * against files that are not directly executed by the kernel but passed to a
 * user space interpreter instead.  All files that contain executable code,
 * from the point of view of the interpreter, should be checked.  However the
 * result of this check should only be enforced according to
 * SECBIT_EXEC_RESTRICT_FILE or SECBIT_EXEC_DENY_INTERACTIVE.  See securebits.h
 * documentation and the samples/check-exec/inc.c example.
 *
 * The main purpose of this flag is to improve the security and consistency of
 * an execution environment to ensure that direct file execution (e.g.
 * `./script.sh`) and indirect file execution (e.g. `sh script.sh`) lead to the
 * same result.  For instance, this can be used to check if a file is
 * trustworthy according to the caller's environment.
 *
 * In a secure environment, libraries and any executable dependencies should
 * also be checked.  For instance, dynamic linking should make sure that all
 * libraries are allowed for execution to avoid trivial bypass (e.g. using
 * LD_PRELOAD).  For such secure execution environment to make sense, only
 * trusted code should be executable, which also requires integrity guarantees.
 *
 * To avoid race conditions leading to time-of-check to time-of-use issues,
 * AT_CHECK should be used with AT_EMPTY_PATH to check against a file
 * descriptor instead of a path.
 */
#define AT_CHECK		0x10000

#endif /* _UAPI_LINUX_FCNTL_H */
+1 −0
Original line number Diff line number Diff line
@@ -187,6 +187,7 @@ struct audit_context {
		} mmap;
		struct {
			int			argc;
			KABI_FILL_HOLE(bool is_check)
		} execve;
		struct {
			char			*name;
Loading