mirror of
				https://github.com/vim/vim.git
				synced 2025-10-31 09:57:14 -04:00 
			
		
		
		
	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)
			
			
This commit is contained in:
		
				
					committed by
					
						 Bram Moolenaar
						Bram Moolenaar
					
				
			
			
				
	
			
			
			
						parent
						
							0256d76a33
						
					
				
				
					commit
					19e6c4fd2d
				
			| @@ -1267,6 +1267,13 @@ crypt_sodium_buffer_decode( | |||||||
| } | } | ||||||
|  |  | ||||||
| # if defined(FEAT_SODIUM) || defined(PROTO) | # if defined(FEAT_SODIUM) || defined(PROTO) | ||||||
|  |     void | ||||||
|  | crypt_sodium_lock_key(char_u *key) | ||||||
|  | { | ||||||
|  |     if (sodium_init() >= 0) | ||||||
|  | 	sodium_mlock(key, STRLEN(key)); | ||||||
|  | } | ||||||
|  |  | ||||||
|     int |     int | ||||||
| crypt_sodium_munlock(void *const addr, const size_t len) | crypt_sodium_munlock(void *const addr, const size_t len) | ||||||
| { | { | ||||||
|   | |||||||
| @@ -424,6 +424,24 @@ error: | |||||||
| } | } | ||||||
|  |  | ||||||
| #if defined(FEAT_CRYPT) || defined(PROTO) | #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. |  * Prepare encryption for "buf" for the current key and method. | ||||||
|  */ |  */ | ||||||
| @@ -440,11 +458,10 @@ ml_set_mfp_crypt(buf_T *buf) | |||||||
| 	// Generate a seed and store it in the memfile. | 	// Generate a seed and store it in the memfile. | ||||||
| 	sha2_seed(buf->b_ml.ml_mfp->mf_seed, MF_SEED_LEN, NULL, 0); | 	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)) |     else if (crypt_method_is_sodium(method_nr)) | ||||||
| 	crypt_sodium_randombytes_buf(buf->b_ml.ml_mfp->mf_seed, | 	crypt_sodium_randombytes_buf(buf->b_ml.ml_mfp->mf_seed, MF_SEED_LEN); | ||||||
| 		MF_SEED_LEN); | # endif | ||||||
| #endif |  | ||||||
| } | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
| @@ -501,16 +518,10 @@ ml_set_crypt_key( | |||||||
| 	return;  // no memfile yet, nothing to do | 	return;  // no memfile yet, nothing to do | ||||||
|     old_method = crypt_method_nr_from_name(old_cm); |     old_method = crypt_method_nr_from_name(old_cm); | ||||||
|  |  | ||||||
|     // Swapfile encryption is not supported by XChaCha20, therefore disable the | #ifdef FEAT_CRYPT | ||||||
|     // swapfile to avoid plain text being written to disk. |     if (crypt_may_close_swapfile(buf, buf->b_p_key, crypt_get_method_nr(buf))) | ||||||
|     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; |  | ||||||
| 	return; | 	return; | ||||||
|     } | #endif | ||||||
|  |  | ||||||
|     // First make sure the swapfile is in a consistent state, using the old |     // First make sure the swapfile is in a consistent state, using the old | ||||||
|     // key and method. |     // key and method. | ||||||
| @@ -2494,6 +2505,12 @@ ml_sync_all(int check_file, int check_char) | |||||||
| 		|| buf->b_ml.ml_mfp->mf_fd < 0) | 		|| buf->b_ml.ml_mfp->mf_fd < 0) | ||||||
| 	    continue;			    // no file | 	    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 | 	ml_flush_line(buf);		    // flush buffered line | ||||||
| 					    // flush locked block | 					    // flush locked block | ||||||
| 	(void)ml_find_line(buf, (linenr_T)0, ML_FLUSH); | 	(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)); | 	    emsg(_(e_cannot_preserve_there_is_no_swap_file)); | ||||||
| 	return; | 	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 |     // We only want to stop when interrupted here, not when interrupted | ||||||
|     // before. |     // before. | ||||||
| @@ -5571,6 +5592,9 @@ ml_crypt_prepare(memfile_T *mfp, off_T offset, int reading) | |||||||
|     if (*key == NUL) |     if (*key == NUL) | ||||||
| 	return NULL; | 	return NULL; | ||||||
|  |  | ||||||
|  |     if (crypt_may_close_swapfile(buf, key, method_nr)) | ||||||
|  | 	return NULL; | ||||||
|  |  | ||||||
|     if (method_nr == CRYPT_M_ZIP) |     if (method_nr == CRYPT_M_ZIP) | ||||||
|     { |     { | ||||||
| 	// For PKzip: Append the offset to the key, so that we use a different | 	// For PKzip: Append the offset to the key, so that we use a different | ||||||
|   | |||||||
| @@ -1174,6 +1174,10 @@ did_set_cryptkey(optset_T *args) | |||||||
| 		*curbuf->b_p_cm == NUL ? p_cm : curbuf->b_p_cm); | 		*curbuf->b_p_cm == NUL ? p_cm : curbuf->b_p_cm); | ||||||
| 	changed_internal(); | 	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; |     return NULL; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -26,6 +26,7 @@ void crypt_check_swapfile_curbuf(void); | |||||||
| void crypt_check_current_method(void); | void crypt_check_current_method(void); | ||||||
| char_u *crypt_get_key(int store, int twice); | char_u *crypt_get_key(int store, int twice); | ||||||
| void crypt_append_msg(buf_T *buf); | 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); | int crypt_sodium_munlock(void *const addr, const size_t len); | ||||||
| void crypt_sodium_randombytes_buf(void *const buf, const size_t size); | void crypt_sodium_randombytes_buf(void *const buf, const size_t size); | ||||||
| int crypt_sodium_init(void); | int crypt_sodium_init(void); | ||||||
|   | |||||||
| @@ -105,7 +105,7 @@ func Test_crypt_sodium_v2_startup() | |||||||
|   exe buf .. 'bwipe!' |   exe buf .. 'bwipe!' | ||||||
|   call assert_true(filereadable('Xfoo')) |   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 g:TermWait(buf, g:RunningWithValgrind() ? 1000 : 50) | ||||||
|   call StopVimInTerminal(buf) |   call StopVimInTerminal(buf) | ||||||
|  |  | ||||||
| @@ -392,4 +392,24 @@ func Test_crypt_set_key_changes_buffer() | |||||||
|   call delete('Xtest1.txt') |   call delete('Xtest1.txt') | ||||||
| endfunc | 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 | " vim: shiftwidth=2 sts=2 expandtab | ||||||
|   | |||||||
| @@ -695,6 +695,8 @@ static char *(features[]) = | |||||||
|  |  | ||||||
| static int included_patches[] = | static int included_patches[] = | ||||||
| {   /* Add new patch number below this line */ | {   /* Add new patch number below this line */ | ||||||
|  | /**/ | ||||||
|  |     1669, | ||||||
| /**/ | /**/ | ||||||
|     1668, |     1668, | ||||||
| /**/ | /**/ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user