1313#include "gpg-interface.h"
1414#include "trailer.h"
1515
16+ /*
17+ * The limit for formatting directives, which enable the caller to append
18+ * arbitrarily many bytes to the formatted buffer. This includes padding
19+ * and wrapping formatters.
20+ */
21+ #define FORMATTING_LIMIT (16 * 1024)
22+
1623static char * user_format ;
1724static struct cmt_fmt_map {
1825 const char * name ;
@@ -915,7 +922,9 @@ static void strbuf_wrap(struct strbuf *sb, size_t pos,
915922 if (pos )
916923 strbuf_add (& tmp , sb -> buf , pos );
917924 strbuf_add_wrapped_text (& tmp , sb -> buf + pos ,
918- (int ) indent1 , (int ) indent2 , (int ) width );
925+ cast_size_t_to_int (indent1 ),
926+ cast_size_t_to_int (indent2 ),
927+ cast_size_t_to_int (width ));
919928 strbuf_swap (& tmp , sb );
920929 strbuf_release (& tmp );
921930}
@@ -1041,9 +1050,18 @@ static size_t parse_padding_placeholder(const char *placeholder,
10411050 const char * end = start + strcspn (start , ",)" );
10421051 char * next ;
10431052 int width ;
1044- if (!end || end == start )
1053+ if (!* end || end == start )
10451054 return 0 ;
10461055 width = strtol (start , & next , 10 );
1056+
1057+ /*
1058+ * We need to limit the amount of padding, or otherwise this
1059+ * would allow the user to pad the buffer by arbitrarily many
1060+ * bytes and thus cause resource exhaustion.
1061+ */
1062+ if (width < - FORMATTING_LIMIT || width > FORMATTING_LIMIT )
1063+ return 0 ;
1064+
10471065 if (next == start || width == 0 )
10481066 return 0 ;
10491067 if (width < 0 ) {
@@ -1203,6 +1221,16 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
12031221 if (* next != ')' )
12041222 return 0 ;
12051223 }
1224+
1225+ /*
1226+ * We need to limit the format here as it allows the
1227+ * user to prepend arbitrarily many bytes to the buffer
1228+ * when rewrapping.
1229+ */
1230+ if (width > FORMATTING_LIMIT ||
1231+ indent1 > FORMATTING_LIMIT ||
1232+ indent2 > FORMATTING_LIMIT )
1233+ return 0 ;
12061234 rewrap_message_tail (sb , c , width , indent1 , indent2 );
12071235 return end - placeholder + 1 ;
12081236 } else
@@ -1473,19 +1501,21 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
14731501 struct format_commit_context * c )
14741502{
14751503 struct strbuf local_sb = STRBUF_INIT ;
1476- int total_consumed = 0 , len , padding = c -> padding ;
1504+ size_t total_consumed = 0 ;
1505+ int len , padding = c -> padding ;
1506+
14771507 if (padding < 0 ) {
14781508 const char * start = strrchr (sb -> buf , '\n' );
14791509 int occupied ;
14801510 if (!start )
14811511 start = sb -> buf ;
1482- occupied = utf8_strnwidth (start , -1 , 1 );
1512+ occupied = utf8_strnwidth (start , strlen ( start ) , 1 );
14831513 occupied += c -> pretty_ctx -> graph_width ;
14841514 padding = (- padding ) - occupied ;
14851515 }
14861516 while (1 ) {
14871517 int modifier = * placeholder == 'C' ;
1488- int consumed = format_commit_one (& local_sb , placeholder , c );
1518+ size_t consumed = format_commit_one (& local_sb , placeholder , c );
14891519 total_consumed += consumed ;
14901520
14911521 if (!modifier )
@@ -1497,7 +1527,7 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
14971527 placeholder ++ ;
14981528 total_consumed ++ ;
14991529 }
1500- len = utf8_strnwidth (local_sb .buf , -1 , 1 );
1530+ len = utf8_strnwidth (local_sb .buf , local_sb . len , 1 );
15011531
15021532 if (c -> flush_type == flush_left_and_steal ) {
15031533 const char * ch = sb -> buf + sb -> len - 1 ;
@@ -1512,7 +1542,7 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
15121542 if (* ch != 'm' )
15131543 break ;
15141544 p = ch - 1 ;
1515- while (ch - p < 10 && * p != '\033' )
1545+ while (p > sb -> buf && ch - p < 10 && * p != '\033' )
15161546 p -- ;
15171547 if (* p != '\033' ||
15181548 ch + 1 - p != display_mode_esc_sequence_len (p ))
@@ -1551,7 +1581,7 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
15511581 }
15521582 strbuf_addbuf (sb , & local_sb );
15531583 } else {
1554- int sb_len = sb -> len , offset = 0 ;
1584+ size_t sb_len = sb -> len , offset = 0 ;
15551585 if (c -> flush_type == flush_left )
15561586 offset = padding - len ;
15571587 else if (c -> flush_type == flush_both )
@@ -1574,8 +1604,7 @@ static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
15741604 const char * placeholder ,
15751605 void * context )
15761606{
1577- int consumed ;
1578- size_t orig_len ;
1607+ size_t consumed , orig_len ;
15791608 enum {
15801609 NO_MAGIC ,
15811610 ADD_LF_BEFORE_NON_EMPTY ,
@@ -1596,9 +1625,21 @@ static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
15961625 default :
15971626 break ;
15981627 }
1599- if (magic != NO_MAGIC )
1628+ if (magic != NO_MAGIC ) {
16001629 placeholder ++ ;
16011630
1631+ switch (placeholder [0 ]) {
1632+ case 'w' :
1633+ /*
1634+ * `%+w()` cannot ever expand to a non-empty string,
1635+ * and it potentially changes the layout of preceding
1636+ * contents. We're thus not able to handle the magic in
1637+ * this combination and refuse the pattern.
1638+ */
1639+ return 0 ;
1640+ };
1641+ }
1642+
16021643 orig_len = sb -> len ;
16031644 if (((struct format_commit_context * )context )-> flush_type != no_flush )
16041645 consumed = format_and_pad_commit (sb , placeholder , context );
0 commit comments