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)
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.
- 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. - Try and provide a PHPCS fix that can auto-update code?
- In 11.0.x remove the ability.
Remaining tasks
- Refactor all the prior refactoring done against 9.2 against 10.3.x using the new attribute.
- 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
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
Comment #4
joachim commentedIt would be nice if this could make use of #2982950: [meta] Standardize the approach for capturing and invoking callables across various subsystems.
Comment #5
samuel.mortensonComment #6
xjmThis one is probably critical.
Comment #8
catchUnless 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.
Comment #9
catchComment #11
fathershawnI 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?
Comment #12
alexpottI 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.
Comment #13
fathershawnComment #14
fathershawnTo 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 inuser_element_info_alter(). Now as documented inFormElementa #process callback should expect to receive $element, $form_state, $form. Based on the prior work I expect that we would deprecateuser_form_process_password_confirmand I'm moving this logic to a static method on classPasswordConfirm.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 refactoringfunction user_form_process_password_confirm($element) {}as follows:and conforming
PasswordConfirm::dynamicPasswordConfirmto the signature expected byFormElementandFormBuilder.Comment #15
fathershawnComment #16
alexpott@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.
Comment #17
fathershawnComment #18
fathershawnFirst draft of #process pushed up
Comment #19
fathershawnFirst draft of #after_build pushed up
Comment #20
fathershawnFirst draft of #value_callback pushed
Comment #21
alexpott@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.
Comment #23
fathershawnI 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.
Comment #24
fathershawnComment #25
fathershawnComment #26
fathershawnStill updating for #validate
Comment #28
fathershawnComment #30
stephencamilo commentedComment #31
gregglesRevert vandalism https://www.drupal.org/project/site_moderators/issues/3276540
Comment #34
catchUntagging for release manager review - we can copy what we did in the render system issue.
Comment #35
andypostWhile working on related I found that callbacks on PHP 8.0+ could be callables so we need to improve checking anyway for future
Comment #36
fathershawnI'm able to get back to this issue after a good while dealing with other things. I'm going to look over the work I did before against 9.2 and update it against 10.1 in light of #3354584: Deprecate TrustedCallbackInterface in favour of TrustedCallback attribute
Comment #37
fathershawnComment #41
fathershawnRefactoring against the 11.x branch
Comment #42
andypostComment #43
fathershawnThanks for changing the status @andypost. I’ll switch it when I finish this refactor
Comment #44
fathershawnTests finally passing for #process on 11.x
Comment #45
fathershawn#after_build passed tests.
Comment #46
fathershawnI’m looking at this section of code in FormBuilder
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.
Comment #47
larowlan@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.
Comment #48
larowlanComment #49
fathershawnI 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?
Comment #50
fathershawnComment #51
larowlanI would try to keep the scope as small as possible to ensure faster progress
Comment #52
fathershawnComment #53
fathershawnComment #54
fathershawnComment #55
fathershawnRemoving scope creep
Comment #56
fathershawnThanks for the review and the notes! If they prompt any questions I'll post on the MR - love that we can do that now!
Comment #57
andypostRenderCallbackInterfaceandElementInterfaceneeds special approach but controllers are fixed in #3354584-35: Deprecate TrustedCallbackInterface in favour of TrustedCallback attribute