# HG changeset patch # User Christian Brabandt # Date 1509828304 -3600 # Node ID 8984342ab09e067ec600ee415a8f7839034bd7bf # Parent 89889fea43e001744a51b18ef189d87bb03ce2fc patch 8.0.1263: others can read the swap file if a user is careless commit https://github.com/vim/vim/commit/5a73e0ca54c77e067c3b12ea6f35e3e8681e8cf8 Author: Bram Moolenaar Date: Sat Nov 4 21:35:01 2017 +0100 patch 8.0.1263: others can read the swap file if a user is careless Problem: Others can read the swap file if a user is careless with his primary group. Solution: If the group permission allows for reading but the world permissions doesn't, make sure the group is right. diff --git a/src/Makefile b/src/Makefile --- a/src/Makefile +++ b/src/Makefile @@ -2259,6 +2259,7 @@ test_arglist \ test_stat \ test_statusline \ test_substitute \ + test_swap \ test_syn_attr \ test_syntax \ test_system \ diff --git a/src/fileio.c b/src/fileio.c --- a/src/fileio.c +++ b/src/fileio.c @@ -716,7 +716,29 @@ readfile( /* Set swap file protection bits after creating it. */ if (swap_mode > 0 && curbuf->b_ml.ml_mfp != NULL && curbuf->b_ml.ml_mfp->mf_fname != NULL) - (void)mch_setperm(curbuf->b_ml.ml_mfp->mf_fname, (long)swap_mode); + { + char_u *swap_fname = curbuf->b_ml.ml_mfp->mf_fname; + + /* + * If the group-read bit is set but not the world-read bit, then + * the group must be equal to the group of the original file. If + * we can't make that happen then reset the group-read bit. This + * avoids making the swap file readable to more users when the + * primary group of the user is too permissive. + */ + if ((swap_mode & 044) == 040) + { + stat_T swap_st; + + if (mch_stat((char *)swap_fname, &swap_st) >= 0 + && st.st_gid != swap_st.st_gid + && fchown(curbuf->b_ml.ml_mfp->mf_fd, -1, st.st_gid) + == -1) + swap_mode &= 0600; + } + + (void)mch_setperm(swap_fname, (long)swap_mode); + } #endif } diff --git a/src/testdir/test_swap.vim b/src/testdir/test_swap.vim --- a/src/testdir/test_swap.vim +++ b/src/testdir/test_swap.vim @@ -1,48 +1,82 @@ " Tests for the swap feature -" Tests for 'directory' option. -func Test_swap_directory() +"" Tests for 'directory' option. +"func Test_swap_directory() +" if !has("unix") +" return +" endif +" let content = ['start of testfile', +" \ 'line 2 Abcdefghij', +" \ 'line 3 Abcdefghij', +" \ 'end of testfile'] +" call writefile(content, 'Xtest1') +" +" " '.', swap file in the same directory as file +" set dir=.,~ +" +" " Verify that the swap file doesn't exist in the current directory +" call assert_equal([], glob(".Xtest1*.swp", 1, 1, 1)) +" edit Xtest1 +" let swfname = split(execute("swapname"))[0] +" call assert_equal([swfname], glob(swfname, 1, 1, 1)) +" +" " './dir', swap file in a directory relative to the file +" set dir=./Xtest2,.,~ +" +" call mkdir("Xtest2") +" edit Xtest1 +" call assert_equal([], glob(swfname, 1, 1, 1)) +" let swfname = "Xtest2/Xtest1.swp" +" call assert_equal(swfname, split(execute("swapname"))[0]) +" call assert_equal([swfname], glob("Xtest2/*", 1, 1, 1)) +" +" " 'dir', swap file in directory relative to the current dir +" set dir=Xtest.je,~ +" +" call mkdir("Xtest.je") +" call writefile(content, 'Xtest2/Xtest3') +" edit Xtest2/Xtest3 +" call assert_equal(["Xtest2/Xtest3"], glob("Xtest2/*", 1, 1, 1)) +" let swfname = "Xtest.je/Xtest3.swp" +" call assert_equal(swfname, split(execute("swapname"))[0]) +" call assert_equal([swfname], glob("Xtest.je/*", 1, 1, 1)) +" +" set dir& +" call delete("Xtest1") +" call delete("Xtest2", "rf") +" call delete("Xtest.je", "rf") +"endfunc + +func Test_swap_group() if !has("unix") return endif - let content = ['start of testfile', - \ 'line 2 Abcdefghij', - \ 'line 3 Abcdefghij', - \ 'end of testfile'] - call writefile(content, 'Xtest1') - - " '.', swap file in the same directory as file - set dir=.,~ - - " Verify that the swap file doesn't exist in the current directory - call assert_equal([], glob(".Xtest1*.swp", 1, 1, 1)) - edit Xtest1 - let swfname = split(execute("swapname"))[0] - call assert_equal([swfname], glob(swfname, 1, 1, 1)) - - " './dir', swap file in a directory relative to the file - set dir=./Xtest2,.,~ + let groups = split(system('groups')) + if len(groups) <= 1 + throw 'Skipped: need at least two groups, got ' . groups + endif - call mkdir("Xtest2") - edit Xtest1 - call assert_equal([], glob(swfname, 1, 1, 1)) - let swfname = "Xtest2/Xtest1.swp" - call assert_equal(swfname, split(execute("swapname"))[0]) - call assert_equal([swfname], glob("Xtest2/*", 1, 1, 1)) - - " 'dir', swap file in directory relative to the current dir - set dir=Xtest.je,~ + call delete('Xtest') + split Xtest + call setline(1, 'just some text') + wq + if system('ls -l Xtest') !~ ' ' . groups[0] . ' \d' + throw 'Skipped: test file does not have the first group' + else + silent !chmod 640 Xtest + call system('chgrp ' . groups[1] . ' Xtest') + if system('ls -l Xtest') !~ ' ' . groups[1] . ' \d' + throw 'Skipped: cannot set second group on test file' + else + split Xtest + let swapname = substitute(execute('swapname'), '[[:space:]]', '', 'g') + call assert_match('Xtest', swapname) + " Group of swapfile must now match original file. + call assert_match(' ' . groups[1] . ' \d', system('ls -l ' . swapname)) - call mkdir("Xtest.je") - call writefile(content, 'Xtest2/Xtest3') - edit Xtest2/Xtest3 - call assert_equal(["Xtest2/Xtest3"], glob("Xtest2/*", 1, 1, 1)) - let swfname = "Xtest.je/Xtest3.swp" - call assert_equal(swfname, split(execute("swapname"))[0]) - call assert_equal([swfname], glob("Xtest.je/*", 1, 1, 1)) + bwipe! + endif + endif - set dir& - call delete("Xtest1") - call delete("Xtest2", "rf") - call delete("Xtest.je", "rf") + call delete('Xtest') endfunc diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -762,6 +762,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1263, +/**/ 1262, /**/ 1261,