Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix escaping of $ and reverts old language file format #42463

Closed
wants to merge 6 commits into from

Conversation

dryabov
Copy link
Contributor

@dryabov dryabov commented Dec 4, 2023

The recent change in the language file format (from the "normal" to "raw" parser) in Joomla 4.4.1/5.0.1 resulted in broken backwards compatibility:

  • Escaped backslashes are not handled
  • Multiline values are not supported
  • Single quoted strings are not supported

There are many related discussions and attempts to "fix" new behaviour: #42416 #42425 #42432 #42440 #42441 #42455 #42456

This patch fixes the escaping of the $ character in the Language Override and reverts the old language file format.

For thorough testing, I'd recommend the following steps:

  1. Install 5.0.0 -> install patch -> confirm that no errors occur.
  2. Install 5.0.1 -> install patch -> confirm that no errors occur.
  3. Install 5.0.0 -> create a language override with ${test} substring (invisible in the Languages Overrides after saving) -> install patch -> the substring is visible in the Languages Overrides.
  4. Install 5.0.1 -> create a language override with ${test} substring (visible in the Languages Overrides after saving) -> install patch -> the substring is visible in the Languages Overrides.

PS. But using a raw ini parser (without post-processing language strings) is a good idea, so I have started a feature request discussion (please join): #42462

@brianteeman
Copy link
Contributor

this reverts a security fix

@dryabov
Copy link
Contributor Author

dryabov commented Dec 4, 2023

this reverts a security fix

It provides another solution via proper escaping of saved strings in the Language Override component.

@dryabov
Copy link
Contributor Author

dryabov commented Dec 4, 2023

And a complete transition to the raw parser is proposed for Joomla 6.0, with a description of how to do this correctly by carefully converting language strings to the new format.

@SniperSister
Copy link
Contributor

The current filter does not properly filter overrides while saving the string. Prefixing the dollar in the string with a slash will lead to another slash being added while saving the string, leading to the escaping of the slashes but not of the dollar char.

@dryabov
Copy link
Contributor Author

dryabov commented Dec 5, 2023

Yes, I forgot that addcslashes doesn't escape backslashes automatically. Fixed now.

@SniperSister
Copy link
Contributor

Yes, I forgot that addcslashes doesn't escape backslashes automatically. Fixed now.

Thank you!

I played around with various payloads but was unable to inject a working placeholder - so from my side this solution is ok

@dryabov
Copy link
Contributor Author

dryabov commented Dec 5, 2023

I've just fixed the issue with automatically regenerating language override files on upgrade (to make sure payloads are removed if they exist). So the patch is ready for all kinds of testing.

Use __DEPLOY_VERSION__ instead of a hardcoded value

Co-authored-by: Quy <quy@nomonkeybiz.com>
@dryabov
Copy link
Contributor Author

dryabov commented Dec 27, 2023

@bembelimen What do you think of this patch? JSST has confirmed that this patch fixes the vulnerability that was attempted to be fixed in versions 4.4.1 and 5.0.1. At the same time, this patch fully restores the original language file parser, i.e. all compatibility issues are resolved. Also note that the 5.0.1 patch negatively impacts performance, and some people are now wasting their time creating compatibility workarounds that affect performance even more, so the sooner this patch is merged, the better.

PS. I would also be interested to hear your opinion on the proposal to actually switch to the raw ini parser in the next version of Joomla: #42462.

@wilsonge
Copy link
Contributor

We still need to fix new language overrides being created. Currently this retrospectively fixes all existing language strings only.

Other than that +1 from me

@dryabov
Copy link
Contributor Author

dryabov commented Dec 28, 2023

We still need to fix new language overrides being created. Currently this retrospectively fixes all existing language strings only.

New overrides are fixed by addcslashes($string, '"$\\') (i.e. all $ are properly escaped).

@bembelimen
Copy link
Contributor

Hi @dryabov ,

thank you for your PR. One thing is to consider: what about 3rd party translations of either core or extensions? I think you have to consider them, too.

@dryabov
Copy link
Contributor Author

dryabov commented Dec 29, 2023

One thing is to consider: what about 3rd party translations of either core or extensions? I think you have to consider them, too.

Yes, I discussed it with David Jardin. Installing 3rdparty extensions requires Super Administrator role, so it's not a problem. However Language Overrides requires Administrator role, that's why it was considered a vulnerability.

@bembelimen
Copy link
Contributor

If we get two tests, including the migration step (e.g. screenshots before/after), I'm happy to merge.

@richard67
Copy link
Member

If we get two tests, including the migration step (e.g. screenshots before/after), I'm happy to merge.

Maybe it would be easier to get tests if there were some testing instructions. However, the author has removed all sections related to that which were provided by the pull request template.

@dryabov
Copy link
Contributor Author

dryabov commented Dec 31, 2023

For thorough testing, I'd recommend the following steps:

  1. Install 5.0.0 -> install patch -> confirm that no errors occur.
  2. Install 5.0.1 -> install patch -> confirm that no errors occur.
  3. Install 5.0.0 -> create a language override with ${test} substring (invisible in the Languages Overrides after saving) -> install patch -> the substring is visible in the Languages Overrides.
  4. Install 5.0.1 -> create a language override with ${test} substring (visible in the Languages Overrides after saving) -> install patch -> the substring is visible in the Languages Overrides.

@richard67
Copy link
Member

For thorough testing, I'd recommend the following steps:

1. Install 5.0.0 -> install patch -> confirm that no errors occur.

2. Install 5.0.1 -> install patch -> confirm that no errors occur.

3. Install 5.0.0 -> create a language override with `${test}` substring (invisible in the Languages Overrides after saving) -> install patch -> the substring is visible in the Languages Overrides.

4. Install 5.0.1 -> create a language override with `${test}` substring (visible in the Languages Overrides after saving) -> install patch -> the substring is visible in the Languages Overrides.

@dryabov Could you add that also to the description (initial post) of this PR? Thanks in advance.

@dryabov
Copy link
Contributor Author

dryabov commented Dec 31, 2023

@dryabov Could you add that also to the description (initial post) of this PR? Thanks in advance.

Done.

@bembelimen
Copy link
Contributor

Hello @dryabov ,
we had a very long and heated discussion about your PR in the maintainer team and at the end we decided that we will not change the "RAW mode" of the language file parser because of many reasons. One of the reasons is your issue here, raw mode is the better way and should be the way forward and now after 6 weeks (or 12, as this PR would not make it in the upcoming release), it's easier to just fix the 3rd party extension.

Thank you very much für your idea, code and discussion, really appreciate it.

@bembelimen bembelimen closed this Jan 3, 2024
@dryabov
Copy link
Contributor Author

dryabov commented Jan 3, 2024

Hmm, the RAW mode is only better if it is not accompanied by post-processing, but currently Joomla runs str_replace on an array with a huge number of strings, which is very, very slow. Did you make an estimate of how many language strings are included in Joomla and the most popular extensions before you adopted the original 5.0.1 patch? I thought Joomla was designed with maximum performance in mind....
Another problem is that I now have to add support to JEDChecker to identify strings in the old format that cannot be read by the new parser, which is not so easy. And until then, extension developers don't have the ability to automatically detect a whole class of related errors.

@bembelimen
Copy link
Contributor

Would you look into the str_replace, how we could overcome that problem in an easy way?

@dryabov
Copy link
Contributor Author

dryabov commented Jan 4, 2024

Okay, if this is the final decision, then you have two options:

  1. In addition to de-escaping the double quotes, it's essential to handle \\ and \$ the same way to maintain backwards compatibility (unfortunately, in the case of 5.0.1 patch there is no easy-way to maintain backwards compatibility without str_replace).
  2. Or, write a post in the Joomla News channel about the backwards compatibility break starting with versions 4.4.1 and 5.0.1, because now the \ and $ characters in language files must be encoded differently (without escaping). It's important for all extension developers to review their language files accordingly. In addition, developers of platforms such as Crowdin and similar services should develop the feature to export strings in the new format.

@dryabov
Copy link
Contributor Author

dryabov commented Jan 4, 2024

Would you look into the str_replace, how we could overcome that problem in an easy way?

As far as I know from the PHP sources, using str_replace is the fastest option, because there is a short-circuit check that the substring is actually in the string. An alternative is strtr, but it has no short-circuit check and does not support processing of array of strings, and iterating the array at VM level (i.e. foreach) is obviously much slower. For the same reason, strip(c)slashes functions are not an option. It's also obvious that preg_replace will be even slower because it uses PCRE bytecode instead of pure C code (PCRE has a good JIT compiler, but anyway pure C is faster).

So there is no alternative, and you have a choice between current 5.0.1 code

$strings = str_replace('\"', '"', $strings);

which breaks backwards compatibility by not stripping escaped \ and $, and

$strings = str_replace(
        array('\"', '\$', '\\\\'),
        array('"',  '$',  '\\'),
        $strings);

which at least partially maintains backwards compatibility, but is obviously slower due to the additional replacements.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants