CVE-2013-7330 (published 2014-10-17T15:55Z)

Jenkins before 1.502 allows remote authenticated users to configure an otherwise restricted project via vectors related to post-build actions.

Severity: MEDIUM
CVSS v2 base score: 4.0 (AV:N/AC:L/Au:S/C:N/I:P/A:N)

Weakness information:
cwe_id: CWE-264
cwe_name: Permissions, Privileges, and Access Controls
description: Weaknesses in this category are related to the management of permissions, privileges, and other security features that are used to perform access control.

Fix information:
repo_url: https://github.com/jenkinsci/jenkins
commit_details: repo_url: https://github.com/jenkinsci/jenkins
author: Jesse Glick
author_date: 2013-02-11 16:47:10-05:00
msg: [SECURITY-55]

This patch makes standard post-build action refuse to let you configure a downstream project you cannot currently build.
The one from parameterized-trigger will show an error in the configure screen but still lets you save the configuration; needs an analogous patch to that plugin.
Does not yet protect against POSTing config.xml with the trigger.
(cherry picked from commit 757bc8a53956e6fbab267214e6e0896f03c3c262)

Conflicts:

	core/src/main/java/hudson/model/Descriptor.java
repository: repo_url: https://github.com/jenkinsci/jenkins
repo_name: jenkinsci/jenkins
description: Jenkins automation server
repo_language: Java
owner: jenkinsci
file_changes: filename: AbstractProject.java
change_type: ModificationType.MODIFY
diff: @@ -1914,6 +1914,13 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
         triggers = buildDescribable(req, Trigger.for_(this));
         for (Trigger t : triggers)
             t.start(this,true);
+
+        for (Publisher _t : Descriptor.newInstancesFromHeteroList(req, json, "publisher", Jenkins.getInstance().getExtensionList(BuildTrigger.DescriptorImpl.class))) {
+            BuildTrigger t = (BuildTrigger) _t;
+            for (AbstractProject downstream : t.getChildProjects(this)) {
+                downstream.checkPermission(BUILD);
+            }
+        }
     }
 
     /**

programming_language: Java
filename: Descriptor.java
change_type: ModificationType.MODIFY
diff: @@ -936,7 +936,10 @@ public abstract class Descriptor<T extends Describable<T>> implements Saveable {
             for (Object o : JSONArray.fromObject(formData)) {
                 JSONObject jo = (JSONObject)o;
                 String kind = jo.getString("kind");
-                items.add(find(descriptors,kind).newInstance(req,jo));
+                Descriptor<T> d = find(descriptors, kind);
+                if (d != null) {
+                    items.add(d.newInstance(req, jo));
+                }
             }
         }
 
@@ -946,7 +949,7 @@ public abstract class Descriptor<T extends Describable<T>> implements Saveable {
     /**
      * Finds a descriptor from a collection by its class name.
      */
-    public static <T extends Descriptor> T find(Collection<? extends T> list, String className) {
+    public static @CheckForNull <T extends Descriptor> T find(Collection<? extends T> list, String className) {
         for (T d : list) {
             if(d.getClass().getName().equals(className))
                 return d;
@@ -960,7 +963,7 @@ public abstract class Descriptor<T extends Describable<T>> implements Saveable {
         return null;
     }
 
-    public static Descriptor find(String className) {
+    public static @CheckForNull Descriptor find(String className) {
         return find(Jenkins.getInstance().getExtensionList(Descriptor.class),className);
     }
 

programming_language: Java
filename: BuildTrigger.java
change_type: ModificationType.MODIFY
diff: @@ -319,7 +319,7 @@ public class BuildTrigger extends Recorder implements DependencyDeclarer {
         /**
          * Form validation method.
          */
-        public FormValidation doCheck(@AncestorInPath Item project, @QueryParameter String value ) {
+        public FormValidation doCheck(@AncestorInPath Item project, @QueryParameter String value, @QueryParameter boolean upstream) {
             // Require CONFIGURE permission on this project
             if(!project.hasPermission(Item.CONFIGURE))      return FormValidation.ok();
 
@@ -334,6 +334,9 @@ public class BuildTrigger extends Recorder implements DependencyDeclarer {
                                 AbstractProject.findNearest(projectName,project.getParent()).getRelativeNameFrom(project)));
                     if(!(item instanceof AbstractProject))
                         return FormValidation.error(Messages.BuildTrigger_NotBuildable(projectName));
+                    if (!upstream && !item.hasPermission(Item.BUILD)) {
+                        return FormValidation.error(Messages.BuildTrigger_you_have_no_permission_to_build_(projectName));
+                    }
                     hasProjects = true;
                 }
             }

programming_language: Java
filename: Messages.properties
change_type: ModificationType.MODIFY
diff: @@ -47,6 +47,7 @@ BuildTrigger.NoSuchProject=No such project ''{0}''. Did you mean ''{1}''?
 BuildTrigger.NoProjectSpecified=No project specified
 BuildTrigger.NotBuildable={0} is not buildable
 BuildTrigger.Triggering=Triggering a new build of {0}
+BuildTrigger.you_have_no_permission_to_build_=You have no permission to build {0}
 
 CommandInterpreter.CommandFailed=command execution failed
 CommandInterpreter.UnableToDelete=Unable to delete script file {0}

programming_language: Markdown
filename: config-upstream-pseudo-trigger.jelly
change_type: ModificationType.MODIFY
diff: @@ -38,7 +38,7 @@ THE SOFTWARE.
     <f:entry title="${%Project names}"
              description="${%Multiple projects can be specified like 'abc, def'}">
       <f:textbox name="upstreamProjects" value="${h.getProjectListString(up)}"
-        checkUrl="'descriptorByName/hudson.tasks.BuildTrigger/check?value='+encodeURIComponent(this.value)"
+        checkUrl="'descriptorByName/hudson.tasks.BuildTrigger/check?upstream=true&amp;value='+encodeURIComponent(this.value)"
         autoCompleteField="upstreamProjects"/>
     </f:entry>
   </f:optionalBlock>

programming_language: Markdown