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

Large files can throw YAMLException due to node limits #23096

Closed
Dav1dde opened this issue Aug 26, 2020 · 5 comments
Closed

Large files can throw YAMLException due to node limits #23096

Dav1dde opened this issue Aug 26, 2020 · 5 comments
Labels
type: regression A regression from a previous release
Milestone

Comments

@Dav1dde
Copy link
Contributor

Dav1dde commented Aug 26, 2020

When using a lot of references to nodes in the application.yaml the parser fails with the error: Number of aliases for non-scalar nodes exceeds the specified max=50.

This happens because in org.springframework.boot.env.OriginTrackedYamlLoader#createYaml a new org.yaml.snakeyaml.LoaderOptions object is created, which has per default an upper limit of 50, because of Billion laugh attacks.

This limit is new with either Spring Boot 2.2 or 2.3, it did not exist (at least wasn't that low) in 2.1.

There is also no way for a user to increase the limit.

In my opinion application.yaml files can be considered trusted and the limit should be severely increased or disabled. I can make a Pull Request for this, but I am not sure what your preferred solution is.

Full Exception:

java.lang.IllegalStateException: Failed to load property source from 'jar:file:/opt/svn/mainframe-application-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/application-defaults.yaml' (classpath:/application-defaults.yaml) for profile defaults
	at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.load(ConfigFileApplicationListener.java:554)
	at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.loadForFileExtension(ConfigFileApplicationListener.java:488)
	at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.load(ConfigFileApplicationListener.java:469)
	at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.lambda$null$7(ConfigFileApplicationListener.java:448)
	at java.base/java.lang.Iterable.forEach(Iterable.java:75)
	at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.lambda$load$8(ConfigFileApplicationListener.java:448)
	at java.base/java.lang.Iterable.forEach(Iterable.java:75)
	at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.load(ConfigFileApplicationListener.java:445)
	at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.lambda$load$0(ConfigFileApplicationListener.java:348)
	at org.springframework.boot.context.config.FilteredPropertySource.apply(FilteredPropertySource.java:54)
	at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.load(ConfigFileApplicationListener.java:336)
	at org.springframework.boot.context.config.ConfigFileApplicationListener.addPropertySources(ConfigFileApplicationListener.java:226)
	at org.springframework.boot.context.config.ConfigFileApplicationListener.postProcessEnvironment(ConfigFileApplicationListener.java:210)
	at org.springframework.boot.context.config.ConfigFileApplicationListener.onApplicationEnvironmentPreparedEvent(ConfigFileApplicationListener.java:200)
	at org.springframework.boot.context.config.ConfigFileApplicationListener.onApplicationEvent(ConfigFileApplicationListener.java:188)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:127)
	at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:80)
	at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:53)
	at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:345)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:308)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1237)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
	at nwi.svn.mainframe.application.SvnMainframeApplication.main(SvnMainframeApplication.java:9)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
	at org.springframework.boot.loader.Launcher.launch(Launcher.java:109)
	at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
	at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88)
Caused by: org.yaml.snakeyaml.error.YAMLException: Number of aliases for non-scalar nodes exceeds the specified max=50
	at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java:147)
	at org.yaml.snakeyaml.composer.Composer.composeValueNode(Composer.java:257)
	at org.yaml.snakeyaml.composer.Composer.composeMappingChildren(Composer.java:248)
	at org.yaml.snakeyaml.composer.Composer.composeMappingNode(Composer.java:236)
	at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java:162)
	at org.yaml.snakeyaml.composer.Composer.composeSequenceNode(Composer.java:209)
	at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java:160)
	at org.yaml.snakeyaml.composer.Composer.composeValueNode(Composer.java:257)
	at org.yaml.snakeyaml.composer.Composer.composeMappingChildren(Composer.java:248)
	at org.yaml.snakeyaml.composer.Composer.composeMappingNode(Composer.java:236)
	at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java:162)
	at org.yaml.snakeyaml.composer.Composer.composeValueNode(Composer.java:257)
	at org.yaml.snakeyaml.composer.Composer.composeMappingChildren(Composer.java:248)
	at org.yaml.snakeyaml.composer.Composer.composeMappingNode(Composer.java:236)
	at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java:162)
	at org.yaml.snakeyaml.composer.Composer.getNode(Composer.java:95)
	at org.yaml.snakeyaml.constructor.BaseConstructor.getData(BaseConstructor.java:134)
	at org.yaml.snakeyaml.Yaml$1.next(Yaml.java:494)
	at org.springframework.beans.factory.config.YamlProcessor.process(YamlProcessor.java:200)
	at org.springframework.beans.factory.config.YamlProcessor.process(YamlProcessor.java:164)
	at org.springframework.boot.env.OriginTrackedYamlLoader.load(OriginTrackedYamlLoader.java:76)
	at org.springframework.boot.env.YamlPropertySourceLoader.load(YamlPropertySourceLoader.java:50)
	at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.loadDocuments(ConfigFileApplicationListener.java:608)
	at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.load(ConfigFileApplicationListener.java:524)
	... 33 common frames omitted
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Aug 26, 2020
@philwebb philwebb added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged labels Aug 27, 2020
@philwebb philwebb added this to the 2.2.x milestone Aug 27, 2020
@wilkinsona
Copy link
Member

The limit of 50 was introduced in SnakeYAML 1.26. We upgraded to 1.26 in 2.3.

@wilkinsona wilkinsona modified the milestones: 2.2.x, 2.3.x Aug 27, 2020
@Dav1dde
Copy link
Contributor Author

Dav1dde commented Aug 27, 2020

Ah this was discussed in #20366 - The way described to upgrade snakeyaml can also be used to downgrade it again.

I haven't tried it, since I already rewrote the configuration, but I assume this works for anyone coming across the issue.

@leonard84
Copy link
Contributor

I would suggest to configure the LoaderOptions used for configuration parsing to allow Integer.MAX_VALUE for maxAliasesForCollections and set allowRecursiveKeys to true.

As already pointed out in #20366

Spring Boot uses SnakeYaml to parse the application configuration - so by default, no untrusted input is fed to the parser.

And I would argue that when an attacker controls your configuration files, that he can do much worse things than the billion laughs attack.

With the current settings you get another type of DOS, as you application simply won't start if you have more than 50 aliases.

And as those LoaderOptions are local to configuration parsing those settings should not negatively affect potential other yaml parser instances.

@philwebb philwebb changed the title YAML Limit on references for repeated nodes Larege files can throw YAMLException due to node limits Aug 31, 2020
@philwebb philwebb added type: regression A regression from a previous release and removed type: bug A general bug labels Aug 31, 2020
@philwebb philwebb changed the title Larege files can throw YAMLException due to node limits Large files can throw YAMLException due to node limits Aug 31, 2020
@philwebb philwebb modified the milestones: 2.3.x, 2.3.4 Aug 31, 2020
@bencalegari
Copy link

We still encountered the same exception when attempting to upgrade from 2.2.6 to 2.3.4, so it appears that this isn't fully resolved:

Caused by: org.yaml.snakeyaml.error.YAMLException: Number of aliases for non-scalar nodes exceeds the specified max=50
	at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java:147)

Downgrading the version of snakeyaml to 1.25 as suggested above now fails as well since these functions in OriginTrackedYamlLoader no longer exist:

loaderOptions.setMaxAliasesForCollections(Integer.MAX_VALUE);
loaderOptions.setAllowRecursiveKeys(true);

Resulting in:

java.lang.NoSuchMethodError: 'void org.yaml.snakeyaml.LoaderOptions.setMaxAliasesForCollections(int)'
	at org.springframework.boot.env.OriginTrackedYamlLoader.createYaml(OriginTrackedYamlLoader.java:67)

Let us know if you need more information to recreate this.

@philwebb
Copy link
Member

philwebb commented Oct 6, 2020

@bencalegari Could you please open a new issue for this. If you have time to create a sample that shows the problem, that would be very helpful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: regression A regression from a previous release
Projects
None yet
Development

No branches or pull requests

6 participants