Merge lp:~pitti/lightdm/write-user-files-as-user into lp:lightdm

Proposed by Martin Pitt
Status: Merged
Merged at revision: 1145
Proposed branch: lp:~pitti/lightdm/write-user-files-as-user
Merge into: lp:lightdm
Diff against target: 116 lines (+38/-12)
3 files modified
NEWS (+1/-0)
src/dmrc.c (+15/-2)
src/xauthority.c (+22/-10)
To merge this branch: bzr merge lp:~pitti/lightdm/write-user-files-as-user
Reviewer Review Type Date Requested Status
LightDM Development Team Pending
Review via email: mp+75184@code.launchpad.net

Description of the change

This drops privileges before writing ~/.dmrc and ~/.Xauthority instead of using
chmod(), to guard against symlink attacks and other potential privilege
escalation.

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'NEWS'
--- NEWS 2011-09-13 05:24:24 +0000
+++ NEWS 2011-09-13 13:54:24 +0000
@@ -2,6 +2,7 @@
22
3 * Only unlock displays if switched to from greeter3 * Only unlock displays if switched to from greeter
4 * Add VNC server support4 * Add VNC server support
5 * Do not write ~/.dmrc and ~/.Xauthority as root. [CVE-2011-3349]
56
6Overview of changes in lightdm 0.9.57Overview of changes in lightdm 0.9.5
78
89
=== modified file 'src/dmrc.c'
--- src/dmrc.c 2011-08-23 01:39:57 +0000
+++ src/dmrc.c 2011-09-13 13:54:24 +0000
@@ -9,6 +9,8 @@
9 * license.9 * license.
10 */10 */
1111
12/* for setres*id() */
13#define _GNU_SOURCE
12#include <errno.h>14#include <errno.h>
13#include <string.h>15#include <string.h>
14#include <unistd.h>16#include <unistd.h>
@@ -80,11 +82,22 @@
80 /* Update the users .dmrc */82 /* Update the users .dmrc */
81 if (user)83 if (user)
82 {84 {
85 gboolean drop_privs = (geteuid () == 0);
86
87 /* Guard against privilege escalation through symlinks, etc. */
88 if (drop_privs)
89 {
90 g_assert (setresgid (user_get_gid (user), user_get_gid (user), -1) == 0);
91 g_assert (setresuid (user_get_uid (user), user_get_uid (user), -1) == 0);
92 }
83 path = g_build_filename (user_get_home_directory (user), ".dmrc", NULL);93 path = g_build_filename (user_get_home_directory (user), ".dmrc", NULL);
84 g_file_set_contents (path, data, length, NULL);94 g_file_set_contents (path, data, length, NULL);
85 if (getuid () == 0 && chown (path, user_get_uid (user), user_get_gid (user)) < 0)
86 g_warning ("Error setting ownership on %s: %s", path, strerror (errno));
87 g_free (path);95 g_free (path);
96 if (drop_privs)
97 {
98 g_assert (setresuid (0, 0, -1) == 0);
99 g_assert (setresgid (0, 0, -1) == 0);
100 }
88 }101 }
89102
90 /* Update the .dmrc cache */103 /* Update the .dmrc cache */
91104
=== modified file 'src/xauthority.c'
--- src/xauthority.c 2011-09-07 05:37:55 +0000
+++ src/xauthority.c 2011-09-13 13:54:24 +0000
@@ -9,6 +9,8 @@
9 * license.9 * license.
10 */10 */
1111
12/* for setres*id() */
13#define _GNU_SOURCE
12#include <string.h>14#include <string.h>
13#include <errno.h>15#include <errno.h>
14#include <unistd.h>16#include <unistd.h>
@@ -244,6 +246,16 @@
244 XAuthority *a;246 XAuthority *a;
245 gboolean result;247 gboolean result;
246 gboolean matched = FALSE;248 gboolean matched = FALSE;
249 gboolean drop_privs = (user && geteuid () == 0);
250 gboolean retval = FALSE;
251
252 /* Guard against privilege escalation through symlinks, etc. */
253 if (drop_privs)
254 {
255 g_debug ("Dropping privileges to uid %i", user_get_uid (user));
256 g_assert (setresgid (user_get_gid (user), user_get_gid (user), -1) == 0);
257 g_assert (setresuid (user_get_uid (user), user_get_uid (user), -1) == 0);
258 }
247259
248 /* Read out existing records */260 /* Read out existing records */
249 if (mode != XAUTH_WRITE_MODE_SET)261 if (mode != XAUTH_WRITE_MODE_SET)
@@ -317,7 +329,7 @@
317329
318 output_stream = g_file_replace (file, NULL, FALSE, G_FILE_CREATE_PRIVATE, NULL, error);330 output_stream = g_file_replace (file, NULL, FALSE, G_FILE_CREATE_PRIVATE, NULL, error);
319 if (!output_stream)331 if (!output_stream)
320 return FALSE;332 goto out;
321333
322 /* Workaround because g_file_replace () generates a file does not exist error even though it can replace it */334 /* Workaround because g_file_replace () generates a file does not exist error even though it can replace it */
323 g_clear_error (error);335 g_clear_error (error);
@@ -345,18 +357,18 @@
345 g_object_unref (output_stream);357 g_object_unref (output_stream);
346358
347 if (!result)359 if (!result)
348 return FALSE;360 goto out;
349361
350 /* NOTE: Would like to do:362 retval = TRUE;
351 * g_file_set_attribute_string (file, G_FILE_ATTRIBUTE_OWNER_USER, username, G_FILE_QUERY_INFO_NONE, NULL, error))363
352 * but not supported. */364out:
353 if (user && getuid () == 0)365 /* reclaim privileges */
366 if (drop_privs)
354 {367 {
355 if (chown (g_file_get_path (file), user_get_uid (user), user_get_gid (user)) < 0)368 g_assert (setresuid (0, 0, -1) == 0);
356 g_warning ("Failed to set authorization owner: %s", strerror (errno));369 g_assert (setresgid (0, 0, -1) == 0);
357 }370 }
358 371 return retval;
359 return TRUE;
360}372}
361373
362static void374static void

Subscribers

People subscribed via source and target branches