[PATCH v1 06/11] landlock: Add support for file reparenting with LANDLOCK_ACCESS_FS_REFER

kernel test robot lkp at intel.com
Tue Feb 22 03:16:32 UTC 2022


Hi "Mickaël,

I love your patch! Yet something to improve:

[auto build test ERROR on cfb92440ee71adcc2105b0890bb01ac3cddb8507]

url:    https://github.com/0day-ci/linux/commits/Micka-l-Sala-n/Landlock-file-linking-and-renaming-support/20220222-051842
base:   cfb92440ee71adcc2105b0890bb01ac3cddb8507
config: hexagon-randconfig-r002-20220221 (https://download.01.org/0day-ci/archive/20220222/202202221149.qLO9DEqo-lkp@intel.com/config)
compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project d271fc04d5b97b12e6b797c6067d3c96a8d7470e)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/c68b879f54d6262963d435a18cedbc238b7faeaf
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Micka-l-Sala-n/Landlock-file-linking-and-renaming-support/20220222-051842
        git checkout c68b879f54d6262963d435a18cedbc238b7faeaf
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=hexagon SHELL=/bin/bash

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp at intel.com>

All errors (new ones prefixed by >>):

>> security/landlock/fs.c:463:2: error: call to __compiletime_assert_228 declared with 'error' attribute: BUILD_BUG_ON failed: !layer_masks_dst_parent
           BUILD_BUG_ON(!layer_masks_dst_parent);
           ^
   include/linux/build_bug.h:50:2: note: expanded from macro 'BUILD_BUG_ON'
           BUILD_BUG_ON_MSG(condition, "BUILD_BUG_ON failed: " #condition)
           ^
   include/linux/build_bug.h:39:37: note: expanded from macro 'BUILD_BUG_ON_MSG'
   #define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg)
                                       ^
   include/linux/compiler_types.h:346:2: note: expanded from macro 'compiletime_assert'
           _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
           ^
   include/linux/compiler_types.h:334:2: note: expanded from macro '_compiletime_assert'
           __compiletime_assert(condition, msg, prefix, suffix)
           ^
   include/linux/compiler_types.h:327:4: note: expanded from macro '__compiletime_assert'
                           prefix ## suffix();                             \
                           ^
   <scratch space>:170:1: note: expanded from here
   __compiletime_assert_228
   ^
>> security/landlock/fs.c:670:2: error: call to __compiletime_assert_229 declared with 'error' attribute: BUILD_BUG_ON failed: !layer_masks_dom
           BUILD_BUG_ON(!layer_masks_dom);
           ^
   include/linux/build_bug.h:50:2: note: expanded from macro 'BUILD_BUG_ON'
           BUILD_BUG_ON_MSG(condition, "BUILD_BUG_ON failed: " #condition)
           ^
   include/linux/build_bug.h:39:37: note: expanded from macro 'BUILD_BUG_ON_MSG'
   #define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg)
                                       ^
   include/linux/compiler_types.h:346:2: note: expanded from macro 'compiletime_assert'
           _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
           ^
   include/linux/compiler_types.h:334:2: note: expanded from macro '_compiletime_assert'
           __compiletime_assert(condition, msg, prefix, suffix)
           ^
   include/linux/compiler_types.h:327:4: note: expanded from macro '__compiletime_assert'
                           prefix ## suffix();                             \
                           ^
   <scratch space>:174:1: note: expanded from here
   __compiletime_assert_229
   ^
   2 errors generated.


vim +/error +463 security/landlock/fs.c

   401	
   402	/**
   403	 * check_access_path_dual - Check a source and a destination accesses
   404	 *
   405	 * @domain: Domain to check against.
   406	 * @path: File hierarchy to walk through.
   407	 * @child_is_directory: Must be set to true if the (original) leaf is a
   408	 *     directory, false otherwise.
   409	 * @access_request_dst_parent: Accesses to check, once @layer_masks_dst_parent
   410	 *     is equal to @layer_masks_src_parent (if any).
   411	 * @layer_masks_dst_parent: Pointer to a matrix of layer masks per access
   412	 *     masks, identifying the layers that forbid a specific access.  Bits from
   413	 *     this matrix can be unset according to the @path walk.  An empty matrix
   414	 *     means that @domain allows all possible Landlock accesses (i.e. not only
   415	 *     those identified by @access_request_dst_parent).  This matrix can
   416	 *     initially refer to domain layer masks and, when the accesses for the
   417	 *     destination and source are the same, to request layer masks.
   418	 * @access_request_src_parent: Similar to @access_request_dst_parent but for an
   419	 *     initial source path request.  Only taken into account if
   420	 *     @layer_masks_src_parent is not NULL.
   421	 * @layer_masks_src_parent: Similar to @layer_masks_dst_parent but for an
   422	 *     initial source path walk.  This can be NULL if only dealing with a
   423	 *     destination access request (i.e. not a rename nor a link action).
   424	 * @layer_masks_child: Similar to @layer_masks_src_parent but only for the
   425	 *     linked or renamed inode (without hierarchy).  This is only used if
   426	 *     @layer_masks_src_parent is not NULL.
   427	 *
   428	 * This helper first checks that the destination has a superset of restrictions
   429	 * compared to the source (if any) for a common path.  It then checks that the
   430	 * collected accesses and the remaining ones are enough to allow the request.
   431	 *
   432	 * Returns:
   433	 * - 0 if the access request is granted;
   434	 * - -EACCES if it is denied because of access right other than
   435	 *   LANDLOCK_ACCESS_FS_REFER;
   436	 * - -EXDEV if the renaming or linking would be a privileged escalation
   437	 *   (according to each layered policies), or if LANDLOCK_ACCESS_FS_REFER is
   438	 *   not allowed by the source or the destination.
   439	 */
   440	static int check_access_path_dual(const struct landlock_ruleset *const domain,
   441			const struct path *const path,
   442			bool child_is_directory,
   443			const access_mask_t access_request_dst_parent,
   444			layer_mask_t (*const
   445				layer_masks_dst_parent)[LANDLOCK_NUM_ACCESS_FS],
   446			const access_mask_t access_request_src_parent,
   447			layer_mask_t (*layer_masks_src_parent)[LANDLOCK_NUM_ACCESS_FS],
   448			layer_mask_t (*layer_masks_child)[LANDLOCK_NUM_ACCESS_FS])
   449	{
   450		bool allowed_dst_parent = false, allowed_src_parent = false, is_dom_check;
   451		struct path walker_path;
   452		access_mask_t access_masked_dst_parent, access_masked_src_parent;
   453	
   454		if (!access_request_dst_parent && !access_request_src_parent)
   455			return 0;
   456		if (WARN_ON_ONCE(!domain || !path))
   457			return 0;
   458		if (is_nouser_or_private(path->dentry))
   459			return 0;
   460		if (WARN_ON_ONCE(domain->num_layers < 1))
   461			return -EACCES;
   462	
 > 463		BUILD_BUG_ON(!layer_masks_dst_parent);
   464		if (layer_masks_src_parent) {
   465			if (WARN_ON_ONCE(!layer_masks_child))
   466				return -EACCES;
   467			access_masked_dst_parent = access_masked_src_parent =
   468				get_handled_accesses(domain);
   469			is_dom_check = true;
   470		} else {
   471			if (WARN_ON_ONCE(layer_masks_child))
   472				return -EACCES;
   473			access_masked_dst_parent = access_request_dst_parent;
   474			access_masked_src_parent = access_request_src_parent;
   475			is_dom_check = false;
   476		}
   477	
   478		walker_path = *path;
   479		path_get(&walker_path);
   480		/*
   481		 * We need to walk through all the hierarchy to not miss any relevant
   482		 * restriction.
   483		 */
   484		while (true) {
   485			struct dentry *parent_dentry;
   486			const struct landlock_rule *rule;
   487	
   488			/*
   489			 * If at least all accesses allowed on the destination are
   490			 * already allowed on the source, respectively if there is at
   491			 * least as much as restrictions on the destination than on the
   492			 * source, then we can safely refer files from the source to
   493			 * the destination without risking a privilege escalation.
   494			 * This is crucial for standalone multilayered security
   495			 * policies.  Furthermore, this helps avoid policy writers to
   496			 * shoot themselves in the foot.
   497			 */
   498			if (is_dom_check && is_superset(child_is_directory,
   499						layer_masks_dst_parent,
   500						layer_masks_src_parent,
   501						layer_masks_child)) {
   502				allowed_dst_parent =
   503					scope_to_request(access_request_dst_parent,
   504							layer_masks_dst_parent);
   505				allowed_src_parent =
   506					scope_to_request(access_request_src_parent,
   507							layer_masks_src_parent);
   508	
   509				/* Stops when all accesses are granted. */
   510				if (allowed_dst_parent && allowed_src_parent)
   511					break;
   512	
   513				/*
   514				 * Downgrades checks from domain handled accesses to
   515				 * requested accesses.
   516				 */
   517				is_dom_check = false;
   518				access_masked_dst_parent = access_request_dst_parent;
   519				access_masked_src_parent = access_request_src_parent;
   520			}
   521	
   522			rule = find_rule(domain, walker_path.dentry);
   523			allowed_dst_parent = unmask_layers(rule, access_masked_dst_parent,
   524					layer_masks_dst_parent);
   525			allowed_src_parent = unmask_layers(rule, access_masked_src_parent,
   526					layer_masks_src_parent);
   527	
   528			/* Stops when a rule from each layer grants access. */
   529			if (allowed_dst_parent && allowed_src_parent)
   530				break;
   531	
   532	jump_up:
   533			if (walker_path.dentry == walker_path.mnt->mnt_root) {
   534				if (follow_up(&walker_path)) {
   535					/* Ignores hidden mount points. */
   536					goto jump_up;
   537				} else {
   538					/*
   539					 * Stops at the real root.  Denies access
   540					 * because not all layers have granted access.
   541					 */
   542					allowed_dst_parent = false;
   543					break;
   544				}
   545			}
   546			if (unlikely(IS_ROOT(walker_path.dentry))) {
   547				/*
   548				 * Stops at disconnected root directories.  Only allows
   549				 * access to internal filesystems (e.g. nsfs, which is
   550				 * reachable through /proc/<pid>/ns/<namespace>).
   551				 */
   552				allowed_dst_parent = !!(walker_path.mnt->mnt_flags &
   553						MNT_INTERNAL);
   554				break;
   555			}
   556			parent_dentry = dget_parent(walker_path.dentry);
   557			dput(walker_path.dentry);
   558			walker_path.dentry = parent_dentry;
   559		}
   560		path_put(&walker_path);
   561	
   562		if (allowed_dst_parent && allowed_src_parent)
   563			return 0;
   564	
   565		/*
   566		 * Unfortunately, we cannot prioritize EACCES over EXDEV for all
   567		 * RENAME_EXCHANGE cases because it depends on the source and
   568		 * destination order.  This could be changed with a new
   569		 * security_path_rename hook implementation.
   570		 */
   571		if (likely(is_eacces(layer_masks_dst_parent, access_request_dst_parent)
   572					|| is_eacces(layer_masks_src_parent,
   573						access_request_src_parent)))
   574			return -EACCES;
   575	
   576		/*
   577		 * Gracefully forbids reparenting if the destination directory
   578		 * hierarchy is not a superset of restrictions of the source directory
   579		 * hierarchy, or if LANDLOCK_ACCESS_FS_REFER is not allowed by the
   580		 * source or the destination.
   581		 */
   582		return -EXDEV;
   583	}
   584	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org



More information about the Linux-security-module-archive mailing list