diff options
author | Nikola Pajkovsky <npajkovs@redhat.com> | 2010-09-03 15:32:48 +0200 |
---|---|---|
committer | Nikola Pajkovsky <npajkovs@redhat.com> | 2010-09-07 18:51:51 +0200 |
commit | 7fa1f5842907af4fb9bb8ce10a37081f0e19240b (patch) | |
tree | f675cb1ca8803da3ada80d518624789be62225e6 /lib/utils/DebugDump.cpp | |
parent | b37ddeee2b08dac0510ebeeaaa20b0db2e50ee6b (diff) | |
download | abrt-7fa1f5842907af4fb9bb8ce10a37081f0e19240b.tar.gz abrt-7fa1f5842907af4fb9bb8ce10a37081f0e19240b.tar.xz abrt-7fa1f5842907af4fb9bb8ce10a37081f0e19240b.zip |
DebugDump.* -> dump_dir.*
Signed-off-by: Nikola Pajkovsky <npajkovs@redhat.com>
Acked-off-by: Jiri Moskovcak <jmoskovc@redhat.com>
Diffstat (limited to 'lib/utils/DebugDump.cpp')
-rw-r--r-- | lib/utils/DebugDump.cpp | 536 |
1 files changed, 0 insertions, 536 deletions
diff --git a/lib/utils/DebugDump.cpp b/lib/utils/DebugDump.cpp deleted file mode 100644 index 2d18be14..00000000 --- a/lib/utils/DebugDump.cpp +++ /dev/null @@ -1,536 +0,0 @@ -/* - DebugDump.cpp - - Copyright (C) 2009 Zdenek Prikryl (zprikryl@redhat.com) - Copyright (C) 2009 RedHat inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ -#include <sys/utsname.h> -#include "abrtlib.h" -#include "debug_dump.h" -#include "comm_layer_inner.h" -#include "strbuf.h" - -static bool isdigit_str(const char *str) -{ - do - { - if (*str < '0' || *str > '9') return false; - str++; - } while (*str); - return true; -} - -static char* rm_trailing_slashes(const char *dir) -{ - unsigned len = strlen(dir); - while (len != 0 && dir[len-1] == '/') - len--; - return xstrndup(dir, len); -} - -static bool exist_file_dir(const char *path) -{ - struct stat buf; - if (stat(path, &buf) == 0) - { - if (S_ISDIR(buf.st_mode) || S_ISREG(buf.st_mode)) - { - return true; - } - } - return false; -} - -static char *load_text_file(const char *path); -static void dd_lock(dump_dir_t *dd); -static void dd_unlock(dump_dir_t *dd); - -dump_dir_t* dd_init(void) -{ - return (dump_dir_t*)xzalloc(sizeof(dump_dir_t)); -} - -void dd_close(dump_dir_t *dd) -{ - if (!dd) - return; - - dd_unlock(dd); - if (dd->next_dir) - { - closedir(dd->next_dir); - free(dd->next_dir); - } - - free(dd->dd_dir); - free(dd); -} - -int dd_opendir(dump_dir_t *dd, const char *dir) -{ - if (dd->opened) - error_msg_and_die("CDebugDump is already opened"); - - dd->dd_dir = rm_trailing_slashes(dir); - if (!dd->dd_dir || !exist_file_dir(dd->dd_dir)) - { - error_msg("'%s' does not exist", dd->dd_dir); - return 0; - } - - dd_lock(dd); - dd->opened = 1; - - /* In case caller would want to create more files, he'll need uid:gid */ - struct stat stat_buf; - if (stat(dd->dd_dir, &stat_buf) == 0) - { - dd->uid = stat_buf.st_uid; - dd->gid = stat_buf.st_gid; - } - - return 1; -} - -int dd_exist(dump_dir_t *dd, const char *path) -{ - char *full_path = concat_path_file(dd->dd_dir, path); - int ret = exist_file_dir(full_path); - free(full_path); - return ret; -} - -static bool get_and_set_lock(const char* lock_file, const char* pid) -{ - while (symlink(pid, lock_file) != 0) - { - if (errno != EEXIST) - perror_msg_and_die("Can't create lock file '%s'", lock_file); - - char pid_buf[sizeof(pid_t)*3 + 4]; - ssize_t r = readlink(lock_file, pid_buf, sizeof(pid_buf) - 1); - if (r < 0) - { - if (errno == ENOENT) - { - /* Looks like lock_file was deleted */ - usleep(10 * 1000); /* avoid CPU eating loop */ - continue; - } - perror_msg_and_die("Can't read lock file '%s'", lock_file); - } - pid_buf[r] = '\0'; - - if (strcmp(pid_buf, pid) == 0) - { - log("Lock file '%s' is already locked by us", lock_file); - return false; - } - if (isdigit_str(pid_buf)) - { - char pid_str[sizeof("/proc/") + strlen(pid_buf)]; - sprintf(pid_str, "/proc/%s", pid_buf); - if (access(pid_str, F_OK) == 0) - { - log("Lock file '%s' is locked by process %s", lock_file, pid_buf); - return false; - } - log("Lock file '%s' was locked by process %s, but it crashed?", lock_file, pid_buf); - } - /* The file may be deleted by now by other process. Ignore ENOENT */ - if (unlink(lock_file) != 0 && errno != ENOENT) - { - perror_msg_and_die("Can't remove stale lock file '%s'", lock_file); - } - } - - VERB1 log("Locked '%s'", lock_file); - return true; - -#if 0 -/* Old code was using ordinary files instead of symlinks, - * but it had a race window between open and write, during which file was - * empty. It was seen to happen in practice. - */ - int fd; - while ((fd = open(pLockFile, O_WRONLY | O_CREAT | O_EXCL, 0640)) < 0) - { - if (errno != EEXIST) - perror_msg_and_die("Can't create lock file '%s'", pLockFile); - fd = open(pLockFile, O_RDONLY); - if (fd < 0) - { - if (errno == ENOENT) - continue; /* someone else deleted the file */ - perror_msg_and_die("Can't open lock file '%s'", pLockFile); - } - char pid_buf[sizeof(pid_t)*3 + 4]; - int r = read(fd, pid_buf, sizeof(pid_buf) - 1); - if (r < 0) - perror_msg_and_die("Can't read lock file '%s'", pLockFile); - close(fd); - if (r == 0) - { - /* Other process did not write out PID yet. - * We HOPE it did not crash... */ - continue; - } - pid_buf[r] = '\0'; - if (strcmp(pid_buf, pPID) == 0) - { - log("Lock file '%s' is already locked by us", pLockFile); - return -1; - } - if (isdigit_str(pid_buf)) - { - if (access(ssprintf("/proc/%s", pid_buf).c_str(), F_OK) == 0) - { - log("Lock file '%s' is locked by process %s", pLockFile, pid_buf); - return -1; - } - log("Lock file '%s' was locked by process %s, but it crashed?", pLockFile, pid_buf); - } - /* The file may be deleted by now by other process. Ignore errors */ - unlink(pLockFile); - } - - int len = strlen(pPID); - if (write(fd, pPID, len) != len) - { - unlink(pLockFile); - /* close(fd); - not needed, exiting does it too */ - perror_msg_and_die("Can't write lock file '%s'", pLockFile); - } - close(fd); - - VERB1 log("Locked '%s'", pLockFile); - return true; -#endif -} - -static void dd_lock(dump_dir_t *dd) -{ - if (dd->locked) - error_msg_and_die("Locking bug on '%s'", dd->dd_dir); - - char lock_buf[strlen(dd->dd_dir) + sizeof(".lock")]; - sprintf(lock_buf, "%s.lock", dd->dd_dir); - - char pid_buf[sizeof(long)*3 + 2]; - sprintf(pid_buf, "%lu", (long)getpid()); - while ((dd->locked = get_and_set_lock(lock_buf, pid_buf)) != true) - { - sleep(1); /* was 0.5 seconds */ - } -} - -static void dd_unlock(dump_dir_t *dd) -{ - if (dd->locked) - { - char lock_buf[strlen(dd->dd_dir) + sizeof(".lock")]; - sprintf(lock_buf, "%s.lock", dd->dd_dir); - xunlink(lock_buf); - VERB1 log("Unlocked '%s'", lock_buf); - } -} - -/* Create a fresh empty debug dump dir. - * - * Security: we should not allow users to write new files or write - * into existing ones, but they should be able to read them. - * - * @param uid - * Crashed application's User Id - * - * We currently have only three callers: - * kernel oops hook: uid=0 - * this hook runs under 0:0 - * ccpp hook: uid=uid of crashed user's binary - * this hook runs under 0:0 - * python hook: uid=uid of crashed user's script - * this hook runs under abrt:gid - * - * Currently, we set dir's gid to passwd(uid)->pw_gid parameter, and we set uid to - * abrt's user id. We do not allow write access to group. - */ -int dd_create(dump_dir_t *dd, const char *dir, uid_t uid) -{ - if (dd->opened) - error_msg_and_die("DebugDump is already opened"); - - dd->dd_dir = rm_trailing_slashes(dir); - if (exist_file_dir(dd->dd_dir)) - { - error_msg("'%s' already exists", dd->dd_dir); - return 0; - } - - dd_lock(dd); - dd->opened = 1; - - /* Was creating it with mode 0700 and user as the owner, but this allows - * the user to replace any file in the directory, changing security-sensitive data - * (e.g. "uid", "analyzer", "executable") - */ - if (mkdir(dd->dd_dir, 0750) == -1) - { - dd_unlock(dd); - dd->opened = 0; - error_msg("Can't create dir '%s'", dir); - return 0; - } - - /* mkdir's mode (above) can be affected by umask, fix it */ - if (chmod(dd->dd_dir, 0750) == -1) - { - dd_unlock(dd); - dd->opened = false; - error_msg("Can't change mode of '%s'", dir); - return false; - } - - /* Get ABRT's user id */ - dd->uid = 0; - struct passwd *pw = getpwnam("abrt"); - if (pw) - dd->uid = pw->pw_uid; - else - error_msg("User 'abrt' does not exist, using uid 0"); - - /* Get crashed application's group id */ - dd->gid = 0; - pw = getpwuid(uid); - if (pw) - dd->gid = pw->pw_gid; - else - error_msg("User %lu does not exist, using gid 0", (long)uid); - - if (chown(dd->dd_dir, dd->uid, dd->gid) == -1) - { - perror_msg("can't change '%s' ownership to %lu:%lu", dd->dd_dir, - (long)dd->uid, (long)dd->gid); - } - - char uid_str[sizeof(long) * 3 + 2]; - sprintf(uid_str, "%lu", (long)uid); - dd_save_text(dd, CD_UID, uid_str); - - { - struct utsname buf; - if (uname(&buf) != 0) - { - perror_msg_and_die("uname"); - } - dd_save_text(dd, FILENAME_KERNEL, buf.release); - dd_save_text(dd, FILENAME_ARCHITECTURE, buf.machine); - char *release = load_text_file("/etc/redhat-release"); - strchrnul(release, '\n')[0] = '\0'; - dd_save_text(dd, FILENAME_RELEASE, release); - free(release); - } - - time_t t = time(NULL); - char t_str[sizeof(time_t) * 3 + 2]; - sprintf(t_str, "%lu", (time_t)t); - dd_save_text(dd, FILENAME_TIME, t_str); - - return 1; -} - -static bool delete_file_dir(const char *dir) -{ - if (!exist_file_dir(dir)) - return true; - - DIR *d = opendir(dir); - if (!d) - { - error_msg("Can't open dir '%s'", dir); - return false; - } - - struct dirent *dent; - while ((dent = readdir(d)) != NULL) - { - if (dot_or_dotdot(dent->d_name)) - continue; - char *full_path = concat_path_file(dir, dent->d_name); - if (unlink(full_path) == -1) - { - if (errno != EISDIR) - { - closedir(d); - error_msg("Can't remove dir '%s'", full_path); - free(full_path); - return false; - } - delete_file_dir(full_path); - } - free(full_path); - } - closedir(d); - if (rmdir(dir) == -1) - { - error_msg("Can't remove dir %s", dir); - return false; - } - - return true; -} - -void dd_delete(dump_dir_t *dd) -{ - if (!exist_file_dir(dd->dd_dir)) - { - return; - } - - delete_file_dir(dd->dd_dir); -} - -static char *load_text_file(const char *path) -{ - FILE *fp = fopen(path, "r"); - if (!fp) - { - perror_msg("Can't open file '%s'", path); - return xstrdup(""); - } - - struct strbuf *buf_content = strbuf_new(); - int ch; - while ((ch = fgetc(fp)) != EOF) - { - if (ch == '\0') - strbuf_append_char(buf_content, ' '); - else if (isspace(ch) || (isascii(ch) && !iscntrl(ch))) - strbuf_append_char(buf_content, ch); - } - fclose(fp); - - return strbuf_free_nobuf(buf_content); -} - -static bool save_binary_file(const char *path, const char* data, unsigned size, uid_t uid, gid_t gid) -{ - /* "Why 0640?!" See ::Create() for security analysis */ - unlink(path); - int fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, 0640); - if (fd < 0) - { - perror_msg("Can't open file '%s'", path); - return false; - } - if (fchown(fd, uid, gid) == -1) - { - perror_msg("can't change '%s' ownership to %lu:%lu", path, (long)uid, (long)gid); - } - unsigned r = full_write(fd, data, size); - close(fd); - if (r != size) - { - error_msg("Can't save file '%s'", path); - return false; - } - - return true; -} - -char* dd_load_text(const dump_dir_t *dd, const char *name) -{ - if (!dd->opened) - error_msg_and_die("DebugDump is not opened"); - - char *full_path = concat_path_file(dd->dd_dir, name); - char *ret = load_text_file(full_path); - free(full_path); - - return ret; -} - -void dd_save_text(dump_dir_t *dd, const char *name, const char *data) -{ - if (!dd->opened) - error_msg_and_die("DebugDump is not opened"); - - char *full_path = concat_path_file(dd->dd_dir, name); - save_binary_file(full_path, data, strlen(data), dd->uid, dd->gid); - free(full_path); -} - -void dd_save_binary(dump_dir_t* dd, const char* name, const char* data, unsigned size) -{ - if (dd->opened) - error_msg_and_die("DebugDump is not opened"); - - char *full_path = concat_path_file(dd->dd_dir, name); - save_binary_file(full_path, data, size, dd->uid, dd->gid); - free(full_path); -} - -int dd_init_next_file(dump_dir_t *dd) -{ - if (!dd->opened) - error_msg_and_die("DebugDump is not opened"); - - if (dd->next_dir) - closedir(dd->next_dir); - - dd->next_dir = opendir(dd->dd_dir); - if (!dd->next_dir) - { - error_msg("Can't open dir '%s'", dd->dd_dir); - return 0; - } - - return 1; -} - -int dd_get_next_file(dump_dir_t *dd, char **short_name, char **full_name) -{ - if (dd->next_dir == NULL) - return 0; - - struct dirent *dent; - while ((dent = readdir(dd->next_dir)) != NULL) - { - if (is_regular_file(dent, dd->dd_dir)) - { - if (short_name) - *short_name = xstrdup(dent->d_name); - if (full_name) - *full_name = concat_path_file(dd->dd_dir, dent->d_name); - return 1; - } - } - - closedir(dd->next_dir); - dd->next_dir = NULL; - return 0; -} - -/* Utility function */ -void delete_debug_dump_dir(const char *dd_dir) -{ - dump_dir_t *dd = dd_init(); - if (dd_opendir(dd, dd_dir)) - dd_delete(dd); - else - VERB1 log("Unable to open debug dump '%s'", dd_dir); - dd_close(dd); -} |