From f28b14412ce82bf0787274da87990b06649aa5a5 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 6 Jan 2011 15:44:41 +0100 Subject: pass old pattern to ccpp hook and use it abrtd: instead of "|/usr/libexec/abrt-ccpp-hook DEBUG_DUMPS_DIR %p %s %u %c", sets coredump handler to "|/usr/libexec/abrt-ccpp-hook DEBUG_DUMPS_DIR %s %c %p %u %g %t %h %e OLD_PATTERN" abrt-ccpp-hook: expands OLD_PATTERN using values of %s %c %p %u %g %t %h %e and uses it as a name of "compat coredump". Patch has a feature which prevents usage of kernel-truncated OLD_PATTERN: it is passed as hex string *with terminating NUL* (encoded as 00). If ccpp hook doesn't see 00, it refuses to use OLD_PATTERN and uses string "core" instead. Run tested. On a new kernel, passes up to 27 char long old pattern. Longer patterns are still truncated. This may be improved in future kernels. Signed-off-by: Denys Vlasenko --- src/Hooks/abrt-hook-ccpp.cpp | 137 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 108 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/Hooks/abrt-hook-ccpp.cpp b/src/Hooks/abrt-hook-ccpp.cpp index 9b0d4383..0da1f200 100644 --- a/src/Hooks/abrt-hook-ccpp.cpp +++ b/src/Hooks/abrt-hook-ccpp.cpp @@ -166,9 +166,22 @@ static char* get_cwd(pid_t pid) return malloc_readlink(buf); } -static char core_basename[sizeof("core.%lu") + sizeof(long)*3] = "core"; +/* + * %s - signal number + * %c - ulimit -c value + * %p - pid + * %u - uid + * %g - gid + * %t - UNIX time of dump + * %h - hostname + * %e - executable filename + * %% - output one "%" + */ +/* Must match CORE_PATTERN order in daemon! */ +static const char percent_specifiers[] = "%scpugthe"; +static char *core_basename = "core"; -static int open_user_core(const char *user_pwd, uid_t uid, pid_t pid) +static int open_user_core(const char *user_pwd, uid_t uid, pid_t pid, char **percent_values) { struct passwd* pw = getpwuid(uid); gid_t gid = pw ? pw->pw_gid : uid; @@ -183,20 +196,63 @@ static int open_user_core(const char *user_pwd, uid_t uid, pid_t pid) return -1; } - /* Mimic "core.PID" if requested */ - char buf[] = "0\n"; - int fd = open("/proc/sys/kernel/core_uses_pid", O_RDONLY); - if (fd >= 0) + if (strcmp(core_basename, "core") == 0) { - read(fd, buf, sizeof(buf)); - close(fd); + /* Mimic "core.PID" if requested */ + char buf[] = "0\n"; + int fd = open("/proc/sys/kernel/core_uses_pid", O_RDONLY); + if (fd >= 0) + { + read(fd, buf, sizeof(buf)); + close(fd); + } + if (strcmp(buf, "1\n") == 0) + { + core_basename = xasprintf("%s.%lu", core_basename, (long)pid); + } } - if (strcmp(buf, "1\n") == 0) + else { - sprintf(core_basename, "core.%lu", (long)pid); + /* Expand old core pattern, put expanded name in core_basename */ + core_basename = xstrdup(core_basename); + unsigned idx = 0; + while (1) + { + char c = core_basename[idx]; + if (!c) + break; + idx++; + if (c != '%') + continue; + + /* We just copied %, look at following char and expand %c */ + c = core_basename[idx]; + unsigned specifier_num = strchrnul(percent_specifiers, c) - percent_specifiers; + if (percent_specifiers[specifier_num] != '\0') /* valid %c (might be %% too) */ + { + const char *val = "%"; + if (specifier_num > 0) /* not %% */ + val = percent_values[specifier_num - 1]; + //log("c:'%c'", c); + //log("val:'%s'", val); + + /* Replace %c at core_basename[idx] by its value */ + idx--; + char *old = core_basename; + core_basename = xasprintf("%.*s%s%s", idx, core_basename, val, core_basename + idx + 2); + //log("pos:'%*s|'", idx, ""); + //log("new:'%s'", core_basename); + //log("old:'%s'", old); + free(old); + idx += strlen(val); + } + /* else: invalid %c, % is already copied verbatim, + * next loop iteration will copy c */ + } } - /* man core: + /* Open (create) compat core file. + * man core: * There are various circumstances in which a core dump file * is not produced: * @@ -214,8 +270,7 @@ static int open_user_core(const char *user_pwd, uid_t uid, pid_t pid) * * The RLIMIT_CORE or RLIMIT_FSIZE resource limits for the process * are set to zero. - * [shouldn't it be checked by kernel? 2.6.30.9-96 doesn't, still - * calls us even if "ulimit -c 0"] + * [we check RLIMIT_CORE, but how can we check RLIMIT_FSIZE?] * * The binary being executed by the process does not have * read permission enabled. [how we can check it here?] @@ -226,7 +281,6 @@ static int open_user_core(const char *user_pwd, uid_t uid, pid_t pid) * (However, see the description of the prctl(2) PR_SET_DUMPABLE operation, * and the description of the /proc/sys/fs/suid_dumpable file in proc(5).) */ - /* Do not O_TRUNC: if later checks fail, we do not want to have file already modified here */ struct stat sb; errno = 0; @@ -245,6 +299,7 @@ static int open_user_core(const char *user_pwd, uid_t uid, pid_t pid) if (ftruncate(user_core_fd, 0) != 0) { /* perror first, otherwise unlink may trash errno */ perror_msg("truncate %s/%s", user_pwd, core_basename); + unlink(core_basename); return -1; } @@ -253,23 +308,28 @@ static int open_user_core(const char *user_pwd, uid_t uid, pid_t pid) int main(int argc, char** argv) { - int i; struct stat sb; - if (argc < 5) + if (argc < 10) /* no argv[9]? */ { - error_msg_and_die("Usage: %s: DUMPDIR PID SIGNO UID CORE_SIZE_LIMIT", argv[0]); + /* percent specifier: %s %c %p %u %g %t %h %e */ + /* argv: [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] */ + error_msg_and_die("Usage: %s DUMPDIR SIGNO CORE_SIZE_LIMIT PID UID GID TIME HOSTNAME BINARY_NAME [OLD_PATTERN]", argv[0]); } /* Not needed on 2.6.30. * At least 2.6.18 has a bug where - * argv[1] = "DUMPDIR PID SIGNO UID CORE_SIZE_LIMIT" - * argv[2] = "PID SIGNO UID CORE_SIZE_LIMIT" + * argv[1] = "DUMPDIR SIGNO CORE_SIZE_LIMIT ..." + * argv[2] = "SIGNO CORE_SIZE_LIMIT ..." * and so on. Fixing it: */ - for (i = 1; argv[i]; i++) + if (strchr(argv[1], ' ')) { - strchrnul(argv[i], ' ')[0] = '\0'; + int i; + for (i = 1; argv[i]; i++) + { + strchrnul(argv[i], ' ')[0] = '\0'; + } } openlog("abrt", LOG_PID, LOG_DAEMON); @@ -277,19 +337,38 @@ int main(int argc, char** argv) errno = 0; const char* dddir = argv[1]; - pid_t pid = xatoi_u(argv[2]); - const char* signal_str = argv[3]; - int signal_no = xatoi_u(argv[3]); - uid_t uid = xatoi_u(argv[4]); - off_t ulimit_c = strtoull(argv[5], NULL, 10); + const char* signal_str = argv[2]; + int signal_no = xatoi_u(signal_str); + off_t ulimit_c = strtoull(argv[3], NULL, 10); if (ulimit_c < 0) /* unlimited? */ { /* set to max possible >0 value */ ulimit_c = ~((off_t)1 << (sizeof(off_t)*8-1)); } + pid_t pid = xatoi_u(argv[4]); + uid_t uid = xatoi_u(argv[5]); if (errno || pid <= 0) { - error_msg_and_die("pid '%s' or limit '%s' is bogus", argv[2], argv[5]); + perror_msg_and_die("pid '%s' or limit '%s' is bogus", argv[4], argv[3]); + } + if (argv[10]) /* OLD_PATTERN */ + { + char *buf = (char*) xzalloc(strlen(argv[10]) / 2 + 2); + char *end = hex2bin(buf, argv[10], strlen(argv[10])); + if (end && end > buf && end[-1] == '\0') + { + core_basename = buf; + //log("core_basename:'%s'", core_basename); + } + else + { + /* Until recently, kernels were truncating expanded core pattern. + * In this case, we end up here... + */ + error_msg("bad old pattern '%s', ignoring and using 'core'", argv[10]); + /* core_basename = "core"; - already is */ + free(buf); + } } int src_fd_binary; @@ -316,8 +395,8 @@ int main(int argc, char** argv) /* Open a fd to compat coredump, if requested and is possible */ int user_core_fd = -1; if (setting_MakeCompatCore && ulimit_c != 0) - /* note: checks "user_pwd == NULL" inside */ - user_core_fd = open_user_core(user_pwd, uid, pid); + /* note: checks "user_pwd == NULL" inside, updates core_basename */ + user_core_fd = open_user_core(user_pwd, uid, pid, &argv[2]); if (executable == NULL) { -- cgit