https://github.com/git/git
Revision 0383bbb9015898cbc79abd7b64316484d7713b44 authored by Jeff King on 30 April 2018, 07:25:25 UTC, committed by Jeff King on 22 May 2018, 03:50:11 UTC
Submodule "names" come from the untrusted .gitmodules file,
but we blindly append them to $GIT_DIR/modules to create our
on-disk repo paths. This means you can do bad things by
putting "../" into the name (among other things).

Let's sanity-check these names to avoid building a path that
can be exploited. There are two main decisions:

  1. What should the allowed syntax be?

     It's tempting to reuse verify_path(), since submodule
     names typically come from in-repo paths. But there are
     two reasons not to:

       a. It's technically more strict than what we need, as
          we really care only about breaking out of the
          $GIT_DIR/modules/ hierarchy.  E.g., having a
          submodule named "foo/.git" isn't actually
          dangerous, and it's possible that somebody has
          manually given such a funny name.

       b. Since we'll eventually use this checking logic in
          fsck to prevent downstream repositories, it should
          be consistent across platforms. Because
          verify_path() relies on is_dir_sep(), it wouldn't
          block "foo\..\bar" on a non-Windows machine.

  2. Where should we enforce it? These days most of the
     .gitmodules reads go through submodule-config.c, so
     I've put it there in the reading step. That should
     cover all of the C code.

     We also construct the name for "git submodule add"
     inside the git-submodule.sh script. This is probably
     not a big deal for security since the name is coming
     from the user anyway, but it would be polite to remind
     them if the name they pick is invalid (and we need to
     expose the name-checker to the shell anyway for our
     test scripts).

     This patch issues a warning when reading .gitmodules
     and just ignores the related config entry completely.
     This will generally end up producing a sensible error,
     as it works the same as a .gitmodules file which is
     missing a submodule entry (so "submodule update" will
     barf, but "git clone --recurse-submodules" will print
     an error but not abort the clone.

     There is one minor oddity, which is that we print the
     warning once per malformed config key (since that's how
     the config subsystem gives us the entries). So in the
     new test, for example, the user would see three
     warnings. That's OK, since the intent is that this case
     should never come up outside of malicious repositories
     (and then it might even benefit the user to see the
     message multiple times).

Credit for finding this vulnerability and the proof of
concept from which the test script was adapted goes to
Etienne Stalmans.

Signed-off-by: Jeff King <peff@peff.net>
1 parent 42e6fde
Raw File
Tip revision: 0383bbb9015898cbc79abd7b64316484d7713b44 authored by Jeff King on 30 April 2018, 07:25:25 UTC
submodule-config: verify submodule names as paths
Tip revision: 0383bbb
graph.h
#ifndef GRAPH_H
#define GRAPH_H
#include "diff.h"

/* A graph is a pointer to this opaque structure */
struct git_graph;

/*
 * Called to setup global display of line_prefix diff option.
 *
 * Passed a diff_options structure which indicates the line_prefix and the
 * file to output the prefix to. This is sort of a hack used so that the
 * line_prefix will be honored by all flows which also honor "--graph"
 * regardless of whether a graph has actually been setup. The normal graph
 * flow will honor the exact diff_options passed, but a NULL graph will cause
 * display of a line_prefix to stdout.
 */
void graph_setup_line_prefix(struct diff_options *diffopt);

/*
 * Set up a custom scheme for column colors.
 *
 * The default column color scheme inserts ANSI color escapes to colorize
 * the graph. The various color escapes are stored in an array of strings
 * where each entry corresponds to a color, except for the last entry,
 * which denotes the escape for resetting the color back to the default.
 * When generating the graph, strings from this array are inserted before
 * and after the various column characters.
 *
 * This function allows you to enable a custom array of color escapes.
 * The 'colors_max' argument is the index of the last "reset" entry.
 *
 * This functions must be called BEFORE graph_init() is called.
 *
 * NOTE: This function isn't used in Git outside graph.c but it is used
 * by CGit (http://git.zx2c4.com/cgit/) to use HTML for colors.
 */
void graph_set_column_colors(const char **colors, unsigned short colors_max);

/*
 * Create a new struct git_graph.
 */
struct git_graph *graph_init(struct rev_info *opt);

/*
 * Update a git_graph with a new commit.
 * This will cause the graph to begin outputting lines for the new commit
 * the next time graph_next_line() is called.
 *
 * If graph_update() is called before graph_is_commit_finished() returns 1,
 * the next call to graph_next_line() will output an ellipsis ("...")
 * to indicate that a portion of the graph is missing.
 */
void graph_update(struct git_graph *graph, struct commit *commit);

/*
 * Determine if a graph has finished outputting lines for the current
 * commit.
 *
 * Returns 1 if graph_next_line() needs to be called again before
 * graph_update() should be called.  Returns 0 if no more lines are needed
 * for this commit.  If 0 is returned, graph_next_line() may still be
 * called without calling graph_update(), and it will merely output
 * appropriate "vertical padding" in the graph.
 */
int graph_is_commit_finished(struct git_graph const *graph);

/*
 * Output the next line for a graph.
 * This formats the next graph line into the specified strbuf.  It is not
 * terminated with a newline.
 *
 * Returns 1 if the line includes the current commit, and 0 otherwise.
 * graph_next_line() will return 1 exactly once for each time
 * graph_update() is called.
 *
 * NOTE: This function isn't used in Git outside graph.c but it is used
 * by CGit (http://git.zx2c4.com/cgit/) to wrap HTML around graph lines.
 */
int graph_next_line(struct git_graph *graph, struct strbuf *sb);


/*
 * Return current width of the graph in on-screen characters.
 */
int graph_width(struct git_graph *graph);

/*
 * graph_show_*: helper functions for printing to stdout
 */


/*
 * If the graph is non-NULL, print the history graph to stdout,
 * up to and including the line containing this commit.
 * Does not print a terminating newline on the last line.
 */
void graph_show_commit(struct git_graph *graph);

/*
 * If the graph is non-NULL, print one line of the history graph to stdout.
 * Does not print a terminating newline on the last line.
 */
void graph_show_oneline(struct git_graph *graph);

/*
 * If the graph is non-NULL, print one line of vertical graph padding to
 * stdout.  Does not print a terminating newline on the last line.
 */
void graph_show_padding(struct git_graph *graph);

/*
 * If the graph is non-NULL, print the rest of the history graph for this
 * commit to stdout.  Does not print a terminating newline on the last line.
 */
int graph_show_remainder(struct git_graph *graph);

/*
 * Print a commit message strbuf and the remainder of the graph to stdout.
 *
 * This is similar to graph_show_strbuf(), but it always prints the
 * remainder of the graph.
 *
 * If the strbuf ends with a newline, the output printed by
 * graph_show_commit_msg() will end with a newline.  If the strbuf is
 * missing a terminating newline (including if it is empty), the output
 * printed by graph_show_commit_msg() will also be missing a terminating
 * newline.
 *
 * Note that unlike some other graph display functions, you must pass the file
 * handle directly. It is assumed that this is the same file handle as the
 * file specified by the graph diff options. This is necessary so that
 * graph_show_commit_msg can be called even with a NULL graph.
 */
void graph_show_commit_msg(struct git_graph *graph,
			   FILE *file,
			   struct strbuf const *sb);

#endif /* GRAPH_H */
back to top