Unverified Commit 54a6e6bb authored by Tahera Fahimi's avatar Tahera Fahimi Committed by Mickaël Salaün
Browse files

landlock: Add signal scoping



Currently, a sandbox process is not restricted to sending a signal (e.g.
SIGKILL) to a process outside the sandbox environment.  The ability to
send a signal for a sandboxed process should be scoped the same way
abstract UNIX sockets are scoped. Therefore, we extend the "scoped"
field in a ruleset with LANDLOCK_SCOPE_SIGNAL to specify that a ruleset
will deny sending any signal from within a sandbox process to its parent
(i.e. any parent sandbox or non-sandboxed processes).

This patch adds file_set_fowner and file_free_security hooks to set and
release a pointer to the file owner's domain. This pointer, fown_domain
in landlock_file_security will be used in file_send_sigiotask to check
if the process can send a signal.

The ruleset_with_unknown_scope test is updated to support
LANDLOCK_SCOPE_SIGNAL.

This depends on two new changes:
- commit 1934b212 ("file: reclaim 24 bytes from f_owner"): replace
  container_of(fown, struct file, f_owner) with fown->file .
- commit 26f20438 ("fs: Fix file_set_fowner LSM hook
  inconsistencies"): lock before calling the hook.

Signed-off-by: default avatarTahera Fahimi <fahimitahera@gmail.com>
Closes: https://github.com/landlock-lsm/linux/issues/8
Link: https://lore.kernel.org/r/df2b4f880a2ed3042992689a793ea0951f6798a5.1725657727.git.fahimitahera@gmail.com


[mic: Update landlock_get_current_domain()'s return type, improve and
fix locking in hook_file_set_fowner(), simplify and fix sleepable call
and locking issue in hook_file_send_sigiotask() and rebase on the latest
VFS tree, simplify hook_task_kill() and quickly return when not
sandboxed, improve comments, rename LANDLOCK_SCOPED_SIGNAL]
Co-developed-by: default avatarMickaël Salaün <mic@digikod.net>
Signed-off-by: default avatarMickaël Salaün <mic@digikod.net>
parent dba40c77
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -296,9 +296,12 @@ struct landlock_net_port_attr {
 * - %LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET: Restrict a sandboxed process from
 *   connecting to an abstract UNIX socket created by a process outside the
 *   related Landlock domain (e.g. a parent domain or a non-sandboxed process).
 * - %LANDLOCK_SCOPE_SIGNAL: Restrict a sandboxed process from sending a signal
 *   to another process outside the domain.
 */
/* clang-format off */
#define LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET		(1ULL << 0)
#define LANDLOCK_SCOPE_SIGNAL		                (1ULL << 1)
/* clang-format on*/

#endif /* _UAPI_LINUX_LANDLOCK_H */
+1 −1
Original line number Diff line number Diff line
@@ -26,7 +26,7 @@ landlock_cred(const struct cred *cred)
	return cred->security + landlock_blob_sizes.lbs_cred;
}

static inline const struct landlock_ruleset *landlock_get_current_domain(void)
static inline struct landlock_ruleset *landlock_get_current_domain(void)
{
	return landlock_cred(current_cred())->domain;
}
+25 −0
Original line number Diff line number Diff line
@@ -1639,6 +1639,29 @@ static int hook_file_ioctl_compat(struct file *file, unsigned int cmd,
	return -EACCES;
}

static void hook_file_set_fowner(struct file *file)
{
	struct landlock_ruleset *new_dom, *prev_dom;

	/*
	 * Lock already held by __f_setown(), see commit 26f204380a3c ("fs: Fix
	 * file_set_fowner LSM hook inconsistencies").
	 */
	lockdep_assert_held(&file_f_owner(file)->lock);
	new_dom = landlock_get_current_domain();
	landlock_get_ruleset(new_dom);
	prev_dom = landlock_file(file)->fown_domain;
	landlock_file(file)->fown_domain = new_dom;

	/* Called in an RCU read-side critical section. */
	landlock_put_ruleset_deferred(prev_dom);
}

static void hook_file_free_security(struct file *file)
{
	landlock_put_ruleset_deferred(landlock_file(file)->fown_domain);
}

static struct security_hook_list landlock_hooks[] __ro_after_init = {
	LSM_HOOK_INIT(inode_free_security_rcu, hook_inode_free_security_rcu),

@@ -1663,6 +1686,8 @@ static struct security_hook_list landlock_hooks[] __ro_after_init = {
	LSM_HOOK_INIT(file_truncate, hook_file_truncate),
	LSM_HOOK_INIT(file_ioctl, hook_file_ioctl),
	LSM_HOOK_INIT(file_ioctl_compat, hook_file_ioctl_compat),
	LSM_HOOK_INIT(file_set_fowner, hook_file_set_fowner),
	LSM_HOOK_INIT(file_free_security, hook_file_free_security),
};

__init void landlock_add_fs_hooks(void)
+7 −0
Original line number Diff line number Diff line
@@ -52,6 +52,13 @@ struct landlock_file_security {
	 * needed to authorize later operations on the open file.
	 */
	access_mask_t allowed_access;
	/**
	 * @fown_domain: Domain of the task that set the PID that may receive a
	 * signal e.g., SIGURG when writing MSG_OOB to the related socket.
	 * This pointer is protected by the related file->f_owner->lock, as for
	 * fown_struct's members: pid, uid, and euid.
	 */
	struct landlock_ruleset *fown_domain;
};

/**
+1 −1
Original line number Diff line number Diff line
@@ -26,7 +26,7 @@
#define LANDLOCK_MASK_ACCESS_NET	((LANDLOCK_LAST_ACCESS_NET << 1) - 1)
#define LANDLOCK_NUM_ACCESS_NET		__const_hweight64(LANDLOCK_MASK_ACCESS_NET)

#define LANDLOCK_LAST_SCOPE		LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET
#define LANDLOCK_LAST_SCOPE		LANDLOCK_SCOPE_SIGNAL
#define LANDLOCK_MASK_SCOPE		((LANDLOCK_LAST_SCOPE << 1) - 1)
#define LANDLOCK_NUM_SCOPE		__const_hweight64(LANDLOCK_MASK_SCOPE)
/* clang-format on */
Loading