On Wed, Mar 31, 2021 at 07:33:50PM +0200, Mickaël Salaün wrote:
+static inline u64 unmask_layers(
const struct landlock_ruleset *const domain,
const struct path *const path, const u32 access_request,
u64 layer_mask)
+{
- const struct landlock_rule *rule;
- const struct inode *inode;
- size_t i;
- if (d_is_negative(path->dentry))
/* Continues to walk while there is no mapped inode. */
^^^^^ Odd comment, that...
+static int check_access_path(const struct landlock_ruleset *const domain,
const struct path *const path, u32 access_request)
+{
- walker_path = *path;
- path_get(&walker_path);
- while (true) {
struct dentry *parent_dentry;
layer_mask = unmask_layers(domain, &walker_path,
access_request, layer_mask);
if (layer_mask == 0) {
/* Stops when a rule from each layer grants access. */
allowed = true;
break;
}
+jump_up:
if (walker_path.dentry == walker_path.mnt->mnt_root) {
if (follow_up(&walker_path)) {
/* Ignores hidden mount points. */
goto jump_up;
} else {
/*
* Stops at the real root. Denies access
* because not all layers have granted access.
*/
allowed = false;
break;
}
}
if (unlikely(IS_ROOT(walker_path.dentry))) {
/*
* Stops at disconnected root directories. Only allows
* access to internal filesystems (e.g. nsfs, which is
* reachable through /proc/<pid>/ns/<namespace>).
*/
allowed = !!(walker_path.mnt->mnt_flags & MNT_INTERNAL);
break;
}
parent_dentry = dget_parent(walker_path.dentry);
dput(walker_path.dentry);
walker_path.dentry = parent_dentry;
- }
- path_put(&walker_path);
- return allowed ? 0 : -EACCES;
That's a whole lot of grabbing/dropping references... I realize that it's an utterly tactless question, but... how costly it is? IOW, do you have profiling data?
+/*
- pivot_root(2), like mount(2), changes the current mount namespace. It must
- then be forbidden for a landlocked process.
... and cross-directory rename(2) can change the tree topology. Do you ban that as well?
[snip]
+static int hook_path_rename(const struct path *const old_dir,
struct dentry *const old_dentry,
const struct path *const new_dir,
struct dentry *const new_dentry)
+{
- const struct landlock_ruleset *const dom =
landlock_get_current_domain();
- if (!dom)
return 0;
- /* The mount points are the same for old and new paths, cf. EXDEV. */
- if (old_dir->dentry != new_dir->dentry)
/* For now, forbids reparenting. */
return -EACCES;
You do, apparently, and not in a way that would have the userland fall back to copy+unlink. Lovely... Does e.g. git survive such restriction? Same question for your average package build...