diff --git a/core/lib/Drupal/Core/Menu/MenuLinkManager.php b/core/lib/Drupal/Core/Menu/MenuLinkManager.php
index 44eeeb3..0cc7727 100644
--- a/core/lib/Drupal/Core/Menu/MenuLinkManager.php
+++ b/core/lib/Drupal/Core/Menu/MenuLinkManager.php
@@ -44,7 +44,8 @@ class MenuLinkManager implements MenuLinkManagerInterface {
// The static title for the menu link. If this came from a YAML definition
// or other safe source this may be a TranslationWrapper object.
'title' => '',
- // The description.
+ // The description. If this came from a YAML definition or other safe source
+ // this maybe be a TranslationWrapper object.
'description' => '',
// The plugin ID of the parent link (or NULL for a top-level link).
'parent' => '',
diff --git a/core/lib/Drupal/Core/Menu/MenuTreeStorage.php b/core/lib/Drupal/Core/Menu/MenuTreeStorage.php
index 11e3711..92b5454 100644
--- a/core/lib/Drupal/Core/Menu/MenuTreeStorage.php
+++ b/core/lib/Drupal/Core/Menu/MenuTreeStorage.php
@@ -1250,14 +1250,14 @@ protected static function schemaDefinition() {
'default' => '',
),
'title' => array(
- 'description' => 'The title for the link. May be a serialized TranslationWrapper',
+ 'description' => 'The serialized title for the link. May be a TranslationWrapper',
'type' => 'blob',
'size' => 'big',
'not null' => FALSE,
'serialize' => TRUE,
),
'description' => array(
- 'description' => 'The description of this link - used for admin pages and title attribute.',
+ 'description' => 'The serialized description of this link - used for admin pages and title attribute. May be a TranslationWrapper.',
'type' => 'blob',
'size' => 'big',
'not null' => FALSE,
diff --git a/core/modules/system/src/Tests/Menu/MenuLinkSecurityTest.php b/core/modules/system/src/Tests/Menu/MenuLinkSecurityTest.php
new file mode 100644
index 0000000..2fe6c3b
--- /dev/null
+++ b/core/modules/system/src/Tests/Menu/MenuLinkSecurityTest.php
@@ -0,0 +1,45 @@
+ '',
+ 'menu_name' => 'tools',
+ 'link' => ['uri' => 'route:'],
+ ]);
+ $menu_link_content->save();
+
+ $this->drupalPlaceBlock('system_menu_block:tools');
+
+ $this->drupalGet('');
+ $this->assertNoRaw('');
+ $this->assertNoRaw('');
+ $this->assertRaw(htmlspecialchars('', ENT_QUOTES, 'UTF-8'));
+ $this->assertRaw(htmlspecialchars('', ENT_QUOTES, 'UTF-8'));
+ }
+
+}
diff --git a/core/modules/system/src/Tests/Update/MenuTreeSerializationTitleTest.php b/core/modules/system/src/Tests/Update/MenuTreeSerializationTitleTest.php
new file mode 100644
index 0000000..b9e247f
--- /dev/null
+++ b/core/modules/system/src/Tests/Update/MenuTreeSerializationTitleTest.php
@@ -0,0 +1,49 @@
+databaseDumpFiles = [
+ __DIR__ . '/../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
+ ];
+ parent::setUp();
+ }
+
+ /**
+ * Ensures that the system_update_8001() runs as expected.
+ */
+ public function testUpdate() {
+ $this->runUpdates();
+
+ // Ensure that some fields got dropped.
+ $this->assertFalse(db_field_exists('menu_tree', 'title_arguments'));
+ $this->assertFalse(db_field_exists('menu_tree', 'title_contexts'));
+
+ // Ensure that all titles/descriptions are unserializable.
+ $select = \Drupal::database()->select('menu_tree');
+ $result = $select->fields('menu_tree', ['mlid', 'title', 'description'])
+ ->execute()
+ ->fetchAllAssoc('mlid');
+
+ foreach ($result as $link) {
+ unserialize($link->title);
+ unserialize($link->description);
+ }
+ }
+
+}
diff --git a/core/modules/system/src/Tests/Update/UpdatePathTestBase.php b/core/modules/system/src/Tests/Update/UpdatePathTestBase.php
index d152432..a9e0ad2 100644
--- a/core/modules/system/src/Tests/Update/UpdatePathTestBase.php
+++ b/core/modules/system/src/Tests/Update/UpdatePathTestBase.php
@@ -141,15 +141,7 @@ protected function setUp() {
// Rebuild and reset.
$this->rebuildAll();
- // Remove the notices we get due to the menu link rebuild prior to running
- // the system updates for the schema change.
- foreach ($this->assertions as $key => $assertion) {
- if ($assertion['message_group'] == 'Notice' && basename($assertion['file']) == 'MenuTreeStorage.php' && strpos($assertion['message'], 'unserialize(): Error at offset 0') !== FALSE) {
- unset($this->assertions[$key]);
- $this->deleteAssert($assertion['message_id']);
- $this->results['#exception']--;
- }
- }
+
// Replace User 1 with the user created here.
/** @var \Drupal\user\UserInterface $account */
$account = User::load(1);
@@ -207,4 +199,21 @@ protected function runUpdates() {
$this->clickLink(t('Apply pending updates'));
}
+ /**
+ * {@inheritdoc}
+ */
+ protected function rebuildAll() {
+ parent::rebuildAll();
+
+ // Remove the notices we get due to the menu link rebuild prior to running
+ // the system updates for the schema change.
+ foreach ($this->assertions as $key => $assertion) {
+ if ($assertion['message_group'] == 'Notice' && basename($assertion['file']) == 'MenuTreeStorage.php' && strpos($assertion['message'], 'unserialize(): Error at offset 0') !== FALSE) {
+ unset($this->assertions[$key]);
+ $this->deleteAssert($assertion['message_id']);
+ $this->results['#exception']--;
+ }
+ }
+ }
+
}
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index c3990c8..2f51cc0 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -1130,7 +1130,7 @@ function system_update_8001(&$sandbox = NULL) {
->condition('mlid', $menu_link['mlid'])
->execute();
- $sandbox['current'] += 50;
+ $sandbox['current']++;;
}
$sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['current'] / $sandbox['max']);
@@ -1144,7 +1144,7 @@ function system_update_8001(&$sandbox = NULL) {
return t('Menu links converted');
}
else {
- return t('Menu link conversion skipped');
+ return t('Menu link conversion skipped, because the {menu_tree} table did not existed yet.');
}
}
diff --git a/core/modules/system/tests/modules/menu_test/menu_test.links.menu.yml b/core/modules/system/tests/modules/menu_test/menu_test.links.menu.yml
index 914fbd5..613bc92 100644
--- a/core/modules/system/tests/modules/menu_test/menu_test.links.menu.yml
+++ b/core/modules/system/tests/modules/menu_test/menu_test.links.menu.yml
@@ -79,3 +79,7 @@ menu_test.child:
title: 'Test menu_name child'
route_name: menu_test.menu_name_test
parent: menu_test.parent
+
+menu_test.unsafe:
+ route_name: menu_test.menu_name_test
+ deriver: '\Drupal\menu_test\Plugin\Derivative\MenuLinkTestWithUnsafeTitle'
diff --git a/core/modules/system/tests/modules/menu_test/src/Plugin/Derivative/MenuLinkTestWithUnsafeTitle.php b/core/modules/system/tests/modules/menu_test/src/Plugin/Derivative/MenuLinkTestWithUnsafeTitle.php
new file mode 100644
index 0000000..a9d9041
--- /dev/null
+++ b/core/modules/system/tests/modules/menu_test/src/Plugin/Derivative/MenuLinkTestWithUnsafeTitle.php
@@ -0,0 +1,30 @@
+derivatives['unsafe'] = [
+ 'title' => '',
+ 'menu_name' => 'tools',
+ ] + $base_plugin_definition;
+
+ return $this->derivatives;
+ }
+
+
+}