~ubuntu-branches/ubuntu/quantal/cups-pk-helper/quantal-updates

« back to all changes in this revision

Viewing changes to debian/patches/CVE-2012-4510-part1.patch

  • Committer: Package Import Robot
  • Author(s): Jeremy Bicha
  • Date: 2012-11-26 22:12:08 UTC
  • Revision ID: package-import@ubuntu.com-20121126221208-bg74o9vm5bm8c1q5
Tags: 0.2.1.2-1ubuntu1.1
* SECURITY UPDATE: CUPS function calls were wrapped insecurely, which
  could be used to upload sensitive data to a CUPS resource, or overwrite
  specific files with the content of a CUPS resource. The user would have
  to explicitly approve the action. (LP: #1083416)
  - CVE-2012-4510
  - debian/patches/CVE-2012-4510-part1.patch: Copied from git
  - debian/patches/CVE-2012-4510-part2.patch: Copied from git

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
From 6995d30816f0c76844dee4dc9022296a03258457 Mon Sep 17 00:00:00 2001
 
2
From: Vincent Untz <vuntz@suse.com>
 
3
Date: Wed, 03 Oct 2012 16:21:41 +0000
 
4
Subject: Fix a bunch of issues when getting/putting a file from cups
 
5
 
 
6
There was basically no check for permissions. Now, we temporarily change
 
7
our effective uid/gid to the one of the user to open the file for
 
8
writing (when getting) or reading (when putting). We then only use
 
9
operations that work on the file descriptor to avoid potential race
 
10
conditions.
 
11
 
 
12
Before that, people could:
 
13
 - overwrite any file with the content of a cups resource
 
14
 - put any file in a cups resource
 
15
 
 
16
Part of fix for CVE-2012-4510.
 
17
---
 
18
diff --git a/src/cups-pk-helper-mechanism.c b/src/cups-pk-helper-mechanism.c
 
19
index d456499..a468a2a 100644
 
20
--- a/src/cups-pk-helper-mechanism.c
 
21
+++ b/src/cups-pk-helper-mechanism.c
 
22
@@ -559,14 +559,28 @@ cph_mechanism_file_get (CphIfaceMechanism     *object,
 
23
                         const char            *filename)
 
24
 {
 
25
         CphMechanism *mechanism = CPH_MECHANISM (object);
 
26
+        unsigned int  sender_uid;
 
27
         gboolean      ret;
 
28
 
 
29
         _cph_mechanism_emit_called (mechanism);
 
30
 
 
31
+        if (!_cph_mechanism_get_sender_uid (mechanism, context, &sender_uid)) {
 
32
+                GError *error;
 
33
+
 
34
+                error = g_error_new (CPH_MECHANISM_ERROR,
 
35
+                                     CPH_MECHANISM_ERROR_GENERAL,
 
36
+                                     "Cannot determine sender UID");
 
37
+                g_dbus_method_invocation_return_gerror (context, error);
 
38
+                g_error_free (error);
 
39
+
 
40
+                return TRUE;
 
41
+        }
 
42
+
 
43
         if (!_check_polkit_for_action (mechanism, context, "server-settings"))
 
44
                 return TRUE;
 
45
 
 
46
-        ret = cph_cups_file_get (mechanism->priv->cups, resource, filename);
 
47
+        ret = cph_cups_file_get (mechanism->priv->cups,
 
48
+                                 resource, filename, sender_uid);
 
49
 
 
50
         cph_iface_mechanism_complete_file_get (
 
51
                         object, context,
 
52
@@ -581,14 +595,28 @@ cph_mechanism_file_put (CphIfaceMechanism     *object,
 
53
                         const char            *filename)
 
54
 {
 
55
         CphMechanism *mechanism = CPH_MECHANISM (object);
 
56
+        unsigned int  sender_uid;
 
57
         gboolean      ret;
 
58
 
 
59
         _cph_mechanism_emit_called (mechanism);
 
60
 
 
61
+        if (!_cph_mechanism_get_sender_uid (mechanism, context, &sender_uid)) {
 
62
+                GError *error;
 
63
+
 
64
+                error = g_error_new (CPH_MECHANISM_ERROR,
 
65
+                                     CPH_MECHANISM_ERROR_GENERAL,
 
66
+                                     "Cannot determine sender UID");
 
67
+                g_dbus_method_invocation_return_gerror (context, error);
 
68
+                g_error_free (error);
 
69
+
 
70
+                return TRUE;
 
71
+        }
 
72
+
 
73
         if (!_check_polkit_for_action (mechanism, context, "server-settings"))
 
74
                 return TRUE;
 
75
 
 
76
-        ret = cph_cups_file_put (mechanism->priv->cups, resource, filename);
 
77
+        ret = cph_cups_file_put (mechanism->priv->cups,
 
78
+                                 resource, filename, sender_uid);
 
79
 
 
80
         cph_iface_mechanism_complete_file_put (
 
81
                         object, context,
 
82
diff --git a/src/cups.c b/src/cups.c
 
83
index 7d46c96..6ff6cba 100644
 
84
--- a/src/cups.c
 
85
+++ b/src/cups.c
 
86
@@ -28,6 +28,7 @@
 
87
 #include <fcntl.h>
 
88
 #include <errno.h>
 
89
 #include <ctype.h>
 
90
+#include <pwd.h>
 
91
 #include <sys/wait.h>
 
92
 #include <sys/types.h>
 
93
 #include <sys/stat.h>
 
94
@@ -510,6 +511,34 @@ _CPH_CUPS_IS_VALID (filename, "filename", TRUE, CPH_STR_MAXLEN)
 
95
  * Helpers
 
96
  ******************************************************/
 
97
 
 
98
+static gboolean
 
99
+_cph_cups_set_effective_id (unsigned int sender_uid)
 
100
+{
 
101
+        struct passwd *password_entry;
 
102
+
 
103
+        password_entry = getpwuid ((uid_t) sender_uid);
 
104
+
 
105
+        if (password_entry == NULL ||
 
106
+            setegid (password_entry->pw_gid) != 0)
 
107
+                return FALSE;
 
108
+
 
109
+        if (seteuid (sender_uid) != 0) {
 
110
+                if (getgid () != getegid ())
 
111
+                        setegid (getgid ());
 
112
+
 
113
+                return FALSE;
 
114
+        }
 
115
+
 
116
+        return TRUE;
 
117
+}
 
118
+
 
119
+static void
 
120
+_cph_cups_reset_effective_id (void)
 
121
+{
 
122
+        seteuid (getuid ());
 
123
+        setegid (getgid ());
 
124
+}
 
125
+
 
126
 static void
 
127
 _cph_cups_add_printer_uri (ipp_t      *request,
 
128
                            const char *name)
 
129
@@ -1081,14 +1110,15 @@ cph_cups_is_printer_local (CphCups    *cups,
 
130
 }
 
131
 
 
132
 gboolean
 
133
-cph_cups_file_get (CphCups    *cups,
 
134
-                   const char *resource,
 
135
-                   const char *filename)
 
136
+cph_cups_file_get (CphCups      *cups,
 
137
+                   const char   *resource,
 
138
+                   const char   *filename,
 
139
+                   unsigned int  sender_uid)
 
140
 {
 
141
         http_status_t status;
 
142
+        int           fd;
 
143
         struct stat   file_stat;
 
144
-        uid_t         uid;
 
145
-        gid_t         gid;
 
146
+        char         *error;
 
147
 
 
148
         g_return_val_if_fail (CPH_IS_CUPS (cups), FALSE);
 
149
 
 
150
@@ -1097,44 +1127,83 @@ cph_cups_file_get (CphCups    *cups,
 
151
         if (!_cph_cups_is_filename_valid (cups, filename))
 
152
                 return FALSE;
 
153
 
 
154
-        stat (filename, &file_stat);
 
155
-        uid = file_stat.st_uid;
 
156
-        gid = file_stat.st_gid;
 
157
+        if (!_cph_cups_set_effective_id (sender_uid)) {
 
158
+                error = g_strdup_printf ("Cannot check if \"%s\" is "
 
159
+                                         "writable: %s",
 
160
+                                         filename, strerror (errno));
 
161
+                _cph_cups_set_internal_status (cups, error);
 
162
+                g_free (error);
 
163
+
 
164
+                return FALSE;
 
165
+        }
 
166
+
 
167
+        fd = open (filename, O_WRONLY | O_NOFOLLOW | O_TRUNC);
 
168
+
 
169
+        _cph_cups_reset_effective_id ();
 
170
+
 
171
+        if (fd < 0) {
 
172
+                error = g_strdup_printf ("Cannot open \"%s\": %s",
 
173
+                                         filename, strerror (errno));
 
174
+                _cph_cups_set_internal_status (cups, error);
 
175
+                g_free (error);
 
176
+
 
177
+                return FALSE;
 
178
+        }
 
179
+
 
180
+
 
181
+        if (fstat (fd, &file_stat) != 0) {
 
182
+                error = g_strdup_printf ("Cannot write to \"%s\": %s",
 
183
+                                         filename, strerror (errno));
 
184
+                _cph_cups_set_internal_status (cups, error);
 
185
+                g_free (error);
 
186
+
 
187
+                close (fd);
 
188
+
 
189
+                return FALSE;
 
190
+        }
 
191
+
 
192
+        if (!S_ISREG (file_stat.st_mode)) {
 
193
+                /* hrm, this looks suspicious... we won't help */
 
194
+                error = g_strdup_printf ("File \"%s\" is not a regular file.",
 
195
+                                         filename);
 
196
+                _cph_cups_set_internal_status (cups, error);
 
197
+                g_free (error);
 
198
+
 
199
+                close (fd);
 
200
+
 
201
+                return FALSE;
 
202
+        }
 
203
 
 
204
         /* reset the internal status: we'll use the http status */
 
205
         _cph_cups_set_internal_status (cups, NULL);
 
206
 
 
207
-        status = cupsGetFile (cups->priv->connection, resource, filename);
 
208
+        status = cupsGetFd (cups->priv->connection, resource, fd);
 
209
 
 
210
         /* FIXME: There's a bug where the cups connection can fail with EPIPE.
 
211
-         * We're work-arounding it here until it's fixed in cups. */
 
212
+         * We're working around it here until it's fixed in cups. */
 
213
         if (status != HTTP_OK) {
 
214
-                if (cph_cups_reconnect (cups)) {
 
215
-                        int fd;
 
216
-
 
217
-                        /* if cupsGetFile fail, then filename is unlinked */
 
218
-                        fd = open (filename, O_CREAT, S_IRUSR | S_IWUSR);
 
219
-                        close (fd);
 
220
-                        chown (filename, uid, gid);
 
221
-
 
222
-                        _cph_cups_set_internal_status (cups, NULL);
 
223
-
 
224
-                        status = cupsGetFile (cups->priv->connection,
 
225
-                                              resource, filename);
 
226
-                }
 
227
+                if (cph_cups_reconnect (cups))
 
228
+                        status = cupsGetFd (cups->priv->connection,
 
229
+                                            resource, fd);
 
230
         }
 
231
 
 
232
+        close (fd);
 
233
+
 
234
         _cph_cups_set_internal_status_from_http (cups, status);
 
235
 
 
236
         return (status == HTTP_OK);
 
237
 }
 
238
 
 
239
 gboolean
 
240
-cph_cups_file_put (CphCups    *cups,
 
241
-                   const char *resource,
 
242
-                   const char *filename)
 
243
+cph_cups_file_put (CphCups      *cups,
 
244
+                   const char   *resource,
 
245
+                   const char   *filename,
 
246
+                   unsigned int  sender_uid)
 
247
 {
 
248
         http_status_t status;
 
249
+        int           fd;
 
250
+        struct stat   file_stat;
 
251
+        char         *error;
 
252
 
 
253
         g_return_val_if_fail (CPH_IS_CUPS (cups), FALSE);
 
254
 
 
255
@@ -1143,10 +1212,58 @@ cph_cups_file_put (CphCups    *cups,
 
256
         if (!_cph_cups_is_filename_valid (cups, filename))
 
257
                 return FALSE;
 
258
 
 
259
+        if (!_cph_cups_set_effective_id (sender_uid)) {
 
260
+                error = g_strdup_printf ("Cannot check if \"%s\" is "
 
261
+                                         "readable: %s",
 
262
+                                         filename, strerror (errno));
 
263
+                _cph_cups_set_internal_status (cups, error);
 
264
+                g_free (error);
 
265
+
 
266
+                return FALSE;
 
267
+        }
 
268
+
 
269
+        fd = open (filename, O_RDONLY);
 
270
+
 
271
+        _cph_cups_reset_effective_id ();
 
272
+
 
273
+        if (fd < 0) {
 
274
+                error = g_strdup_printf ("Cannot open \"%s\": %s",
 
275
+                                         filename, strerror (errno));
 
276
+                _cph_cups_set_internal_status (cups, error);
 
277
+                g_free (error);
 
278
+
 
279
+                return FALSE;
 
280
+        }
 
281
+
 
282
+        if (fstat (fd, &file_stat) != 0) {
 
283
+                error = g_strdup_printf ("Cannot read \"%s\": %s",
 
284
+                                         filename, strerror (errno));
 
285
+                _cph_cups_set_internal_status (cups, error);
 
286
+                g_free (error);
 
287
+
 
288
+                close (fd);
 
289
+
 
290
+                return FALSE;
 
291
+        }
 
292
+
 
293
+        if (!S_ISREG (file_stat.st_mode)) {
 
294
+                /* hrm, this looks suspicious... we won't help */
 
295
+                error = g_strdup_printf ("File \"%s\" is not a regular file.",
 
296
+                                         filename);
 
297
+                _cph_cups_set_internal_status (cups, error);
 
298
+                g_free (error);
 
299
+
 
300
+                close (fd);
 
301
+
 
302
+                return FALSE;
 
303
+        }
 
304
+
 
305
         /* reset the internal status: we'll use the http status */
 
306
         _cph_cups_set_internal_status (cups, NULL);
 
307
 
 
308
-        status = cupsPutFile (cups->priv->connection, resource, filename);
 
309
+        status = cupsPutFd (cups->priv->connection, resource, fd);
 
310
+
 
311
+        close (fd);
 
312
 
 
313
         _cph_cups_set_internal_status_from_http (cups, status);
 
314
 
 
315
diff --git a/src/cups.h b/src/cups.h
 
316
index 2832533..3017792 100644
 
317
--- a/src/cups.h
 
318
+++ b/src/cups.h
 
319
@@ -70,13 +70,15 @@ char *cph_cups_printer_get_uri (CphCups    *cups,
 
320
 gboolean cph_cups_is_printer_local (CphCups    *cups,
 
321
                                     const char *printer_name);
 
322
 
 
323
-gboolean cph_cups_file_get (CphCups    *cups,
 
324
-                            const char *resource,
 
325
-                            const char *filename);
 
326
-
 
327
-gboolean cph_cups_file_put (CphCups    *cups,
 
328
-                            const char *resource,
 
329
-                            const char *filename);
 
330
+gboolean cph_cups_file_get (CphCups      *cups,
 
331
+                            const char   *resource,
 
332
+                            const char   *filename,
 
333
+                            unsigned int  sender_uid);
 
334
+
 
335
+gboolean cph_cups_file_put (CphCups      *cups,
 
336
+                            const char   *resource,
 
337
+                            const char   *filename,
 
338
+                            unsigned int  sender_uid);
 
339
 
 
340
 gboolean cph_cups_server_get_settings (CphCups   *cups,
 
341
                                        GVariant **settings);
 
342