Implement TARGET_SO_PEERSEC

Fix rt signals management
 -----BEGIN PGP SIGNATURE-----
 
 iQJGBAABCAAwFiEEzS913cjjpNwuT1Fz8ww4vT8vvjwFAl5FPyISHGxhdXJlbnRA
 dml2aWVyLmV1AAoJEPMMOL0/L748z/sP/iXFvyZmpydvZOfE23+XOnrn2LihYnJe
 0WgXmdJz4Ie5kJ0LUzM9iDdRJ9jTMpSSqfrflLUFpaKHOiFo4VPkRRrV90aDnCYB
 l/Wou2haCHavm7KVd/hTw4R5w97zZwXhSRb9j5dgplmT8WM5mCrIPx82LP0ZhPes
 MwVTKSbckKizEX4T5P4YtD75BmPSwJvFBDxAfz7hyYSnNvmRybaYQP+di73HFCI7
 Ux1ossYUs0HSf0AwENavza07NF53kimLqGXFOX/K0ALqvcx1dknF69TtLSo29vwR
 +Hu8wRHkyZb6EESc+pXKcHJYxIBWB4LXp6KFDkP/NEBcARcCe41kVn4SHaejy1oE
 4il6OHzc0FlB7ws3kdDF/lQSJl9sECVeOGLk/n724taY4mLtzcXBfTFnhTyPHDBO
 8L98jjUJr8BbzbaCMnozVaEMxavodw30CZyv2AwgzCi37pqWHISuneq6679uJQvT
 o91Md43ZHMGrCpCoiJ+FaI4ubAhZDK2H09l6r1WoFYgeHz5EoiRk/b3qOJ1ato2t
 cjWssOeoSpBSG893ZoH5LdVSM0qtjuQLHowUxu9uWbr28DPkJFNqNtY1Vp0fd/0i
 Uhuw3lygulnzLLQWToWVLmorrlqBFp+/mdQ+X+dXMK5b+1I1Aw2wr4947JwdsYB8
 boYSTv1rgYbL
 =ooan
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/vivier2/tags/linux-user-for-5.0-pull-request' into staging

Implement TARGET_SO_PEERSEC
Fix rt signals management

# gpg: Signature made Thu 13 Feb 2020 12:20:50 GMT
# gpg:                using RSA key CD2F75DDC8E3A4DC2E4F5173F30C38BD3F2FBE3C
# gpg:                issuer "laurent@vivier.eu"
# gpg: Good signature from "Laurent Vivier <lvivier@redhat.com>" [full]
# gpg:                 aka "Laurent Vivier <laurent@vivier.eu>" [full]
# gpg:                 aka "Laurent Vivier (Red Hat) <lvivier@redhat.com>" [full]
# Primary key fingerprint: CD2F 75DD C8E3 A4DC 2E4F  5173 F30C 38BD 3F2F BE3C

* remotes/vivier2/tags/linux-user-for-5.0-pull-request:
  linux-user: implement TARGET_SO_PEERSEC
  linux-user: fix use of SIGRTMIN
  linux-user: fix TARGET_NSIG and _NSIG uses
  linux-user: cleanup signal.c
  linux-user: add missing TARGET_SIGRTMIN for hppa

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

# Conflicts:
#	linux-user/signal.c
This commit is contained in:
Peter Maydell 2020-02-14 16:54:23 +00:00
commit 71cd1bccf3
4 changed files with 128 additions and 32 deletions

View File

@ -34,6 +34,7 @@
#define TARGET_SIGURG 29
#define TARGET_SIGXFSZ 30
#define TARGET_SIGSYS 31
#define TARGET_SIGRTMIN 32
#define TARGET_SIG_BLOCK 0
#define TARGET_SIG_UNBLOCK 1

View File

@ -30,6 +30,15 @@ static struct target_sigaction sigact_table[TARGET_NSIG];
static void host_signal_handler(int host_signum, siginfo_t *info,
void *puc);
/*
* System includes define _NSIG as SIGRTMAX + 1,
* but qemu (like the kernel) defines TARGET_NSIG as TARGET_SIGRTMAX
* and the first signal is SIGHUP defined as 1
* Signal number 0 is reserved for use as kill(pid, 0), to test whether
* a process exists without sending it a signal.
*/
QEMU_BUILD_BUG_ON(__SIGRTMAX + 1 != _NSIG);
static uint8_t host_to_target_signal_table[_NSIG] = {
[SIGHUP] = TARGET_SIGHUP,
[SIGINT] = TARGET_SIGINT,
@ -66,26 +75,25 @@ static uint8_t host_to_target_signal_table[_NSIG] = {
[SIGPWR] = TARGET_SIGPWR,
[SIGSYS] = TARGET_SIGSYS,
/* next signals stay the same */
/* Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with
host libpthread signals. This assumes no one actually uses SIGRTMAX :-/
To fix this properly we need to do manual signal delivery multiplexed
over a single host signal. */
[__SIGRTMIN] = __SIGRTMAX,
[__SIGRTMAX] = __SIGRTMIN,
};
static uint8_t target_to_host_signal_table[_NSIG];
static uint8_t target_to_host_signal_table[TARGET_NSIG + 1];
/* valid sig is between 1 and _NSIG - 1 */
int host_to_target_signal(int sig)
{
if (sig < 0 || sig >= _NSIG)
if (sig < 1 || sig >= _NSIG) {
return sig;
}
return host_to_target_signal_table[sig];
}
/* valid sig is between 1 and TARGET_NSIG */
int target_to_host_signal(int sig)
{
if (sig < 0 || sig >= _NSIG)
if (sig < 1 || sig > TARGET_NSIG) {
return sig;
}
return target_to_host_signal_table[sig];
}
@ -106,11 +114,15 @@ static inline int target_sigismember(const target_sigset_t *set, int signum)
void host_to_target_sigset_internal(target_sigset_t *d,
const sigset_t *s)
{
int i;
int host_sig, target_sig;
target_sigemptyset(d);
for (i = 1; i <= TARGET_NSIG; i++) {
if (sigismember(s, i)) {
target_sigaddset(d, host_to_target_signal(i));
for (host_sig = 1; host_sig < _NSIG; host_sig++) {
target_sig = host_to_target_signal(host_sig);
if (target_sig < 1 || target_sig > TARGET_NSIG) {
continue;
}
if (sigismember(s, host_sig)) {
target_sigaddset(d, target_sig);
}
}
}
@ -128,11 +140,15 @@ void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
void target_to_host_sigset_internal(sigset_t *d,
const target_sigset_t *s)
{
int i;
int host_sig, target_sig;
sigemptyset(d);
for (i = 1; i <= TARGET_NSIG; i++) {
if (target_sigismember(s, i)) {
sigaddset(d, target_to_host_signal(i));
for (target_sig = 1; target_sig <= TARGET_NSIG; target_sig++) {
host_sig = target_to_host_signal(target_sig);
if (host_sig < 1 || host_sig >= _NSIG) {
continue;
}
if (target_sigismember(s, target_sig)) {
sigaddset(d, host_sig);
}
}
}
@ -480,37 +496,72 @@ static int core_dump_signal(int sig)
}
}
static void signal_table_init(void)
{
int host_sig, target_sig, count;
/*
* Signals are supported starting from TARGET_SIGRTMIN and going up
* until we run out of host realtime signals.
* glibc at least uses only the lower 2 rt signals and probably
* nobody's using the upper ones.
* it's why SIGRTMIN (34) is generally greater than __SIGRTMIN (32)
* To fix this properly we need to do manual signal delivery multiplexed
* over a single host signal.
* Attempts for configure "missing" signals via sigaction will be
* silently ignored.
*/
for (host_sig = SIGRTMIN; host_sig <= SIGRTMAX; host_sig++) {
target_sig = host_sig - SIGRTMIN + TARGET_SIGRTMIN;
if (target_sig <= TARGET_NSIG) {
host_to_target_signal_table[host_sig] = target_sig;
}
}
/* generate signal conversion tables */
for (target_sig = 1; target_sig <= TARGET_NSIG; target_sig++) {
target_to_host_signal_table[target_sig] = _NSIG; /* poison */
}
for (host_sig = 1; host_sig < _NSIG; host_sig++) {
if (host_to_target_signal_table[host_sig] == 0) {
host_to_target_signal_table[host_sig] = host_sig;
}
target_sig = host_to_target_signal_table[host_sig];
if (target_sig <= TARGET_NSIG) {
target_to_host_signal_table[target_sig] = host_sig;
}
}
if (trace_event_get_state_backends(TRACE_SIGNAL_TABLE_INIT)) {
for (target_sig = 1, count = 0; target_sig <= TARGET_NSIG; target_sig++) {
if (target_to_host_signal_table[target_sig] == _NSIG) {
count++;
}
}
trace_signal_table_init(count);
}
}
void signal_init(void)
{
TaskState *ts = (TaskState *)thread_cpu->opaque;
struct sigaction act;
struct sigaction oact;
int i, j;
int i;
int host_sig;
/* generate signal conversion tables */
for(i = 1; i < _NSIG; i++) {
if (host_to_target_signal_table[i] == 0)
host_to_target_signal_table[i] = i;
}
for(i = 1; i < _NSIG; i++) {
j = host_to_target_signal_table[i];
target_to_host_signal_table[j] = i;
}
/* initialize signal conversion tables */
signal_table_init();
/* Set the signal mask from the host mask. */
sigprocmask(0, 0, &ts->signal_mask);
/* set all host signal handlers. ALL signals are blocked during
the handlers to serialize them. */
memset(sigact_table, 0, sizeof(sigact_table));
sigfillset(&act.sa_mask);
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = host_signal_handler;
for(i = 1; i <= TARGET_NSIG; i++) {
#ifdef CONFIG_GPROF
if (i == SIGPROF) {
if (i == TARGET_SIGPROF) {
continue;
}
#endif
@ -787,6 +838,8 @@ int do_sigaction(int sig, const struct target_sigaction *act,
int host_sig;
int ret = 0;
trace_signal_do_sigaction_guest(sig, TARGET_NSIG);
if (sig < 1 || sig > TARGET_NSIG || sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP) {
return -TARGET_EINVAL;
}
@ -817,6 +870,23 @@ int do_sigaction(int sig, const struct target_sigaction *act,
/* we update the host linux signal state */
host_sig = target_to_host_signal(sig);
trace_signal_do_sigaction_host(host_sig, TARGET_NSIG);
if (host_sig > SIGRTMAX) {
/* we don't have enough host signals to map all target signals */
qemu_log_mask(LOG_UNIMP, "Unsupported target signal #%d, ignored\n",
sig);
/*
* we don't return an error here because some programs try to
* register an handler for all possible rt signals even if they
* don't need it.
* An error here can abort them whereas there can be no problem
* to not have the signal available later.
* This is the case for golang,
* See https://github.com/golang/go/issues/33746
* So we silently ignore the error.
*/
return 0;
}
if (host_sig != SIGSEGV && host_sig != SIGBUS) {
sigfillset(&act1.sa_mask);
act1.sa_flags = SA_SIGINFO;

View File

@ -2344,6 +2344,28 @@ static abi_long do_getsockopt(int sockfd, int level, int optname,
}
break;
}
case TARGET_SO_PEERSEC: {
char *name;
if (get_user_u32(len, optlen)) {
return -TARGET_EFAULT;
}
if (len < 0) {
return -TARGET_EINVAL;
}
name = lock_user(VERIFY_WRITE, optval_addr, len, 0);
if (!name) {
return -TARGET_EFAULT;
}
lv = len;
ret = get_errno(getsockopt(sockfd, level, SO_PEERSEC,
name, &lv));
if (put_user_u32(lv, optlen)) {
ret = -TARGET_EFAULT;
}
unlock_user(name, optval_addr, lv);
break;
}
case TARGET_SO_LINGER:
{
struct linger lg;

View File

@ -1,6 +1,9 @@
# See docs/devel/tracing.txt for syntax documentation.
# signal.c
signal_table_init(int i) "number of unavailable signals: %d"
signal_do_sigaction_guest(int sig, int max) "target signal %d (MAX %d)"
signal_do_sigaction_host(int sig, int max) "host signal %d (MAX %d)"
# */signal.c
user_setup_frame(void *env, uint64_t frame_addr) "env=%p frame_addr=0x%"PRIx64
user_setup_rt_frame(void *env, uint64_t frame_addr) "env=%p frame_addr=0x%"PRIx64