1 /* 2 * Copyright (C) 2018, Google LLC. 3 * and other copyright owners as documented in the project's IP log. 4 * 5 * This program and the accompanying materials are made available 6 * under the terms of the Eclipse Distribution License v1.0 which 7 * accompanies this distribution, is reproduced below, and is 8 * available at http://www.eclipse.org/org/documents/edl-v10.php 9 * 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or 13 * without modification, are permitted provided that the following 14 * conditions are met: 15 * 16 * - Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 19 * - Redistributions in binary form must reproduce the above 20 * copyright notice, this list of conditions and the following 21 * disclaimer in the documentation and/or other materials provided 22 * with the distribution. 23 * 24 * - Neither the name of the Eclipse Foundation, Inc. nor the 25 * names of its contributors may be used to endorse or promote 26 * products derived from this software without specific prior 27 * written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 30 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 31 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 32 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 34 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 35 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 38 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 41 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 */ 43 package org.eclipse.jgit.internal.submodule; 44 45 import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PATH; 46 import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_URL; 47 import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_SUBMODULE_SECTION; 48 49 import java.io.IOException; 50 import java.text.MessageFormat; 51 52 import org.eclipse.jgit.errors.ConfigInvalidException; 53 import org.eclipse.jgit.internal.JGitText; 54 import org.eclipse.jgit.lib.Config; 55 56 /** 57 * Validations for the git submodule fields (name, path, uri). 58 * 59 * Invalid values in these fields can cause security problems as reported in 60 * CVE-2018-11235 and and CVE-2018-17456 61 */ 62 public class SubmoduleValidator { 63 64 /** 65 * Error validating a git submodule declaration 66 */ 67 public static class SubmoduleValidationException extends Exception { 68 69 /** 70 * @param message 71 * Description of the problem 72 */ 73 public SubmoduleValidationException(String message) { 74 super(message); 75 } 76 77 private static final long serialVersionUID = 1L; 78 } 79 80 /** 81 * Validate name for a submodule 82 * 83 * @param name 84 * name of a submodule 85 * @throws SubmoduleValidationException 86 * name doesn't seem valid (detail in message) 87 */ 88 public static void assertValidSubmoduleName(String name) 89 throws SubmoduleValidationException { 90 if (name.contains("/../") || name.contains("\\..\\") //$NON-NLS-1$ //$NON-NLS-2$ 91 || name.startsWith("../") || name.startsWith("..\\") //$NON-NLS-1$ //$NON-NLS-2$ 92 || name.endsWith("/..") || name.endsWith("\\..")) { //$NON-NLS-1$ //$NON-NLS-2$ 93 // Submodule names are used to store the submodule repositories 94 // under $GIT_DIR/modules. Having ".." in submodule names makes a 95 // vulnerability (CVE-2018-11235 96 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=535027#c0) 97 // Reject names containing ".." path segments. We don't 98 // automatically replace these characters or canonicalize by 99 // regarding the name as a file path. 100 // Since Path class is platform dependent, we manually check '/' and 101 // '\\' patterns here. 102 throw new SubmoduleValidationException(MessageFormat 103 .format(JGitText.get().invalidNameContainsDotDot, name)); 104 } 105 106 if (name.startsWith("-")) { //$NON-NLS-1$ 107 throw new SubmoduleValidationException( 108 MessageFormat.format( 109 JGitText.get().submoduleNameInvalid, name)); 110 } 111 } 112 113 /** 114 * Validate URI for a submodule 115 * 116 * @param uri 117 * uri of a submodule 118 * @throws SubmoduleValidationException 119 * uri doesn't seem valid 120 */ 121 public static void assertValidSubmoduleUri(String uri) 122 throws SubmoduleValidationException { 123 if (uri.startsWith("-")) { //$NON-NLS-1$ 124 throw new SubmoduleValidationException( 125 MessageFormat.format( 126 JGitText.get().submoduleUrlInvalid, uri)); 127 } 128 } 129 130 /** 131 * Validate path for a submodule 132 * 133 * @param path 134 * path of a submodule 135 * @throws SubmoduleValidationException 136 * path doesn't look right 137 */ 138 public static void assertValidSubmodulePath(String path) 139 throws SubmoduleValidationException { 140 if (path.startsWith("-")) { //$NON-NLS-1$ 141 throw new SubmoduleValidationException( 142 MessageFormat.format( 143 JGitText.get().submodulePathInvalid, path)); 144 } 145 } 146 147 /** 148 * @param gitModulesContents 149 * Contents of a .gitmodule file. They will be parsed internally. 150 * @throws IOException 151 * If the contents 152 */ 153 public static void assertValidGitModulesFile(String gitModulesContents) 154 throws IOException { 155 // Validate .gitmodules file 156 Config c = new Config(); 157 try { 158 c.fromText(gitModulesContents); 159 for (String subsection : 160 c.getSubsections(CONFIG_SUBMODULE_SECTION)) { 161 assertValidSubmoduleName(subsection); 162 163 String url = c.getString( 164 CONFIG_SUBMODULE_SECTION, subsection, CONFIG_KEY_URL); 165 if (url != null) { 166 assertValidSubmoduleUri(url); 167 } 168 169 String path = c.getString( 170 CONFIG_SUBMODULE_SECTION, subsection, CONFIG_KEY_PATH); 171 if (path != null) { 172 assertValidSubmodulePath(path); 173 } 174 } 175 } catch (ConfigInvalidException e) { 176 throw new IOException( 177 MessageFormat.format( 178 JGitText.get().invalidGitModules, 179 e)); 180 } catch (SubmoduleValidationException e) { 181 throw new IOException(e.getMessage(), e); 182 } 183 } 184 }