Skip to content

Commit 19e6c4f

Browse files
chrisbrabrammool
authored andcommitted
patch 9.0.1669: Crash syncing swapfile in new buffer when using sodium crypt
Problem: Crash syncing swapfile in new buffer when using sodium crypt. (James McCoy) Solution: Add checks for sodium encryption. (Christian Brabandt, closes #12591, closes #12585)
1 parent 0256d76 commit 19e6c4f

6 files changed

Lines changed: 72 additions & 14 deletions

File tree

src/crypt.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1267,6 +1267,13 @@ crypt_sodium_buffer_decode(
12671267
}
12681268

12691269
# if defined(FEAT_SODIUM) || defined(PROTO)
1270+
void
1271+
crypt_sodium_lock_key(char_u *key)
1272+
{
1273+
if (sodium_init() >= 0)
1274+
sodium_mlock(key, STRLEN(key));
1275+
}
1276+
12701277
int
12711278
crypt_sodium_munlock(void *const addr, const size_t len)
12721279
{

src/memline.c

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,24 @@ ml_open(buf_T *buf)
424424
}
425425

426426
#if defined(FEAT_CRYPT) || defined(PROTO)
427+
/*
428+
* Swapfile encryption is not supported by XChaCha20. If this crypt method is
429+
* used then disable the swapfile, to avoid plain text being written to disk,
430+
* and return TRUE.
431+
* Otherwise return FALSE.
432+
*/
433+
static int
434+
crypt_may_close_swapfile(buf_T *buf, char_u *key, int method)
435+
{
436+
if (crypt_method_is_sodium(method) && *key != NUL)
437+
{
438+
mf_close_file(buf, TRUE);
439+
buf->b_p_swf = FALSE;
440+
return TRUE;
441+
}
442+
return FALSE;
443+
}
444+
427445
/*
428446
* Prepare encryption for "buf" for the current key and method.
429447
*/
@@ -440,11 +458,10 @@ ml_set_mfp_crypt(buf_T *buf)
440458
// Generate a seed and store it in the memfile.
441459
sha2_seed(buf->b_ml.ml_mfp->mf_seed, MF_SEED_LEN, NULL, 0);
442460
}
443-
#ifdef FEAT_SODIUM
461+
# ifdef FEAT_SODIUM
444462
else if (crypt_method_is_sodium(method_nr))
445-
crypt_sodium_randombytes_buf(buf->b_ml.ml_mfp->mf_seed,
446-
MF_SEED_LEN);
447-
#endif
463+
crypt_sodium_randombytes_buf(buf->b_ml.ml_mfp->mf_seed, MF_SEED_LEN);
464+
# endif
448465
}
449466

450467
/*
@@ -501,16 +518,10 @@ ml_set_crypt_key(
501518
return; // no memfile yet, nothing to do
502519
old_method = crypt_method_nr_from_name(old_cm);
503520

504-
// Swapfile encryption is not supported by XChaCha20, therefore disable the
505-
// swapfile to avoid plain text being written to disk.
506-
if (crypt_method_is_sodium(crypt_get_method_nr(buf))
507-
&& *buf->b_p_key != NUL)
508-
{
509-
// close the swapfile
510-
mf_close_file(buf, TRUE);
511-
buf->b_p_swf = FALSE;
521+
#ifdef FEAT_CRYPT
522+
if (crypt_may_close_swapfile(buf, buf->b_p_key, crypt_get_method_nr(buf)))
512523
return;
513-
}
524+
#endif
514525

515526
// First make sure the swapfile is in a consistent state, using the old
516527
// key and method.
@@ -2494,6 +2505,12 @@ ml_sync_all(int check_file, int check_char)
24942505
|| buf->b_ml.ml_mfp->mf_fd < 0)
24952506
continue; // no file
24962507

2508+
#ifdef FEAT_CRYPT
2509+
if (crypt_may_close_swapfile(buf, buf->b_p_key,
2510+
crypt_get_method_nr(buf)))
2511+
continue;
2512+
#endif
2513+
24972514
ml_flush_line(buf); // flush buffered line
24982515
// flush locked block
24992516
(void)ml_find_line(buf, (linenr_T)0, ML_FLUSH);
@@ -2551,6 +2568,10 @@ ml_preserve(buf_T *buf, int message)
25512568
emsg(_(e_cannot_preserve_there_is_no_swap_file));
25522569
return;
25532570
}
2571+
#ifdef FEAT_CRYPT
2572+
if (crypt_may_close_swapfile(buf, buf->b_p_key, crypt_get_method_nr(buf)))
2573+
return;
2574+
#endif
25542575

25552576
// We only want to stop when interrupted here, not when interrupted
25562577
// before.
@@ -5571,6 +5592,9 @@ ml_crypt_prepare(memfile_T *mfp, off_T offset, int reading)
55715592
if (*key == NUL)
55725593
return NULL;
55735594

5595+
if (crypt_may_close_swapfile(buf, key, method_nr))
5596+
return NULL;
5597+
55745598
if (method_nr == CRYPT_M_ZIP)
55755599
{
55765600
// For PKzip: Append the offset to the key, so that we use a different

src/optionstr.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,6 +1174,10 @@ did_set_cryptkey(optset_T *args)
11741174
*curbuf->b_p_cm == NUL ? p_cm : curbuf->b_p_cm);
11751175
changed_internal();
11761176
}
1177+
# ifdef FEAT_SODIUM
1178+
if (crypt_method_is_sodium(crypt_get_method_nr(curbuf)))
1179+
crypt_sodium_lock_key(args->os_newval.string);
1180+
# endif
11771181

11781182
return NULL;
11791183
}

src/proto/crypt.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ void crypt_check_swapfile_curbuf(void);
2626
void crypt_check_current_method(void);
2727
char_u *crypt_get_key(int store, int twice);
2828
void crypt_append_msg(buf_T *buf);
29+
void crypt_sodium_lock_key(char_u *key);
2930
int crypt_sodium_munlock(void *const addr, const size_t len);
3031
void crypt_sodium_randombytes_buf(void *const buf, const size_t size);
3132
int crypt_sodium_init(void);

src/testdir/test_crypt.vim

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ func Test_crypt_sodium_v2_startup()
105105
exe buf .. 'bwipe!'
106106
call assert_true(filereadable('Xfoo'))
107107

108-
let buf = RunVimInTerminal('--cmd "set ch=3 cm=xchacha20v2 key=foo" Xfoo', #{rows: 10})
108+
let buf = RunVimInTerminal('--cmd "set ch=3 cm=xchacha20v2 key=foo" Xfoo', #{wait_for_ruler: 0, rows: 10})
109109
call g:TermWait(buf, g:RunningWithValgrind() ? 1000 : 50)
110110
call StopVimInTerminal(buf)
111111

@@ -392,4 +392,24 @@ func Test_crypt_set_key_changes_buffer()
392392
call delete('Xtest1.txt')
393393
endfunc
394394

395+
func Test_crypt_set_key_segfault()
396+
CheckFeature sodium
397+
398+
defer delete('Xtest2.txt')
399+
new Xtest2.txt
400+
call setline(1, 'nothing')
401+
set cryptmethod=xchacha20
402+
set key=foobar
403+
w
404+
new Xtest3
405+
put ='other content'
406+
setl modified
407+
sil! preserve
408+
bwipe!
409+
410+
set cryptmethod&
411+
set key=
412+
bwipe!
413+
endfunc
414+
395415
" vim: shiftwidth=2 sts=2 expandtab

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,8 @@ static char *(features[]) =
695695

696696
static int included_patches[] =
697697
{ /* Add new patch number below this line */
698+
/**/
699+
1669,
698700
/**/
699701
1668,
700702
/**/

0 commit comments

Comments
 (0)