History

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 1934b212615d ("file: reclaim 24 bytes from f_owner"): replace container_of(fown, struct file, f_owner) with fown->file . - commit 26f204380a3c ("fs: Fix file_set_fowner LSM hook inconsistencies"): lock before calling the hook.

Tahera Fahimi committed 2 years ago

Commit 54a6e6b1 parent dba40c77 files · +94 −3Browse files

Unified · Split

7 files
  1. include/uapi/linux/landlock.h +3 −0
  2. security/landlock/cred.h +1 −1
  3. security/landlock/fs.c +25 −0
  4. security/landlock/fs.h +7 −0
  5. security/landlock/limits.h +1 −1
  6. security/landlock/task.c +56 −0
  7. tools/testing/selftests/landlock/scoped_test.c +1 −1
include/uapi/linux/landlock.h+3−0
@@ -296,9 +296,12 @@ struct landlock_net_port_attr { · 295 unmodified lines
296 * - %LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET: Restrict a sandboxed process from296 * - %LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET: Restrict a sandboxed process from
297 * connecting to an abstract UNIX socket created by a process outside the297 * connecting to an abstract UNIX socket created by a process outside the
298 * related Landlock domain (e.g. a parent domain or a non-sandboxed process).298 * 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.
299 */301 */
300/* clang-format off */302/* clang-format off */
301#define LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET (1ULL << 0)303#define LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET (1ULL << 0)
304#define LANDLOCK_SCOPE_SIGNAL (1ULL << 1)
302/* clang-format on*/305/* clang-format on*/
303 306
304#endif /* _UAPI_LINUX_LANDLOCK_H */307#endif /* _UAPI_LINUX_LANDLOCK_H */
security/landlock/cred.h+1−1
@@ -26,7 +26,7 @@ landlock_cred(const struct cred *cred) · 25 unmodified lines
26 return cred->security + landlock_blob_sizes.lbs_cred;26 return cred->security + landlock_blob_sizes.lbs_cred;
27}27}
28 28
29static inline const struct landlock_ruleset *landlock_get_current_domain(void)29static inline struct landlock_ruleset *landlock_get_current_domain(void)
30{30{
31 return landlock_cred(current_cred())->domain;31 return landlock_cred(current_cred())->domain;
32}32}
security/landlock/fs.c+25−0
@@ -1639,6 +1639,29 @@ static int hook_file_ioctl_compat(struct file *file, unsigned int cmd, · 1638 unmodified lines
1639 return -EACCES;1639 return -EACCES;
1640}1640}
1641 1641
1642static 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
1660static void hook_file_free_security(struct file *file)
1661{
1662 landlock_put_ruleset_deferred(landlock_file(file)->fown_domain);
1663}
1664
1642static struct security_hook_list landlock_hooks[] __ro_after_init = {1665static struct security_hook_list landlock_hooks[] __ro_after_init = {
1643 LSM_HOOK_INIT(inode_free_security_rcu, hook_inode_free_security_rcu),1666 LSM_HOOK_INIT(inode_free_security_rcu, hook_inode_free_security_rcu),
1644 1667
@@ -1663,6 +1686,8 @@ static struct security_hook_list landlock_hooks[] __ro_after_init = { · 18 unmodified lines
1663 LSM_HOOK_INIT(file_truncate, hook_file_truncate),1686 LSM_HOOK_INIT(file_truncate, hook_file_truncate),
1664 LSM_HOOK_INIT(file_ioctl, hook_file_ioctl),1687 LSM_HOOK_INIT(file_ioctl, hook_file_ioctl),
1665 LSM_HOOK_INIT(file_ioctl_compat, hook_file_ioctl_compat),1688 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),
1666};1691};
1667 1692
1668__init void landlock_add_fs_hooks(void)1693__init void landlock_add_fs_hooks(void)
security/landlock/fs.h+7−0
@@ -52,6 +52,13 @@ struct landlock_file_security { · 51 unmodified lines
52 * needed to authorize later operations on the open file.52 * needed to authorize later operations on the open file.
53 */53 */
54 access_mask_t allowed_access;54 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;
55};62};
56 63
57/**64/**
security/landlock/limits.h+1−1
@@ -26,7 +26,7 @@ · 25 unmodified lines
26#define LANDLOCK_MASK_ACCESS_NET ((LANDLOCK_LAST_ACCESS_NET << 1) - 1)26#define LANDLOCK_MASK_ACCESS_NET ((LANDLOCK_LAST_ACCESS_NET << 1) - 1)
27#define LANDLOCK_NUM_ACCESS_NET __const_hweight64(LANDLOCK_MASK_ACCESS_NET)27#define LANDLOCK_NUM_ACCESS_NET __const_hweight64(LANDLOCK_MASK_ACCESS_NET)
28 28
29#define LANDLOCK_LAST_SCOPE LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET29#define LANDLOCK_LAST_SCOPE LANDLOCK_SCOPE_SIGNAL
30#define LANDLOCK_MASK_SCOPE ((LANDLOCK_LAST_SCOPE << 1) - 1)30#define LANDLOCK_MASK_SCOPE ((LANDLOCK_LAST_SCOPE << 1) - 1)
31#define LANDLOCK_NUM_SCOPE __const_hweight64(LANDLOCK_MASK_SCOPE)31#define LANDLOCK_NUM_SCOPE __const_hweight64(LANDLOCK_MASK_SCOPE)
32/* clang-format on */32/* clang-format on */
security/landlock/task.c+56−0
@@ -18,6 +18,7 @@ · 17 unmodified lines
18 18
19#include "common.h"19#include "common.h"
20#include "cred.h"20#include "cred.h"
21#include "fs.h"
21#include "ruleset.h"22#include "ruleset.h"
22#include "setup.h"23#include "setup.h"
23#include "task.h"24#include "task.h"
@@ -242,12 +243,67 @@ static int hook_unix_may_send(struct socket *const sock, · 218 unmodified lines
242 return 0;243 return 0;
243}244}
244 245
246static 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
274static 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
245static struct security_hook_list landlock_hooks[] __ro_after_init = {298static struct security_hook_list landlock_hooks[] __ro_after_init = {
246 LSM_HOOK_INIT(ptrace_access_check, hook_ptrace_access_check),299 LSM_HOOK_INIT(ptrace_access_check, hook_ptrace_access_check),
247 LSM_HOOK_INIT(ptrace_traceme, hook_ptrace_traceme),300 LSM_HOOK_INIT(ptrace_traceme, hook_ptrace_traceme),
248 301
249 LSM_HOOK_INIT(unix_stream_connect, hook_unix_stream_connect),302 LSM_HOOK_INIT(unix_stream_connect, hook_unix_stream_connect),
250 LSM_HOOK_INIT(unix_may_send, hook_unix_may_send),303 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),
251};307};
252 308
253__init void landlock_add_task_hooks(void)309__init void landlock_add_task_hooks(void)
tools/testing/selftests/landlock/scoped_test.c+1−1
@@ -12,7 +12,7 @@ · 11 unmodified lines
12 12
13#include "common.h"13#include "common.h"
14 14
15#define ACCESS_LAST LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET15#define ACCESS_LAST LANDLOCK_SCOPE_SIGNAL
16 16
17TEST(ruleset_with_unknown_scope)17TEST(ruleset_with_unknown_scope)
18{18{