|
|
8ec399 |
From 7814554e0827ece778ca88fd90832bd4d05520b1 Mon Sep 17 00:00:00 2001
|
|
|
8ec399 |
From: Jakub Filak <jfilak@redhat.com>
|
|
|
8ec399 |
Date: Fri, 24 Apr 2015 13:48:32 +0200
|
|
|
8ec399 |
Subject: [ABRT PATCH] dbus: avoid race-conditions in tests for dum dir
|
|
|
8ec399 |
availability
|
|
|
8ec399 |
|
|
|
8ec399 |
Florian Weimer <fweimer@redhat.com>
|
|
|
8ec399 |
|
|
|
8ec399 |
dump_dir_accessible_by_uid() is fundamentally insecure because it
|
|
|
8ec399 |
opens up a classic time-of-check-time-of-use race between this
|
|
|
8ec399 |
function and and dd_opendir().
|
|
|
8ec399 |
|
|
|
8ec399 |
Related: #1214745
|
|
|
8ec399 |
|
|
|
8ec399 |
Signed-off-by: Jakub Filak <jfilak@redhat.com>
|
|
|
8ec399 |
---
|
|
|
8ec399 |
src/dbus/abrt-dbus.c | 66 ++++++++++++++++++++++++++++++++++++++++++++-------
|
|
|
8ec399 |
src/lib/problem_api.c | 15 ++++++++++--
|
|
|
8ec399 |
2 files changed, 71 insertions(+), 10 deletions(-)
|
|
|
8ec399 |
|
|
|
8ec399 |
diff --git a/src/dbus/abrt-dbus.c b/src/dbus/abrt-dbus.c
|
|
|
8ec399 |
index 7400dff..9e1844a 100644
|
|
|
8ec399 |
--- a/src/dbus/abrt-dbus.c
|
|
|
8ec399 |
+++ b/src/dbus/abrt-dbus.c
|
|
|
8ec399 |
@@ -245,7 +245,15 @@ static struct dump_dir *open_directory_for_modification_of_element(
|
|
|
8ec399 |
}
|
|
|
8ec399 |
}
|
|
|
8ec399 |
|
|
|
8ec399 |
- if (!dump_dir_accessible_by_uid(problem_id, caller_uid))
|
|
|
8ec399 |
+ int dir_fd = dd_openfd(problem_id);
|
|
|
8ec399 |
+ if (dir_fd < 0)
|
|
|
8ec399 |
+ {
|
|
|
8ec399 |
+ perror_msg("can't open problem directory '%s'", problem_id);
|
|
|
8ec399 |
+ return_InvalidProblemDir_error(invocation, problem_id);
|
|
|
8ec399 |
+ return NULL;
|
|
|
8ec399 |
+ }
|
|
|
8ec399 |
+
|
|
|
8ec399 |
+ if (!fdump_dir_accessible_by_uid(dir_fd, caller_uid))
|
|
|
8ec399 |
{
|
|
|
8ec399 |
if (errno == ENOTDIR)
|
|
|
8ec399 |
{
|
|
|
8ec399 |
@@ -260,10 +268,11 @@ static struct dump_dir *open_directory_for_modification_of_element(
|
|
|
8ec399 |
_("Not Authorized"));
|
|
|
8ec399 |
}
|
|
|
8ec399 |
|
|
|
8ec399 |
+ close(dir_fd);
|
|
|
8ec399 |
return NULL;
|
|
|
8ec399 |
}
|
|
|
8ec399 |
|
|
|
8ec399 |
- struct dump_dir *dd = dd_opendir(problem_id, /* flags : */ 0);
|
|
|
8ec399 |
+ struct dump_dir *dd = dd_fdopendir(dir_fd, problem_id, /* flags : */ 0);
|
|
|
8ec399 |
if (!dd)
|
|
|
8ec399 |
{ /* This should not happen because of the access check above */
|
|
|
8ec399 |
log_notice("Can't access the problem '%s' for modification", problem_id);
|
|
|
8ec399 |
@@ -429,7 +438,15 @@ static void handle_method_call(GDBusConnection *connection,
|
|
|
8ec399 |
return;
|
|
|
8ec399 |
}
|
|
|
8ec399 |
|
|
|
8ec399 |
- int ddstat = dump_dir_stat_for_uid(problem_dir, caller_uid);
|
|
|
8ec399 |
+ int dir_fd = dd_openfd(problem_dir);
|
|
|
8ec399 |
+ if (dir_fd < 0)
|
|
|
8ec399 |
+ {
|
|
|
8ec399 |
+ perror_msg("can't open problem directory '%s'", problem_dir);
|
|
|
8ec399 |
+ return_InvalidProblemDir_error(invocation, problem_dir);
|
|
|
8ec399 |
+ return;
|
|
|
8ec399 |
+ }
|
|
|
8ec399 |
+
|
|
|
8ec399 |
+ int ddstat = fdump_dir_stat_for_uid(dir_fd, caller_uid);
|
|
|
8ec399 |
if (ddstat < 0)
|
|
|
8ec399 |
{
|
|
|
8ec399 |
if (errno == ENOTDIR)
|
|
|
8ec399 |
@@ -443,6 +460,7 @@ static void handle_method_call(GDBusConnection *connection,
|
|
|
8ec399 |
|
|
|
8ec399 |
return_InvalidProblemDir_error(invocation, problem_dir);
|
|
|
8ec399 |
|
|
|
8ec399 |
+ close(dir_fd);
|
|
|
8ec399 |
return;
|
|
|
8ec399 |
}
|
|
|
8ec399 |
|
|
|
8ec399 |
@@ -450,6 +468,7 @@ static void handle_method_call(GDBusConnection *connection,
|
|
|
8ec399 |
{ //caller seems to be in group with access to this dir, so no action needed
|
|
|
8ec399 |
log_notice("caller has access to the requested directory %s", problem_dir);
|
|
|
8ec399 |
g_dbus_method_invocation_return_value(invocation, NULL);
|
|
|
8ec399 |
+ close(dir_fd);
|
|
|
8ec399 |
return;
|
|
|
8ec399 |
}
|
|
|
8ec399 |
|
|
|
8ec399 |
@@ -460,10 +479,11 @@ static void handle_method_call(GDBusConnection *connection,
|
|
|
8ec399 |
g_dbus_method_invocation_return_dbus_error(invocation,
|
|
|
8ec399 |
"org.freedesktop.problems.AuthFailure",
|
|
|
8ec399 |
_("Not Authorized"));
|
|
|
8ec399 |
+ close(dir_fd);
|
|
|
8ec399 |
return;
|
|
|
8ec399 |
}
|
|
|
8ec399 |
|
|
|
8ec399 |
- struct dump_dir *dd = dd_opendir(problem_dir, DD_OPEN_READONLY | DD_FAIL_QUIETLY_EACCES);
|
|
|
8ec399 |
+ struct dump_dir *dd = dd_fdopendir(dir_fd, problem_dir, DD_OPEN_READONLY | DD_FAIL_QUIETLY_EACCES);
|
|
|
8ec399 |
if (!dd)
|
|
|
8ec399 |
{
|
|
|
8ec399 |
return_InvalidProblemDir_error(invocation, problem_dir);
|
|
|
8ec399 |
@@ -497,12 +517,21 @@ static void handle_method_call(GDBusConnection *connection,
|
|
|
8ec399 |
return;
|
|
|
8ec399 |
}
|
|
|
8ec399 |
|
|
|
8ec399 |
- if (!dump_dir_accessible_by_uid(problem_dir, caller_uid))
|
|
|
8ec399 |
+ int dir_fd = dd_openfd(problem_dir);
|
|
|
8ec399 |
+ if (dir_fd < 0)
|
|
|
8ec399 |
+ {
|
|
|
8ec399 |
+ perror_msg("can't open problem directory '%s'", problem_dir);
|
|
|
8ec399 |
+ return_InvalidProblemDir_error(invocation, problem_dir);
|
|
|
8ec399 |
+ return;
|
|
|
8ec399 |
+ }
|
|
|
8ec399 |
+
|
|
|
8ec399 |
+ if (!fdump_dir_accessible_by_uid(dir_fd, caller_uid))
|
|
|
8ec399 |
{
|
|
|
8ec399 |
if (errno == ENOTDIR)
|
|
|
8ec399 |
{
|
|
|
8ec399 |
log_notice("Requested directory does not exist '%s'", problem_dir);
|
|
|
8ec399 |
return_InvalidProblemDir_error(invocation, problem_dir);
|
|
|
8ec399 |
+ close(dir_fd);
|
|
|
8ec399 |
return;
|
|
|
8ec399 |
}
|
|
|
8ec399 |
|
|
|
8ec399 |
@@ -512,11 +541,12 @@ static void handle_method_call(GDBusConnection *connection,
|
|
|
8ec399 |
g_dbus_method_invocation_return_dbus_error(invocation,
|
|
|
8ec399 |
"org.freedesktop.problems.AuthFailure",
|
|
|
8ec399 |
_("Not Authorized"));
|
|
|
8ec399 |
+ close(dir_fd);
|
|
|
8ec399 |
return;
|
|
|
8ec399 |
}
|
|
|
8ec399 |
}
|
|
|
8ec399 |
|
|
|
8ec399 |
- struct dump_dir *dd = dd_opendir(problem_dir, DD_OPEN_READONLY | DD_FAIL_QUIETLY_EACCES);
|
|
|
8ec399 |
+ struct dump_dir *dd = dd_fdopendir(dir_fd, problem_dir, DD_OPEN_READONLY | DD_FAIL_QUIETLY_EACCES);
|
|
|
8ec399 |
if (!dd)
|
|
|
8ec399 |
{
|
|
|
8ec399 |
return_InvalidProblemDir_error(invocation, problem_dir);
|
|
|
8ec399 |
@@ -677,20 +707,40 @@ static void handle_method_call(GDBusConnection *connection,
|
|
|
8ec399 |
for (GList *l = problem_dirs; l; l = l->next)
|
|
|
8ec399 |
{
|
|
|
8ec399 |
const char *dir_name = (const char*)l->data;
|
|
|
8ec399 |
- if (!dump_dir_accessible_by_uid(dir_name, caller_uid))
|
|
|
8ec399 |
+
|
|
|
8ec399 |
+ int dir_fd = dd_openfd(dir_name);
|
|
|
8ec399 |
+ if (dir_fd < 0)
|
|
|
8ec399 |
+ {
|
|
|
8ec399 |
+ perror_msg("can't open problem directory '%s'", dir_name);
|
|
|
8ec399 |
+ return_InvalidProblemDir_error(invocation, dir_name);
|
|
|
8ec399 |
+ return;
|
|
|
8ec399 |
+ }
|
|
|
8ec399 |
+
|
|
|
8ec399 |
+ if (!fdump_dir_accessible_by_uid(dir_fd, caller_uid))
|
|
|
8ec399 |
{
|
|
|
8ec399 |
if (errno == ENOTDIR)
|
|
|
8ec399 |
{
|
|
|
8ec399 |
log_notice("Requested directory does not exist '%s'", dir_name);
|
|
|
8ec399 |
+ close(dir_fd);
|
|
|
8ec399 |
continue;
|
|
|
8ec399 |
}
|
|
|
8ec399 |
|
|
|
8ec399 |
if (polkit_check_authorization_dname(caller, "org.freedesktop.problems.getall") != PolkitYes)
|
|
|
8ec399 |
{ // if user didn't provide correct credentials, just move to the next dir
|
|
|
8ec399 |
+ close(dir_fd);
|
|
|
8ec399 |
continue;
|
|
|
8ec399 |
}
|
|
|
8ec399 |
}
|
|
|
8ec399 |
- delete_dump_dir(dir_name);
|
|
|
8ec399 |
+
|
|
|
8ec399 |
+ struct dump_dir *dd = dd_fdopendir(dir_fd, dir_name, /*flags:*/ 0);
|
|
|
8ec399 |
+ if (dd)
|
|
|
8ec399 |
+ {
|
|
|
8ec399 |
+ if (dd_delete(dd) != 0)
|
|
|
8ec399 |
+ {
|
|
|
8ec399 |
+ error_msg("Failed to delete problem directory '%s'", dir_name);
|
|
|
8ec399 |
+ dd_close(dd);
|
|
|
8ec399 |
+ }
|
|
|
8ec399 |
+ }
|
|
|
8ec399 |
}
|
|
|
8ec399 |
|
|
|
8ec399 |
g_dbus_method_invocation_return_value(invocation, NULL);
|
|
|
8ec399 |
diff --git a/src/lib/problem_api.c b/src/lib/problem_api.c
|
|
|
8ec399 |
index c2b4b1c..b343882 100644
|
|
|
8ec399 |
--- a/src/lib/problem_api.c
|
|
|
8ec399 |
+++ b/src/lib/problem_api.c
|
|
|
8ec399 |
@@ -46,7 +46,15 @@ int for_each_problem_in_dir(const char *path,
|
|
|
8ec399 |
continue; /* skip "." and ".." */
|
|
|
8ec399 |
|
|
|
8ec399 |
char *full_name = concat_path_file(path, dent->d_name);
|
|
|
8ec399 |
- if (caller_uid == -1 || dump_dir_accessible_by_uid(full_name, caller_uid))
|
|
|
8ec399 |
+
|
|
|
8ec399 |
+ int dir_fd = dd_openfd(full_name);
|
|
|
8ec399 |
+ if (dir_fd < 0)
|
|
|
8ec399 |
+ {
|
|
|
8ec399 |
+ VERB2 perror_msg("can't open problem directory '%s'", full_name);
|
|
|
8ec399 |
+ continue;
|
|
|
8ec399 |
+ }
|
|
|
8ec399 |
+
|
|
|
8ec399 |
+ if (caller_uid == -1 || fdump_dir_accessible_by_uid(dir_fd, caller_uid))
|
|
|
8ec399 |
{
|
|
|
8ec399 |
/* Silently ignore *any* errors, not only EACCES.
|
|
|
8ec399 |
* We saw "lock file is locked by process PID" error
|
|
|
8ec399 |
@@ -54,7 +62,7 @@ int for_each_problem_in_dir(const char *path,
|
|
|
8ec399 |
*/
|
|
|
8ec399 |
int sv_logmode = logmode;
|
|
|
8ec399 |
logmode = 0;
|
|
|
8ec399 |
- struct dump_dir *dd = dd_opendir(full_name, DD_OPEN_READONLY | DD_FAIL_QUIETLY_EACCES | DD_DONT_WAIT_FOR_LOCK);
|
|
|
8ec399 |
+ struct dump_dir *dd = dd_fdopendir(dir_fd, full_name, DD_OPEN_READONLY | DD_FAIL_QUIETLY_EACCES | DD_DONT_WAIT_FOR_LOCK);
|
|
|
8ec399 |
logmode = sv_logmode;
|
|
|
8ec399 |
if (dd)
|
|
|
8ec399 |
{
|
|
|
8ec399 |
@@ -62,6 +70,9 @@ int for_each_problem_in_dir(const char *path,
|
|
|
8ec399 |
dd_close(dd);
|
|
|
8ec399 |
}
|
|
|
8ec399 |
}
|
|
|
8ec399 |
+ else
|
|
|
8ec399 |
+ close(dir_fd);
|
|
|
8ec399 |
+
|
|
|
8ec399 |
free(full_name);
|
|
|
8ec399 |
if (brk)
|
|
|
8ec399 |
break;
|
|
|
8ec399 |
--
|
|
|
8ec399 |
1.8.3.1
|
|
|
8ec399 |
|