aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2021-04-25 11:55:01 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2021-04-28 11:29:33 +0200
commit852ffbee341ccbcdb6400ad5cb4688b410e236b5 (patch)
tree387aaa90dcebd1b66b4b79eae1a1b99905f09b74
parentdadd90974639c0b8cb0561eb946746ca2678b5fb (diff)
downloadbusybox-w32-852ffbee341ccbcdb6400ad5cb4688b410e236b5.tar.gz
busybox-w32-852ffbee341ccbcdb6400ad5cb4688b410e236b5.tar.bz2
busybox-w32-852ffbee341ccbcdb6400ad5cb4688b410e236b5.zip
vi: fix buffer overrun; code shrink
It was possible for get_input_line() to store its NUL terminator one character beyond the end of its buffer. Code shrink in colon(): - Certain colon commands can be matched exactly, as any shorter string would be matched earlier, e.g. ':wq' versus ':write'. - Command matching is now case sensitive so there's no need to check for 'N' or 'Q' suffixes. - Rewrite how commands and arguments are split. function old new delta colon 3848 3751 -97 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-97) Total: -97 bytes Signed-off-by: Ron Yorston <rmy@pobox.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--editors/vi.c53
1 files changed, 22 insertions, 31 deletions
diff --git a/editors/vi.c b/editors/vi.c
index dd22eb45b..715961019 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -1191,7 +1191,7 @@ static char *get_input_line(const char *prompt)
1191 write1(prompt); // write out the :, /, or ? prompt 1191 write1(prompt); // write out the :, /, or ? prompt
1192 1192
1193 i = strlen(buf); 1193 i = strlen(buf);
1194 while (i < MAX_INPUT_LEN) { 1194 while (i < MAX_INPUT_LEN - 1) {
1195 c = get_one_char(); 1195 c = get_one_char();
1196 if (c == '\n' || c == '\r' || c == 27) 1196 if (c == '\n' || c == '\r' || c == 27)
1197 break; // this is end of input 1197 break; // this is end of input
@@ -2572,7 +2572,7 @@ static void colon(char *buf)
2572 if (cnt == 0) 2572 if (cnt == 0)
2573 return; 2573 return;
2574 if (strncmp(p, "quit", cnt) == 0 2574 if (strncmp(p, "quit", cnt) == 0
2575 || strncmp(p, "q!", cnt) == 0 2575 || strcmp(p, "q!") == 0
2576 ) { 2576 ) {
2577 if (modified_count && p[1] != '!') { 2577 if (modified_count && p[1] != '!') {
2578 status_line_bold("No write since last change (:%s! overrides)", p); 2578 status_line_bold("No write since last change (:%s! overrides)", p);
@@ -2582,8 +2582,8 @@ static void colon(char *buf)
2582 return; 2582 return;
2583 } 2583 }
2584 if (strncmp(p, "write", cnt) == 0 2584 if (strncmp(p, "write", cnt) == 0
2585 || strncmp(p, "wq", cnt) == 0 2585 || strcmp(p, "wq") == 0
2586 || strncmp(p, "wn", cnt) == 0 2586 || strcmp(p, "wn") == 0
2587 || (p[0] == 'x' && !p[1]) 2587 || (p[0] == 'x' && !p[1])
2588 ) { 2588 ) {
2589 if (modified_count != 0 || p[0] != 'x') { 2589 if (modified_count != 0 || p[0] != 'x') {
@@ -2601,7 +2601,6 @@ static void colon(char *buf)
2601 ); 2601 );
2602 if (p[0] == 'x' 2602 if (p[0] == 'x'
2603 || p[1] == 'q' || p[1] == 'n' 2603 || p[1] == 'q' || p[1] == 'n'
2604 || p[1] == 'Q' || p[1] == 'N'
2605 ) { 2604 ) {
2606 editing = 0; 2605 editing = 0;
2607 } 2606 }
@@ -2621,10 +2620,9 @@ static void colon(char *buf)
2621#else 2620#else
2622 2621
2623 char c, *buf1, *q, *r; 2622 char c, *buf1, *q, *r;
2624 char *fn, cmd[MAX_INPUT_LEN], args[MAX_INPUT_LEN]; 2623 char *fn, cmd[MAX_INPUT_LEN], *cmdend, *args;
2625 int i, l, li, b, e; 2624 int i, l, li, b, e;
2626 int useforce; 2625 int useforce;
2627 char *orig_buf;
2628 2626
2629 // :3154 // if (-e line 3154) goto it else stay put 2627 // :3154 // if (-e line 3154) goto it else stay put
2630 // :4,33w! foo // write a portion of buffer to file "foo" 2628 // :4,33w! foo // write a portion of buffer to file "foo"
@@ -2652,35 +2650,29 @@ static void colon(char *buf)
2652 fn = current_filename; 2650 fn = current_filename;
2653 2651
2654 // look for optional address(es) :. :1 :1,9 :'q,'a :% 2652 // look for optional address(es) :. :1 :1,9 :'q,'a :%
2655 orig_buf = buf; 2653 buf1 = buf;
2656 buf = get_address(buf, &b, &e); 2654 buf = get_address(buf, &b, &e);
2657 if (buf == NULL) { 2655 if (buf == NULL) {
2658 status_line_bold("Bad address: %s", orig_buf); 2656 status_line_bold("Bad address: %s", buf1);
2659 goto ret; 2657 goto ret;
2660 } 2658 }
2661 2659
2662# if ENABLE_FEATURE_VI_SEARCH || ENABLE_FEATURE_ALLOW_EXEC
2663 // remember orig command line
2664 orig_buf = buf;
2665# endif
2666
2667 // get the COMMAND into cmd[] 2660 // get the COMMAND into cmd[]
2661 strcpy(cmd, buf);
2668 buf1 = cmd; 2662 buf1 = cmd;
2669 while (*buf != '\0') { 2663 while (!isspace(*buf1) && *buf1 != '\0') {
2670 if (isspace(*buf)) 2664 buf1++;
2671 break;
2672 *buf1++ = *buf++;
2673 } 2665 }
2674 *buf1 = '\0'; 2666 cmdend = buf1;
2675 // get any ARGuments 2667 // get any ARGuments
2676 while (isblank(*buf)) 2668 while (isblank(*buf1))
2677 buf++; 2669 buf1++;
2678 strcpy(args, buf); 2670 args = buf1;
2671 *cmdend = '\0';
2679 useforce = FALSE; 2672 useforce = FALSE;
2680 buf1 = last_char_is(cmd, '!'); 2673 if (cmdend > cmd && cmdend[-1] == '!') {
2681 if (buf1) {
2682 useforce = TRUE; 2674 useforce = TRUE;
2683 *buf1 = '\0'; // get rid of ! 2675 cmdend[-1] = '\0'; // get rid of !
2684 } 2676 }
2685 // assume the command will want a range, certain commands 2677 // assume the command will want a range, certain commands
2686 // (read, substitute) need to adjust these assumptions 2678 // (read, substitute) need to adjust these assumptions
@@ -2718,7 +2710,7 @@ static void colon(char *buf)
2718 // :!ls run the <cmd> 2710 // :!ls run the <cmd>
2719 go_bottom_and_clear_to_eol(); 2711 go_bottom_and_clear_to_eol();
2720 cookmode(); 2712 cookmode();
2721 retcode = system(orig_buf + 1); // run the cmd 2713 retcode = system(buf + 1); // run the cmd
2722 if (retcode) 2714 if (retcode)
2723 printf("\nshell returned %i\n\n", retcode); 2715 printf("\nshell returned %i\n\n", retcode);
2724 rawmode(); 2716 rawmode();
@@ -2969,8 +2961,8 @@ static void colon(char *buf)
2969 // F points to the "find" pattern 2961 // F points to the "find" pattern
2970 // R points to the "replace" pattern 2962 // R points to the "replace" pattern
2971 // replace the cmd line delimiters "/" with NULs 2963 // replace the cmd line delimiters "/" with NULs
2972 c = orig_buf[1]; // what is the delimiter 2964 c = buf[1]; // what is the delimiter
2973 F = orig_buf + 2; // start of "find" 2965 F = buf + 2; // start of "find"
2974 R = strchr(F, c); // middle delimiter 2966 R = strchr(F, c); // middle delimiter
2975 if (!R) 2967 if (!R)
2976 goto colon_s_fail; 2968 goto colon_s_fail;
@@ -3039,8 +3031,8 @@ static void colon(char *buf)
3039 } else if (strncmp(cmd, "version", i) == 0) { // show software version 3031 } else if (strncmp(cmd, "version", i) == 0) { // show software version
3040 status_line(BB_VER); 3032 status_line(BB_VER);
3041 } else if (strncmp(cmd, "write", i) == 0 // write text to file 3033 } else if (strncmp(cmd, "write", i) == 0 // write text to file
3042 || strncmp(cmd, "wq", i) == 0 3034 || strcmp(cmd, "wq") == 0
3043 || strncmp(cmd, "wn", i) == 0 3035 || strcmp(cmd, "wn") == 0
3044 || (cmd[0] == 'x' && !cmd[1]) 3036 || (cmd[0] == 'x' && !cmd[1])
3045 ) { 3037 ) {
3046 int size; 3038 int size;
@@ -3096,7 +3088,6 @@ static void colon(char *buf)
3096 } 3088 }
3097 if (cmd[0] == 'x' 3089 if (cmd[0] == 'x'
3098 || cmd[1] == 'q' || cmd[1] == 'n' 3090 || cmd[1] == 'q' || cmd[1] == 'n'
3099 || cmd[1] == 'Q' || cmd[1] == 'N'
3100 ) { 3091 ) {
3101 editing = 0; 3092 editing = 0;
3102 } 3093 }