Skip to content

Commit 1630f53

Browse files
committed
mime-actions: use file metadata for trusting desktop files
Currently we only trust desktop files that have the executable bit set, and don't replace the displayed icon or the displayed name until it's trusted, which prevents for running random programs by a malicious desktop file. However, the executable permission is preserved if the desktop file comes from a compressed file. To prevent this, add a metadata::trusted metadata to the file once the user acknowledges the file as trusted. This adds metadata to the file, which cannot be added unless it has access to the computer. Also remove the SHEBANG "trusted" content we were putting inside the desktop file, since that doesn't add more security since it can come with the file itself. https://bugzilla.gnome.org/show_bug.cgi?id=777991
1 parent cc6910f commit 1630f53

6 files changed

+73
-146
lines changed

Diff for: src/nautilus-directory-async.c

+6-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "nautilus-global-preferences.h"
3131
#include "nautilus-link.h"
3232
#include "nautilus-profile.h"
33+
#include "nautilus-metadata.h"
3334
#include <eel/eel-glib-extensions.h>
3435
#include <gtk/gtk.h>
3536
#include <libxml/parser.h>
@@ -3580,13 +3581,17 @@ is_link_trusted (NautilusFile *file,
35803581
{
35813582
GFile *location;
35823583
gboolean res;
3584+
g_autofree gchar* trusted = NULL;
35833585

35843586
if (!is_launcher)
35853587
{
35863588
return TRUE;
35873589
}
35883590

3589-
if (nautilus_file_can_execute (file))
3591+
trusted = nautilus_file_get_metadata (file,
3592+
NAUTILUS_METADATA_KEY_DESKTOP_FILE_TRUSTED,
3593+
NULL);
3594+
if (nautilus_file_can_execute (file) && trusted != NULL)
35903595
{
35913596
return TRUE;
35923597
}

Diff for: src/nautilus-file-operations.c

+31-122
Original file line numberDiff line numberDiff line change
@@ -235,10 +235,10 @@ typedef struct
235235
#define COPY_FORCE _("Copy _Anyway")
236236

237237
static void
238-
mark_desktop_file_trusted (CommonJob *common,
239-
GCancellable *cancellable,
240-
GFile *file,
241-
gboolean interactive);
238+
mark_desktop_file_executable (CommonJob *common,
239+
GCancellable *cancellable,
240+
GFile *file,
241+
gboolean interactive);
242242

243243
static gboolean
244244
is_all_button_text (const char *button_text)
@@ -5290,10 +5290,10 @@ copy_move_file (CopyMoveJob *copy_job,
52905290
g_file_equal (copy_job->desktop_location, dest_dir) &&
52915291
is_trusted_desktop_file (src, job->cancellable))
52925292
{
5293-
mark_desktop_file_trusted (job,
5294-
job->cancellable,
5295-
dest,
5296-
FALSE);
5293+
mark_desktop_file_executable (job,
5294+
job->cancellable,
5295+
dest,
5296+
FALSE);
52975297
}
52985298

52995299
if (job->undo_info != NULL)
@@ -7887,9 +7887,9 @@ nautilus_file_operations_empty_trash (GtkWidget *parent_view)
78877887
}
78887888

78897889
static void
7890-
mark_trusted_task_done (GObject *source_object,
7891-
GAsyncResult *res,
7892-
gpointer user_data)
7890+
mark_desktop_file_executable_task_done (GObject *source_object,
7891+
GAsyncResult *res,
7892+
gpointer user_data)
78937893
{
78947894
MarkTrustedJob *job = user_data;
78957895

@@ -7907,110 +7907,19 @@ mark_trusted_task_done (GObject *source_object,
79077907
#define TRUSTED_SHEBANG "#!/usr/bin/env xdg-open\n"
79087908

79097909
static void
7910-
mark_desktop_file_trusted (CommonJob *common,
7911-
GCancellable *cancellable,
7912-
GFile *file,
7913-
gboolean interactive)
7910+
mark_desktop_file_executable (CommonJob *common,
7911+
GCancellable *cancellable,
7912+
GFile *file,
7913+
gboolean interactive)
79147914
{
7915-
char *contents, *new_contents;
7916-
gsize length, new_length;
79177915
GError *error;
79187916
guint32 current_perms, new_perms;
79197917
int response;
79207918
GFileInfo *info;
79217919

79227920
retry:
7923-
error = NULL;
7924-
if (!g_file_load_contents (file,
7925-
cancellable,
7926-
&contents, &length,
7927-
NULL, &error))
7928-
{
7929-
if (interactive)
7930-
{
7931-
response = run_error (common,
7932-
g_strdup (_("Unable to mark launcher trusted (executable)")),
7933-
error->message,
7934-
NULL,
7935-
FALSE,
7936-
CANCEL, RETRY,
7937-
NULL);
7938-
}
7939-
else
7940-
{
7941-
response = 0;
7942-
}
7943-
7944-
7945-
if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT)
7946-
{
7947-
abort_job (common);
7948-
}
7949-
else if (response == 1)
7950-
{
7951-
goto retry;
7952-
}
7953-
else
7954-
{
7955-
g_assert_not_reached ();
7956-
}
7957-
7958-
goto out;
7959-
}
7960-
7961-
if (!g_str_has_prefix (contents, "#!"))
7962-
{
7963-
new_length = length + strlen (TRUSTED_SHEBANG);
7964-
new_contents = g_malloc (new_length);
7965-
7966-
strcpy (new_contents, TRUSTED_SHEBANG);
7967-
memcpy (new_contents + strlen (TRUSTED_SHEBANG),
7968-
contents, length);
7969-
7970-
if (!g_file_replace_contents (file,
7971-
new_contents,
7972-
new_length,
7973-
NULL,
7974-
FALSE, 0,
7975-
NULL, cancellable, &error))
7976-
{
7977-
g_free (contents);
7978-
g_free (new_contents);
7979-
7980-
if (interactive)
7981-
{
7982-
response = run_error (common,
7983-
g_strdup (_("Unable to mark launcher trusted (executable)")),
7984-
error->message,
7985-
NULL,
7986-
FALSE,
7987-
CANCEL, RETRY,
7988-
NULL);
7989-
}
7990-
else
7991-
{
7992-
response = 0;
7993-
}
7994-
7995-
if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT)
7996-
{
7997-
abort_job (common);
7998-
}
7999-
else if (response == 1)
8000-
{
8001-
goto retry;
8002-
}
8003-
else
8004-
{
8005-
g_assert_not_reached ();
8006-
}
8007-
8008-
goto out;
8009-
}
8010-
g_free (new_contents);
8011-
}
8012-
g_free (contents);
80137921

7922+
error = NULL;
80147923
info = g_file_query_info (file,
80157924
G_FILE_ATTRIBUTE_STANDARD_TYPE ","
80167925
G_FILE_ATTRIBUTE_UNIX_MODE,
@@ -8101,10 +8010,10 @@ mark_desktop_file_trusted (CommonJob *common,
81018010
}
81028011

81038012
static void
8104-
mark_trusted_task_thread_func (GTask *task,
8105-
gpointer source_object,
8106-
gpointer task_data,
8107-
GCancellable *cancellable)
8013+
mark_desktop_file_executable_task_thread_func (GTask *task,
8014+
gpointer source_object,
8015+
gpointer task_data,
8016+
GCancellable *cancellable)
81088017
{
81098018
MarkTrustedJob *job = task_data;
81108019
CommonJob *common;
@@ -8113,18 +8022,18 @@ mark_trusted_task_thread_func (GTask *task,
81138022

81148023
nautilus_progress_info_start (job->common.progress);
81158024

8116-
mark_desktop_file_trusted (common,
8117-
cancellable,
8118-
job->file,
8119-
job->interactive);
8025+
mark_desktop_file_executable (common,
8026+
cancellable,
8027+
job->file,
8028+
job->interactive);
81208029
}
81218030

81228031
void
8123-
nautilus_file_mark_desktop_file_trusted (GFile *file,
8124-
GtkWindow *parent_window,
8125-
gboolean interactive,
8126-
NautilusOpCallback done_callback,
8127-
gpointer done_callback_data)
8032+
nautilus_file_mark_desktop_file_executable (GFile *file,
8033+
GtkWindow *parent_window,
8034+
gboolean interactive,
8035+
NautilusOpCallback done_callback,
8036+
gpointer done_callback_data)
81288037
{
81298038
GTask *task;
81308039
MarkTrustedJob *job;
@@ -8135,9 +8044,9 @@ nautilus_file_mark_desktop_file_trusted (GFile *file,
81358044
job->done_callback = done_callback;
81368045
job->done_callback_data = done_callback_data;
81378046

8138-
task = g_task_new (NULL, NULL, mark_trusted_task_done, job);
8047+
task = g_task_new (NULL, NULL, mark_desktop_file_executable_task_done, job);
81398048
g_task_set_task_data (task, job, NULL);
8140-
g_task_run_in_thread (task, mark_trusted_task_thread_func);
8049+
g_task_run_in_thread (task, mark_desktop_file_executable_task_thread_func);
81418050
g_object_unref (task);
81428051
}
81438052

Diff for: src/nautilus-file-operations.h

+5-5
Original file line numberDiff line numberDiff line change
@@ -146,11 +146,11 @@ void nautilus_file_operations_link (GList *files,
146146
GtkWindow *parent_window,
147147
NautilusCopyCallback done_callback,
148148
gpointer done_callback_data);
149-
void nautilus_file_mark_desktop_file_trusted (GFile *file,
150-
GtkWindow *parent_window,
151-
gboolean interactive,
152-
NautilusOpCallback done_callback,
153-
gpointer done_callback_data);
149+
void nautilus_file_mark_desktop_file_executable (GFile *file,
150+
GtkWindow *parent_window,
151+
gboolean interactive,
152+
NautilusOpCallback done_callback,
153+
gpointer done_callback_data);
154154
void nautilus_file_operations_extract_files (GList *files,
155155
GFile *destination_directory,
156156
GtkWindow *parent_window,

Diff for: src/nautilus-metadata.c

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ static char *used_metadata_names[] =
5151
NAUTILUS_METADATA_KEY_CUSTOM_ICON_NAME,
5252
NAUTILUS_METADATA_KEY_SCREEN,
5353
NAUTILUS_METADATA_KEY_EMBLEMS,
54+
NAUTILUS_METADATA_KEY_DESKTOP_FILE_TRUSTED,
5455
NULL
5556
};
5657

Diff for: src/nautilus-metadata.h

+2
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@
6767
#define NAUTILUS_METADATA_KEY_SCREEN "screen"
6868
#define NAUTILUS_METADATA_KEY_EMBLEMS "emblems"
6969

70+
#define NAUTILUS_METADATA_KEY_DESKTOP_FILE_TRUSTED "trusted"
71+
7072
guint nautilus_metadata_get_id (const char *metadata);
7173

7274
#endif /* NAUTILUS_METADATA_H */

Diff for: src/nautilus-mime-actions.c

+28-18
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include "nautilus-program-choosing.h"
4343
#include "nautilus-global-preferences.h"
4444
#include "nautilus-signaller.h"
45+
#include "nautilus-metadata.h"
4546

4647
#define DEBUG_FLAG NAUTILUS_DEBUG_MIME
4748
#include "nautilus-debug.h"
@@ -221,7 +222,6 @@ struct
221222
#define RESPONSE_RUN 1000
222223
#define RESPONSE_DISPLAY 1001
223224
#define RESPONSE_RUN_IN_TERMINAL 1002
224-
#define RESPONSE_MARK_TRUSTED 1003
225225

226226
#define SILENT_WINDOW_OPEN_LIMIT 5
227227
#define SILENT_OPEN_LIMIT 5
@@ -1517,24 +1517,35 @@ untrusted_launcher_response_callback (GtkDialog *dialog,
15171517

15181518
switch (response_id)
15191519
{
1520-
case RESPONSE_RUN:
1520+
case GTK_RESPONSE_OK:
15211521
{
1522+
file = nautilus_file_get_location (parameters->file);
1523+
1524+
/* We need to do this in order to prevent malicious desktop files
1525+
* with the executable bit already set.
1526+
* See https://bugzilla.gnome.org/show_bug.cgi?id=777991
1527+
*/
1528+
nautilus_file_set_metadata (parameters->file, NAUTILUS_METADATA_KEY_DESKTOP_FILE_TRUSTED,
1529+
NULL,
1530+
"yes");
1531+
1532+
nautilus_file_mark_desktop_file_executable (file,
1533+
parameters->parent_window,
1534+
TRUE,
1535+
NULL, NULL);
1536+
1537+
/* Need to force a reload of the attributes so is_trusted is marked
1538+
* correctly. Not sure why the general monitor doesn't fire in this
1539+
* case when setting the metadata
1540+
*/
1541+
nautilus_file_invalidate_all_attributes (parameters->file);
1542+
15221543
screen = gtk_widget_get_screen (GTK_WIDGET (parameters->parent_window));
15231544
uri = nautilus_file_get_uri (parameters->file);
15241545
DEBUG ("Launching untrusted launcher %s", uri);
15251546
nautilus_launch_desktop_file (screen, uri, NULL,
15261547
parameters->parent_window);
15271548
g_free (uri);
1528-
}
1529-
break;
1530-
1531-
case RESPONSE_MARK_TRUSTED:
1532-
{
1533-
file = nautilus_file_get_location (parameters->file);
1534-
nautilus_file_mark_desktop_file_trusted (file,
1535-
parameters->parent_window,
1536-
TRUE,
1537-
NULL, NULL);
15381549
g_object_unref (file);
15391550
}
15401551
break;
@@ -1590,17 +1601,16 @@ activate_desktop_file (ActivateParameters *parameters,
15901601
"text", primary,
15911602
"secondary-text", secondary,
15921603
NULL);
1604+
15931605
gtk_dialog_add_button (GTK_DIALOG (dialog),
1594-
_("_Launch Anyway"), RESPONSE_RUN);
1606+
_("_Cancel"), GTK_RESPONSE_CANCEL);
1607+
1608+
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL);
15951609
if (nautilus_file_can_set_permissions (file))
15961610
{
15971611
gtk_dialog_add_button (GTK_DIALOG (dialog),
1598-
_("Mark as _Trusted"), RESPONSE_MARK_TRUSTED);
1612+
_("Trust and _Launch"), GTK_RESPONSE_OK);
15991613
}
1600-
gtk_dialog_add_button (GTK_DIALOG (dialog),
1601-
_("_Cancel"), GTK_RESPONSE_CANCEL);
1602-
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL);
1603-
16041614
g_signal_connect (dialog, "response",
16051615
G_CALLBACK (untrusted_launcher_response_callback),
16061616
parameters_desktop);

0 commit comments

Comments
 (0)