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