|
|
8ec399 |
From 806bb07571b698d90169c3b73cb65cd09c900284 Mon Sep 17 00:00:00 2001
|
|
|
8ec399 |
From: Jakub Filak <jfilak@redhat.com>
|
|
|
8ec399 |
Date: Fri, 17 Apr 2015 14:40:20 +0200
|
|
|
8ec399 |
Subject: [ABRT PATCH] ccpp: do not use value of /proc/PID/cwd for chdir
|
|
|
8ec399 |
|
|
|
8ec399 |
Avoid symlink resolutions.
|
|
|
8ec399 |
|
|
|
8ec399 |
This issue was discovered by Florian Weimer of Red Hat Product Security.
|
|
|
8ec399 |
|
|
|
8ec399 |
Signed-off-by: Jakub Filak <jfilak@redhat.com>
|
|
|
8ec399 |
---
|
|
|
8ec399 |
src/hooks/abrt-hook-ccpp.c | 85 +++++++++++++++++++++++-----------------------
|
|
|
8ec399 |
1 file changed, 42 insertions(+), 43 deletions(-)
|
|
|
8ec399 |
|
|
|
8ec399 |
diff --git a/src/hooks/abrt-hook-ccpp.c b/src/hooks/abrt-hook-ccpp.c
|
|
|
8ec399 |
index 82ff555..d600bb7 100644
|
|
|
8ec399 |
--- a/src/hooks/abrt-hook-ccpp.c
|
|
|
8ec399 |
+++ b/src/hooks/abrt-hook-ccpp.c
|
|
|
8ec399 |
@@ -144,6 +144,7 @@ static off_t copyfd_sparse(int src_fd, int dst_fd1, int dst_fd2, off_t size2)
|
|
|
8ec399 |
/* Global data */
|
|
|
8ec399 |
|
|
|
8ec399 |
static char *user_pwd;
|
|
|
8ec399 |
+static DIR *proc_cwd;
|
|
|
8ec399 |
static char *proc_pid_status;
|
|
|
8ec399 |
static struct dump_dir *dd;
|
|
|
8ec399 |
static int user_core_fd = -1;
|
|
|
8ec399 |
@@ -163,13 +164,6 @@ static int user_core_fd = -1;
|
|
|
8ec399 |
*/
|
|
|
8ec399 |
static const char percent_specifiers[] = "%scpugteh";
|
|
|
8ec399 |
static char *core_basename = (char*) "core";
|
|
|
8ec399 |
-/*
|
|
|
8ec399 |
- * Used for error messages only.
|
|
|
8ec399 |
- * It is either the same as core_basename if it is absolute,
|
|
|
8ec399 |
- * or $PWD/core_basename.
|
|
|
8ec399 |
- */
|
|
|
8ec399 |
-static char *full_core_basename;
|
|
|
8ec399 |
-
|
|
|
8ec399 |
|
|
|
8ec399 |
static char* get_executable(pid_t pid, int *fd_p)
|
|
|
8ec399 |
{
|
|
|
8ec399 |
@@ -198,6 +192,18 @@ static char* get_executable(pid_t pid, int *fd_p)
|
|
|
8ec399 |
return executable;
|
|
|
8ec399 |
}
|
|
|
8ec399 |
|
|
|
8ec399 |
+static DIR *open_cwd(pid_t pid)
|
|
|
8ec399 |
+{
|
|
|
8ec399 |
+ char buf[sizeof("/proc/%lu/cwd") + sizeof(long)*3];
|
|
|
8ec399 |
+ sprintf(buf, "/proc/%lu/cwd", (long)pid);
|
|
|
8ec399 |
+
|
|
|
8ec399 |
+ DIR *cwd = opendir(buf);
|
|
|
8ec399 |
+ if (cwd == NULL)
|
|
|
8ec399 |
+ perror_msg("Can't open process's CWD for CompatCore");
|
|
|
8ec399 |
+
|
|
|
8ec399 |
+ return cwd;
|
|
|
8ec399 |
+}
|
|
|
8ec399 |
+
|
|
|
8ec399 |
static char* get_cwd(pid_t pid)
|
|
|
8ec399 |
{
|
|
|
8ec399 |
char buf[sizeof("/proc/%lu/cwd") + sizeof(long)*3];
|
|
|
8ec399 |
@@ -268,13 +274,9 @@ static int dump_suid_policy()
|
|
|
8ec399 |
|
|
|
8ec399 |
static int open_user_core(uid_t uid, uid_t fsuid, pid_t pid, char **percent_values)
|
|
|
8ec399 |
{
|
|
|
8ec399 |
- errno = 0;
|
|
|
8ec399 |
- if (user_pwd == NULL
|
|
|
8ec399 |
- || chdir(user_pwd) != 0
|
|
|
8ec399 |
- ) {
|
|
|
8ec399 |
- perror_msg("Can't cd to '%s'", user_pwd);
|
|
|
8ec399 |
+ proc_cwd = open_cwd(pid);
|
|
|
8ec399 |
+ if (proc_cwd == NULL)
|
|
|
8ec399 |
return -1;
|
|
|
8ec399 |
- }
|
|
|
8ec399 |
|
|
|
8ec399 |
struct passwd* pw = getpwuid(uid);
|
|
|
8ec399 |
gid_t gid = pw ? pw->pw_gid : uid;
|
|
|
8ec399 |
@@ -337,15 +339,10 @@ static int open_user_core(uid_t uid, uid_t fsuid, pid_t pid, char **percent_valu
|
|
|
8ec399 |
}
|
|
|
8ec399 |
}
|
|
|
8ec399 |
|
|
|
8ec399 |
- full_core_basename = core_basename;
|
|
|
8ec399 |
- if (core_basename[0] != '/')
|
|
|
8ec399 |
+ if (g_need_nonrelative && core_basename[0] != '/')
|
|
|
8ec399 |
{
|
|
|
8ec399 |
- if (g_need_nonrelative)
|
|
|
8ec399 |
- {
|
|
|
8ec399 |
- error_msg("Current suid_dumpable policy prevents from saving core dumps according to relative core_pattern");
|
|
|
8ec399 |
- return -1;
|
|
|
8ec399 |
- }
|
|
|
8ec399 |
- core_basename = concat_path_file(user_pwd, core_basename);
|
|
|
8ec399 |
+ error_msg("Current suid_dumpable policy prevents from saving core dumps according to relative core_pattern");
|
|
|
8ec399 |
+ return -1;
|
|
|
8ec399 |
}
|
|
|
8ec399 |
|
|
|
8ec399 |
/* Open (create) compat core file.
|
|
|
8ec399 |
@@ -381,7 +378,7 @@ static int open_user_core(uid_t uid, uid_t fsuid, pid_t pid, char **percent_valu
|
|
|
8ec399 |
struct stat sb;
|
|
|
8ec399 |
errno = 0;
|
|
|
8ec399 |
/* Do not O_TRUNC: if later checks fail, we do not want to have file already modified here */
|
|
|
8ec399 |
- int user_core_fd = open(core_basename, O_WRONLY | O_CREAT | O_NOFOLLOW | g_user_core_flags, 0600); /* kernel makes 0600 too */
|
|
|
8ec399 |
+ int user_core_fd = openat(dirfd(proc_cwd), core_basename, O_WRONLY | O_CREAT | O_NOFOLLOW | g_user_core_flags, 0600); /* kernel makes 0600 too */
|
|
|
8ec399 |
xsetegid(0);
|
|
|
8ec399 |
xseteuid(0);
|
|
|
8ec399 |
if (user_core_fd < 0
|
|
|
8ec399 |
@@ -391,15 +388,15 @@ static int open_user_core(uid_t uid, uid_t fsuid, pid_t pid, char **percent_valu
|
|
|
8ec399 |
|| sb.st_uid != fsuid
|
|
|
8ec399 |
) {
|
|
|
8ec399 |
if (user_core_fd < 0)
|
|
|
8ec399 |
- perror_msg("Can't open '%s'", full_core_basename);
|
|
|
8ec399 |
+ perror_msg("Can't open '%s' at '%s'", core_basename, user_pwd);
|
|
|
8ec399 |
else
|
|
|
8ec399 |
- perror_msg("'%s' is not a regular file with link count 1 owned by UID(%d)", full_core_basename, fsuid);
|
|
|
8ec399 |
+ perror_msg("'%s' at '%s' is not a regular file with link count 1 owned by UID(%d)", core_basename, user_pwd, fsuid);
|
|
|
8ec399 |
return -1;
|
|
|
8ec399 |
}
|
|
|
8ec399 |
if (ftruncate(user_core_fd, 0) != 0) {
|
|
|
8ec399 |
/* perror first, otherwise unlink may trash errno */
|
|
|
8ec399 |
- perror_msg("Can't truncate '%s' to size 0", full_core_basename);
|
|
|
8ec399 |
- unlink(core_basename);
|
|
|
8ec399 |
+ perror_msg("Can't truncate '%s' at '%s' to size 0", core_basename, user_pwd);
|
|
|
8ec399 |
+ unlinkat(dirfd(proc_cwd), core_basename, /*unlink file*/0);
|
|
|
8ec399 |
return -1;
|
|
|
8ec399 |
}
|
|
|
8ec399 |
|
|
|
8ec399 |
@@ -466,10 +463,8 @@ static int create_or_die(const char *filename)
|
|
|
8ec399 |
if (dd)
|
|
|
8ec399 |
dd_delete(dd);
|
|
|
8ec399 |
if (user_core_fd >= 0)
|
|
|
8ec399 |
- {
|
|
|
8ec399 |
- xchdir(user_pwd);
|
|
|
8ec399 |
- unlink(core_basename);
|
|
|
8ec399 |
- }
|
|
|
8ec399 |
+ unlinkat(dirfd(proc_cwd), core_basename, /*unlink file*/0);
|
|
|
8ec399 |
+
|
|
|
8ec399 |
errno = sv_errno;
|
|
|
8ec399 |
perror_msg_and_die("Can't open '%s'", filename);
|
|
|
8ec399 |
}
|
|
|
8ec399 |
@@ -573,7 +568,7 @@ int main(int argc, char** argv)
|
|
|
8ec399 |
(long)pid, executable);
|
|
|
8ec399 |
}
|
|
|
8ec399 |
|
|
|
8ec399 |
- user_pwd = get_cwd(pid); /* may be NULL on error */
|
|
|
8ec399 |
+ user_pwd = get_cwd(pid);
|
|
|
8ec399 |
log_notice("user_pwd:'%s'", user_pwd);
|
|
|
8ec399 |
|
|
|
8ec399 |
sprintf(path, "/proc/%lu/status", (long)pid);
|
|
|
8ec399 |
@@ -672,6 +667,8 @@ int main(int argc, char** argv)
|
|
|
8ec399 |
error_msg_and_die("Error saving '%s'", path);
|
|
|
8ec399 |
}
|
|
|
8ec399 |
log("Saved core dump of pid %lu (%s) to %s (%llu bytes)", (long)pid, executable, path, (long long)core_size);
|
|
|
8ec399 |
+ if (proc_cwd != NULL)
|
|
|
8ec399 |
+ closedir(proc_cwd);
|
|
|
8ec399 |
return 0;
|
|
|
8ec399 |
}
|
|
|
8ec399 |
|
|
|
8ec399 |
@@ -791,10 +788,7 @@ int main(int argc, char** argv)
|
|
|
8ec399 |
unlink(path);
|
|
|
8ec399 |
dd_delete(dd);
|
|
|
8ec399 |
if (user_core_fd >= 0)
|
|
|
8ec399 |
- {
|
|
|
8ec399 |
- xchdir(user_pwd);
|
|
|
8ec399 |
- unlink(core_basename);
|
|
|
8ec399 |
- }
|
|
|
8ec399 |
+ unlinkat(dirfd(proc_cwd), core_basename, /*unlink file*/0);
|
|
|
8ec399 |
/* copyfd_sparse logs the error including errno string,
|
|
|
8ec399 |
* but it does not log file name */
|
|
|
8ec399 |
error_msg_and_die("Error writing '%s'", path);
|
|
|
8ec399 |
@@ -807,8 +801,7 @@ int main(int argc, char** argv)
|
|
|
8ec399 |
)
|
|
|
8ec399 |
) {
|
|
|
8ec399 |
/* nuke it (silently) */
|
|
|
8ec399 |
- xchdir(user_pwd);
|
|
|
8ec399 |
- unlink(core_basename);
|
|
|
8ec399 |
+ unlinkat(dirfd(proc_cwd), core_basename, /*unlink file*/0);
|
|
|
8ec399 |
}
|
|
|
8ec399 |
|
|
|
8ec399 |
/* Because of #1211835 and #1126850 */
|
|
|
8ec399 |
@@ -879,6 +872,8 @@ int main(int argc, char** argv)
|
|
|
8ec399 |
}
|
|
|
8ec399 |
|
|
|
8ec399 |
free(rootdir);
|
|
|
8ec399 |
+ if (proc_cwd != NULL)
|
|
|
8ec399 |
+ closedir(proc_cwd);
|
|
|
8ec399 |
return 0;
|
|
|
8ec399 |
}
|
|
|
8ec399 |
|
|
|
8ec399 |
@@ -890,19 +885,23 @@ int main(int argc, char** argv)
|
|
|
8ec399 |
if (fsync(user_core_fd) != 0 || close(user_core_fd) != 0 || core_size < 0)
|
|
|
8ec399 |
{
|
|
|
8ec399 |
/* perror first, otherwise unlink may trash errno */
|
|
|
8ec399 |
- perror_msg("Error writing '%s'", full_core_basename);
|
|
|
8ec399 |
- xchdir(user_pwd);
|
|
|
8ec399 |
- unlink(core_basename);
|
|
|
8ec399 |
+ perror_msg("Error writing '%s' at '%s'", core_basename, user_pwd);
|
|
|
8ec399 |
+ unlinkat(dirfd(proc_cwd), core_basename, /*unlink file*/0);
|
|
|
8ec399 |
+ if (proc_cwd != NULL)
|
|
|
8ec399 |
+ closedir(proc_cwd);
|
|
|
8ec399 |
return 1;
|
|
|
8ec399 |
}
|
|
|
8ec399 |
if (ulimit_c == 0 || core_size > ulimit_c)
|
|
|
8ec399 |
{
|
|
|
8ec399 |
- xchdir(user_pwd);
|
|
|
8ec399 |
- unlink(core_basename);
|
|
|
8ec399 |
+ unlinkat(dirfd(proc_cwd), core_basename, /*unlink file*/0);
|
|
|
8ec399 |
+ if (proc_cwd != NULL)
|
|
|
8ec399 |
+ closedir(proc_cwd);
|
|
|
8ec399 |
return 1;
|
|
|
8ec399 |
}
|
|
|
8ec399 |
- log("Saved core dump of pid %lu to %s (%llu bytes)", (long)pid, full_core_basename, (long long)core_size);
|
|
|
8ec399 |
+ log("Saved core dump of pid %lu to %s at %s (%llu bytes)", (long)pid, core_basename, user_pwd, (long long)core_size);
|
|
|
8ec399 |
}
|
|
|
8ec399 |
|
|
|
8ec399 |
+ if (proc_cwd != NULL)
|
|
|
8ec399 |
+ closedir(proc_cwd);
|
|
|
8ec399 |
return 0;
|
|
|
8ec399 |
}
|
|
|
8ec399 |
--
|
|
|
8ec399 |
1.8.3.1
|
|
|
8ec399 |
|