aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZyX <kp-pav@yandex.ru>2017-04-09 22:02:26 +0300
committerZyX <kp-pav@yandex.ru>2017-04-09 22:02:51 +0300
commitecce981dba367d61be170b535083691dd9c40cd2 (patch)
treec36b55635897530dd91c24399dfeb10f8f814d8b
parent5b4f07ee86194a7c6032991102c96387581029c9 (diff)
downloadrneovim-ecce981dba367d61be170b535083691dd9c40cd2.tar.gz
rneovim-ecce981dba367d61be170b535083691dd9c40cd2.tar.bz2
rneovim-ecce981dba367d61be170b535083691dd9c40cd2.zip
coverity/13687: Do not allow NUL byte in region names
-rw-r--r--src/nvim/spellfile.c51
-rw-r--r--test/functional/spell/spellfile_spec.lua18
2 files changed, 57 insertions, 12 deletions
diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c
index 4909b7b14e..97a82582c0 100644
--- a/src/nvim/spellfile.c
+++ b/src/nvim/spellfile.c
@@ -494,6 +494,41 @@ typedef struct spellinfo_S {
# include "spellfile.c.generated.h"
#endif
+/// Read n bytes from fd to buf, returning on errors
+///
+/// @param[out] buf Buffer to read to, must be at least n bytes long.
+/// @param[in] n Amount of bytes to read.
+/// @param fd FILE* to read from.
+///
+/// @return Allows to proceed if everything is OK, returns SP_TRUNCERROR if
+/// there are not enough bytes, returns SP_OTHERERROR if reading failed.
+#define SPELL_READ_BYTES(buf, n, fd) \
+ do { \
+ const size_t n__SPRB = (n); \
+ FILE *const fd__SPRB = (fd); \
+ char *const buf__SPRB = (buf); \
+ const size_t read_bytes__SPRB = fread(buf__SPRB, 1, n__SPRB, fd__SPRB); \
+ if (read_bytes__SPRB != n__SPRB) { \
+ return feof(fd__SPRB) ? SP_TRUNCERROR : SP_OTHERERROR; \
+ } \
+ } while (0)
+
+/// Like #SPELL_READ_BYTES, but also error out if NUL byte was read
+///
+/// @return Allows to proceed if everything is OK, returns SP_TRUNCERROR if
+/// there are not enough bytes, returns SP_OTHERERROR if reading failed,
+/// returns SP_FORMERROR if read out a NUL byte.
+#define SPELL_READ_NONNUL_BYTES(buf, n, fd) \
+ do { \
+ const size_t n__SPRNB = (n); \
+ FILE *const fd__SPRNB = (fd); \
+ char *const buf__SPRNB = (buf); \
+ SPELL_READ_BYTES(buf__SPRNB, n__SPRNB, fd__SPRNB); \
+ if (memchr(buf__SPRNB, NUL, (size_t)n__SPRNB)) { \
+ return SP_FORMERROR; \
+ } \
+ } while (0)
+
// Load one spell file and store the info into a slang_T.
//
// This is invoked in three ways:
@@ -935,12 +970,10 @@ static char_u *read_cnt_string(FILE *fd, int cnt_bytes, int *cntp)
// Return SP_*ERROR flags.
static int read_region_section(FILE *fd, slang_T *lp, int len)
{
- int i;
-
- if (len > 16)
+ if (len > 16) {
return SP_FORMERROR;
- for (i = 0; i < len; ++i)
- lp->sl_regions[i] = getc(fd); // <regionname>
+ }
+ SPELL_READ_NONNUL_BYTES((char *)lp->sl_regions, (size_t)len, fd);
lp->sl_regions[len] = NUL;
return 0;
}
@@ -1004,13 +1037,7 @@ static int read_prefcond_section(FILE *fd, slang_T *lp)
if (n > 0) {
char buf[MAXWLEN + 1];
buf[0] = '^'; // always match at one position only
- const size_t read_byte = fread(buf + 1, 1, (size_t)n, fd);
- if (read_byte != (size_t)n) {
- return feof(fd) ? SP_TRUNCERROR : SP_OTHERERROR;
- }
- if (memchr(buf + 1, NUL, (size_t)n)) {
- return SP_FORMERROR;
- }
+ SPELL_READ_NONNUL_BYTES(buf + 1, (size_t)n, fd);
buf[n + 1] = NUL;
lp->sl_prefprog[i] = vim_regcomp((char_u *)buf, RE_MAGIC | RE_STRING);
}
diff --git a/test/functional/spell/spellfile_spec.lua b/test/functional/spell/spellfile_spec.lua
index e7ad79c009..4b76077605 100644
--- a/test/functional/spell/spellfile_spec.lua
+++ b/test/functional/spell/spellfile_spec.lua
@@ -58,4 +58,22 @@ describe('spellfile', function()
eq('Vim(set):E759: Format error in spell file',
exc_exec('set spell'))
end)
+ it('errors out when region contains NUL byte', function()
+ meths.set_option('runtimepath', testdir)
+ write_file(testdir .. '/spell/en.ascii.spl',
+ -- ┌ Section identifier (#SN_REGION)
+ -- │ ┌ Section flags (#SNF_REQUIRED or zero)
+ -- │ │ ┌ Section length (4 bytes, MSB first)
+ -- │ │ │
+ spellheader .. '\000\001\000\000\000\008'
+ -- ┌ Regions ┌ End of sections marker
+ .. '01234\00067\255'
+ -- ┌ LWORDTREE tree length (4 bytes)
+ -- │ ┌ KWORDTREE tree length (4 bytes)
+ -- │ │ ┌ PREFIXTREE tree length
+ .. '\000\000\000\000\000\000\000\000\000\000\000\000')
+ meths.set_option('spelllang', 'en')
+ eq('Vim(set):E759: Format error in spell file',
+ exc_exec('set spell'))
+ end)
end)