44 *
55 * Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net>
66 * Copyright © 2020 ANSSI
7- * Copyright © 2020-2021 Microsoft Corporation
7+ * Copyright © 2020-2022 Microsoft Corporation
88 */
99
1010#define _GNU_SOURCE
@@ -371,6 +371,13 @@ TEST_F_FORK(layout1, inval)
371371 ASSERT_EQ (EINVAL , errno );
372372 path_beneath .allowed_access &= ~LANDLOCK_ACCESS_FS_EXECUTE ;
373373
374+ /* Tests with denied-by-default access right. */
375+ path_beneath .allowed_access |= LANDLOCK_ACCESS_FS_REFER ;
376+ ASSERT_EQ (-1 , landlock_add_rule (ruleset_fd , LANDLOCK_RULE_PATH_BENEATH ,
377+ & path_beneath , 0 ));
378+ ASSERT_EQ (EINVAL , errno );
379+ path_beneath .allowed_access &= ~LANDLOCK_ACCESS_FS_REFER ;
380+
374381 /* Test with unknown (64-bits) value. */
375382 path_beneath .allowed_access |= (1ULL << 60 );
376383 ASSERT_EQ (-1 , landlock_add_rule (ruleset_fd , LANDLOCK_RULE_PATH_BENEATH ,
@@ -1826,6 +1833,20 @@ TEST_F_FORK(layout1, link)
18261833 ASSERT_EQ (0 , link (file1_s1d3 , file2_s1d3 ));
18271834}
18281835
1836+ static int test_rename (const char * const oldpath , const char * const newpath )
1837+ {
1838+ if (rename (oldpath , newpath ))
1839+ return errno ;
1840+ return 0 ;
1841+ }
1842+
1843+ static int test_exchange (const char * const oldpath , const char * const newpath )
1844+ {
1845+ if (renameat2 (AT_FDCWD , oldpath , AT_FDCWD , newpath , RENAME_EXCHANGE ))
1846+ return errno ;
1847+ return 0 ;
1848+ }
1849+
18291850TEST_F_FORK (layout1 , rename_file )
18301851{
18311852 const struct rule rules [] = {
@@ -1867,10 +1888,10 @@ TEST_F_FORK(layout1, rename_file)
18671888 * to a different directory (which allows file removal).
18681889 */
18691890 ASSERT_EQ (-1 , rename (file1_s2d1 , file1_s1d3 ));
1870- ASSERT_EQ (EXDEV , errno );
1891+ ASSERT_EQ (EACCES , errno );
18711892 ASSERT_EQ (-1 , renameat2 (AT_FDCWD , file1_s2d1 , AT_FDCWD , file1_s1d3 ,
18721893 RENAME_EXCHANGE ));
1873- ASSERT_EQ (EXDEV , errno );
1894+ ASSERT_EQ (EACCES , errno );
18741895 ASSERT_EQ (-1 , renameat2 (AT_FDCWD , dir_s2d2 , AT_FDCWD , file1_s1d3 ,
18751896 RENAME_EXCHANGE ));
18761897 ASSERT_EQ (EXDEV , errno );
@@ -1894,7 +1915,7 @@ TEST_F_FORK(layout1, rename_file)
18941915 ASSERT_EQ (EXDEV , errno );
18951916 ASSERT_EQ (0 , unlink (file1_s1d3 ));
18961917 ASSERT_EQ (-1 , rename (file1_s2d1 , file1_s1d3 ));
1897- ASSERT_EQ (EXDEV , errno );
1918+ ASSERT_EQ (EACCES , errno );
18981919
18991920 /* Exchanges and renames files with same parent. */
19001921 ASSERT_EQ (0 , renameat2 (AT_FDCWD , file2_s2d3 , AT_FDCWD , file1_s2d3 ,
@@ -2014,6 +2035,115 @@ TEST_F_FORK(layout1, reparent_refer)
20142035 ASSERT_EQ (0 , rename (dir_s1d3 , dir_s2d3 ));
20152036}
20162037
2038+ /* Checks renames beneath dir_s1d1. */
2039+ static void refer_denied_by_default (struct __test_metadata * const _metadata ,
2040+ const struct rule layer1 [],
2041+ const int layer1_err ,
2042+ const struct rule layer2 [])
2043+ {
2044+ int ruleset_fd ;
2045+
2046+ ASSERT_EQ (0 , unlink (file1_s1d2 ));
2047+
2048+ ruleset_fd = create_ruleset (_metadata , layer1 [0 ].access , layer1 );
2049+ ASSERT_LE (0 , ruleset_fd );
2050+ enforce_ruleset (_metadata , ruleset_fd );
2051+ ASSERT_EQ (0 , close (ruleset_fd ));
2052+
2053+ /*
2054+ * If the first layer handles LANDLOCK_ACCESS_FS_REFER (according to
2055+ * layer1_err), then it allows some different-parent renames and links.
2056+ */
2057+ ASSERT_EQ (layer1_err , test_rename (file1_s1d1 , file1_s1d2 ));
2058+ if (layer1_err == 0 )
2059+ ASSERT_EQ (layer1_err , test_rename (file1_s1d2 , file1_s1d1 ));
2060+ ASSERT_EQ (layer1_err , test_exchange (file2_s1d1 , file2_s1d2 ));
2061+ ASSERT_EQ (layer1_err , test_exchange (file2_s1d2 , file2_s1d1 ));
2062+
2063+ ruleset_fd = create_ruleset (_metadata , layer2 [0 ].access , layer2 );
2064+ ASSERT_LE (0 , ruleset_fd );
2065+ enforce_ruleset (_metadata , ruleset_fd );
2066+ ASSERT_EQ (0 , close (ruleset_fd ));
2067+
2068+ /*
2069+ * Now, either the first or the second layer does not handle
2070+ * LANDLOCK_ACCESS_FS_REFER, which means that any different-parent
2071+ * renames and links are denied, thus making the layer handling
2072+ * LANDLOCK_ACCESS_FS_REFER null and void.
2073+ */
2074+ ASSERT_EQ (EXDEV , test_rename (file1_s1d1 , file1_s1d2 ));
2075+ ASSERT_EQ (EXDEV , test_exchange (file2_s1d1 , file2_s1d2 ));
2076+ ASSERT_EQ (EXDEV , test_exchange (file2_s1d2 , file2_s1d1 ));
2077+ }
2078+
2079+ const struct rule layer_dir_s1d1_refer [] = {
2080+ {
2081+ .path = dir_s1d1 ,
2082+ .access = LANDLOCK_ACCESS_FS_REFER ,
2083+ },
2084+ {},
2085+ };
2086+
2087+ const struct rule layer_dir_s1d1_execute [] = {
2088+ {
2089+ /* Matches a parent directory. */
2090+ .path = dir_s1d1 ,
2091+ .access = LANDLOCK_ACCESS_FS_EXECUTE ,
2092+ },
2093+ {},
2094+ };
2095+
2096+ const struct rule layer_dir_s2d1_execute [] = {
2097+ {
2098+ /* Does not match a parent directory. */
2099+ .path = dir_s2d1 ,
2100+ .access = LANDLOCK_ACCESS_FS_EXECUTE ,
2101+ },
2102+ {},
2103+ };
2104+
2105+ /*
2106+ * Tests precedence over renames: denied by default for different parent
2107+ * directories, *with* a rule matching a parent directory, but not directly
2108+ * denying access (with MAKE_REG nor REMOVE).
2109+ */
2110+ TEST_F_FORK (layout1 , refer_denied_by_default1 )
2111+ {
2112+ refer_denied_by_default (_metadata , layer_dir_s1d1_refer , 0 ,
2113+ layer_dir_s1d1_execute );
2114+ }
2115+
2116+ /*
2117+ * Same test but this time turning around the ABI version order: the first
2118+ * layer does not handle LANDLOCK_ACCESS_FS_REFER.
2119+ */
2120+ TEST_F_FORK (layout1 , refer_denied_by_default2 )
2121+ {
2122+ refer_denied_by_default (_metadata , layer_dir_s1d1_execute , EXDEV ,
2123+ layer_dir_s1d1_refer );
2124+ }
2125+
2126+ /*
2127+ * Tests precedence over renames: denied by default for different parent
2128+ * directories, *without* a rule matching a parent directory, but not directly
2129+ * denying access (with MAKE_REG nor REMOVE).
2130+ */
2131+ TEST_F_FORK (layout1 , refer_denied_by_default3 )
2132+ {
2133+ refer_denied_by_default (_metadata , layer_dir_s1d1_refer , 0 ,
2134+ layer_dir_s2d1_execute );
2135+ }
2136+
2137+ /*
2138+ * Same test but this time turning around the ABI version order: the first
2139+ * layer does not handle LANDLOCK_ACCESS_FS_REFER.
2140+ */
2141+ TEST_F_FORK (layout1 , refer_denied_by_default4 )
2142+ {
2143+ refer_denied_by_default (_metadata , layer_dir_s2d1_execute , EXDEV ,
2144+ layer_dir_s1d1_refer );
2145+ }
2146+
20172147TEST_F_FORK (layout1 , reparent_link )
20182148{
20192149 const struct rule layer1 [] = {
@@ -2336,11 +2466,12 @@ TEST_F_FORK(layout1, reparent_exdev_layers_rename1)
23362466 ASSERT_EQ (EXDEV , errno );
23372467
23382468 /*
2339- * However, moving the file2_s1d3 file below dir_s2d3 is allowed
2340- * because it cannot inherit MAKE_REG nor MAKE_DIR rights (which are
2341- * dedicated to directories) .
2469+ * Moving the file2_s1d3 file below dir_s2d3 is denied because the
2470+ * second layer does not handle REFER, which is always denied by
2471+ * default .
23422472 */
2343- ASSERT_EQ (0 , rename (file2_s1d3 , file1_s2d3 ));
2473+ ASSERT_EQ (-1 , rename (file2_s1d3 , file1_s2d3 ));
2474+ ASSERT_EQ (EXDEV , errno );
23442475}
23452476
23462477TEST_F_FORK (layout1 , reparent_exdev_layers_rename2 )
@@ -2373,8 +2504,12 @@ TEST_F_FORK(layout1, reparent_exdev_layers_rename2)
23732504 ASSERT_EQ (EACCES , errno );
23742505 ASSERT_EQ (-1 , rename (file1_s1d1 , file1_s2d3 ));
23752506 ASSERT_EQ (EXDEV , errno );
2376- /* Modify layout! */
2377- ASSERT_EQ (0 , rename (file2_s1d2 , file1_s2d3 ));
2507+ /*
2508+ * Modifying the layout is now denied because the second layer does not
2509+ * handle REFER, which is always denied by default.
2510+ */
2511+ ASSERT_EQ (-1 , rename (file2_s1d2 , file1_s2d3 ));
2512+ ASSERT_EQ (EXDEV , errno );
23782513
23792514 /* Without REFER source, EACCES wins over EXDEV. */
23802515 ASSERT_EQ (-1 , rename (dir_s1d1 , file1_s2d2 ));
0 commit comments