SubmoduleValidator.java

  1. /*
  2.  * Copyright (C) 2018, Google LLC. and others
  3.  *
  4.  * This program and the accompanying materials are made available under the
  5.  * terms of the Eclipse Distribution License v. 1.0 which is available at
  6.  * https://www.eclipse.org/org/documents/edl-v10.php.
  7.  *
  8.  * SPDX-License-Identifier: BSD-3-Clause
  9.  */
  10. package org.eclipse.jgit.internal.submodule;

  11. import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PATH;
  12. import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_URL;
  13. import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_SUBMODULE_SECTION;
  14. import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.GITMODULES_NAME;
  15. import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.GITMODULES_PARSE;
  16. import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.GITMODULES_PATH;
  17. import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.GITMODULES_URL;

  18. import java.text.MessageFormat;

  19. import org.eclipse.jgit.errors.ConfigInvalidException;
  20. import org.eclipse.jgit.internal.JGitText;
  21. import org.eclipse.jgit.lib.Config;
  22. import org.eclipse.jgit.lib.ObjectChecker;

  23. /**
  24.  * Validations for the git submodule fields (name, path, uri).
  25.  *
  26.  * Invalid values in these fields can cause security problems as reported in
  27.  * CVE-2018-11235 and CVE-2018-17456
  28.  */
  29. public class SubmoduleValidator {

  30.     /**
  31.      * Error validating a git submodule declaration
  32.      */
  33.     public static class SubmoduleValidationException extends Exception {

  34.         private static final long serialVersionUID = 1L;

  35.         private final ObjectChecker.ErrorType fsckMessageId;

  36.         /**
  37.          * @param message
  38.          *            Description of the problem
  39.          * @param fsckMessageId
  40.          *            Error identifier, following the git fsck fsck.<msg-id>
  41.          *            format
  42.          */
  43.         SubmoduleValidationException(String message,
  44.                 ObjectChecker.ErrorType fsckMessageId) {
  45.             super(message);
  46.             this.fsckMessageId = fsckMessageId;
  47.         }


  48.         /**
  49.          * @return the error identifier
  50.          */
  51.         public ObjectChecker.ErrorType getFsckMessageId() {
  52.             return fsckMessageId;
  53.         }
  54.     }

  55.     /**
  56.      * Validate name for a submodule
  57.      *
  58.      * @param name
  59.      *            name of a submodule
  60.      * @throws SubmoduleValidationException
  61.      *             name doesn't seem valid (detail in message)
  62.      */
  63.     public static void assertValidSubmoduleName(String name)
  64.             throws SubmoduleValidationException {
  65.         if (name.contains("/../") || name.contains("\\..\\") //$NON-NLS-1$ //$NON-NLS-2$
  66.                 || name.startsWith("../") || name.startsWith("..\\") //$NON-NLS-1$ //$NON-NLS-2$
  67.                 || name.endsWith("/..") || name.endsWith("\\..")) { //$NON-NLS-1$ //$NON-NLS-2$
  68.             // Submodule names are used to store the submodule repositories
  69.             // under $GIT_DIR/modules. Having ".." in submodule names makes a
  70.             // vulnerability (CVE-2018-11235
  71.             // https://bugs.eclipse.org/bugs/show_bug.cgi?id=535027#c0)
  72.             // Reject names containing ".." path segments. We don't
  73.             // automatically replace these characters or canonicalize by
  74.             // regarding the name as a file path.
  75.             // Since Path class is platform dependent, we manually check '/' and
  76.             // '\\' patterns here.
  77.             throw new SubmoduleValidationException(MessageFormat
  78.                     .format(JGitText.get().invalidNameContainsDotDot, name),
  79.                     GITMODULES_NAME);
  80.         }

  81.         if (name.startsWith("-")) { //$NON-NLS-1$
  82.             throw new SubmoduleValidationException(
  83.                     MessageFormat.format(
  84.                             JGitText.get().submoduleNameInvalid, name),
  85.                     GITMODULES_NAME);
  86.         }
  87.     }

  88.     /**
  89.      * Validate URI for a submodule
  90.      *
  91.      * @param uri
  92.      *            uri of a submodule
  93.      * @throws SubmoduleValidationException
  94.      *             uri doesn't seem valid
  95.      */
  96.     public static void assertValidSubmoduleUri(String uri)
  97.             throws SubmoduleValidationException {
  98.         if (uri.startsWith("-")) { //$NON-NLS-1$
  99.             throw new SubmoduleValidationException(
  100.                     MessageFormat.format(
  101.                             JGitText.get().submoduleUrlInvalid, uri),
  102.                     GITMODULES_URL);
  103.         }
  104.     }

  105.     /**
  106.      * Validate path for a submodule
  107.      *
  108.      * @param path
  109.      *            path of a submodule
  110.      * @throws SubmoduleValidationException
  111.      *             path doesn't look right
  112.      */
  113.     public static void assertValidSubmodulePath(String path)
  114.             throws SubmoduleValidationException {
  115.         if (path.startsWith("-")) { //$NON-NLS-1$
  116.             throw new SubmoduleValidationException(
  117.                     MessageFormat.format(
  118.                             JGitText.get().submodulePathInvalid, path),
  119.                     GITMODULES_PATH);
  120.         }
  121.     }

  122.     /**
  123.      * Validate a .gitmodules file
  124.      *
  125.      * @param gitModulesContents
  126.      *            Contents of a .gitmodule file. They will be parsed internally.
  127.      * @throws SubmoduleValidationException
  128.      *             if the contents don't look like a configuration file or field
  129.      *             values are not valid
  130.      */
  131.     public static void assertValidGitModulesFile(String gitModulesContents)
  132.             throws SubmoduleValidationException {
  133.         Config c = new Config();
  134.         try {
  135.             c.fromText(gitModulesContents);
  136.             for (String subsection :
  137.                     c.getSubsections(CONFIG_SUBMODULE_SECTION)) {
  138.                 assertValidSubmoduleName(subsection);

  139.                 String url = c.getString(
  140.                         CONFIG_SUBMODULE_SECTION, subsection, CONFIG_KEY_URL);
  141.                 if (url != null) {
  142.                     assertValidSubmoduleUri(url);
  143.                 }

  144.                 String path = c.getString(
  145.                         CONFIG_SUBMODULE_SECTION, subsection, CONFIG_KEY_PATH);
  146.                 if (path != null) {
  147.                     assertValidSubmodulePath(path);
  148.                 }
  149.             }
  150.         } catch (ConfigInvalidException e) {
  151.             SubmoduleValidationException sve = new SubmoduleValidationException(
  152.                     JGitText.get().invalidGitModules, GITMODULES_PARSE);
  153.             sve.initCause(e);
  154.             throw sve;
  155.         }
  156.     }
  157. }