Date: Sat, 1 Jul 2017 19:42:11 -0700 From: Mark Millard <markmi@dsl-only.net> To: Konstantin Belousov <kib@freebsd.org>, FreeBSD PowerPC ML <freebsd-ppc@freebsd.org>, FreeBSD Current <freebsd-current@freebsd.org>, freebsd-hackers@freebsd.org Subject: head -r320521 (e.g.): another powerpc64 problem: programs using fgets crash trying to store address over code instead of into __cleanup_info__ Message-ID: <B203F272-002C-48BE-ADB1-8D03881380C1@dsl-only.net>
next in thread | raw e-mail | index | archive | help
[Note: this is from a amd64 -> powerpc64 cross-build based
on system clang 4 instead of gcc 4.2.1. I'm building a
gcc 4.2.1 based system currently so that I can test
a more standard configuration. But I'm one of the ones
that experiments with finding things to report for
clang targeting powerpc64 and powerpc.]
powerpc64 is having programs crash with an attempt
to store addresses over code instead of into
__cleanup_info__ when fgets is used. ntpd is an
example. As is sshd (although I've looked at
its details less).
Building up the context for this claim. . .
public declaration:
struct _pthread_cleanup_info {
__uintptr_t pthread_cleanup_pad[8];
};
private declaration:
struct pthread_cleanup {
struct pthread_cleanup *prev;
void (*routine)(void *);
void *routine_arg;
int onheap;
};
ntpd and sshd die with segmentation faults in:
void
__pthread_cleanup_push_imp(void (*routine)(void *), void *arg,
struct _pthread_cleanup_info *info)
{
struct pthread *curthread =3D _get_curthread();
struct pthread_cleanup *newbuf;
newbuf =3D (void *)info;
newbuf->routine =3D routine;
newbuf->routine_arg =3D arg;
newbuf->onheap =3D 0;
newbuf->prev =3D curthread->cleanup;
curthread->cleanup =3D newbuf;
}
at the statement: newbuf->routine =3D routine;
But it turns out that the bt is like:
__pthread_cleanup_push_imp(routine=3D0x507b1248 =
<__stdio_cancel_cleanup>, arg=3D0x0, info=3D0x509eaaf4)
__pthread_cleanup_push_imp_int(p0=3D0x507b1248,p1=3D0x0)
fgets (buf=3D0x51415000 "", n=3D511, fp=3D0x507d4c40)
. . .
Note the 2 arguments to __pthread_cleanup_push_imp_int when called
from fgets but the 3 arguemnts to __pthread_cleanup_push_imp . . .
fgets uses FLOCK_CANCELSAFE(fp) :
#define FLOCKFILE_CANCELSAFE(fp) =
\
{ =
\
struct _pthread_cleanup_info __cleanup_info__; =
\
if (__isthreaded) { =
\
_FLOCKFILE(fp); =
\
___pthread_cleanup_push_imp( =
\
__stdio_cancel_cleanup, (fp), =
\
&__cleanup_info__); =
\
} else { =
\
___pthread_cleanup_push_imp( =
\
__stdio_cancel_cleanup, NULL, =
\
&__cleanup_info__); =
\
} =
\
{
#define FUNLOCKFILE_CANCELSAFE() =
\
(void)0; =
\
} =
\
___pthread_cleanup_pop_imp(1); =
\
}
where here the NULL case is in use. 3 arguments.
But:
STUB_FUNC2(__pthread_cleanup_push_imp, PJT_CLEANUP_PUSH_IMP, void, =
void*, void *);
which is use of:
#define STUB_FUNC2(name, idx, ret, p0_type, p1_type) \
static ret FUNC_EXP(name)(p0_type, p1_type) __used; \
static ret FUNC_INT(name)(p0_type, p1_type) __used; \
WEAK_REF(FUNC_EXP(name), name); \
WEAK_REF(FUNC_INT(name), __CONCAT(_, name)); \
typedef ret (*FUNC_TYPE(name))(p0_type, p1_type); \
static ret FUNC_EXP(name)(p0_type p0, p1_type p1) \
{ \
FUNC_TYPE(name) func; \
func =3D (FUNC_TYPE(name))__thr_jtable[idx][0]; \
return (func(p0, p1)); \
} \
static ret FUNC_INT(name)(p0_type p0, p1_type p1) \
{ \
FUNC_TYPE(name) func; \
func =3D (FUNC_TYPE(name))__thr_jtable[idx][1]; \
return (func(p0, p1)); \
}
so only 2 arguments to func (i.e., __pthread_cleanup_push_imp
here).
Compared to:
___pthread_cleanup_push_imp( =
\
__stdio_cancel_cleanup, NULL, =
\
&__cleanup_info__); =
\
As a result junk is used instead of &__cleanup_info__.
On powerpc64 it happens to be the address of
___pthread_cleanup_push_imp that happens to be
in r5 (normally the third argument) at the time.
So:
newbuf->routine =3D routine;
tries to replace the first instruction of
___pthread_cleanup_push_imp .
As far as I can tell what should be used is:
=20
#define STUB_FUNC3(name, idx, ret, p0_type, p1_type, p2_type) \
static ret FUNC_EXP(name)(p0_type, p1_type, p2_type) __used; \
static ret FUNC_INT(name)(p0_type, p1_type, p2_type) __used; \
WEAK_REF(FUNC_EXP(name), name); \
WEAK_REF(FUNC_INT(name), __CONCAT(_, name)); \
typedef ret (*FUNC_TYPE(name))(p0_type, p1_type, p2_type); \
static ret FUNC_EXP(name)(p0_type p0, p1_type p1, p2_type p2) \
{ \
FUNC_TYPE(name) func; \
func =3D (FUNC_TYPE(name))__thr_jtable[idx][0]; \
return (func(p0, p1, p2)); \
} \
static ret FUNC_INT(name)(p0_type p0, p1_type p1, p2_type p2) \
{ \
FUNC_TYPE(name) func; \
func =3D (FUNC_TYPE(name))__thr_jtable[idx][1]; \
return (func(p0, p1, p2)); \
}
with the p2_type being: struct _pthread_cleanup_info *
but I'm not expert in this code.
=3D=3D=3D
Mark Millard
markmi at dsl-only.net
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?B203F272-002C-48BE-ADB1-8D03881380C1>
