~ubuntu-branches/ubuntu/quantal/ecryptfs-utils/quantal-proposed

« back to all changes in this revision

Viewing changes to src/utils/mount.ecryptfs_private.c

  • Committer: Bazaar Package Importer
  • Author(s): Marc Deslauriers
  • Date: 2011-08-04 10:37:40 UTC
  • Revision ID: james.westby@ubuntu.com-20110804103740-k4bobcj7qpe94xuv
Tags: 89-0ubuntu2
* SECURITY UPDATE: privilege escalation via mountpoint race conditions
  (LP: #732628)
  - debian/patches/CVE-2011-1831,1832,1834.patch: chdir into mountpoint
    before checking permissions in src/utils/mount.ecryptfs_private.c.
  - CVE-2011-1831
  - CVE-2011-1832
* SECURITY UPDATE: race condition when checking source during mount
  (LP: #732628)
  - debian/patches/CVE-2011-1833.patch: use new ecryptfs_check_dev_ruid
    kernel option when mounting directory in
    src/utils/mount.ecryptfs_private.c.
  - CVE-2011-1833
* SECURITY UPDATE: mtab corruption via improper handling (LP: #732628)
  - debian/patches/CVE-2011-1831,1832,1834.patch: modify mtab via a temp
    file first and make sure it succeeds before replacing the real mtab
    in src/utils/mount.ecryptfs_private.c.
  - CVE-2011-1834
* SECURITY UPDATE: key poisoning via insecure temp directory handling
  (LP: #732628)
  - debian/patches/CVE-2011-1835.patch: make sure we don't copy into a
    user controlled directory in src/utils/ecryptfs-setup-private.
  - CVE-2011-1835
* SECURITY UPDATE: information disclosure via recovery mount in /tmp
  (LP: #732628)
  - debian/patches/CVE-2011-1836.patch: mount inside protected
    subdirectory in src/utils/ecryptfs-recover-private.
  - CVE-2011-1836
* SECURITY UPDATE: arbitrary file overwrite via lock counter race
  condition (LP: #732628)
  - debian/patches/CVE-2011-1837.patch: verify permissions with a file
    descriptor, and don't follow symlinks in
    src/utils/mount.ecryptfs_private.c.
  - CVE-2011-1837

Show diffs side-by-side

added added

removed removed

Lines of Context:
196
196
        return sig;
197
197
}
198
198
 
 
199
int check_ownership_mnt(int uid, char **mnt) {
 
200
/* Check ownership of mount point, chdir into it, and
 
201
 * canonicalize the path for use in mtab updating.
 
202
 * Return 0 if everything is in order, 1 on error.
 
203
 */
 
204
        struct stat s;
 
205
        char *cwd;
 
206
 
 
207
        /* From here on, we'll refer to "." as our mountpoint, to avoid
 
208
         * races.
 
209
         */
 
210
        if (chdir(*mnt) != 0) {
 
211
                fputs("Cannot chdir into mountpoint.\n", stderr);
 
212
                return 1;
 
213
        }
 
214
        if (stat(".", &s) != 0) {
 
215
                fputs("Cannot examine mountpoint.\n", stderr);
 
216
                return 1;
 
217
        }
 
218
        if (!S_ISDIR(s.st_mode)) {
 
219
                fputs("Mountpoint is not a directory.\n", stderr);
 
220
                return 1;
 
221
        }
 
222
        if (s.st_uid != uid) {
 
223
                fputs("You do not own that mountpoint.\n", stderr);
 
224
                return 1;
 
225
        }
 
226
 
 
227
        /* Canonicalize our pathname based on the current directory to
 
228
         * avoid races.
 
229
         */
 
230
        cwd = getcwd(NULL, 0);
 
231
        if (!cwd) {
 
232
                fputs("Failed to get current directory\n", stderr);
 
233
                return 1;
 
234
        }
 
235
        *mnt = cwd;
 
236
        return 0;
 
237
}
 
238
 
 
239
 
199
240
int check_ownerships(int uid, char *path) {
200
241
/* Check ownership of device and mount point.
201
242
 * Return 0 if everything is in order, 1 on error.
230
271
                return 0;
231
272
        }
232
273
 
233
 
        FILE *fh;
234
 
        struct mntent m;
235
 
        fh = setmntent("/etc/mtab", "a");
236
 
        if (fh == NULL) {
237
 
                perror("setmntent");
238
 
                /* Unmount if mtab cannot be updated */
239
 
                umount(mnt);
240
 
                return 1;
241
 
        }
242
 
        m.mnt_fsname = dev;
243
 
        m.mnt_dir = mnt;
244
 
        m.mnt_type = FSTYPE;
245
 
        m.mnt_opts = opt;
246
 
        m.mnt_freq = 0;
247
 
        m.mnt_passno = 0;
248
 
        flockfile(fh);
249
 
        if (addmntent(fh, &m) != 0) {
 
274
        int fd;
 
275
        FILE *old_mtab, *new_mtab;
 
276
        struct mntent *old_ent, new_ent;
 
277
 
 
278
        /* Make an attempt to play nice with other mount helpers
 
279
         * by creating an /etc/mtab~ lock file. Of course this
 
280
         * only works if those other helpers actually check for
 
281
         * this.
 
282
         */
 
283
        fd = open("/etc/mtab~", O_RDONLY | O_CREAT | O_EXCL, 0644);
 
284
        if (fd < 0) {
 
285
                perror("open");
 
286
                return 1;
 
287
        }
 
288
        close(fd);
 
289
 
 
290
        old_mtab = setmntent("/etc/mtab", "r");
 
291
        if (old_mtab == NULL) {
 
292
                perror("setmntent");
 
293
                return 1;
 
294
        }
 
295
 
 
296
        new_mtab = setmntent("/etc/mtab.tmp", "w");
 
297
        if (new_mtab == NULL) {
 
298
                perror("setmntent");
 
299
                goto fail_early;
 
300
        }
 
301
 
 
302
        while (old_ent = getmntent(old_mtab)) {
 
303
                if (addmntent(new_mtab, old_ent) != 0) {
 
304
                        perror("addmntent");
 
305
                        goto fail;
 
306
                }
 
307
        }
 
308
        endmntent(old_mtab);
 
309
 
 
310
        new_ent.mnt_fsname = dev;
 
311
        new_ent.mnt_dir = mnt;
 
312
        new_ent.mnt_type = FSTYPE;
 
313
        new_ent.mnt_opts = opt;
 
314
        new_ent.mnt_freq = 0;
 
315
        new_ent.mnt_passno = 0;
 
316
 
 
317
        if (addmntent(new_mtab, &new_ent) != 0) {
250
318
                perror("addmntent");
251
 
                endmntent(fh);
252
 
                /* Unmount if mtab cannot be updated */
253
 
                umount(mnt);
254
 
                return 1;
255
 
        }
256
 
        endmntent(fh);
 
319
                goto fail;
 
320
        }
 
321
 
 
322
        if (fchmod(fileno(new_mtab), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) {
 
323
                perror("fchmod");
 
324
                goto fail;
 
325
        }
 
326
        endmntent(new_mtab);
 
327
 
 
328
        if (rename("/etc/mtab.tmp", "/etc/mtab") < 0) {
 
329
                perror("rename");
 
330
                goto fail_late;
 
331
        }
 
332
 
 
333
        unlink("/etc/mtab~");
 
334
 
257
335
        return 0;
 
336
 
 
337
fail:
 
338
        endmntent(new_mtab);
 
339
fail_late:
 
340
        unlink("/etc/mtab.tmp");
 
341
fail_early:
 
342
        endmntent(old_mtab);
 
343
        unlink("/etc/mtab~");
 
344
        return 1;
258
345
}
259
346
 
260
347
FILE *lock_counter(char *u, int uid, char *alias) {
273
360
         * file, or it's not owned by the current user, append iterator
274
361
         * until we find a filename we can use.
275
362
         */
276
 
        while (1) {
277
 
                if (stat(f, &s)==0 && (!S_ISREG(s.st_mode) || s.st_uid!=uid)) {
 
363
        while (i < 50) {
 
364
                if (((fd = open(f, O_RDWR | O_CREAT | O_NOFOLLOW, 0600)) >= 0) &&
 
365
                    (fstat(fd, &s)==0 && (S_ISREG(s.st_mode) && s.st_uid==uid))) {
 
366
                        break;
 
367
                } else {
 
368
                        if (fd >= 0)
 
369
                                close(fd);
278
370
                        free(f);
279
371
                        if (asprintf(&f, "%s/%s-%s-%s-%d", TMP, FSTYPE, u,
280
372
                            alias, i++) < 0) {
281
373
                                perror("asprintf");
282
374
                                return NULL;
283
375
                        }
284
 
                } else {
285
 
                        break;
286
 
                }
287
 
        }
288
 
        /* open file for reading and writing */
289
 
        if ((fd = open(f, O_RDWR)) < 0) {
290
 
                /* Could not open it, so try to safely create it */
291
 
                if ((fd = open(f, O_RDWR | O_CREAT | O_EXCL, 0600)) < 0) {
292
 
                        perror("open");
293
 
                        return NULL;
294
 
                }
295
 
        }
 
376
                }
 
377
        }
 
378
 
 
379
        if (fd < 0) {
 
380
                perror("open");
 
381
                return NULL;
 
382
        }
 
383
 
296
384
        flock(fd, LOCK_EX);
297
385
        fh = fdopen(fd, "r+");
298
386
        if (fh == NULL) {
485
573
 
486
574
        /* Build mount options */
487
575
        if (
488
 
            (asprintf(&opt, "ecryptfs_cipher=%s,ecryptfs_key_bytes=%d,ecryptfs_unlink_sigs%s%s%s%s",
 
576
            (asprintf(&opt, "ecryptfs_check_dev_ruid,ecryptfs_cipher=%s,ecryptfs_key_bytes=%d,ecryptfs_unlink_sigs%s%s%s%s",
489
577
                      KEY_CIPHER,
490
578
                      KEY_BYTES,
491
579
                      sig ? ",ecryptfs_sig=" : "",
499
587
                goto fail;
500
588
        }
501
589
 
 
590
        /* Check ownership of the mountpoint. From here on, dest refers
 
591
         * to a canonicalized path, and the mountpoint is the cwd. */
 
592
        if (check_ownership_mnt(uid, &dest) != 0) {
 
593
                goto fail;
 
594
        }
 
595
 
502
596
        if (mounting == 1) {
503
597
                /* Increment mount counter, errors non-fatal */
504
598
                if (increment(fh_counter) < 0) {
518
612
                 * And we need the effective uid to be root in order to mount.
519
613
                 */
520
614
                setreuid(-1, 0);
521
 
                /* Check ownerships and perform mount */
522
 
                if (check_ownerships(uid, src) == 0 &&
523
 
                    check_ownerships(uid, dest) == 0 &&
524
 
                    mount(src, dest, FSTYPE, 0, opt) == 0) {
 
615
                /* Perform mount */
 
616
                if (mount(src, ".", FSTYPE, 0, opt) == 0) {
525
617
                        if (update_mtab(src, dest, opt) != 0) {
526
618
                                goto fail;
527
619
                        }
565
657
                 * update mtab for us, and replace the current process.
566
658
                 * Do not use the umount.ecryptfs helper (-i).
567
659
                 */
568
 
                if (check_ownerships(uid, dest) != 0)
569
 
                        goto fail;
570
660
                setresuid(0,0,0);
571
 
                execl("/bin/umount", "umount", "-i", "-l", dest, NULL);
 
661
 
 
662
                /* Since we're doing a lazy unmount anyway, just unmount the current
 
663
                 * directory. This avoids a lot of complexity in dealing with race
 
664
                 * conditions, and guarantees that we're only unmounting a filesystem
 
665
                 * that we own. */
 
666
                execl("/bin/umount", "umount", "-i", "-l", ".", NULL);
572
667
                perror("execl unmount failed");
573
668
                goto fail;
574
669
        }