Problem/Motivation
Recent security releases have shown that the render system needs to be stricter about what it allow to be called by a callback. See:
- https://www.drupal.org/sa-core-2018-002
- https://www.drupal.org/sa-core-2018-004
- #2860607: Code execution via Twig templates (including inline)
Render list of callbacks to target:
- #access_callback
- #lazy_builder
- #post_render
- #pre_render
Because render callbacks use \Drupal\Core\Controller\ControllerResolverInterface::getControllerFromDefinition
this allows them to instantiate any service and call public methods on them. Therefore for non-ElementInterface objects we need an additional RenderCallbackInterface object to declare with objects contain a callback and which methods can be called on said object.
Procedural function support is removed.
Form callbacks will be handled in #2966711: Limit what can be called by a callback in form arrays
Proposed resolution
- In 8.7.x deprecate the ability to call any function using
call_user_func*()
and limit to object implementing TrustedCallbackInterface, ElementInterface or a closure. For non-ElementInterface objects also limit to specific methods to further narrow the surface area. - Try and provide a PHPCS fix that can auto-update code?
- In 8.8.x or 8.9.x remove the ability? Definitely for 9.0.0
Remaining tasks
Review.
User interface changes
None
API changes
- Add \Drupal\Core\Security\TrustedCallbackInterface.
- Add \Drupal\Core\Security\TrustedCallbackTrait to make doing a trusted callback simple
- Trigger a deprecation error if a render callback is a procedural function or an object that does not implement TrustedCallbackInterface or RenderElementInterface or a closure.
drupal_pre_render_links()
replaced with\Drupal\Core\Render\Element\Link::preRenderLinks()
color_block_view_pre_render()
replaced with\Drupal\color\ColorBlock::preRender()
filter_form_access_denied()
replaced with\Drupal\filter\Element\TextFormat::accessDeniedCallback()
history_attach_timestamp()
replaced with\Drupal\history\HistoryRenderCallback::lazyBuilder()
_toolbar_do_get_rendered_subtrees()
replaced with\Drupal\toolbar\Controller\ToolbarController::preRenderGetRenderedSubtrees()
toolbar_prerender_toolbar_administration_tray()
replaced with\Drupal\toolbar\Controller\ToolbarController::preRenderAdministrationTray()
views_pre_render_views_form_views_form()
replaced with\Drupal\views\Form\ViewsFormMainForm::preRenderViewsForm()
Data model changes
None.