diff --git a/share/man/man4/linux.4 b/share/man/man4/linux.4 --- a/share/man/man4/linux.4 +++ b/share/man/man4/linux.4 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd July 5, 2020 +.Dd May 6, 2021 .Dt LINUX 4 .Os .Sh NAME @@ -130,6 +130,18 @@ .Va SIGINFO work for Linux executables. Defaults to 0. +.It Va compat.linux.setid_allowed +Disable handling of set-user-ID and set-group-ID mode bits for the new +process image file when image is to be executed under Linux ABI. +When set, new Linux images always use credentials of the program +that issued +.Xr execve 2 +call, regardless of the image file mode. +.Pp +This might be reasonable or even required, because +.Fx +does not emulate Linux environment completely, and missed features +could become holes. .El .Sh FILES .Bl -tag -width /compat/linux/dev/shm -compact diff --git a/sys/amd64/linux/linux_sysvec.c b/sys/amd64/linux/linux_sysvec.c --- a/sys/amd64/linux/linux_sysvec.c +++ b/sys/amd64/linux/linux_sysvec.c @@ -764,6 +764,7 @@ .sv_onexec = linux_on_exec, .sv_onexit = linux_on_exit, .sv_ontdexit = linux_thread_dtor, + .sv_setid_allowed = &linux_setid_allowed_query, }; static void diff --git a/sys/amd64/linux32/linux32_sysvec.c b/sys/amd64/linux32/linux32_sysvec.c --- a/sys/amd64/linux32/linux32_sysvec.c +++ b/sys/amd64/linux32/linux32_sysvec.c @@ -931,6 +931,7 @@ .sv_onexec = linux_on_exec, .sv_onexit = linux_on_exit, .sv_ontdexit = linux_thread_dtor, + .sv_setid_allowed = &linux_setid_allowed_query, }; static void diff --git a/sys/arm64/linux/linux_sysvec.c b/sys/arm64/linux/linux_sysvec.c --- a/sys/arm64/linux/linux_sysvec.c +++ b/sys/arm64/linux/linux_sysvec.c @@ -441,6 +441,7 @@ .sv_onexec = linux_on_exec, .sv_onexit = linux_on_exit, .sv_ontdexit = linux_thread_dtor, + .sv_setid_allowed = &linux_setid_allowed_query, }; static void diff --git a/sys/compat/linux/linux_mib.h b/sys/compat/linux/linux_mib.h --- a/sys/compat/linux/linux_mib.h +++ b/sys/compat/linux/linux_mib.h @@ -70,4 +70,7 @@ extern int linux_preserve_vstatus; extern bool linux_map_sched_prio; +struct image_params; +bool linux_setid_allowed_query(struct thread *td, struct image_params *imgp); + #endif /* _LINUX_MIB_H_ */ diff --git a/sys/compat/linux/linux_mib.c b/sys/compat/linux/linux_mib.c --- a/sys/compat/linux/linux_mib.c +++ b/sys/compat/linux/linux_mib.c @@ -99,6 +99,18 @@ SYSCTL_INT(_compat_linux, OID_AUTO, use_emul_path, CTLFLAG_RWTUN, &linux_use_emul_path, 0, "Use linux.compat.emul_path"); +static bool linux_setid_allowed = true; +SYSCTL_BOOL(_compat_linux, OID_AUTO, setid_allowed, CTLFLAG_RWTUN, + &linux_setid_allowed, 0, + "Allow setuid/setgid on execve of Linux binary"); + +bool +linux_setid_allowed_query(struct thread *td __unused, + struct image_params *imgp __unused) +{ + return (linux_setid_allowed); +} + static int linux_set_osname(struct thread *td, char *osname); static int linux_set_osrelease(struct thread *td, char *osrelease); static int linux_set_oss_version(struct thread *td, int oss_version); diff --git a/sys/i386/linux/linux_sysvec.c b/sys/i386/linux/linux_sysvec.c --- a/sys/i386/linux/linux_sysvec.c +++ b/sys/i386/linux/linux_sysvec.c @@ -871,6 +871,7 @@ .sv_onexec = linux_on_exec, .sv_onexit = linux_on_exit, .sv_ontdexit = linux_thread_dtor, + .sv_setid_allowed = &linux_setid_allowed_query, }; INIT_SYSENTVEC(aout_sysvec, &linux_sysvec); @@ -908,6 +909,7 @@ .sv_onexec = linux_on_exec, .sv_onexit = linux_on_exit, .sv_ontdexit = linux_thread_dtor, + .sv_setid_allowed = &linux_setid_allowed_query, }; static void diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -354,6 +354,16 @@ return (do_execve(td, args, mac_p, oldvmspace)); } +static void +execve_nosetid(struct image_params *imgp) +{ + imgp->credential_setid = false; + if (imgp->newcred != NULL) { + crfree(imgp->newcred); + imgp->newcred = NULL; + } +} + /* * In-kernel implementation of execve(). All arguments are assumed to be * userspace pointers from the passed thread. @@ -640,11 +650,7 @@ vput(newtextvp); vm_object_deallocate(imgp->object); imgp->object = NULL; - imgp->credential_setid = false; - if (imgp->newcred != NULL) { - crfree(imgp->newcred); - imgp->newcred = NULL; - } + execve_nosetid(imgp); imgp->execpath = NULL; free(imgp->freepath, M_TEMP); imgp->freepath = NULL; @@ -769,6 +775,10 @@ signotify(td); } + if (imgp->sysent->sv_setid_allowed != NULL && + !(*imgp->sysent->sv_setid_allowed)(td, imgp)) + execve_nosetid(imgp); + /* * Implement image setuid/setgid installation. */ diff --git a/sys/sys/sysent.h b/sys/sys/sysent.h --- a/sys/sys/sysent.h +++ b/sys/sys/sysent.h @@ -148,6 +148,8 @@ void (*sv_onexec)(struct proc *, struct image_params *); void (*sv_onexit)(struct proc *); void (*sv_ontdexit)(struct thread *td); + bool (*sv_setid_allowed)(struct thread *td, + struct image_params *imgp); }; #define SV_ILP32 0x000100 /* 32-bit executable. */