[PATCH 1/8] exec: bump exec_update_seq across the exec_update_lock write side
From: Christian Brauner
Date: Mon May 25 2026 - 03:16:13 EST
execve() (exec_mmap() -> begin_new_exec() -> setup_new_exec()) and
Landlock TSYNC are the only writers of exec_update_lock. Bump
exec_update_seq to odd for the duration of each write-held section, the
way mmap_lock maintains mm->mm_lock_seq:
- exec: exec_update_seq_begin() right after down_write_killable() in
exec_mmap(); exec_update_seq_end() before each matching up_write() (the
exec_mmap() error path, the begin_new_exec() error path, and the normal
release in setup_new_exec()). Every acquire reaches exactly one of
those releases, so the seqcount is even whenever the lock is not held
for writing.
- Landlock: begin after down_write_trylock(), end before up_write().
The bump uses the non-preempt-disabling do_raw_write_seqcount_*() helpers,
so the sleeping exec and TSYNC write sections are unaffected.
No reader consults exec_update_seq yet: no functional change.
Signed-off-by: Christian Brauner (Amutable) <brauner@xxxxxxxxxx>
---
fs/exec.c | 4 ++++
security/landlock/tsync.c | 2 ++
2 files changed, 6 insertions(+)
diff --git a/fs/exec.c b/fs/exec.c
index 824b46c069ae..1915acb0b44d 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -859,6 +859,7 @@ static int exec_mmap(struct linux_binprm *bprm)
ret = down_write_killable(&tsk->signal->exec_update_lock);
if (ret)
return ret;
+ exec_update_seq_begin(tsk->signal);
if (old_mm) {
/*
@@ -868,6 +869,7 @@ static int exec_mmap(struct linux_binprm *bprm)
*/
ret = mmap_read_lock_killable(old_mm);
if (ret) {
+ exec_update_seq_end(tsk->signal);
up_write(&tsk->signal->exec_update_lock);
return ret;
}
@@ -1300,6 +1302,7 @@ int begin_new_exec(struct linux_binprm * bprm)
return 0;
out_unlock:
+ exec_update_seq_end(me->signal);
up_write(&me->signal->exec_update_lock);
if (!bprm->cred)
mutex_unlock(&me->signal->cred_guard_mutex);
@@ -1345,6 +1348,7 @@ void setup_new_exec(struct linux_binprm * bprm)
* some architectures like powerpc
*/
me->mm->task_size = TASK_SIZE;
+ exec_update_seq_end(me->signal);
up_write(&me->signal->exec_update_lock);
mutex_unlock(&me->signal->cred_guard_mutex);
diff --git a/security/landlock/tsync.c b/security/landlock/tsync.c
index c5730bbd9ed3..472c02cf71e9 100644
--- a/security/landlock/tsync.c
+++ b/security/landlock/tsync.c
@@ -492,6 +492,7 @@ int landlock_restrict_sibling_threads(const struct cred *old_cred,
*/
if (!down_write_trylock(¤t->signal->exec_update_lock))
return restart_syscall();
+ exec_update_seq_begin(current->signal);
/*
* We schedule a pseudo-signal task_work for each of the calling task's
@@ -614,6 +615,7 @@ int landlock_restrict_sibling_threads(const struct cred *old_cred,
wait_for_completion(&shared_ctx.all_finished);
tsync_works_release(&works);
+ exec_update_seq_end(current->signal);
up_write(¤t->signal->exec_update_lock);
return atomic_read(&shared_ctx.preparation_error);
}
--
2.47.3
--j3ezp33mpunnwnqz
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0002-exec-add-a-speculate-or-lock-helper-for-exec_update-.patch"