linux(4): Implement clone3 system call.

clone3 system call is used by glibc-2.34.

Differential revision:	https://reviews.freebsd.org/D31475
MFC after:		2 weeks
This commit is contained in:
Dmitry Chagin 2021-08-12 11:49:36 +03:00
parent 0a4b664ae8
commit 17913b0b6b
7 changed files with 107 additions and 4 deletions

View File

@ -2082,7 +2082,10 @@
int linux_pidfd_open(void);
}
435 AUE_NULL STD {
int linux_clone3(void);
int linux_clone3(
struct l_user_clone_args *uargs,
l_size_t usize
);
}
436 AUE_NULL STD {
int linux_close_range(void);

View File

@ -2484,7 +2484,10 @@
int linux_pidfd_open(void);
}
435 AUE_NULL STD {
int linux_clone3(void);
int linux_clone3(
struct l_user_clone_args *uargs,
l_size_t usize
);
}
436 AUE_NULL STD {
int linux_close_range(void);

View File

@ -1731,7 +1731,10 @@
int linux_pidfd_open(void);
}
435 AUE_NULL STD {
int linux_clone3(void);
int linux_clone3(
struct l_user_clone_args *uargs,
l_size_t usize
);
}
436 AUE_NULL STD {
int linux_close_range(void);

View File

@ -377,6 +377,86 @@ linux_clone(struct thread *td, struct linux_clone_args *args)
return (linux_clone_proc(td, &ca));
}
static int
linux_clone3_args_valid(struct l_user_clone_args *uca)
{
/* Verify that no unknown flags are passed along. */
if ((uca->flags & ~(LINUX_CLONE_LEGACY_FLAGS |
LINUX_CLONE_CLEAR_SIGHAND | LINUX_CLONE_INTO_CGROUP)) != 0)
return (EINVAL);
if ((uca->flags & (LINUX_CLONE_DETACHED | LINUX_CSIGNAL)) != 0)
return (EINVAL);
if ((uca->flags & (LINUX_CLONE_SIGHAND | LINUX_CLONE_CLEAR_SIGHAND)) ==
(LINUX_CLONE_SIGHAND | LINUX_CLONE_CLEAR_SIGHAND))
return (EINVAL);
if ((uca->flags & (LINUX_CLONE_THREAD | LINUX_CLONE_PARENT)) != 0 &&
uca->exit_signal != 0)
return (EINVAL);
/* We don't support set_tid, only validate input. */
if (uca->set_tid_size > LINUX_MAX_PID_NS_LEVEL)
return (EINVAL);
if (uca->set_tid == 0 && uca->set_tid_size > 0)
return (EINVAL);
if (uca->set_tid != 0 && uca->set_tid_size == 0)
return (EINVAL);
if (uca->stack == 0 && uca->stack_size > 0)
return (EINVAL);
if (uca->stack != 0 && uca->stack_size == 0)
return (EINVAL);
return (0);
}
int
linux_clone3(struct thread *td, struct linux_clone3_args *args)
{
struct l_user_clone_args *uca;
struct l_clone_args *ca;
size_t size;
int error;
if (args->usize > PAGE_SIZE)
return (E2BIG);
if (args->usize < LINUX_CLONE_ARGS_SIZE_VER0)
return (EINVAL);
/*
* usize can be less than size of struct clone_args, to avoid using
* of uninitialized data of struct clone_args, allocate at least
* sizeof(struct clone_args) storage and zero it.
*/
size = max(args->usize, sizeof(*uca));
uca = malloc(size, M_LINUX, M_WAITOK | M_ZERO);
error = copyin(args->uargs, uca, args->usize);
if (error != 0)
goto out;
error = linux_clone3_args_valid(uca);
if (error != 0)
goto out;
ca = malloc(sizeof(*ca), M_LINUX, M_WAITOK | M_ZERO);
ca->flags = uca->flags;
ca->child_tid = PTRIN(uca->child_tid);
ca->parent_tid = PTRIN(uca->parent_tid);
ca->exit_signal = uca->exit_signal;
ca->stack = uca->stack + uca->stack_size;
ca->stack_size = uca->stack_size;
ca->tls = uca->tls;
if ((ca->flags & LINUX_CLONE_THREAD) != 0)
error = linux_clone_thread(td, ca);
else
error = linux_clone_proc(td, ca);
free(ca, M_LINUX);
out:
free(uca, M_LINUX);
return (error);
}
int
linux_exit(struct thread *td, struct linux_exit_args *args)
{

View File

@ -53,6 +53,13 @@
#define LINUX_CLONE_NEWNET 0x40000000
#define LINUX_CLONE_IO 0x80000000
/* Flags for the clone3() syscall. */
#define LINUX_CLONE_CLEAR_SIGHAND 0x100000000ULL
#define LINUX_CLONE_INTO_CGROUP 0x200000000ULL
#define LINUX_CLONE_NEWTIME 0x00000080
#define LINUX_CLONE_LEGACY_FLAGS 0xffffffffULL
#define LINUX_CSIGNAL 0x000000ff
/*
@ -85,6 +92,8 @@ struct l_clone_args {
l_ulong tls;
};
#define LINUX_CLONE_ARGS_SIZE_VER0 64
int linux_set_upcall(struct thread *, register_t);
int linux_set_cloned_tls(struct thread *, void *);
void linux_thread_detach(struct thread *);

View File

@ -33,6 +33,8 @@
#include <sys/sysctl.h>
#define LINUX_MAX_PID_NS_LEVEL 32
/* bits per mask */
#define LINUX_NFDBITS sizeof(l_fd_mask) * 8

View File

@ -2502,7 +2502,10 @@
int linux_pidfd_open(void);
}
435 AUE_NULL STD {
int linux_clone3(void);
int linux_clone3(
struct l_user_clone_args *uargs,
l_size_t usize
);
}
436 AUE_NULL STD {
int linux_close_range(void);