LCOV - code coverage report
Current view: top level - source3/lib - dumpcore.c (source / functions) Hit Total Coverage
Test: coverage report for fix-15632 9995c5c2 Lines: 38 93 40.9 %
Date: 2024-04-13 12:30:31 Functions: 4 5 80.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    Samba utility functions
       4             : 
       5             :    Copyright (C) Andrew Tridgell 1992-2011
       6             : 
       7             :    based on old fault.c code, which had:
       8             : 
       9             :    Copyright (C) Jeremy Allison 2001-2007
      10             :    Copyright (C) Simo Sorce 2001
      11             :    Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
      12             :    Copyright (C) James Peach 2006
      13             : 
      14             :    This program is free software; you can redistribute it and/or modify
      15             :    it under the terms of the GNU General Public License as published by
      16             :    the Free Software Foundation; either version 3 of the License, or
      17             :    (at your option) any later version.
      18             : 
      19             :    This program is distributed in the hope that it will be useful,
      20             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      21             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      22             :    GNU General Public License for more details.
      23             : 
      24             :    You should have received a copy of the GNU General Public License
      25             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      26             : */
      27             : 
      28             : #include "includes.h"
      29             : #include "system/filesys.h"
      30             : 
      31             : #ifdef HAVE_SYS_SYSCTL_H
      32             : #include <sys/sysctl.h>
      33             : #endif
      34             : 
      35             : #ifdef HAVE_SYS_PRCTL_H
      36             : #include <sys/prctl.h>
      37             : #endif
      38             : 
      39             : static char *corepath;
      40             : static bool using_helper_binary = false;
      41             : 
      42             : /**
      43             :  * Build up the default corepath as "<logbase>/cores/<progname>"
      44             :  */
      45         825 : static char *get_default_corepath(const char *logbase, const char *progname)
      46             : {
      47         825 :         const mode_t mode = 0700;
      48         825 :         const uid_t uid = getuid();
      49           0 :         char *tmp_corepath;
      50             : 
      51             :         /* Setup core dir in logbase. */
      52         825 :         tmp_corepath = talloc_asprintf(NULL, "%s/cores", logbase);
      53         825 :         if (!tmp_corepath) {
      54           0 :                 DEBUG(0, ("Out of memory\n"));
      55           0 :                 return NULL;
      56             :         }
      57             : 
      58         825 :         if (!directory_create_or_exist_strict(tmp_corepath, uid, mode)) {
      59           0 :                 DEBUG(0, ("Failed to create %s for user %d with mode 0%o\n",
      60             :                           tmp_corepath, (int)uid, (int)mode));
      61           0 :                 goto err_out;
      62             :         }
      63             : 
      64             :         /* Setup progname-specific core subdir */
      65         825 :         tmp_corepath = talloc_asprintf_append(tmp_corepath, "/%s", progname);
      66         825 :         if (!tmp_corepath) {
      67           0 :                 DEBUG(0, ("Out of memory\n"));
      68           0 :                 goto err_out;
      69             :         }
      70             : 
      71         825 :         if (!directory_create_or_exist(tmp_corepath, mode)) {
      72           0 :                 DEBUG(0, ("Failed to create %s for user %d with mode 0%o\n",
      73             :                           tmp_corepath, (int)uid, (int)mode));
      74           0 :                 goto err_out;
      75             :         }
      76             : 
      77         825 :         return tmp_corepath;
      78             : 
      79           0 :  err_out:
      80           0 :         talloc_free(tmp_corepath);
      81           0 :         return NULL;
      82             : }
      83             : 
      84             : 
      85             : /**
      86             :  * Get the FreeBSD corepath.
      87             :  *
      88             :  * On FreeBSD the current working directory is ignored when creating a core
      89             :  * file.  Instead the core directory is controlled via sysctl.  This consults
      90             :  * the value of "kern.corefile" so the correct corepath can be printed out
      91             :  * before dump_core() calls abort.
      92             :  */
      93             : #if (defined(FREEBSD) && defined(HAVE_SYSCTLBYNAME))
      94             : static char *get_freebsd_corepath(void)
      95             : {
      96             :         char *tmp_corepath = NULL;
      97             :         char *end = NULL;
      98             :         size_t len = 128;
      99             :         int ret;
     100             : 
     101             :         /* Loop with increasing sizes so we don't allocate too much. */
     102             :         do {
     103             :                 if (len > 1024)  {
     104             :                         goto err_out;
     105             :                 }
     106             : 
     107             :                 tmp_corepath = (char *)talloc_realloc(NULL, tmp_corepath,
     108             :                                                       char, len);
     109             :                 if (!tmp_corepath) {
     110             :                         return NULL;
     111             :                 }
     112             : 
     113             :                 ret = sysctlbyname("kern.corefile", tmp_corepath, &len, NULL,
     114             :                                    0);
     115             :                 if (ret == -1) {
     116             :                         if (errno != ENOMEM) {
     117             :                                 DEBUG(0, ("sysctlbyname failed getting "
     118             :                                           "kern.corefile %s\n",
     119             :                                           strerror(errno)));
     120             :                                 goto err_out;
     121             :                         }
     122             : 
     123             :                         /* Not a large enough array, try a bigger one. */
     124             :                         len = len << 1;
     125             :                 }
     126             :         } while (ret == -1);
     127             : 
     128             :         /* Strip off the common filename expansion */
     129             :         if ((end = strrchr_m(tmp_corepath, '/'))) {
     130             :                 *end = '\0';
     131             :         }
     132             : 
     133             :         return tmp_corepath;
     134             : 
     135             :  err_out:
     136             :         if (tmp_corepath) {
     137             :                 talloc_free(tmp_corepath);
     138             :         }
     139             :         return NULL;
     140             : }
     141             : #endif
     142             : 
     143             : #if defined(HAVE_SYS_KERNEL_PROC_CORE_PATTERN)
     144             : 
     145             : /**
     146             :  * Get the Linux corepath.
     147             :  *
     148             :  * On Linux the contents of /proc/sys/kernel/core_pattern indicates the
     149             :  * location of the core path.
     150             :  */
     151         825 : static char *get_linux_corepath(void)
     152             : {
     153           0 :         char *end;
     154           0 :         int fd;
     155           0 :         char *result;
     156             : 
     157         825 :         fd = open("/proc/sys/kernel/core_pattern", O_RDONLY, 0);
     158         825 :         if (fd == -1) {
     159           0 :                 return NULL;
     160             :         }
     161             : 
     162         825 :         result = afdgets(fd, NULL, 0);
     163         825 :         close(fd);
     164             : 
     165         825 :         if (result == NULL) {
     166           0 :                 return NULL;
     167             :         }
     168             : 
     169         825 :         if (result[0] != '/') {
     170             :                 /*
     171             :                  * No absolute path, use the default (cwd)
     172             :                  */
     173         825 :                 if (result[0] == '|') {
     174             :                         /*
     175             :                         * Core dump handled by helper binaries
     176             :                         */
     177         825 :                         using_helper_binary = true;
     178             :                 }
     179         825 :                 TALLOC_FREE(result);
     180         825 :                 return NULL;
     181             :         }
     182             :         /* Strip off the common filename expansion */
     183             : 
     184           0 :         end = strrchr_m(result, '/');
     185             : 
     186           0 :         if ((end != result) /* this would be the only / */
     187           0 :             && (end != NULL)) {
     188           0 :                 *end = '\0';
     189             :         }
     190           0 :         return result;
     191             : }
     192             : #endif
     193             : 
     194             : 
     195             : /**
     196             :  * Try getting system-specific corepath if one exists.
     197             :  *
     198             :  * If the system doesn't define a corepath, then the default is used.
     199             :  */
     200         825 : static char *get_corepath(const char *logbase, const char *progname)
     201             : {
     202             : #if (defined(FREEBSD) && defined(HAVE_SYSCTLBYNAME))
     203             :         char *tmp_corepath = NULL;
     204             :         tmp_corepath = get_freebsd_corepath();
     205             : 
     206             :         /* If this has been set correctly, we're done. */
     207             :         if (tmp_corepath) {
     208             :                 return tmp_corepath;
     209             :         }
     210             : #endif
     211             : 
     212             : #if defined(HAVE_SYS_KERNEL_PROC_CORE_PATTERN)
     213         825 :         char *tmp_corepath = NULL;
     214         825 :         tmp_corepath = get_linux_corepath();
     215             : 
     216             :         /* If this has been set correctly, we're done. */
     217         825 :         if (tmp_corepath) {
     218           0 :                 return tmp_corepath;
     219             :         }
     220             : #endif
     221             : 
     222             :         /* Fall back to the default. */
     223         825 :         return get_default_corepath(logbase, progname);
     224             : }
     225             : 
     226             : /*******************************************************************
     227             : make all the preparations to safely dump a core file
     228             : ********************************************************************/
     229             : 
     230         825 : void dump_core_setup(const char *progname, const char *log_file)
     231             : {
     232         825 :         char *logbase = NULL;
     233         825 :         char *end = NULL;
     234             : 
     235         825 :         if (log_file && *log_file) {
     236         825 :                 if (asprintf(&logbase, "%s", log_file) < 0) {
     237           0 :                         return;
     238             :                 }
     239        1014 :                 if ((end = strrchr_m(logbase, '/'))) {
     240         825 :                         *end = '\0';
     241             :                 }
     242             :         } else {
     243             :                 /* We will end up here if the log file is given on the command
     244             :                  * line by the -l option but the "log file" option is not set
     245             :                  * in smb.conf.
     246             :                  */
     247           0 :                 if (asprintf(&logbase, "%s", get_dyn_LOGFILEBASE()) < 0) {
     248           0 :                         return;
     249             :                 }
     250             :         }
     251             : 
     252         825 :         SMB_ASSERT(progname != NULL);
     253             : 
     254         825 :         corepath = get_corepath(logbase, progname);
     255         825 :         if (!corepath) {
     256           0 :                 DEBUG(0, ("Unable to setup corepath for %s: %s\n", progname,
     257             :                           strerror(errno)));
     258           0 :                 goto out;
     259             :         }
     260             : 
     261             :         /* FIXME: if we have a core-plus-pid facility, configurably set
     262             :          * this up here.
     263             :          */
     264         825 :  out:
     265         825 :         SAFE_FREE(logbase);
     266             : }
     267             : 
     268           0 :  void dump_core(void)
     269             : {
     270           0 :         static bool called;
     271             : 
     272           0 :         if (called) {
     273           0 :                 DEBUG(0, ("dump_core() called recursive\n"));
     274           0 :                 exit(1);
     275             :         }
     276           0 :         called = true;
     277             : 
     278             :         /* Note that even if core dumping has been disabled, we still set up
     279             :          * the core path. This is to handle the case where core dumping is
     280             :          * turned on in smb.conf and the relevant daemon is not restarted.
     281             :          */
     282           0 :         if (!lp_enable_core_files()) {
     283           0 :                 DEBUG(0, ("Exiting on internal error (core file administratively disabled)\n"));
     284           0 :                 exit(1);
     285             :         }
     286             : 
     287             : #if DUMP_CORE
     288             :         /* If we're running as non root we might not be able to dump the core
     289             :          * file to the corepath.  There must not be an unbecome_root() before
     290             :          * we call abort(). */
     291           0 :         if (geteuid() != sec_initial_uid()) {
     292           0 :                 become_root();
     293             :         }
     294             : 
     295           0 :         if (corepath == NULL) {
     296           0 :                 DEBUG(0, ("Can not dump core: corepath not set up\n"));
     297           0 :                 exit(1);
     298             :         }
     299             : 
     300           0 :         if (*corepath != '\0') {
     301             :                 /*
     302             :                  * Check whether coredump is handled by helper binaries or not.
     303             :                  * If so skip chdir().
     304             :                  */
     305           0 :                 if (!using_helper_binary) {
     306             :                         /* The chdir might fail if we dump core before we finish
     307             :                          * processing the config file.
     308             :                          */
     309           0 :                         if (chdir(corepath) != 0) {
     310           0 :                                 DEBUG(0, ("unable to change to %s\n", corepath));
     311           0 :                                 DEBUGADD(0, ("refusing to dump core\n"));
     312           0 :                                 exit(1);
     313             :                         }
     314             : 
     315           0 :                         DEBUG(0,("dumping core in %s\n", corepath));
     316             :                 } else {
     317           0 :                         DEBUG(0,("coredump is handled by helper binary "
     318             :                                  "specified at /proc/sys/kernel/core_pattern\n"));
     319             :                 }
     320             :         }
     321             : 
     322           0 :         umask(~(0700));
     323           0 :         dbgflush();
     324             : 
     325             : #if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE)
     326             :         /* On Linux we lose the ability to dump core when we change our user
     327             :          * ID. We know how to dump core safely, so let's make sure we have our
     328             :          * dumpable flag set.
     329             :          */
     330           0 :         prctl(PR_SET_DUMPABLE, 1);
     331             : #endif
     332             : 
     333             :         /* Ensure we don't have a signal handler for abort. */
     334             : #ifdef SIGABRT
     335           0 :         CatchSignal(SIGABRT, SIG_DFL);
     336             : #endif
     337             : 
     338           0 :         abort();
     339             : 
     340             : #else /* DUMP_CORE */
     341             :         exit(1);
     342             : #endif /* DUMP_CORE */
     343             : }

Generated by: LCOV version 1.14