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

Generated by: LCOV version 1.14