]> git.ipfire.org Git - thirdparty/git.git/blobdiff - pretty.c
Merge branch 'maint-2.34' into maint-2.35
[thirdparty/git.git] / pretty.c
index ee6114e3f0aa1dcf8737794bbe8dc8f6e23f5f7b..29579f89b759c197f4bd8a4bad43920404ed72d7 100644 (file)
--- a/pretty.c
+++ b/pretty.c
 #include "trailer.h"
 #include "run-command.h"
 
+/*
+ * The limit for formatting directives, which enable the caller to append
+ * arbitrarily many bytes to the formatted buffer. This includes padding
+ * and wrapping formatters.
+ */
+#define FORMATTING_LIMIT (16 * 1024)
+
 static char *user_format;
 static struct cmt_fmt_map {
        const char *name;
@@ -983,7 +990,9 @@ static void strbuf_wrap(struct strbuf *sb, size_t pos,
        if (pos)
                strbuf_add(&tmp, sb->buf, pos);
        strbuf_add_wrapped_text(&tmp, sb->buf + pos,
-                               (int) indent1, (int) indent2, (int) width);
+                               cast_size_t_to_int(indent1),
+                               cast_size_t_to_int(indent2),
+                               cast_size_t_to_int(width));
        strbuf_swap(&tmp, sb);
        strbuf_release(&tmp);
 }
@@ -1109,9 +1118,18 @@ static size_t parse_padding_placeholder(const char *placeholder,
                const char *end = start + strcspn(start, ",)");
                char *next;
                int width;
-               if (!end || end == start)
+               if (!*end || end == start)
                        return 0;
                width = strtol(start, &next, 10);
+
+               /*
+                * We need to limit the amount of padding, or otherwise this
+                * would allow the user to pad the buffer by arbitrarily many
+                * bytes and thus cause resource exhaustion.
+                */
+               if (width < -FORMATTING_LIMIT || width > FORMATTING_LIMIT)
+                       return 0;
+
                if (next == start || width == 0)
                        return 0;
                if (width < 0) {
@@ -1394,6 +1412,16 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
                                if (*next != ')')
                                        return 0;
                        }
+
+                       /*
+                        * We need to limit the format here as it allows the
+                        * user to prepend arbitrarily many bytes to the buffer
+                        * when rewrapping.
+                        */
+                       if (width > FORMATTING_LIMIT ||
+                           indent1 > FORMATTING_LIMIT ||
+                           indent2 > FORMATTING_LIMIT)
+                               return 0;
                        rewrap_message_tail(sb, c, width, indent1, indent2);
                        return end - placeholder + 1;
                } else
@@ -1675,19 +1703,21 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
                                    struct format_commit_context *c)
 {
        struct strbuf local_sb = STRBUF_INIT;
-       int total_consumed = 0, len, padding = c->padding;
+       size_t total_consumed = 0;
+       int len, padding = c->padding;
+
        if (padding < 0) {
                const char *start = strrchr(sb->buf, '\n');
                int occupied;
                if (!start)
                        start = sb->buf;
-               occupied = utf8_strnwidth(start, -1, 1);
+               occupied = utf8_strnwidth(start, strlen(start), 1);
                occupied += c->pretty_ctx->graph_width;
                padding = (-padding) - occupied;
        }
        while (1) {
                int modifier = *placeholder == 'C';
-               int consumed = format_commit_one(&local_sb, placeholder, c);
+               size_t consumed = format_commit_one(&local_sb, placeholder, c);
                total_consumed += consumed;
 
                if (!modifier)
@@ -1699,7 +1729,7 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
                placeholder++;
                total_consumed++;
        }
-       len = utf8_strnwidth(local_sb.buf, -1, 1);
+       len = utf8_strnwidth(local_sb.buf, local_sb.len, 1);
 
        if (c->flush_type == flush_left_and_steal) {
                const char *ch = sb->buf + sb->len - 1;
@@ -1714,7 +1744,7 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
                        if (*ch != 'm')
                                break;
                        p = ch - 1;
-                       while (ch - p < 10 && *p != '\033')
+                       while (p > sb->buf && ch - p < 10 && *p != '\033')
                                p--;
                        if (*p != '\033' ||
                            ch + 1 - p != display_mode_esc_sequence_len(p))
@@ -1753,7 +1783,7 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
                }
                strbuf_addbuf(sb, &local_sb);
        } else {
-               int sb_len = sb->len, offset = 0;
+               size_t sb_len = sb->len, offset = 0;
                if (c->flush_type == flush_left)
                        offset = padding - len;
                else if (c->flush_type == flush_both)
@@ -1776,8 +1806,7 @@ static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
                                 const char *placeholder,
                                 void *context)
 {
-       int consumed;
-       size_t orig_len;
+       size_t consumed, orig_len;
        enum {
                NO_MAGIC,
                ADD_LF_BEFORE_NON_EMPTY,
@@ -1798,9 +1827,21 @@ static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
        default:
                break;
        }
-       if (magic != NO_MAGIC)
+       if (magic != NO_MAGIC) {
                placeholder++;
 
+               switch (placeholder[0]) {
+               case 'w':
+                       /*
+                        * `%+w()` cannot ever expand to a non-empty string,
+                        * and it potentially changes the layout of preceding
+                        * contents. We're thus not able to handle the magic in
+                        * this combination and refuse the pattern.
+                        */
+                       return 0;
+               };
+       }
+
        orig_len = sb->len;
        if (((struct format_commit_context *)context)->flush_type != no_flush)
                consumed = format_and_pad_commit(sb, placeholder, context);