timja / jenkins-gh-issues-poc-06-18

0 stars 0 forks source link

[JENKINS-52523] Extended Choice Parameter broken by whitelisting change #9967

Closed timja closed 6 years ago

timja commented 6 years ago

We just went thru a fair amount of effort to switch to Extended Choice Parameters as a replacement for Dynamic Parameters, to get scripted defaults in text-box input  (eg timestamp-derived filenames) while avoiding the security concerns of DP. So we sorta need this working.

Meanwhile I'm playing with the workaround mechanism and hoping to make it work quickly. If not, I'll have to downgrade Jenkins again.

Y'know, you REALLY should have implemented this change first in Warning/Deprecation mode, giving us a switch to turn on hard whitelisting when we had achieved a stable environment under the new rules. Oh well.

Stack trace from a trivial Job which just accepts one value and echoes it back:

java.lang.UnsupportedOperationException: Refusing to marshal com.cwctravel.hudson.plugins.extended_choice_parameter.ExtendedChoiceParameterDefinition for security reasons; see https://jenkins.io/redirect/class-filter/
 at hudson.util.XStream2$BlacklistedTypesConverter.marshal(XStream2.java:543)
 at com.thoughtworks.xstream.core.AbstractReferenceMarshaller.convert(AbstractReferenceMarshaller.java:69)
 at com.thoughtworks.xstream.core.TreeMarshaller.convertAnother(TreeMarshaller.java:58)
 at com.thoughtworks.xstream.core.TreeMarshaller.convertAnother(TreeMarshaller.java:43)
 at com.thoughtworks.xstream.core.AbstractReferenceMarshaller$1.convertAnother(AbstractReferenceMarshaller.java:88)
 at com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter.writeItem(AbstractCollectionConverter.java:64)
 at com.thoughtworks.xstream.converters.collections.CollectionConverter.marshal(CollectionConverter.java:74)
 at com.thoughtworks.xstream.core.AbstractReferenceMarshaller.convert(AbstractReferenceMarshaller.java:69)
 at com.thoughtworks.xstream.core.TreeMarshaller.convertAnother(TreeMarshaller.java:58)
 at com.thoughtworks.xstream.core.AbstractReferenceMarshaller$1.convertAnother(AbstractReferenceMarshaller.java:84)
 at hudson.util.RobustReflectionConverter.marshallField(RobustReflectionConverter.java:265)
 at hudson.util.RobustReflectionConverter$2.writeField(RobustReflectionConverter.java:252)
Caused: java.lang.RuntimeException: Failed to serialize hudson.model.ParametersDefinitionProperty#parameterDefinitions for class hudson.model.ParametersDefinitionProperty
 at hudson.util.RobustReflectionConverter$2.writeField(RobustReflectionConverter.java:256)
 at hudson.util.RobustReflectionConverter$2.visit(RobustReflectionConverter.java:224)
 at com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider.visitSerializableFields(PureJavaReflectionProvider.java:138)
 at hudson.util.RobustReflectionConverter.doMarshal(RobustReflectionConverter.java:209)
 at hudson.util.RobustReflectionConverter.marshal(RobustReflectionConverter.java:150)
 at com.thoughtworks.xstream.core.AbstractReferenceMarshaller.convert(AbstractReferenceMarshaller.java:69)
 at com.thoughtworks.xstream.core.TreeMarshaller.convertAnother(TreeMarshaller.java:58)
 at com.thoughtworks.xstream.core.TreeMarshaller.convertAnother(TreeMarshaller.java:43)
 at com.thoughtworks.xstream.core.AbstractReferenceMarshaller$1.convertAnother(AbstractReferenceMarshaller.java:88)
 at com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter.writeItem(AbstractCollectionConverter.java:64)
 at hudson.util.CopyOnWriteList$ConverterImpl.marshal(CopyOnWriteList.java:187)
 at hudson.util.XStream2$AssociatedConverterImpl.marshal(XStream2.java:461)
 at com.thoughtworks.xstream.core.AbstractReferenceMarshaller.convert(AbstractReferenceMarshaller.java:69)
 at com.thoughtworks.xstream.core.TreeMarshaller.convertAnother(TreeMarshaller.java:58)
 at com.thoughtworks.xstream.core.AbstractReferenceMarshaller$1.convertAnother(AbstractReferenceMarshaller.java:84)
 at hudson.util.RobustReflectionConverter.marshallField(RobustReflectionConverter.java:265)
 at hudson.util.RobustReflectionConverter$2.writeField(RobustReflectionConverter.java:252)
Caused: java.lang.RuntimeException: Failed to serialize hudson.model.Job#properties for class hudson.model.FreeStyleProject
 at hudson.util.RobustReflectionConverter$2.writeField(RobustReflectionConverter.java:256)
 at hudson.util.RobustReflectionConverter$2.visit(RobustReflectionConverter.java:224)
 at com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider.visitSerializableFields(PureJavaReflectionProvider.java:138)
 at hudson.util.RobustReflectionConverter.doMarshal(RobustReflectionConverter.java:209)
 at hudson.util.RobustReflectionConverter.marshal(RobustReflectionConverter.java:150)
 at com.thoughtworks.xstream.core.AbstractReferenceMarshaller.convert(AbstractReferenceMarshaller.java:69)
 at com.thoughtworks.xstream.core.TreeMarshaller.convertAnother(TreeMarshaller.java:58)
 at com.thoughtworks.xstream.core.TreeMarshaller.convertAnother(TreeMarshaller.java:43)
 at com.thoughtworks.xstream.core.TreeMarshaller.start(TreeMarshaller.java:82)
 at com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.marshal(AbstractTreeMarshallingStrategy.java:37)
 at com.thoughtworks.xstream.XStream.marshal(XStream.java:1026)
 at com.thoughtworks.xstream.XStream.marshal(XStream.java:1015)
 at com.thoughtworks.xstream.XStream.toXML(XStream.java:988)
 at hudson.XmlFile.write(XmlFile.java:193)
Caused: java.io.IOException
 at hudson.XmlFile.write(XmlFile.java:200)
 at hudson.model.AbstractItem.save(AbstractItem.java:597)
 at hudson.model.Job.save(Job.java:191)
 at hudson.model.AbstractProject.save(AbstractProject.java:289)
 at hudson.BulkChange.commit(BulkChange.java:98)
 at hudson.model.Job.doConfigSubmit(Job.java:1351)
 at hudson.model.AbstractProject.doConfigSubmit(AbstractProject.java:772)
 at java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:627)
 at org.kohsuke.stapler.Function$MethodFunction.invoke(Function.java:343)
 at org.kohsuke.stapler.interceptor.RequirePOST$Processor.invoke(RequirePOST.java:77)
 at org.kohsuke.stapler.PreInvokeInterceptedFunction.invoke(PreInvokeInterceptedFunction.java:26)
 at org.kohsuke.stapler.Function.bindAndInvoke(Function.java:184)
 at org.kohsuke.stapler.Function.bindAndInvokeAndServeResponse(Function.java:117)
 at org.kohsuke.stapler.MetaClass$1.doDispatch(MetaClass.java:129)
 at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:58)
 at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:715)
 at org.kohsuke.stapler.Stapler.invoke(Stapler.java:845)
 at org.kohsuke.stapler.MetaClass$5.doDispatch(MetaClass.java:248)
 at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:58)
 at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:715)
 at org.kohsuke.stapler.Stapler.invoke(Stapler.java:845)
 at org.kohsuke.stapler.MetaClass$5.doDispatch(MetaClass.java:248)
 at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:58)
 at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:715)
 at org.kohsuke.stapler.Stapler.invoke(Stapler.java:845)
 at org.kohsuke.stapler.Stapler.invoke(Stapler.java:649)
 at org.kohsuke.stapler.Stapler.service(Stapler.java:238)
 at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
 at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:860)
 at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1650)
 at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:154)
 at net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:239)
 at net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:215)
 at net.bull.javamelody.PluginMonitoringFilter.doFilter(PluginMonitoringFilter.java:88)
 at org.jvnet.hudson.plugins.monitoring.HudsonMonitoringFilter.doFilter(HudsonMonitoringFilter.java:114)
 at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:151)
 at hudson.util.PluginServletFilter.doFilter(PluginServletFilter.java:157)
 at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1637)
 at hudson.security.csrf.CrumbFilter.doFilter(CrumbFilter.java:99)
 at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1637)
 at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:84)
 at hudson.security.UnwrapSecurityExceptionFilter.doFilter(UnwrapSecurityExceptionFilter.java:51)
 at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
 at jenkins.security.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:117)
 at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
 at org.acegisecurity.providers.anonymous.AnonymousProcessingFilter.doFilter(AnonymousProcessingFilter.java:125)
 at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
 at org.acegisecurity.ui.rememberme.RememberMeProcessingFilter.doFilter(RememberMeProcessingFilter.java:142)
 at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
 at org.acegisecurity.ui.AbstractProcessingFilter.doFilter(AbstractProcessingFilter.java:271)
 at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
 at jenkins.security.BasicHeaderProcessor.doFilter(BasicHeaderProcessor.java:93)
 at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
 at org.acegisecurity.context.HttpSessionContextIntegrationFilter.doFilter(HttpSessionContextIntegrationFilter.java:249)
 at hudson.security.HttpSessionContextIntegrationFilter2.doFilter(HttpSessionContextIntegrationFilter2.java:67)
 at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
 at hudson.security.ChainedServletFilter.doFilter(ChainedServletFilter.java:90)
 at hudson.security.HudsonFilter.doFilter(HudsonFilter.java:171)
 at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1637)
 at org.kohsuke.stapler.compression.CompressionFilter.doFilter(CompressionFilter.java:49)
 at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1637)
 at hudson.util.CharacterEncodingFilter.doFilter(CharacterEncodingFilter.java:82)
 at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1637)
 at org.kohsuke.stapler.DiagnosticThreadNameFilter.doFilter(DiagnosticThreadNameFilter.java:30)
 at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1637)
 at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:533)
 at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
 at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:524)
 at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
 at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:190)
 at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1595)
 at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:188)
 at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1253)
 at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:168)
 at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:473)
 at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1564)
 at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:166)
 at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1155)
 at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
 at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
 at org.eclipse.jetty.server.Server.handle(Server.java:530)
 at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:347)
 at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:256)
 at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:279)
 at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:102)
 at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:124)
 at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:247)
 at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.produce(EatWhatYouKill.java:140)
 at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:131)
 at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:382)
 at winstone.BoundedExecutorService$1.run(BoundedExecutorService.java:77)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
 at java.lang.Thread.run(Thread.java:748) 

Originally reported by keshlam, imported from: Extended Choice Parameter broken by whitelisting change
  • assignee: vimil
  • status: Closed
  • priority: Major
  • resolution: Cannot Reproduce
  • resolved: 2018-07-16T07:49:52+00:00
  • imported: 2022/01/10
timja commented 6 years ago

keshlam:

It would also have made a huge amount of sense to offer a tool which did a census of the jobs already written, reading them and checking for unserializables, rather than having us discover this only when we try to run. Might also have helped you flush out the issues before releasing.

timja commented 6 years ago

oleg_nenashev:

> It would also have made a huge amount of sense to offer a tool which did a census of the jobs already written, reading them and checking for unserializables, rather than having us discover this only when we try to run. Might also have helped you flush out the issues before releasing.

Do not disagree. We actually have such tool: https://github.com/jenkinsci/plugin-compat-tester . Hundreds of plugins have been tested with it, but we can test only plugins using modern Plugin POM and having proper test automation. Extended choice was briefly tested from what I see, but we had a limited test coverage since the plugin has zero autotests.

The next step to improve testing for us is to adopt Telemetry API in order to get heads up from live instances before the release (https://github.com/jenkinsci/jep/tree/master/jep/308, CC batmat and rtyler).

> java.lang.UnsupportedOperationException: Refusing to marshal com.cwctravel.hudson.plugins.extended_choice_parameter.ExtendedChoiceParameterDefinition for security reasons; 

This is a thing I do not understand. This class is a part of the plugin, and it should be permitted. So something weird is going on. If it happens, most likely the plugin is bundled as a library in another plugin. It could make classloader crazy and finally lead to this issue.

Please provide a full list of plugins you have installed. I also need to know versions of Custom Tools and Extended Choice Parameter plugin versions

 

 

 

timja commented 6 years ago

oleg_nenashev:

> Y'know, you REALLY should have implemented this change first in Warning/Deprecation mode, giving us a switch to turn on hard whitelisting when we had achieved a stable environment under the new rules. Oh well.

Maybe. The concern was that any discovered security issue would have became publicly visible then. So such rollout was an intentional decision, and we did our best to notify users about potential issues.

We have a switch which allows to opt-out from the logic. In your case I am not sure it is going to help, because something seems to go REALLY wrong on the instance

 

timja commented 6 years ago

keshlam:

As far as I know, we're just invoking ExtendedChoiceParameter normally. But we did have to patch the jarfile to fix its rendering of Text Boxes (as shipped it gratutiously limits their width to a specific number of pixels, which is both the wrong approach and far too short for values like paths; we kick it back to 100% and everything is much happier), so if you're keying the approval on jarfile checksums, we're breaking that.

List of currently installed plugins: I'll try to get that to you, but I don't think it's relevant to this specific issue.

timja commented 6 years ago

oleg_nenashev:

keshlam "But we did have to patch the jarfile". If you modified this plugins and added it is JAR, JEP-200 engine will not work. Plugins must be always packaged as HPIs or JPIs, all other use-cases are not supported

timja commented 6 years ago

danielbeck:

Needs to happen with actual unmodified builds of the plugin (even private snapshots) to be relevant. If this is limited to affecting manually put together jars, I wouldn't consider this a problem.

timja commented 6 years ago

keshlam:

The modification is to unpack the product HPI, change one line in a template file, and repack. I can give you a script which applies the change if you want to check whether this is what caused the issue.

For now, I've rolled back to earlier Jenkins.

timja commented 6 years ago

oleg_nenashev:

keshlam a script and the produced HPI would be helpful. Preferably it would be great to have a Docker image which reproduces the issue, or some guidelines about how to reproduce it with the script you provide.

Most likely the HPI is missing some manifest attributes so that ClassFilter logic does not recognize it as a plugin

 

timja commented 6 years ago

keshlam:

#!/bin/bash
#
# Kluge to fix the Extended Choice Parameter.
#
# ECP's "text box" mode, for whatever reason, was hardcoded to use a
# 200-pixel-wide entry box. Using absolute values in HTML rendering
# sizes is almost always wrong; in this case it means the box will
# be about 30 characters wide – painfully small if the parameter
# value is intended to be a path.
#
# Luckily, this can be fixed by changing one text file inside the
# plugin's jar, replacing that "width:200px" with "width:100%".
# This value will use as much space as the parent rendering element
# is willing to give it.
#
# Caveat: Pasting this into Jira may have glitched some line breaks...
#
# Debug trace, if desired
#set -xv######################################################################function restart_server {
  if [ -z $USER ]; then
    USER=${jenkinsUser}
  fi
  if [ -z $PASSWORD ]; then
    PASSWORD=${jenkinsApiToken}
  fi

  if [ -z $USER -o -z $PASSWORD ]; then
    echo "User and/or password not provided. Please restart Jenkins manually to pick up modified jarfile."
{{  else }}
    CRUMB=`curl -s -u ${USER}:${PASSWORD} "${JENKINS_URL}/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,\":\",//crumb)"`
    if [[ ${CRUMB} != "Jenkins-Crumb:"* ]]; then
      echo "Crumb not successfully retrieved; continuing without"
      CRUMB=""
    else
      CRUMB="-H $CRUMB"
    fi

    curl -s -X POST -u $USER:$PASSWORD $CRUMB ${JENKINS_URL}/safeRestart

    if [ $? -eq 0 ]; then
      echo "Restart requested. There will be a delay for quiescance before restart occurs."
    else
       echo "User and password not accepted. Please restart Jenkins manually to pick up modified jarfile."
    fi

  fi
}######################################################################

# Default assumption: success
{{rc=0 }}

# Files to be patched: Jarfile, and path within it
ecpJarfile=$JENKINS_HOME/plugins/extended-choice-parameter/WEB-INF/lib/extended-choice-parameter.jar
textBox="com/cwctravel/hudson/plugins/extended_choice_parameter/ExtendedChoiceParameterDefinition/textboxContent.jelly"
# Get a scratch space
tmpdir=$(mktemp -d)
cd $tmpdir
# Unpack the jarfile for patching
jar xvf $ecpJarfile
rc=$?
if [ $rc -ne 0 ]; then
   echo "Couldn't unpack $ecpJarfile, rc=$rc"
else
  # Check whether this has already been fixed. (We can't count on
  # exit status of sed; it thinks "no match" on a global replace is
  # a successful operation.)
  grep "width:200px" $textBox
  rrc=$?
  if [ $rrc -ne 0 ]; then
    grep "width:100%" $textBox
    rc=$?
    if [ $rc -eq 0 ]; then
   

timja commented 6 years ago

keshlam:

.... Hm. That is assuming a jarfile rather than HPI. OK, I'm willing to believe it's my goof, then. Could have sworn otherwise.

Of course what I really want is to get this trivial change made in the extension officially rather than patching my own copy. I didn't seem to be getting traction on that, though.

timja commented 6 years ago

oleg_nenashev:

keshlam https://github.com/jenkinsci/extended-choice-parameter-plugin does not seem to be actively maintained (vimil please correct me if I am wrong). If you are interested, you can request plugin ownership transfer. https://wiki.jenkins.io/display/JENKINS/Adopt+a+Plugin

 

 

timja commented 6 years ago

keshlam:

Willing to take ownership at least for a while, if vimil has indeed abandoned it.

timja commented 6 years ago

vimil:

Send me a pull request and I can merge the change in.