diff options
-rw-r--r-- | src/crypt.c | 7 | ||||
-rw-r--r-- | src/memline.c | 50 | ||||
-rw-r--r-- | src/optionstr.c | 4 | ||||
-rw-r--r-- | src/proto/crypt.pro | 1 | ||||
-rw-r--r-- | src/testdir/test_crypt.vim | 22 | ||||
-rw-r--r-- | src/version.c | 2 |
6 files changed, 72 insertions, 14 deletions
diff --git a/src/crypt.c b/src/crypt.c index daa608ae68..9f0f68a2d4 100644 --- a/src/crypt.c +++ b/src/crypt.c @@ -1267,6 +1267,13 @@ crypt_sodium_buffer_decode( } # if defined(FEAT_SODIUM) || defined(PROTO) + void +crypt_sodium_lock_key(char_u *key) +{ + if (sodium_init() >= 0) + sodium_mlock(key, STRLEN(key)); +} + int crypt_sodium_munlock(void *const addr, const size_t len) { diff --git a/src/memline.c b/src/memline.c index 3483f09ae8..cf2dc8c312 100644 --- a/src/memline.c +++ b/src/memline.c @@ -425,6 +425,24 @@ error: #if defined(FEAT_CRYPT) || defined(PROTO) /* + * Swapfile encryption is not supported by XChaCha20. If this crypt method is + * used then disable the swapfile, to avoid plain text being written to disk, + * and return TRUE. + * Otherwise return FALSE. + */ + static int +crypt_may_close_swapfile(buf_T *buf, char_u *key, int method) +{ + if (crypt_method_is_sodium(method) && *key != NUL) + { + mf_close_file(buf, TRUE); + buf->b_p_swf = FALSE; + return TRUE; + } + return FALSE; +} + +/* * Prepare encryption for "buf" for the current key and method. */ static void @@ -440,11 +458,10 @@ ml_set_mfp_crypt(buf_T *buf) // Generate a seed and store it in the memfile. sha2_seed(buf->b_ml.ml_mfp->mf_seed, MF_SEED_LEN, NULL, 0); } -#ifdef FEAT_SODIUM +# ifdef FEAT_SODIUM else if (crypt_method_is_sodium(method_nr)) - crypt_sodium_randombytes_buf(buf->b_ml.ml_mfp->mf_seed, - MF_SEED_LEN); -#endif + crypt_sodium_randombytes_buf(buf->b_ml.ml_mfp->mf_seed, MF_SEED_LEN); +# endif } /* @@ -501,16 +518,10 @@ ml_set_crypt_key( return; // no memfile yet, nothing to do old_method = crypt_method_nr_from_name(old_cm); - // Swapfile encryption is not supported by XChaCha20, therefore disable the - // swapfile to avoid plain text being written to disk. - if (crypt_method_is_sodium(crypt_get_method_nr(buf)) - && *buf->b_p_key != NUL) - { - // close the swapfile - mf_close_file(buf, TRUE); - buf->b_p_swf = FALSE; +#ifdef FEAT_CRYPT + if (crypt_may_close_swapfile(buf, buf->b_p_key, crypt_get_method_nr(buf))) return; - } +#endif // First make sure the swapfile is in a consistent state, using the old // key and method. @@ -2494,6 +2505,12 @@ ml_sync_all(int check_file, int check_char) || buf->b_ml.ml_mfp->mf_fd < 0) continue; // no file +#ifdef FEAT_CRYPT + if (crypt_may_close_swapfile(buf, buf->b_p_key, + crypt_get_method_nr(buf))) + continue; +#endif + ml_flush_line(buf); // flush buffered line // flush locked block (void)ml_find_line(buf, (linenr_T)0, ML_FLUSH); @@ -2551,6 +2568,10 @@ ml_preserve(buf_T *buf, int message) emsg(_(e_cannot_preserve_there_is_no_swap_file)); return; } +#ifdef FEAT_CRYPT + if (crypt_may_close_swapfile(buf, buf->b_p_key, crypt_get_method_nr(buf))) + return; +#endif // We only want to stop when interrupted here, not when interrupted // before. @@ -5571,6 +5592,9 @@ ml_crypt_prepare(memfile_T *mfp, off_T offset, int reading) if (*key == NUL) return NULL; + if (crypt_may_close_swapfile(buf, key, method_nr)) + return NULL; + if (method_nr == CRYPT_M_ZIP) { // For PKzip: Append the offset to the key, so that we use a different diff --git a/src/optionstr.c b/src/optionstr.c index fa7084c65c..06958aab2c 100644 --- a/src/optionstr.c +++ b/src/optionstr.c @@ -1174,6 +1174,10 @@ did_set_cryptkey(optset_T *args) *curbuf->b_p_cm == NUL ? p_cm : curbuf->b_p_cm); changed_internal(); } +# ifdef FEAT_SODIUM + if (crypt_method_is_sodium(crypt_get_method_nr(curbuf))) + crypt_sodium_lock_key(args->os_newval.string); +# endif return NULL; } diff --git a/src/proto/crypt.pro b/src/proto/crypt.pro index d599238593..e3ef693c72 100644 --- a/src/proto/crypt.pro +++ b/src/proto/crypt.pro @@ -26,6 +26,7 @@ void crypt_check_swapfile_curbuf(void); void crypt_check_current_method(void); char_u *crypt_get_key(int store, int twice); void crypt_append_msg(buf_T *buf); +void crypt_sodium_lock_key(char_u *key); int crypt_sodium_munlock(void *const addr, const size_t len); void crypt_sodium_randombytes_buf(void *const buf, const size_t size); int crypt_sodium_init(void); diff --git a/src/testdir/test_crypt.vim b/src/testdir/test_crypt.vim index cb94c183e4..4ffb7200e2 100644 --- a/src/testdir/test_crypt.vim +++ b/src/testdir/test_crypt.vim @@ -105,7 +105,7 @@ func Test_crypt_sodium_v2_startup() exe buf .. 'bwipe!' call assert_true(filereadable('Xfoo')) - let buf = RunVimInTerminal('--cmd "set ch=3 cm=xchacha20v2 key=foo" Xfoo', #{rows: 10}) + let buf = RunVimInTerminal('--cmd "set ch=3 cm=xchacha20v2 key=foo" Xfoo', #{wait_for_ruler: 0, rows: 10}) call g:TermWait(buf, g:RunningWithValgrind() ? 1000 : 50) call StopVimInTerminal(buf) @@ -392,4 +392,24 @@ func Test_crypt_set_key_changes_buffer() call delete('Xtest1.txt') endfunc +func Test_crypt_set_key_segfault() + CheckFeature sodium + + defer delete('Xtest2.txt') + new Xtest2.txt + call setline(1, 'nothing') + set cryptmethod=xchacha20 + set key=foobar + w + new Xtest3 + put ='other content' + setl modified + sil! preserve + bwipe! + + set cryptmethod& + set key= + bwipe! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index d18ecc1a6a..316649fdd1 100644 --- a/src/version.c +++ b/src/version.c @@ -696,6 +696,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1669, +/**/ 1668, /**/ 1667, |