Skip to content

Commit b8bff59

Browse files
committed
exec: Factor security_bprm_creds_for_exec out of security_bprm_set_creds
Today security_bprm_set_creds has several implementations: apparmor_bprm_set_creds, cap_bprm_set_creds, selinux_bprm_set_creds, smack_bprm_set_creds, and tomoyo_bprm_set_creds. Except for cap_bprm_set_creds they all test bprm->called_set_creds and return immediately if it is true. The function cap_bprm_set_creds ignores bprm->calld_sed_creds entirely. Create a new LSM hook security_bprm_creds_for_exec that is called just before prepare_binprm in __do_execve_file, resulting in a LSM hook that is called exactly once for the entire of exec. Modify the bits of security_bprm_set_creds that only want to be called once per exec into security_bprm_creds_for_exec, leaving only cap_bprm_set_creds behind. Remove bprm->called_set_creds all of it's former users have been moved to security_bprm_creds_for_exec. Add or upate comments a appropriate to bring them up to date and to reflect this change. Link: https://lkml.kernel.org/r/[email protected] Acked-by: Linus Torvalds <[email protected]> Acked-by: Casey Schaufler <[email protected]> # For the LSM and Smack bits Reviewed-by: Kees Cook <[email protected]> Signed-off-by: "Eric W. Biederman" <[email protected]>
1 parent 87b047d commit b8bff59

File tree

12 files changed

+63
-63
lines changed

12 files changed

+63
-63
lines changed

fs/exec.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1640,7 +1640,6 @@ int prepare_binprm(struct linux_binprm *bprm)
16401640
retval = security_bprm_set_creds(bprm);
16411641
if (retval)
16421642
return retval;
1643-
bprm->called_set_creds = 1;
16441643

16451644
memset(bprm->buf, 0, BINPRM_BUF_SIZE);
16461645
return kernel_read(bprm->file, bprm->buf, BINPRM_BUF_SIZE, &pos);
@@ -1855,6 +1854,11 @@ static int __do_execve_file(int fd, struct filename *filename,
18551854
if (retval < 0)
18561855
goto out;
18571856

1857+
/* Set the unchanging part of bprm->cred */
1858+
retval = security_bprm_creds_for_exec(bprm);
1859+
if (retval)
1860+
goto out;
1861+
18581862
retval = prepare_binprm(bprm);
18591863
if (retval < 0)
18601864
goto out;

include/linux/binfmts.h

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,14 @@ struct linux_binprm {
2727
unsigned long argmin; /* rlimit marker for copy_strings() */
2828
unsigned int
2929
/*
30-
* True after the bprm_set_creds hook has been called once
31-
* (multiple calls can be made via prepare_binprm() for
32-
* binfmt_script/misc).
33-
*/
34-
called_set_creds:1,
35-
/*
36-
* True if most recent call to the commoncaps bprm_set_creds
37-
* hook (due to multiple prepare_binprm() calls from the
38-
* binfmt_script/misc handlers) resulted in elevated
39-
* privileges.
30+
* True if most recent call to cap_bprm_set_creds
31+
* resulted in elevated privileges.
4032
*/
4133
cap_elevated:1,
4234
/*
43-
* Set by bprm_set_creds hook to indicate a privilege-gaining
44-
* exec has happened. Used to sanitize execution environment
45-
* and to set AT_SECURE auxv for glibc.
35+
* Set by bprm_creds_for_exec hook to indicate a
36+
* privilege-gaining exec has happened. Used to set
37+
* AT_SECURE auxv for glibc.
4638
*/
4739
secureexec:1,
4840
/*

include/linux/lsm_hook_defs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ LSM_HOOK(int, 0, syslog, int type)
4949
LSM_HOOK(int, 0, settime, const struct timespec64 *ts,
5050
const struct timezone *tz)
5151
LSM_HOOK(int, 0, vm_enough_memory, struct mm_struct *mm, long pages)
52+
LSM_HOOK(int, 0, bprm_creds_for_exec, struct linux_binprm *bprm)
5253
LSM_HOOK(int, 0, bprm_set_creds, struct linux_binprm *bprm)
5354
LSM_HOOK(int, 0, bprm_check_security, struct linux_binprm *bprm)
5455
LSM_HOOK(void, LSM_RET_VOID, bprm_committing_creds, struct linux_binprm *bprm)

include/linux/lsm_hooks.h

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -34,40 +34,46 @@
3434
*
3535
* Security hooks for program execution operations.
3636
*
37+
* @bprm_creds_for_exec:
38+
* If the setup in prepare_exec_creds did not setup @bprm->cred->security
39+
* properly for executing @bprm->file, update the LSM's portion of
40+
* @bprm->cred->security to be what commit_creds needs to install for the
41+
* new program. This hook may also optionally check permissions
42+
* (e.g. for transitions between security domains).
43+
* The hook must set @bprm->secureexec to 1 if AT_SECURE should be set to
44+
* request libc enable secure mode.
45+
* @bprm contains the linux_binprm structure.
46+
* Return 0 if the hook is successful and permission is granted.
3747
* @bprm_set_creds:
38-
* Save security information in the bprm->security field, typically based
39-
* on information about the bprm->file, for later use by the apply_creds
40-
* hook. This hook may also optionally check permissions (e.g. for
48+
* Assuming that the relevant bits of @bprm->cred->security have been
49+
* previously set, examine @bprm->file and regenerate them. This is
50+
* so that the credentials derived from the interpreter the code is
51+
* actually going to run are used rather than credentials derived
52+
* from a script. This done because the interpreter binary needs to
53+
* reopen script, and may end up opening something completely different.
54+
* This hook may also optionally check permissions (e.g. for
4155
* transitions between security domains).
42-
* This hook may be called multiple times during a single execve, e.g. for
43-
* interpreters. The hook can tell whether it has already been called by
44-
* checking to see if @bprm->security is non-NULL. If so, then the hook
45-
* may decide either to retain the security information saved earlier or
46-
* to replace it. The hook must set @bprm->secureexec to 1 if a "secure
47-
* exec" has happened as a result of this hook call. The flag is used to
48-
* indicate the need for a sanitized execution environment, and is also
49-
* passed in the ELF auxiliary table on the initial stack to indicate
50-
* whether libc should enable secure mode.
56+
* The hook must set @bprm->cap_elevated to 1 if AT_SECURE should be set to
57+
* request libc enable secure mode.
5158
* @bprm contains the linux_binprm structure.
5259
* Return 0 if the hook is successful and permission is granted.
5360
* @bprm_check_security:
5461
* This hook mediates the point when a search for a binary handler will
55-
* begin. It allows a check the @bprm->security value which is set in the
56-
* preceding set_creds call. The primary difference from set_creds is
57-
* that the argv list and envp list are reliably available in @bprm. This
58-
* hook may be called multiple times during a single execve; and in each
59-
* pass set_creds is called first.
62+
* begin. It allows a check against the @bprm->cred->security value
63+
* which was set in the preceding creds_for_exec call. The argv list and
64+
* envp list are reliably available in @bprm. This hook may be called
65+
* multiple times during a single execve.
6066
* @bprm contains the linux_binprm structure.
6167
* Return 0 if the hook is successful and permission is granted.
6268
* @bprm_committing_creds:
6369
* Prepare to install the new security attributes of a process being
6470
* transformed by an execve operation, based on the old credentials
6571
* pointed to by @current->cred and the information set in @bprm->cred by
66-
* the bprm_set_creds hook. @bprm points to the linux_binprm structure.
67-
* This hook is a good place to perform state changes on the process such
68-
* as closing open file descriptors to which access will no longer be
69-
* granted when the attributes are changed. This is called immediately
70-
* before commit_creds().
72+
* the bprm_creds_for_exec hook. @bprm points to the linux_binprm
73+
* structure. This hook is a good place to perform state changes on the
74+
* process such as closing open file descriptors to which access will no
75+
* longer be granted when the attributes are changed. This is called
76+
* immediately before commit_creds().
7177
* @bprm_committed_creds:
7278
* Tidy up after the installation of the new security attributes of a
7379
* process being transformed by an execve operation. The new credentials

include/linux/security.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ int security_quota_on(struct dentry *dentry);
276276
int security_syslog(int type);
277277
int security_settime64(const struct timespec64 *ts, const struct timezone *tz);
278278
int security_vm_enough_memory_mm(struct mm_struct *mm, long pages);
279+
int security_bprm_creds_for_exec(struct linux_binprm *bprm);
279280
int security_bprm_set_creds(struct linux_binprm *bprm);
280281
int security_bprm_check(struct linux_binprm *bprm);
281282
void security_bprm_committing_creds(struct linux_binprm *bprm);
@@ -569,6 +570,11 @@ static inline int security_vm_enough_memory_mm(struct mm_struct *mm, long pages)
569570
return __vm_enough_memory(mm, pages, cap_vm_enough_memory(mm, pages));
570571
}
571572

573+
static inline int security_bprm_creds_for_exec(struct linux_binprm *bprm)
574+
{
575+
return 0;
576+
}
577+
572578
static inline int security_bprm_set_creds(struct linux_binprm *bprm)
573579
{
574580
return cap_bprm_set_creds(bprm);

security/apparmor/domain.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -854,14 +854,14 @@ static struct aa_label *handle_onexec(struct aa_label *label,
854854
}
855855

856856
/**
857-
* apparmor_bprm_set_creds - set the new creds on the bprm struct
857+
* apparmor_bprm_creds_for_exec - Update the new creds on the bprm struct
858858
* @bprm: binprm for the exec (NOT NULL)
859859
*
860860
* Returns: %0 or error on failure
861861
*
862862
* TODO: once the other paths are done see if we can't refactor into a fn
863863
*/
864-
int apparmor_bprm_set_creds(struct linux_binprm *bprm)
864+
int apparmor_bprm_creds_for_exec(struct linux_binprm *bprm)
865865
{
866866
struct aa_task_ctx *ctx;
867867
struct aa_label *label, *new = NULL;
@@ -875,9 +875,6 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
875875
file_inode(bprm->file)->i_mode
876876
};
877877

878-
if (bprm->called_set_creds)
879-
return 0;
880-
881878
ctx = task_ctx(current);
882879
AA_BUG(!cred_label(bprm->cred));
883880
AA_BUG(!ctx);

security/apparmor/include/domain.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ struct aa_domain {
3030
struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex,
3131
const char **name);
3232

33-
int apparmor_bprm_set_creds(struct linux_binprm *bprm);
33+
int apparmor_bprm_creds_for_exec(struct linux_binprm *bprm);
3434

3535
void aa_free_domain_entries(struct aa_domain *domain);
3636
int aa_change_hat(const char *hats[], int count, u64 token, int flags);

security/apparmor/lsm.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1232,7 +1232,7 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
12321232
LSM_HOOK_INIT(cred_prepare, apparmor_cred_prepare),
12331233
LSM_HOOK_INIT(cred_transfer, apparmor_cred_transfer),
12341234

1235-
LSM_HOOK_INIT(bprm_set_creds, apparmor_bprm_set_creds),
1235+
LSM_HOOK_INIT(bprm_creds_for_exec, apparmor_bprm_creds_for_exec),
12361236
LSM_HOOK_INIT(bprm_committing_creds, apparmor_bprm_committing_creds),
12371237
LSM_HOOK_INIT(bprm_committed_creds, apparmor_bprm_committed_creds),
12381238

security/security.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -823,6 +823,11 @@ int security_vm_enough_memory_mm(struct mm_struct *mm, long pages)
823823
return __vm_enough_memory(mm, pages, cap_sys_admin);
824824
}
825825

826+
int security_bprm_creds_for_exec(struct linux_binprm *bprm)
827+
{
828+
return call_int_hook(bprm_creds_for_exec, 0, bprm);
829+
}
830+
826831
int security_bprm_set_creds(struct linux_binprm *bprm)
827832
{
828833
return call_int_hook(bprm_set_creds, 0, bprm);

security/selinux/hooks.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2286,7 +2286,7 @@ static int check_nnp_nosuid(const struct linux_binprm *bprm,
22862286
return -EACCES;
22872287
}
22882288

2289-
static int selinux_bprm_set_creds(struct linux_binprm *bprm)
2289+
static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
22902290
{
22912291
const struct task_security_struct *old_tsec;
22922292
struct task_security_struct *new_tsec;
@@ -2297,8 +2297,6 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
22972297

22982298
/* SELinux context only depends on initial program or script and not
22992299
* the script interpreter */
2300-
if (bprm->called_set_creds)
2301-
return 0;
23022300

23032301
old_tsec = selinux_cred(current_cred());
23042302
new_tsec = selinux_cred(bprm->cred);
@@ -6385,7 +6383,7 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
63856383
/* Permission checking based on the specified context is
63866384
performed during the actual operation (execve,
63876385
open/mkdir/...), when we know the full context of the
6388-
operation. See selinux_bprm_set_creds for the execve
6386+
operation. See selinux_bprm_creds_for_exec for the execve
63896387
checks and may_create for the file creation checks. The
63906388
operation will then fail if the context is not permitted. */
63916389
tsec = selinux_cred(new);
@@ -6914,7 +6912,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
69146912

69156913
LSM_HOOK_INIT(netlink_send, selinux_netlink_send),
69166914

6917-
LSM_HOOK_INIT(bprm_set_creds, selinux_bprm_set_creds),
6915+
LSM_HOOK_INIT(bprm_creds_for_exec, selinux_bprm_creds_for_exec),
69186916
LSM_HOOK_INIT(bprm_committing_creds, selinux_bprm_committing_creds),
69196917
LSM_HOOK_INIT(bprm_committed_creds, selinux_bprm_committed_creds),
69206918

0 commit comments

Comments
 (0)