Skip to content

Commit b213c2d

Browse files
committed
exec: Promised cleanups after introducing exec_update_mutex
In the patchset that introduced exec_update_mutex there were a few last minute discoveries and fixes that left the code in a state that can be very easily be improved. During the merge window we discussed the first three of these patches and I promised I would resend them. What the first patch does is it makes the the calls in the binfmts: flush_old_exec(); /* set the personality */ setup_new_exec(); install_exec_creds(); With no sleeps or anything in between. At the conclusion of this set of changes the the calls in the binfmts are: begin_new_exec(); /* set the personality */ setup_new_exec(); The intent is to make the code easier to follow and easier to change. Eric W. Biederman (7): binfmt: Move install_exec_creds after setup_new_exec to match binfmt_elf exec: Make unlocking exec_update_mutex explict exec: Rename the flag called_exec_mmap point_of_no_return exec: Merge install_exec_creds into setup_new_exec exec: In setup_new_exec cache current in the local variable me exec: Move most of setup_new_exec into flush_old_exec exec: Rename flush_old_exec begin_new_exec Documentation/trace/ftrace.rst | 2 +- arch/x86/ia32/ia32_aout.c | 4 +- fs/binfmt_aout.c | 3 +- fs/binfmt_elf.c | 3 +- fs/binfmt_elf_fdpic.c | 3 +- fs/binfmt_flat.c | 4 +- fs/exec.c | 162 ++++++++++++++++++++--------------------- include/linux/binfmts.h | 10 +-- kernel/events/core.c | 2 +- 9 files changed, 92 insertions(+), 101 deletions(-) Link: https://lkml.kernel.org/r/[email protected] Reviewed-by: Kees Cook <[email protected]> Reviewed-by: Greg Ungerer <[email protected]> Signed-off-by: "Eric W. Biederman" <[email protected]>
2 parents 6a8b55e + 2388777 commit b213c2d

File tree

9 files changed

+92
-101
lines changed

9 files changed

+92
-101
lines changed

Documentation/trace/ftrace.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1524,7 +1524,7 @@ display-graph option::
15241524
=> remove_vma
15251525
=> exit_mmap
15261526
=> mmput
1527-
=> flush_old_exec
1527+
=> begin_new_exec
15281528
=> load_elf_binary
15291529
=> search_binary_handler
15301530
=> __do_execve_file.isra.32

arch/x86/ia32/ia32_aout.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ static int load_aout_binary(struct linux_binprm *bprm)
131131
return -ENOMEM;
132132

133133
/* Flush all traces of the currently running executable */
134-
retval = flush_old_exec(bprm);
134+
retval = begin_new_exec(bprm);
135135
if (retval)
136136
return retval;
137137

@@ -156,8 +156,6 @@ static int load_aout_binary(struct linux_binprm *bprm)
156156
if (retval < 0)
157157
return retval;
158158

159-
install_exec_creds(bprm);
160-
161159
if (N_MAGIC(ex) == OMAGIC) {
162160
unsigned long text_addr, map_size;
163161

fs/binfmt_aout.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ static int load_aout_binary(struct linux_binprm * bprm)
151151
return -ENOMEM;
152152

153153
/* Flush all traces of the currently running executable */
154-
retval = flush_old_exec(bprm);
154+
retval = begin_new_exec(bprm);
155155
if (retval)
156156
return retval;
157157

@@ -174,7 +174,6 @@ static int load_aout_binary(struct linux_binprm * bprm)
174174
if (retval < 0)
175175
return retval;
176176

177-
install_exec_creds(bprm);
178177

179178
if (N_MAGIC(ex) == OMAGIC) {
180179
unsigned long text_addr, map_size;

fs/binfmt_elf.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -844,7 +844,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
844844
goto out_free_dentry;
845845

846846
/* Flush all traces of the currently running executable */
847-
retval = flush_old_exec(bprm);
847+
retval = begin_new_exec(bprm);
848848
if (retval)
849849
goto out_free_dentry;
850850

@@ -858,7 +858,6 @@ static int load_elf_binary(struct linux_binprm *bprm)
858858
current->flags |= PF_RANDOMIZE;
859859

860860
setup_new_exec(bprm);
861-
install_exec_creds(bprm);
862861

863862
/* Do this so that we can load the interpreter, if need be. We will
864863
change some of these later */

fs/binfmt_elf_fdpic.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm)
338338
interp_params.flags |= ELF_FDPIC_FLAG_CONSTDISP;
339339

340340
/* flush all traces of the currently running executable */
341-
retval = flush_old_exec(bprm);
341+
retval = begin_new_exec(bprm);
342342
if (retval)
343343
goto error;
344344

@@ -434,7 +434,6 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm)
434434
current->mm->start_stack = current->mm->start_brk + stack_size;
435435
#endif
436436

437-
install_exec_creds(bprm);
438437
if (create_elf_fdpic_tables(bprm, current->mm,
439438
&exec_params, &interp_params) < 0)
440439
goto error;

fs/binfmt_flat.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,7 @@ static int load_flat_file(struct linux_binprm *bprm,
534534

535535
/* Flush all traces of the currently running executable */
536536
if (id == 0) {
537-
ret = flush_old_exec(bprm);
537+
ret = begin_new_exec(bprm);
538538
if (ret)
539539
goto err;
540540

@@ -963,8 +963,6 @@ static int load_flat_binary(struct linux_binprm *bprm)
963963
}
964964
}
965965

966-
install_exec_creds(bprm);
967-
968966
set_binfmt(&flat_format);
969967

970968
#ifdef CONFIG_MMU

fs/exec.c

Lines changed: 81 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1298,7 +1298,7 @@ void __set_task_comm(struct task_struct *tsk, const char *buf, bool exec)
12981298
* signal (via de_thread() or coredump), or will have SEGV raised
12991299
* (after exec_mmap()) by search_binary_handlers (see below).
13001300
*/
1301-
int flush_old_exec(struct linux_binprm * bprm)
1301+
int begin_new_exec(struct linux_binprm * bprm)
13021302
{
13031303
struct task_struct *me = current;
13041304
int retval;
@@ -1326,12 +1326,12 @@ int flush_old_exec(struct linux_binprm * bprm)
13261326
goto out;
13271327

13281328
/*
1329-
* After setting bprm->called_exec_mmap (to mark that current is
1330-
* using the prepared mm now), we have nothing left of the original
1331-
* process. If anything from here on returns an error, the check
1332-
* in search_binary_handler() will SEGV current.
1329+
* With the new mm installed it is completely impossible to
1330+
* fail and return to the original process. If anything from
1331+
* here on returns an error, the check in
1332+
* search_binary_handler() will SEGV current.
13331333
*/
1334-
bprm->called_exec_mmap = 1;
1334+
bprm->point_of_no_return = true;
13351335
bprm->mm = NULL;
13361336

13371337
#ifdef CONFIG_POSIX_TIMERS
@@ -1344,7 +1344,7 @@ int flush_old_exec(struct linux_binprm * bprm)
13441344
*/
13451345
retval = unshare_sighand(me);
13461346
if (retval)
1347-
goto out;
1347+
goto out_unlock;
13481348

13491349
set_fs(USER_DS);
13501350
me->flags &= ~(PF_RANDOMIZE | PF_FORKNOEXEC | PF_KTHREAD |
@@ -1359,36 +1359,7 @@ int flush_old_exec(struct linux_binprm * bprm)
13591359
* undergoing exec(2).
13601360
*/
13611361
do_close_on_exec(me->files);
1362-
return 0;
1363-
1364-
out:
1365-
return retval;
1366-
}
1367-
EXPORT_SYMBOL(flush_old_exec);
13681362

1369-
void would_dump(struct linux_binprm *bprm, struct file *file)
1370-
{
1371-
struct inode *inode = file_inode(file);
1372-
if (inode_permission(inode, MAY_READ) < 0) {
1373-
struct user_namespace *old, *user_ns;
1374-
bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP;
1375-
1376-
/* Ensure mm->user_ns contains the executable */
1377-
user_ns = old = bprm->mm->user_ns;
1378-
while ((user_ns != &init_user_ns) &&
1379-
!privileged_wrt_inode_uidgid(user_ns, inode))
1380-
user_ns = user_ns->parent;
1381-
1382-
if (old != user_ns) {
1383-
bprm->mm->user_ns = get_user_ns(user_ns);
1384-
put_user_ns(old);
1385-
}
1386-
}
1387-
}
1388-
EXPORT_SYMBOL(would_dump);
1389-
1390-
void setup_new_exec(struct linux_binprm * bprm)
1391-
{
13921363
/*
13931364
* Once here, prepare_binrpm() will not be called any more, so
13941365
* the final state of setuid/setgid/fscaps can be merged into the
@@ -1398,7 +1369,7 @@ void setup_new_exec(struct linux_binprm * bprm)
13981369

13991370
if (bprm->secureexec) {
14001371
/* Make sure parent cannot signal privileged process. */
1401-
current->pdeath_signal = 0;
1372+
me->pdeath_signal = 0;
14021373

14031374
/*
14041375
* For secureexec, reset the stack limit to sane default to
@@ -1411,9 +1382,7 @@ void setup_new_exec(struct linux_binprm * bprm)
14111382
bprm->rlim_stack.rlim_cur = _STK_LIM;
14121383
}
14131384

1414-
arch_pick_mmap_layout(current->mm, &bprm->rlim_stack);
1415-
1416-
current->sas_ss_sp = current->sas_ss_size = 0;
1385+
me->sas_ss_sp = me->sas_ss_size = 0;
14171386

14181387
/*
14191388
* Figure out dumpability. Note that this checking only of current
@@ -1427,20 +1396,82 @@ void setup_new_exec(struct linux_binprm * bprm)
14271396
else
14281397
set_dumpable(current->mm, SUID_DUMP_USER);
14291398

1430-
arch_setup_new_exec();
14311399
perf_event_exec();
1432-
__set_task_comm(current, kbasename(bprm->filename), true);
1400+
__set_task_comm(me, kbasename(bprm->filename), true);
1401+
1402+
/* An exec changes our domain. We are no longer part of the thread
1403+
group */
1404+
WRITE_ONCE(me->self_exec_id, me->self_exec_id + 1);
1405+
flush_signal_handlers(me, 0);
1406+
1407+
/*
1408+
* install the new credentials for this executable
1409+
*/
1410+
security_bprm_committing_creds(bprm);
1411+
1412+
commit_creds(bprm->cred);
1413+
bprm->cred = NULL;
1414+
1415+
/*
1416+
* Disable monitoring for regular users
1417+
* when executing setuid binaries. Must
1418+
* wait until new credentials are committed
1419+
* by commit_creds() above
1420+
*/
1421+
if (get_dumpable(me->mm) != SUID_DUMP_USER)
1422+
perf_event_exit_task(me);
1423+
/*
1424+
* cred_guard_mutex must be held at least to this point to prevent
1425+
* ptrace_attach() from altering our determination of the task's
1426+
* credentials; any time after this it may be unlocked.
1427+
*/
1428+
security_bprm_committed_creds(bprm);
1429+
return 0;
1430+
1431+
out_unlock:
1432+
mutex_unlock(&me->signal->exec_update_mutex);
1433+
out:
1434+
return retval;
1435+
}
1436+
EXPORT_SYMBOL(begin_new_exec);
1437+
1438+
void would_dump(struct linux_binprm *bprm, struct file *file)
1439+
{
1440+
struct inode *inode = file_inode(file);
1441+
if (inode_permission(inode, MAY_READ) < 0) {
1442+
struct user_namespace *old, *user_ns;
1443+
bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP;
1444+
1445+
/* Ensure mm->user_ns contains the executable */
1446+
user_ns = old = bprm->mm->user_ns;
1447+
while ((user_ns != &init_user_ns) &&
1448+
!privileged_wrt_inode_uidgid(user_ns, inode))
1449+
user_ns = user_ns->parent;
1450+
1451+
if (old != user_ns) {
1452+
bprm->mm->user_ns = get_user_ns(user_ns);
1453+
put_user_ns(old);
1454+
}
1455+
}
1456+
}
1457+
EXPORT_SYMBOL(would_dump);
1458+
1459+
void setup_new_exec(struct linux_binprm * bprm)
1460+
{
1461+
/* Setup things that can depend upon the personality */
1462+
struct task_struct *me = current;
1463+
1464+
arch_pick_mmap_layout(me->mm, &bprm->rlim_stack);
1465+
1466+
arch_setup_new_exec();
14331467

14341468
/* Set the new mm task size. We have to do that late because it may
14351469
* depend on TIF_32BIT which is only updated in flush_thread() on
14361470
* some architectures like powerpc
14371471
*/
1438-
current->mm->task_size = TASK_SIZE;
1439-
1440-
/* An exec changes our domain. We are no longer part of the thread
1441-
group */
1442-
WRITE_ONCE(current->self_exec_id, current->self_exec_id + 1);
1443-
flush_signal_handlers(current, 0);
1472+
me->mm->task_size = TASK_SIZE;
1473+
mutex_unlock(&me->signal->exec_update_mutex);
1474+
mutex_unlock(&me->signal->cred_guard_mutex);
14441475
}
14451476
EXPORT_SYMBOL(setup_new_exec);
14461477

@@ -1456,7 +1487,7 @@ EXPORT_SYMBOL(finalize_exec);
14561487

14571488
/*
14581489
* Prepare credentials and lock ->cred_guard_mutex.
1459-
* install_exec_creds() commits the new creds and drops the lock.
1490+
* setup_new_exec() commits the new creds and drops the lock.
14601491
* Or, if exec fails before, free_bprm() should release ->cred and
14611492
* and unlock.
14621493
*/
@@ -1477,8 +1508,6 @@ static void free_bprm(struct linux_binprm *bprm)
14771508
{
14781509
free_arg_pages(bprm);
14791510
if (bprm->cred) {
1480-
if (bprm->called_exec_mmap)
1481-
mutex_unlock(&current->signal->exec_update_mutex);
14821511
mutex_unlock(&current->signal->cred_guard_mutex);
14831512
abort_creds(bprm->cred);
14841513
}
@@ -1504,35 +1533,6 @@ int bprm_change_interp(const char *interp, struct linux_binprm *bprm)
15041533
}
15051534
EXPORT_SYMBOL(bprm_change_interp);
15061535

1507-
/*
1508-
* install the new credentials for this executable
1509-
*/
1510-
void install_exec_creds(struct linux_binprm *bprm)
1511-
{
1512-
security_bprm_committing_creds(bprm);
1513-
1514-
commit_creds(bprm->cred);
1515-
bprm->cred = NULL;
1516-
1517-
/*
1518-
* Disable monitoring for regular users
1519-
* when executing setuid binaries. Must
1520-
* wait until new credentials are committed
1521-
* by commit_creds() above
1522-
*/
1523-
if (get_dumpable(current->mm) != SUID_DUMP_USER)
1524-
perf_event_exit_task(current);
1525-
/*
1526-
* cred_guard_mutex must be held at least to this point to prevent
1527-
* ptrace_attach() from altering our determination of the task's
1528-
* credentials; any time after this it may be unlocked.
1529-
*/
1530-
security_bprm_committed_creds(bprm);
1531-
mutex_unlock(&current->signal->exec_update_mutex);
1532-
mutex_unlock(&current->signal->cred_guard_mutex);
1533-
}
1534-
EXPORT_SYMBOL(install_exec_creds);
1535-
15361536
/*
15371537
* determine how safe it is to execute the proposed program
15381538
* - the caller must hold ->cred_guard_mutex to protect against
@@ -1720,7 +1720,7 @@ int search_binary_handler(struct linux_binprm *bprm)
17201720

17211721
read_lock(&binfmt_lock);
17221722
put_binfmt(fmt);
1723-
if (retval < 0 && bprm->called_exec_mmap) {
1723+
if (retval < 0 && bprm->point_of_no_return) {
17241724
/* we got to flush_old_exec() and failed after it */
17251725
read_unlock(&binfmt_lock);
17261726
force_sigsegv(SIGSEGV);

include/linux/binfmts.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,10 @@ struct linux_binprm {
4646
*/
4747
secureexec:1,
4848
/*
49-
* Set by flush_old_exec, when exec_mmap has been called.
50-
* This is past the point of no return, when the
51-
* exec_update_mutex has been taken.
49+
* Set when errors can no longer be returned to the
50+
* original userspace.
5251
*/
53-
called_exec_mmap:1;
52+
point_of_no_return:1;
5453
#ifdef __alpha__
5554
unsigned int taso:1;
5655
#endif
@@ -126,7 +125,7 @@ extern void unregister_binfmt(struct linux_binfmt *);
126125
extern int prepare_binprm(struct linux_binprm *);
127126
extern int __must_check remove_arg_zero(struct linux_binprm *);
128127
extern int search_binary_handler(struct linux_binprm *);
129-
extern int flush_old_exec(struct linux_binprm * bprm);
128+
extern int begin_new_exec(struct linux_binprm * bprm);
130129
extern void setup_new_exec(struct linux_binprm * bprm);
131130
extern void finalize_exec(struct linux_binprm *bprm);
132131
extern void would_dump(struct linux_binprm *, struct file *);
@@ -146,7 +145,6 @@ extern int transfer_args_to_stack(struct linux_binprm *bprm,
146145
extern int bprm_change_interp(const char *interp, struct linux_binprm *bprm);
147146
extern int copy_strings_kernel(int argc, const char *const *argv,
148147
struct linux_binprm *bprm);
149-
extern void install_exec_creds(struct linux_binprm *bprm);
150148
extern void set_binfmt(struct linux_binfmt *new);
151149
extern ssize_t read_code(struct file *, unsigned long, loff_t, size_t);
152150

kernel/events/core.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12217,7 +12217,7 @@ static void perf_event_exit_task_context(struct task_struct *child, int ctxn)
1221712217
* When a child task exits, feed back event values to parent events.
1221812218
*
1221912219
* Can be called with exec_update_mutex held when called from
12220-
* install_exec_creds().
12220+
* setup_new_exec().
1222112221
*/
1222212222
void perf_event_exit_task(struct task_struct *child)
1222312223
{

0 commit comments

Comments
 (0)