diff --git a/includes/common.inc b/includes/common.inc
index 268e36b..ab11d8d 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -2494,12 +2494,19 @@ function drupal_deliver_html_page($page_callback_result) {
 
         if (empty($return) || $return == MENU_NOT_FOUND || $return == MENU_ACCESS_DENIED) {
           // Standard 404 handler.
-          drupal_set_title(t('Page not found'));
-          $return = t('The requested page "@path" could not be found.', array('@path' => request_uri()));
+          $path = 'system/404';
+          menu_set_active_item($path);
+          $return = menu_execute_active_handler($path, FALSE);
         }
 
         drupal_set_page_content($return);
         $page = element_info('page');
+        $page['#cache'] = array(
+          'keys' => array('system', '404'),
+          'granularity' => DRUPAL_CACHE_PER_ROLE,
+          'expire' => CACHE_TEMPORARY,
+          'bin' => 'cache_page',
+        );
         print drupal_render_page($page);
         break;
 
@@ -2523,11 +2530,20 @@ function drupal_deliver_html_page($page_callback_result) {
 
         if (empty($return) || $return == MENU_NOT_FOUND || $return == MENU_ACCESS_DENIED) {
           // Standard 403 handler.
-          drupal_set_title(t('Access denied'));
-          $return = t('You are not authorized to access this page.');
+          $path = 'system/403';
+          menu_set_active_item($path);
+          $return = menu_execute_active_handler($path, FALSE);
         }
 
-        print drupal_render_page($return);
+        drupal_set_page_content($return);
+        $page = element_info('page');
+        $page['#cache'] = array(
+          'keys' => array('system', '403'),
+          'granularity' => DRUPAL_CACHE_PER_ROLE,
+          'expire' => CACHE_TEMPORARY,
+          'bin' => 'cache_page',
+        );
+        print drupal_render_page($page);
         break;
 
       case MENU_SITE_OFFLINE:
diff --git a/modules/node/node.test b/modules/node/node.test
index 5de6081..3acac22 100644
--- a/modules/node/node.test
+++ b/modules/node/node.test
@@ -1879,14 +1879,18 @@ class NodeBlockFunctionalTest extends DrupalWebTestCase {
     $this->assertTrue($bid, t('Custom block with visibility rule was created.'));
 
     // Verify visibility rules.
+    $this->drupalLogout();
+    $this->drupalLogin($this->web_user);
     $this->drupalGet('');
-    $this->assertNoText($custom_block['title'], t('Block was displayed on the front page.'));
+    $this->assertNoText($custom_block['title'], t('Block was not displayed on the front page.'));
     $this->drupalGet('node/add/article');
     $this->assertText($custom_block['title'], t('Block was displayed on the node/add/article page.'));
     $this->drupalGet('node/' . $node1->nid);
     $this->assertText($custom_block['title'], t('Block was displayed on the node/N.'));
 
     // Delete the created custom block & verify that it's been deleted.
+    $this->drupalLogout();
+    $this->drupalLogin($this->admin_user);
     $this->drupalPost('admin/structure/block/manage/block/' . $bid . '/delete', array(), t('Delete'));
     $bid = db_query("SELECT 1 FROM {block_node_type} WHERE module = 'block' AND delta = :delta", array(':delta' => $bid))->fetchField();
     $this->assertFalse($bid, t('Custom block was deleted.'));
diff --git a/modules/system/system.module b/modules/system/system.module
index d7dc69c..2655612 100644
--- a/modules/system/system.module
+++ b/modules/system/system.module
@@ -510,6 +510,18 @@ function system_element_info() {
  * Implements hook_menu().
  */
 function system_menu() {
+  $items['system/403'] = array(
+    'title' => 'Access denied',
+    'page callback' => 'system_access_denied',
+    'access callback' => TRUE,
+    'type' => MENU_CALLBACK,
+  );
+  $items['system/404'] = array(
+    'title' => 'Page not found',
+    'page callback' => 'system_not_found',
+    'access callback' => TRUE,
+    'type' => MENU_CALLBACK,
+  );
   $items['system/files'] = array(
     'title' => 'File download',
     'page callback' => 'file_download',
@@ -2136,6 +2148,26 @@ function system_admin_menu_block($item) {
 }
 
 /**
+ * Menu callback; returns a 403 error message.
+ *
+ * Page callback functions wanting to report an "access denied" message should
+ * not use this function. Instead see drupal_access_denied().
+ */
+function system_access_denied() {
+  return array('#markup' => t('You are not authorized to access this page.'));
+}
+
+/**
+ * Menu callback; returns a 404 error message.
+ *
+ * Page callback functions wanting to report a "not found" message should not
+ * use this function. Instead see drupal_not_found().
+ */
+function system_not_found() {
+  return array('#markup' => t('The requested page could not be found.'));
+}
+
+/**
  * Checks the existence of the directory specified in $form_element.
  *
  * This function is called from the system_settings form to check all core
diff --git a/modules/system/system.test b/modules/system/system.test
index 846653b..603b434 100644
--- a/modules/system/system.test
+++ b/modules/system/system.test
@@ -881,24 +881,26 @@ class AccessDeniedTestCase extends DrupalWebTestCase {
     $this->drupalGet('admin');
     $this->assertText($node->title, t('Found the custom 403 page'));
 
-    // Logout and check that the user login block is shown on custom 403 pages.
+    // Logout and check that blocks and menu items are shown on custom 403 pages.
     $this->drupalLogout();
 
     $this->drupalGet('admin');
     $this->assertText($node->title, t('Found the custom 403 page'));
     $this->assertText(t('User login'), t('Blocks are shown on the custom 403 page'));
+    $this->assertText(t('Main menu'), t('Menu items are shown on the custom 403 page'));
 
     // Log back in and remove the custom 403 page.
     $this->drupalLogin($this->admin_user);
     $this->drupalPost('admin/config/system/site-information', array('site_403' => ''), t('Save configuration'));
 
-    // Logout and check that the user login block is shown on default 403 pages.
+    // Logout and check that blocks and menu items are shown on default 403 pages.
     $this->drupalLogout();
 
     $this->drupalGet('admin');
     $this->assertText(t('Access denied'), t('Found the default 403 page'));
     $this->assertResponse(403);
     $this->assertText(t('User login'), t('Blocks are shown on the default 403 page'));
+    $this->assertText(t('Main menu'), t('Menu items are shown on the default 403 page'));
 
     // Log back in, set the custom 403 page to /user and remove the block
     $this->drupalLogin($this->admin_user);
@@ -944,20 +946,29 @@ class PageNotFoundTestCase extends DrupalWebTestCase {
   }
 
   function testPageNotFound() {
+    // Logout and check that blocks and menu items are shown on default 404 pages.
+    $this->drupalLogout();
     $this->drupalGet($this->randomName(10));
     $this->assertText(t('Page not found'), t('Found the default 404 page'));
+    $this->assertText(t('User login'), t('Blocks are shown on the default 404 page'));
+    $this->assertText(t('Main menu'), t('Menu items are shown on the default 404 page'));
 
+    // Log back in and add a custom 404 page.
+    $this->drupalLogin($this->admin_user);
     $edit = array(
       'title' => $this->randomName(10),
       'body' => array(LANGUAGE_NONE => array(array('value' => $this->randomName(100)))),
     );
     $node = $this->drupalCreateNode($edit);
-
-    // Use a custom 404 page.
     $this->drupalPost('admin/config/system/site-information', array('site_404' => 'node/' . $node->nid), t('Save configuration'));
 
+    // Logout and check that blocks and menu items are shown on custom 404 pages.
+    $this->drupalLogout();
+
     $this->drupalGet($this->randomName(10));
     $this->assertText($node->title, t('Found the custom 404 page'));
+    $this->assertText(t('User login'), t('Blocks are shown on the custom 404 page'));
+    $this->assertText(t('Main menu'), t('Menu items are shown on the custom 404 page'));
   }
 }
 
