Memory corruption issue when samba4 is the target of a net vampire command
Angelos Oikonomopoulos
angelos.oikonomopoulos at fp-commerce.de
Tue Oct 26 09:23:17 MDT 2010
Hello all,
I've been playing around with Samba 4 from git master (specifically
5785f08268bac332d09bdf71d1907ecb54f3b5bd from last Thursday). It seems
to work well so far, but I've run into a bug when trying to add a second
samba4 server as an additional DC, following the instructions in
http://wiki.samba.org/index.php/Samba4/HOWTO/Join_a_domain_as_a_DC.
Specifically, the net vampire command described in that page crashes the
existing DC pretty reliably. I've tried looking into it today but I
think I'll need some help to track down the root cause (and produce a fix).
The problem manifests as a SIGSEGV or SIGABRT in lpcfg_netbios_name:
#5 <signal handler called>
#6 0x00007fcfaeab3a76 in lpcfg_netbios_name (lp_ctx=0x6d742e64626d732f)
at ../param/loadparm.c:691
#7 0x00007fcfad2553c9 in auth_anonymous_session_info
(parent_ctx=0x260b6b0, lp_ctx=0x6d742e64626d732f,
_session_info=0x7fff7d038670) at ../auth/system_session.c:439
#8 0x00007fcfac69f8f8 in ldapsrv_accept_nonpriv (c=0x260b6b0) at
../ldap_server/ldap_server.c:757
#9 0x00007fcfac5a7ea9 in stream_new_connection (ev=0x25fd840,
lp_ctx=0x25eb7e0, sock=0x3b385c0, server_id=..., private_data=0x39cb550)
at ../smbd/service_stream.c:230
#10 0x00007fcfac579834 in single_accept_connection (ev=0x25fd840,
lp_ctx=0x25eb7e0, listen_socket=0x39cb5e0, new_conn=0x7fcfac5a7aac
<stream_new_connection>, private_data=0x39cb550) at
../smbd/process_single.c:74
#11 0x00007fcfac5a7f1e in stream_accept_handler (ev=0x25fd840,
fde=0x39cb7c0, flags=1, private_data=0x39cb550) at
../smbd/service_stream.c:245
#12 0x00007fcfabec6717 in epoll_event_loop (std_ev=0x25fced0,
tvalp=0x7fff7d038890) at ../../lib/tevent/tevent_standard.c:309
#13 0x00007fcfabec6e8d in std_event_loop_once (ev=0x25fd840,
location=0x405f3f "../smbd/server.c:480") at
../../lib/tevent/tevent_standard.c:544
#14 0x00007fcfabec2ac2 in _tevent_loop_once (ev=0x25fd840,
location=0x405f3f "../smbd/server.c:480") at ../../lib/tevent/tevent.c:493
#15 0x00007fcfabec2cff in tevent_common_loop_wait (ev=0x25fd840,
location=0x405f3f "../smbd/server.c:480") at ../../lib/tevent/tevent.c:594
#16 0x00007fcfabec2dca in _tevent_loop_wait (ev=0x25fd840,
location=0x405f3f "../smbd/server.c:480") at ../../lib/tevent/tevent.c:613
#17 0x0000000000404d7c in binary_smbd_main (binary_name=0x4059f3
"samba", argc=5, argv=0x7fff7d038d48) at ../smbd/server.c:480
#18 0x0000000000404dc2 in main (argc=5, argv=0x7fff7d038d48) at
../smbd/server.c:491
There seems to be some memory corruption, so I've run it under valgrind
to try and locate the cause. This immediately stood out:
==9155== Memcheck, a memory error detector
==9155== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==9155== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for
copyright info
==9155== Command: /usr/bin/python /usr/local/samba/sbin/samba_spnupdate
==9155== Parent PID: 9126
===9126== Invalid read of size 8
==9126== at 0x86378E1: ldapsrv_accept_nonpriv (ldap_server.c:757)
==9126== by 0x853FEA8: stream_new_connection (service_stream.c:230)
==9126== by 0x8511833: single_accept_connection (process_single.c:74)
==9126== by 0x853FF1D: stream_accept_handler (service_stream.c:245)
==9126== by 0x8D34716: epoll_event_loop (tevent_standard.c:309)
==9126== by 0x8D34E8C: std_event_loop_once (tevent_standard.c:544)
==9126== by 0x8D30AC1: _tevent_loop_once (tevent.c:493)
==9126== by 0x8D30CFE: tevent_common_loop_wait (tevent.c:594)
==9126== by 0x8D30DC9: _tevent_loop_wait (tevent.c:613)
==9126== by 0x404D7B: binary_smbd_main (server.c:480)
==9126== by 0x404DC1: main (server.c:491)
==9126== Address 0x19eef338 is not stack'd, malloc'd or (recently) free'd
==9126==
I think this is a valid use-of-garbage-value issue. My analysis follows,
comments separated from code by '#+' lines:
##########################################################
static void ldapsrv_accept_nonpriv(struct stream_connection *c)
{
struct ldapsrv_service *ldapsrv_service = talloc_get_type_abort(
c->private_data, struct ldapsrv_service);
struct auth_session_info *session_info;
NTSTATUS status;
status = auth_anonymous_session_info(
c, ldapsrv_service->task->lp_ctx, &session_info); <--
ldap_server.c:757
##########################################################
so it's either the ldapsrv_service or the task dereference. They both
come from c->private_data.
Where does c come from?
###########################################
static void stream_new_connection(struct tevent_context *ev,
struct loadparm_context *lp_ctx,
struct socket_context *sock,
struct server_id server_id, void
*private_data)
{
struct stream_socket *stream_socket =
talloc_get_type(private_data, struct stream_socket);
struct stream_connection *srv_conn;
srv_conn = talloc_zero(ev, struct stream_connection);
/* ... */
srv_conn->private_data = stream_socket->private_data;
/* ... */
/* call the server specific accept code */
stream_socket->ops->accept_connection(srv_conn); <--
service_stream.c:230
##############################################
So a) srv_conn is talloc()ed and barring very serious corruption it's
not garbage =>
the segfault is due to the task-> dereference
b) task comes from srv_conn->private_data, which comes from the argument
###################################################
static void single_accept_connection(struct tevent_context *ev,
struct loadparm_context *lp_ctx,
struct socket_context *listen_socket,
void (*new_conn)(struct
tevent_context *,
struct
loadparm_context *,
struct
socket_context *,
struct server_id
, void *),
void *private_data)
{
/* ... */
new_conn(ev, lp_ctx, connected_socket,
cluster_id(0, socket_get_fd(connected_socket)),
private_data);
####################################################
So, task comes again from private_data
###################################################
static void stream_accept_handler(struct tevent_context *ev, struct
tevent_fd *fde,
uint16_t flags, void *private_data)
{
struct stream_socket *stream_socket =
talloc_get_type(private_data, struct stream_socket);
stream_socket->model_ops->accept_connection(ev,
stream_socket->lp_ctx,
stream_socket->sock,
stream_new_connection, stream_socket); <-service_stream.c:245
}
#####################################################
So task comes from stream_socket which is, yet again, private_data
####################################################
static int epoll_event_loop(struct std_event_context *std_ev, struct
timeval *tvalp)
{
int ret, i;
#define MAXEVENTS 1
struct epoll_event events[MAXEVENTS];
/* ... */
ret = epoll_wait(std_ev->epoll_fd, events, MAXEVENTS, timeout);
/* ... */
for (i=0;i<ret;i++) {
struct tevent_fd *fde = talloc_get_type(events[i].data.ptr,
struct tevent_fd);
/* ... */
if (flags) {
fde->handler(std_ev->ev, fde, flags,
fde->private_data);
break;
}
}
###################################################
So, task comes from fde->private_data. fde comes from
events[0].data.ptr, which comes from a
call to epoll_ctl. The parameter can be either EPOLL_CTL_ADD or
EPOLL_CTL_MOD.
##################################################
./lib/tevent/tevent_standard.c:155: if (epoll_ctl(std_ev->epoll_fd,
EPOLL_CTL_ADD, fde->fd, &event) != 0) {
./lib/tevent/tevent_standard.c:199: if (epoll_ctl(std_ev->epoll_fd,
EPOLL_CTL_MOD, fde->fd, &event) != 0) {
./lib/tevent/tevent_epoll.c:139: if
(epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event) != 0) {
./lib/tevent/tevent_epoll.c:188: if
(epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event) != 0) {
##############################################
epoll_add_event
-> epoll_check_reopen
-> epoll_change_event
-> std_event_add_fd
-> struct tevent_ops std_event_ops = { .add_fd =
std_event_add_fd }
-> _tevent_add_fd
-> tevent_add_fd
======== and, afaict, none of the callers pass anything
resembling a task...
epoll_mod_event
-> ...
More information about the samba-technical
mailing list