tex: prevent buffer overflow after expanding % and # - neatvi - [fork] simple vi-type editor with UTF-8 support
 (HTM) git clone git://src.adamsgaard.dk/neatvi
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
       ---
 (DIR) commit 86745f7e230cc2ceb023cab75ff3105d713bb6d6
 (DIR) parent 3932f52736caa572c60ab3dae7b5302ce361146a
 (HTM) Author: Ali Gholami Rudi <ali@rudi.ir>
       Date:   Fri, 24 Sep 2021 12:27:39 +0330
       
       ex: prevent buffer overflow after expanding % and #
       
       Diffstat:
         M ex.c                                |      59 +++++++++++++++++++------------
       
       1 file changed, 37 insertions(+), 22 deletions(-)
       ---
 (DIR) diff --git a/ex.c b/ex.c
       t@@ -149,7 +149,7 @@ static char *ex_cmd(char *src, char *cmd)
                src = ex_loc(src, cmd);
                while (*src == ' ' || *src == '\t')
                        src++;
       -        while (isalpha((unsigned char) *src))
       +        while (isalpha((unsigned char) *src) && cmd < cmd0 + 16)
                        if ((*cmd++ = *src++) == 'k' && cmd == cmd0 + 1)
                                break;
                if (*src == '!' || *src == '=')
       t@@ -159,35 +159,35 @@ static char *ex_cmd(char *src, char *cmd)
        }
        
        /* read ex file argument */
       -static char *ex_filearg(char *src, char *dst, int spaceallowed)
       +static char *ex_filearg(char *src, int spaceallowed)
        {
       +        struct sbuf *sb = sbuf_make();
                while (*src && *src != '\n' && (spaceallowed || (*src != ' ' && *src != '\t'))) {
                        if (*src == '%') {
                                if (!bufs[0].path || !bufs[0].path[0]) {
                                        ex_show("\"%\" is unset\n");
       +                                sbuf_free(sb);
                                        return NULL;
                                }
       -                        strcpy(dst, bufs[0].path);
       -                        dst = strchr(dst, '\0');
       +                        sbuf_str(sb, bufs[0].path);
                                src++;
                                continue;
                        }
                        if (*src == '#') {
                                if (!bufs[1].path || !bufs[1].path[0]) {
                                        ex_show("\"#\" is unset\n");
       +                                sbuf_free(sb);
                                        return NULL;
                                }
       -                        strcpy(dst, bufs[1].path);
       -                        dst = strchr(dst, '\0');
       +                        sbuf_str(sb, bufs[1].path);
                                src++;
                                continue;
                        }
                        if (*src == '\\' && src[1])
                                src++;
       -                *dst++ = *src++;
       +                sbuf_chr(sb, *src++);
                }
       -        *dst = '\0';
       -        return src;
       +        return sbuf_done(sb);
        }
        
        /* the previous search keyword */
       t@@ -372,17 +372,18 @@ static int ec_edit(char *ec)
                char msg[128];
                char cmd[EXLEN];
                char arg[EXLEN];
       -        char path[EXLEN];
       +        char *path;
                int fd;
                ex_cmd(ec, cmd);
                ex_arg(ec, arg);
       -        if (!ex_filearg(arg, path, 0))
       -                return 1;
                if (!strchr(cmd, '!'))
                        if (xb && ex_modifiedbuffer("buffer modified\n"))
                                return 1;
       +        if (!(path = ex_filearg(arg, 0)))
       +                return 1;
                if (path[0] && bufs_find(path) >= 0) {
                        bufs_switch(bufs_find(path));
       +                free(path);
                        return 0;
                }
                if (path[0] || !bufs[0].path)
       t@@ -403,6 +404,7 @@ static int ec_edit(char *ec)
                xrow = MAX(0, MIN(xrow, lbuf_len(xb) - 1));
                xoff = 0;
                xtop = MAX(0, MIN(xtop, lbuf_len(xb) - 1));
       +        free(path);
                return 0;
        }
        
       t@@ -421,12 +423,13 @@ static int ec_read(char *ec)
                        return 1;
                if (arg[0] == '!') {
                        int pos = MIN(xrow + 1, lbuf_len(xb));
       -                char ecmd[EXLEN * 2];
       -                if (!ex_filearg(arg, ecmd, 1))
       +                char *ecmd = ex_filearg(arg, 1);
       +                if (!ecmd)
                                return 1;
                        obuf = cmd_pipe(ecmd + 1, NULL, 0, 1);
                        if (obuf)
                                lbuf_edit(xb, obuf, pos, pos);
       +                free(ecmd);
                        free(obuf);
                } else {
                        int fd = open(path, O_RDONLY);
       t@@ -469,12 +472,13 @@ static int ec_write(char *ec)
                        end = lbuf_len(xb);
                }
                if (arg[0] == '!') {
       -                char ecmd[EXLEN * 2];
       -                if (!ex_filearg(arg, ecmd, 1))
       +                char *ecmd = ex_filearg(arg, 1);
       +                if (!ecmd)
                                return 1;
                        ibuf = lbuf_cp(xb, beg, end);
                        ex_print(NULL);
                        cmd_pipe(ecmd + 1, ibuf, 1, 0);
       +                free(ecmd);
                        free(ibuf);
                } else {
                        int fd;
       t@@ -751,25 +755,31 @@ static int ec_exec(char *ec)
        {
                char loc[EXLEN];
                char arg[EXLEN];
       -        char ecmd[EXLEN * 2];
                int beg, end;
                char *text;
                char *rep;
       +        char *ecmd;
                ex_modifiedbuffer(NULL);
                ex_loc(ec, loc);
                ex_arg(ec, arg);
       -        if (!ex_filearg(arg, ecmd, 1))
       +        if (!(ecmd = ex_filearg(arg, 1)))
                        return 1;
                if (!loc[0]) {
       +                int ret;
                        ex_print(NULL);
       -                return cmd_exec(ecmd);
       +                ret = cmd_exec(ecmd);
       +                free(ecmd);
       +                return ret;
                }
       -        if (ex_region(loc, &beg, &end))
       +        if (ex_region(loc, &beg, &end)) {
       +                free(ecmd);
                        return 1;
       +        }
                text = lbuf_cp(xb, beg, end);
                rep = cmd_pipe(ecmd, text, 1, 1);
                if (rep)
                        lbuf_edit(xb, rep, beg, end);
       +        free(ecmd);
                free(text);
                free(rep);
                return 0;
       t@@ -779,12 +789,13 @@ static int ec_make(char *ec)
        {
                char arg[EXLEN];
                char make[EXLEN];
       -        char target[EXLEN * 2];
       +        char *target;
                ex_modifiedbuffer(NULL);
                ex_arg(ec, arg);
       -        if (!ex_filearg(arg, target, 0))
       +        if (!(target = ex_filearg(arg, 0)))
                        return 1;
                sprintf(make, "make %s", target);
       +        free(target);
                ex_print(NULL);
                if (cmd_exec(make))
                        return 1;
       t@@ -1049,6 +1060,10 @@ static int ex_exec(char *ln)
                int ret = 0;
                while (*ln) {
                        ex_cmd(ln, cmd);
       +                if (strlen(ln) >= EXLEN) {
       +                        ex_show("command too long");
       +                        return 1;
       +                }
                        ln = ex_line(ln, ec);
                        if ((idx = ex_idx(cmd)) >= 0)
                                ret = excmds[idx].ec(ec);