Patch from Love: when opening an existing replay cache, check more
authorGreg Hudson <ghudson@mit.edu>
Wed, 21 Jan 2009 19:38:12 +0000 (19:38 +0000)
committerGreg Hudson <ghudson@mit.edu>
Wed, 21 Jan 2009 19:38:12 +0000 (19:38 +0000)
thoroughly to prevent symlink attacks.

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@21770 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/krb5/rcache/rc_io.c

index 5abf109c6c09b03aab01f1765d589f0520d58360..82b56297b4c9f5aaf1650cec799ec4bcb9ab1ccd 100644 (file)
@@ -223,7 +223,7 @@ krb5_rc_io_open_internal(krb5_context context, krb5_rc_iostuff *d, char *fn,
     krb5_error_code retval = 0;
     int do_not_unlink = 1;
 #ifndef NO_USERID
-    struct stat statb;
+    struct stat sb1, sb2;
 #endif
     char *dir;
     size_t dirlen;
@@ -239,24 +239,50 @@ krb5_rc_io_open_internal(krb5_context context, krb5_rc_iostuff *d, char *fn,
 
 #ifdef NO_USERID
     d->fd = THREEPARAMOPEN(d->fn, O_RDWR | O_BINARY, 0600);
+    if (d->fd == -1) {
+        retval = rc_map_errno(context, errno, d->fn, "open");
+        goto cleanup;
+    }
 #else
-    if ((d->fd = stat(d->fn, &statb)) != -1) {
-        uid_t me;
-
-        me = geteuid();
-        /* must be owned by this user, to prevent some security problems with
-         * other users modifying replay cache stufff */
-        if ((statb.st_uid != me) || ((statb.st_mode & S_IFMT) != S_IFREG)) {
-            FREE(d->fn);
-            return KRB5_RC_IO_PERM;
-        }
-        d->fd = THREEPARAMOPEN(d->fn, O_RDWR | O_BINARY, 0600);
+    d->fd = -1;
+    retval = lstat(d->fn, &sb1);
+    if (retval != 0) {
+        retval = rc_map_errno(context, errno, d->fn, "lstat");
+        goto cleanup;
     }
-#endif
-    if (d->fd == -1) {
+    d->fd = THREEPARAMOPEN(d->fn, O_RDWR | O_BINARY, 0600);
+    if (d->fd < 0) {
         retval = rc_map_errno(context, errno, d->fn, "open");
         goto cleanup;
     }
+    retval = fstat(d->fd, &sb2);
+    if (retval < 0) {
+        retval = rc_map_errno(context, errno, d->fn, "fstat");
+        goto cleanup;
+    }
+    /* check if someone was playing with symlinks */
+    if ((sb1.st_dev != sb2.st_dev || sb1.st_ino != sb2.st_ino)
+        || (sb1.st_mode & S_IFMT) != S_IFREG)
+        {
+            retval = KRB5_RC_IO_PERM;
+            krb5_set_error_message(context, retval,
+                                   "rcache not a file %s", d->fn);
+            goto cleanup;
+        }
+    /* check that non other can read/write/execute the file */
+    if (sb1.st_mode & 077) {
+        krb5_set_error_message(context, retval, "Insecure file mode "
+                               "for replay cache file %s", d->fn);
+        return KRB5_RC_IO_UNKNOWN;
+    }
+    /* owned by me */
+    if (sb1.st_uid != geteuid()) {
+        retval = KRB5_RC_IO_PERM;
+        krb5_set_error_message(context, retval, "rcache not owned by %d",
+                               (int)geteuid());
+        goto cleanup;
+    }
+#endif
     set_cloexec_fd(d->fd);
 
     do_not_unlink = 0;