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:

Form list of callbacks to target:

  • ✓ #process
  • ✓ #after_build
  • ✓ #value_callback
  • ✓ #element_validate
  • ✓ #validate
  • #submit

Proposed resolution

Postponed on the render system solution - #2966327: Limit what can be called by a callback in render arrays to reduce the risk of RCE - once we have an agreed solution there we should largely copy it.

  1. In 10.3.x deprecate the ability to call any function using call_user_func*() and limit to object implementing FormCallback interface, FormElementInterface or a closure. For objects also limit to specific methods to further narrow the surface area.
  2. Try and provide a PHPCS fix that can auto-update code?
  3. In 11.0.x remove the ability.

Remaining tasks

  1. Refactor all the prior refactoring done against 9.2 against 10.3.x using the new attribute.
  2. Find any additional callbacks added since 9.2 and refactor those.

User interface changes

None

API changes

Yes

Data model changes

None.

Issue fork drupal-2966711

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

alexpott created an issue. See original summary.

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

samuel.mortenson’s picture

Status: Postponed » Active
xjm’s picture

Priority: Major » Critical
Issue summary: View changes

This one is probably critical.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

catch’s picture

Version: 8.9.x-dev » 9.1.x-dev

Unless we make an exception, the new deprecation message would need to be 9.1.x-only. It might be OK to backport any new interfaces or similar without an exception message though.

catch’s picture

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

fathershawn’s picture

I have some time to help with this - do maintainers want to deal with #4 first or should I just work at understanding and copying the approach in #2966327: Limit what can be called by a callback in render arrays to reduce the risk of RCE?

alexpott’s picture

I think #4 can be done separately - if it lands before this then we'll use that approach - if not then this will land and that will have one more place to update.

fathershawn’s picture

Issue summary: View changes
fathershawn’s picture

To invite direction from more experienced core contributors and promote collaboration, I'm going to comment on inconsistencies that I find as I work. Starting with #process simply because it was first.

In testing this refactoring, I encountered function user_form_process_password_confirm($element) {} which is declared as a #process callback in user_element_info_alter(). Now as documented in FormElement a #process callback should expect to receive $element, $form_state, $form. Based on the prior work I expect that we would deprecate user_form_process_password_confirm and I'm moving this logic to a static method on class PasswordConfirm.

In prior work the internals of the deprecated function is replaced with a call to the replacement static method, but if the static method is constructed to conform to the expected signature, we now have too few parameters. But changing the function signature of function user_form_process_password_confirm($element) {} would be a breaking change - so pending other guidance I'm refactoring function user_form_process_password_confirm($element) {} as follows:

function user_form_process_password_confirm($element) {
  // Refactored method expects the full #process parameters.
  $unused_form_state = new FormState();
  $unused_form = [];
  return PasswordConfirm::dynamicPasswordConfirm($element, $unused_form_state, $unused_form);
}

and conforming PasswordConfirm::dynamicPasswordConfirm to the signature expected by FormElement and FormBuilder.

fathershawn’s picture

Issue summary: View changes
alexpott’s picture

@FatherShawn - I think form callbacks are not part of the API so we can add the arguments to user_form_process_password_confirm and pass them along.

fathershawn’s picture

Issue summary: View changes
fathershawn’s picture

First draft of #process pushed up

fathershawn’s picture

First draft of #after_build pushed up

fathershawn’s picture

First draft of #value_callback pushed

alexpott’s picture

@FatherShawn you need to create a merge request for your branch when your tests run. You should get a link to do that when you push.

fathershawn’s picture

I pulled down the drupalci box and am re-running the last test run locally to try to get to the bottom of those last 3 failures before moving on.

fathershawn’s picture

Issue summary: View changes
fathershawn’s picture

Issue summary: View changes
fathershawn’s picture

Issue summary: View changes

Still updating for #validate

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

fathershawn’s picture

Issue summary: View changes

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

stephencamilo’s picture

Status: Active » Closed (won't fix)
greggles’s picture

Status: Closed (won't fix) » Active

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

catch’s picture

Untagging for release manager review - we can copy what we did in the render system issue.

andypost’s picture

While working on related I found that callbacks on PHP 8.0+ could be callables so we need to improve checking anyway for future

fathershawn’s picture

fathershawn’s picture

Issue summary: View changes

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

fathershawn’s picture

Refactoring against the 11.x branch

andypost’s picture

Status: Active » Needs work
fathershawn’s picture

Assigned: Unassigned » fathershawn

Thanks for changing the status @andypost. I’ll switch it when I finish this refactor

fathershawn’s picture

Tests finally passing for #process on 11.x

fathershawn’s picture

Issue summary: View changes

#after_build passed tests.

fathershawn’s picture

I’m looking at this section of code in FormBuilder

      // @todo Once all elements are converted to plugins in
      //   https://www.drupal.org/node/2311393, rely on
      //   $element['#value_callback'] directly.
      $value_callable = !empty($element['#value_callback']) ? $element['#value_callback'] : 'form_type_' . $element['#type'] . '_value';
      if (!is_callable($value_callable)) {
        $value_callable = '\Drupal\Core\Render\Element\FormElement::valueCallback';
      }

The issue #2311393: Remove hook_element_info() and all references to it is long closed with associated change record published 9 years ago. We have no form_type_TYPE_value functions in core now. It seems that this can be simplified and the @todo removed.

larowlan’s picture

@FatherShawn re #46 is that #3221798: Remove stale processing and reference to form_type_TYPE_value, I think I came to the same conclusion a few years back.

larowlan’s picture

fathershawn’s picture

I fixed #3221798: Remove stale processing and reference to form_type_TYPE_value as I was working on #value_callback here before I saw your comment @larowan. Thanks for connecting them! Can we simply close that issue when we close this one?

fathershawn’s picture

Issue summary: View changes
larowlan’s picture

I would try to keep the scope as small as possible to ensure faster progress

fathershawn’s picture

Issue summary: View changes
fathershawn’s picture

Issue summary: View changes
fathershawn’s picture

Issue summary: View changes
fathershawn’s picture

Issue summary: View changes

Removing scope creep

fathershawn’s picture

Thanks for the review and the notes! If they prompt any questions I'll post on the MR - love that we can do that now!

andypost’s picture

RenderCallbackInterface and ElementInterface needs special approach but controllers are fixed in #3354584-35: Deprecate TrustedCallbackInterface in favour of TrustedCallback attribute

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.