Skip to content

Commit 54a6e6b

Browse files
tahifahimil0kod
authored andcommitted
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 1934b21 ("file: reclaim 24 bytes from f_owner"): replace container_of(fown, struct file, f_owner) with fown->file . - commit 26f2043 ("fs: Fix file_set_fowner LSM hook inconsistencies"): lock before calling the hook. Signed-off-by: Tahera Fahimi <[email protected]> Closes: landlock-lsm#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: Mickaël Salaün <[email protected]> Signed-off-by: Mickaël Salaün <[email protected]>
1 parent dba40c7 commit 54a6e6b

File tree

7 files changed

+94
-3
lines changed

7 files changed

+94
-3
lines changed

include/uapi/linux/landlock.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,9 +296,12 @@ struct landlock_net_port_attr {
296296
* - %LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET: Restrict a sandboxed process from
297297
* connecting to an abstract UNIX socket created by a process outside the
298298
* related Landlock domain (e.g. a parent domain or a non-sandboxed process).
299+
* - %LANDLOCK_SCOPE_SIGNAL: Restrict a sandboxed process from sending a signal
300+
* to another process outside the domain.
299301
*/
300302
/* clang-format off */
301303
#define LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET (1ULL << 0)
304+
#define LANDLOCK_SCOPE_SIGNAL (1ULL << 1)
302305
/* clang-format on*/
303306

304307
#endif /* _UAPI_LINUX_LANDLOCK_H */

security/landlock/cred.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ landlock_cred(const struct cred *cred)
2626
return cred->security + landlock_blob_sizes.lbs_cred;
2727
}
2828

29-
static inline const struct landlock_ruleset *landlock_get_current_domain(void)
29+
static inline struct landlock_ruleset *landlock_get_current_domain(void)
3030
{
3131
return landlock_cred(current_cred())->domain;
3232
}

security/landlock/fs.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1639,6 +1639,29 @@ static int hook_file_ioctl_compat(struct file *file, unsigned int cmd,
16391639
return -EACCES;
16401640
}
16411641

1642+
static void hook_file_set_fowner(struct file *file)
1643+
{
1644+
struct landlock_ruleset *new_dom, *prev_dom;
1645+
1646+
/*
1647+
* Lock already held by __f_setown(), see commit 26f204380a3c ("fs: Fix
1648+
* file_set_fowner LSM hook inconsistencies").
1649+
*/
1650+
lockdep_assert_held(&file_f_owner(file)->lock);
1651+
new_dom = landlock_get_current_domain();
1652+
landlock_get_ruleset(new_dom);
1653+
prev_dom = landlock_file(file)->fown_domain;
1654+
landlock_file(file)->fown_domain = new_dom;
1655+
1656+
/* Called in an RCU read-side critical section. */
1657+
landlock_put_ruleset_deferred(prev_dom);
1658+
}
1659+
1660+
static void hook_file_free_security(struct file *file)
1661+
{
1662+
landlock_put_ruleset_deferred(landlock_file(file)->fown_domain);
1663+
}
1664+
16421665
static struct security_hook_list landlock_hooks[] __ro_after_init = {
16431666
LSM_HOOK_INIT(inode_free_security_rcu, hook_inode_free_security_rcu),
16441667

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

16681693
__init void landlock_add_fs_hooks(void)

security/landlock/fs.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ struct landlock_file_security {
5252
* needed to authorize later operations on the open file.
5353
*/
5454
access_mask_t allowed_access;
55+
/**
56+
* @fown_domain: Domain of the task that set the PID that may receive a
57+
* signal e.g., SIGURG when writing MSG_OOB to the related socket.
58+
* This pointer is protected by the related file->f_owner->lock, as for
59+
* fown_struct's members: pid, uid, and euid.
60+
*/
61+
struct landlock_ruleset *fown_domain;
5562
};
5663

5764
/**

security/landlock/limits.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
#define LANDLOCK_MASK_ACCESS_NET ((LANDLOCK_LAST_ACCESS_NET << 1) - 1)
2727
#define LANDLOCK_NUM_ACCESS_NET __const_hweight64(LANDLOCK_MASK_ACCESS_NET)
2828

29-
#define LANDLOCK_LAST_SCOPE LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET
29+
#define LANDLOCK_LAST_SCOPE LANDLOCK_SCOPE_SIGNAL
3030
#define LANDLOCK_MASK_SCOPE ((LANDLOCK_LAST_SCOPE << 1) - 1)
3131
#define LANDLOCK_NUM_SCOPE __const_hweight64(LANDLOCK_MASK_SCOPE)
3232
/* clang-format on */

security/landlock/task.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include "common.h"
2020
#include "cred.h"
21+
#include "fs.h"
2122
#include "ruleset.h"
2223
#include "setup.h"
2324
#include "task.h"
@@ -242,12 +243,67 @@ static int hook_unix_may_send(struct socket *const sock,
242243
return 0;
243244
}
244245

246+
static int hook_task_kill(struct task_struct *const p,
247+
struct kernel_siginfo *const info, const int sig,
248+
const struct cred *const cred)
249+
{
250+
bool is_scoped;
251+
const struct landlock_ruleset *dom;
252+
253+
if (cred) {
254+
/* Dealing with USB IO. */
255+
dom = landlock_cred(cred)->domain;
256+
} else {
257+
dom = landlock_get_current_domain();
258+
}
259+
260+
/* Quick return for non-landlocked tasks. */
261+
if (!dom)
262+
return 0;
263+
264+
rcu_read_lock();
265+
is_scoped = domain_is_scoped(dom, landlock_get_task_domain(p),
266+
LANDLOCK_SCOPE_SIGNAL);
267+
rcu_read_unlock();
268+
if (is_scoped)
269+
return -EPERM;
270+
271+
return 0;
272+
}
273+
274+
static int hook_file_send_sigiotask(struct task_struct *tsk,
275+
struct fown_struct *fown, int signum)
276+
{
277+
const struct landlock_ruleset *dom;
278+
bool is_scoped = false;
279+
280+
/* Lock already held by send_sigio() and send_sigurg(). */
281+
lockdep_assert_held(&fown->lock);
282+
dom = landlock_file(fown->file)->fown_domain;
283+
284+
/* Quick return for unowned socket. */
285+
if (!dom)
286+
return 0;
287+
288+
rcu_read_lock();
289+
is_scoped = domain_is_scoped(dom, landlock_get_task_domain(tsk),
290+
LANDLOCK_SCOPE_SIGNAL);
291+
rcu_read_unlock();
292+
if (is_scoped)
293+
return -EPERM;
294+
295+
return 0;
296+
}
297+
245298
static struct security_hook_list landlock_hooks[] __ro_after_init = {
246299
LSM_HOOK_INIT(ptrace_access_check, hook_ptrace_access_check),
247300
LSM_HOOK_INIT(ptrace_traceme, hook_ptrace_traceme),
248301

249302
LSM_HOOK_INIT(unix_stream_connect, hook_unix_stream_connect),
250303
LSM_HOOK_INIT(unix_may_send, hook_unix_may_send),
304+
305+
LSM_HOOK_INIT(task_kill, hook_task_kill),
306+
LSM_HOOK_INIT(file_send_sigiotask, hook_file_send_sigiotask),
251307
};
252308

253309
__init void landlock_add_task_hooks(void)

tools/testing/selftests/landlock/scoped_test.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
#include "common.h"
1414

15-
#define ACCESS_LAST LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET
15+
#define ACCESS_LAST LANDLOCK_SCOPE_SIGNAL
1616

1717
TEST(ruleset_with_unknown_scope)
1818
{

0 commit comments

Comments
 (0)