Bug 14614 - In tdb_mutex_munmap(), munmap() when addr == 0
Summary: In tdb_mutex_munmap(), munmap() when addr == 0
Status: NEW
Alias: None
Product: TDB
Classification: Unclassified
Component: libtdb (show other bugs)
Version: unspecified
Hardware: All All
: P5 normal
Target Milestone: ---
Assignee: Samba QA Contact
QA Contact: Samba QA Contact
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2021-01-14 09:09 UTC by Albert Chin
Modified: 2021-01-14 09:09 UTC (History)
0 users

See Also:


Attachments
Patch to check if tdb->mutex is NULL before munmap() (646 bytes, patch)
2021-01-14 09:09 UTC, Albert Chin
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Albert Chin 2021-01-14 09:09:36 UTC
Created attachment 16397 [details]
Patch to check if tdb->mutex is NULL before munmap()

We're running 4.9.18, 4.10.18, and 4.11.17 on Solaris 10/SPARC and
11/SPARC and are seeing a SEGV when running smbstatus. In
lib/tdb/common/open.c, we have:
  _PUBLIC_ int tdb_close(struct tdb_context *tdb)
  {
          ...
          tdb_mutex_munmap(tdb);

          SAFE_FREE(tdb->name);
          ...
  }

And in lib/tdb/common/mutex.c, we have:
  int tdb_mutex_munmap(struct tdb_context *tdb)
  {
          ...
          ret = munmap(tdb->mutexes, len);
          if (ret == -1) {
                  return -1;
          }
          ...
  }

Should tdb->mutexes be non-NULL? I looked at the value on both Solaris
and RHEL 6 and tdb->mutexes is NULL at this point.

Before munmap(), we have:
  (dbx) print *tdb
*tdb = { name = 0x355d8 "/var/opt/TWWfsw/samba4918/lock/locking.tdb",
  map_ptr = (nil), fd = 11, map_size = 90112U, read_only = 1,
  traverse_read = 0, traverse_write = 0, allrecord_lock = { off = 0,
  count = 0, ltype = 0 }, num_lockrecs = 0, lockrecs = (nil),
  lockrecs_array_length = 0, hdr_ofs = 245760U, mutexes = (nil),
  ecode = TDB_SUCCESS, hash_size = 10007U, feature_flags = 1U,
  flags = 2596U, travlocks = { next = (nil), off = 0, list = 0,
  lock_rw = 0 }, next = 0x47d00, device = 74776595U, inode = 5617ULL,
  log = { log_fn = 0xfd120cc0 =
&`libtdb-wrap-samba4.so`tdb_wrap.c`tdb_wrap_log(TDB_CONTEXT *tdb, enum
tdb_debug_level level, const char *format, void *..., ...),
  log_private = (nil) }, hash_fn = 0xfee575b8 = &tdb_jenkins_hash(),
  open_flags = 0, methods = 0xfee70fcc, transaction = (nil),
  page_size = 8192, max_dead_records = 0, interrupt_sig_ptr = (nil) }

On RHEL, I see the following:
  (gdb) print *tdb
$2 = {name = 0x55555577d600 "/var/opt/TWWfsw/samba4918/lock/locking.tdb",
  map_ptr = 0x0, fd = 14, map_size = 86016, read_only = 1, traverse_read = 0,
  traverse_write = 0, allrecord_lock = {off = 0, count = 0, ltype = 0},
  num_lockrecs = 0, lockrecs = 0x0, lockrecs_array_length = 0,
  hdr_ofs = 401408, mutexes = 0x0, ecode = TDB_SUCCESS, hash_size = 10007,
  feature_flags = 1, flags = 2564, travlocks = {next = 0x0, off = 0, list = 0,
    lock_rw = 0}, next = 0x55555577d6c0, device = 64768, inode = 3153808,
  log = {log_fn = 0x7ffff236adbc <tdb_wrap_log>, log_private = 0x0},
  hash_fn = 0x7ffff21603da <tdb_jenkins_hash>, open_flags = 0,
  methods = 0x7ffff2368ae0, transaction = 0x0, page_size = 4096,
  max_dead_records = 0, interrupt_sig_ptr = 0x0}

After munmap(), we have:
  (dbx) print *tdb
*tdb = { name = 0x355d8 "<bad address 0x000355d8>",
  map_ptr = (nil), fd = 11, map_size = 90112U, read_only = 1,
  traverse_read = 0, traverse_write = 0, allrecord_lock = { off = 0,
  count = 0, ltype = 0 }, num_lockrecs = 0, lockrecs = (nil),
  lockrecs_array_length = 0, hdr_ofs = 245760U, mutexes = (nil),
  ecode = TDB_SUCCESS, hash_size = 10007U, feature_flags = 1U,
  flags = 2596U, travlocks = { next = (nil), off = 0, list = 0,
  lock_rw = 0 }, next = 0x47d00, device = 74776595U, inode = 5617ULL,
  log = { log_fn = 0xfd120cc0 =
&`libtdb-wrap-samba4.so`tdb_wrap.c`tdb_wrap_log(TDB_CONTEXT *tdb, enum
tdb_debug_level level, const char *format, void *..., ...),
  log_private = (nil) }, hash_fn = 0xfee575b8 = &tdb_jenkins_hash(),
  open_flags = 0, methods = 0xfee70fcc, transaction = (nil),
  page_size = 8192, max_dead_records = 0, interrupt_sig_ptr = (nil) }

  (gdb) print *tdb
$3 = {name = 0x55555577d600 "/var/opt/TWWfsw/samba4918/lock/locking.tdb",
  map_ptr = 0x0, fd = 14, map_size = 86016, read_only = 1, traverse_read = 0,
  traverse_write = 0, allrecord_lock = {off = 0, count = 0, ltype = 0},
  num_lockrecs = 0, lockrecs = 0x0, lockrecs_array_length = 0,
  hdr_ofs = 401408, mutexes = 0x0, ecode = TDB_SUCCESS, hash_size = 10007,
  feature_flags = 1, flags = 2564, travlocks = {next = 0x0, off = 0, list = 0,
    lock_rw = 0}, next = 0x55555577d6c0, device = 64768, inode = 3153808,
  log = {log_fn = 0x7ffff236adbc <tdb_wrap_log>, log_private = 0x0},
  hash_fn = 0x7ffff21603da <tdb_jenkins_hash>, open_flags = 0,
  methods = 0x7ffff2368ae0, transaction = 0x0, page_size = 4096,
  max_dead_records = 0, interrupt_sig_ptr = 0x0}

On Solaris, the differences are:
-*tdb = { name = 0x355d8 "/var/opt/TWWfsw/samba4918/lock/locking.tdb",
+*tdb = { name = 0x355d8 "<bad address 0x000355d8>",

From munmap(2) on Solaris:
  The  munmap()  function  removes  the  mappings  for pages in the range
  [addr, addr + len), rounding the len argument up to the  next  multiple
  of the page size as returned by sysconf(3C). If addr is not the address
  of a mapping established by a prior call to mmap(2),  the  behavior  is
  undefined.  After  a  successful call to munmap() and before any subse-
  quent mapping of the unmapped pages, further references to these  pages
  will  result  in  the  delivery  of  a  SIGBUS or SIGSEGV signal to the
  process.