Mickaël Salaün d9d2a68ed4
landlock: Add unique ID generator
Landlock IDs can be generated to uniquely identify Landlock objects.
For now, only Landlock domains get an ID at creation time.  These IDs
map to immutable domain hierarchies.

Landlock IDs have important properties:
- They are unique during the lifetime of the running system thanks to
  the 64-bit values: at worse, 2^60 - 2*2^32 useful IDs.
- They are always greater than 2^32 and must then be stored in 64-bit
  integer types.
- The initial ID (at boot time) is randomly picked between 2^32 and
  2^33, which limits collisions in logs across different boots.
- IDs are sequential, which enables users to order them.
- IDs may not be consecutive but increase with a random 2^4 step, which
  limits side channels.

Such IDs can be exposed to unprivileged processes, even if it is not the
case with this audit patch series.  The domain IDs will be useful for
user space to identify sandboxes and get their properties.

These Landlock IDs are more secure that other absolute kernel IDs such
as pipe's inodes which rely on a shared global counter.

For checkpoint/restore features (i.e. CRIU), we could easily implement a
privileged interface (e.g. sysfs) to set the next ID counter.

IDR/IDA are not used because we only need a bijection from Landlock
objects to Landlock IDs, and we must not recycle IDs.  This enables us
to identify all Landlock objects during the lifetime of the system (e.g.
in logs), but not to access an object from an ID nor know if an ID is
assigned.   Using a counter is simpler, it scales (i.e. avoids growing
memory footprint), and it does not require locking.  We'll use proper
file descriptors (with IDs used as inode numbers) to access Landlock
objects.

Cc: Günther Noack <gnoack@google.com>
Cc: Paul Moore <paul@paul-moore.com>
Link: https://lore.kernel.org/r/20250320190717.2287696-3-mic@digikod.net
Signed-off-by: Mickaël Salaün <mic@digikod.net>
2025-03-26 13:59:34 +01:00

82 lines
1.8 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Landlock LSM - Security framework setup
*
* Copyright © 2016-2020 Mickaël Salaün <mic@digikod.net>
* Copyright © 2018-2020 ANSSI
*/
#include <linux/bits.h>
#include <linux/init.h>
#include <linux/lsm_hooks.h>
#include <uapi/linux/lsm.h>
#include "common.h"
#include "cred.h"
#include "errata.h"
#include "fs.h"
#include "id.h"
#include "net.h"
#include "setup.h"
#include "task.h"
bool landlock_initialized __ro_after_init = false;
const struct lsm_id landlock_lsmid = {
.name = LANDLOCK_NAME,
.id = LSM_ID_LANDLOCK,
};
struct lsm_blob_sizes landlock_blob_sizes __ro_after_init = {
.lbs_cred = sizeof(struct landlock_cred_security),
.lbs_file = sizeof(struct landlock_file_security),
.lbs_inode = sizeof(struct landlock_inode_security),
.lbs_superblock = sizeof(struct landlock_superblock_security),
};
int landlock_errata __ro_after_init;
static void __init compute_errata(void)
{
size_t i;
#ifndef __has_include
/*
* This is a safeguard to make sure the compiler implements
* __has_include (see errata.h).
*/
WARN_ON_ONCE(1);
return;
#endif
for (i = 0; landlock_errata_init[i].number; i++) {
const int prev_errata = landlock_errata;
if (WARN_ON_ONCE(landlock_errata_init[i].abi >
landlock_abi_version))
continue;
landlock_errata |= BIT(landlock_errata_init[i].number - 1);
WARN_ON_ONCE(prev_errata == landlock_errata);
}
}
static int __init landlock_init(void)
{
compute_errata();
landlock_add_cred_hooks();
landlock_add_task_hooks();
landlock_add_fs_hooks();
landlock_add_net_hooks();
landlock_init_id();
landlock_initialized = true;
pr_info("Up and running.\n");
return 0;
}
DEFINE_LSM(LANDLOCK_NAME) = {
.name = LANDLOCK_NAME,
.init = landlock_init,
.blobs = &landlock_blob_sizes,
};