mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-08-26 21:52:20 +00:00

landlock_put_hierarchy() can be called when an error occurs in landlock_merge_ruleset() due to insufficient memory. In this case, the domain's audit details might not have been allocated yet, which would cause landlock_free_hierarchy_details() to print a warning (but still safely handle this case). We could keep the WARN_ON_ONCE(!hierarchy) but it's not worth it for this kind of function, so let's remove it entirely. Cc: Paul Moore <paul@paul-moore.com> Reported-by: syzbot+8bca99e91de7e060e4ea@syzkaller.appspotmail.com Link: https://lore.kernel.org/r/20250331104709.897062-1-mic@digikod.net Reviewed-by: Günther Noack <gnoack@google.com> Signed-off-by: Mickaël Salaün <mic@digikod.net>
175 lines
4.6 KiB
C
175 lines
4.6 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/*
|
|
* Landlock - Domain management
|
|
*
|
|
* Copyright © 2016-2020 Mickaël Salaün <mic@digikod.net>
|
|
* Copyright © 2018-2020 ANSSI
|
|
* Copyright © 2024-2025 Microsoft Corporation
|
|
*/
|
|
|
|
#ifndef _SECURITY_LANDLOCK_DOMAIN_H
|
|
#define _SECURITY_LANDLOCK_DOMAIN_H
|
|
|
|
#include <linux/limits.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/path.h>
|
|
#include <linux/pid.h>
|
|
#include <linux/refcount.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/slab.h>
|
|
|
|
#include "access.h"
|
|
#include "audit.h"
|
|
|
|
enum landlock_log_status {
|
|
LANDLOCK_LOG_PENDING = 0,
|
|
LANDLOCK_LOG_RECORDED,
|
|
LANDLOCK_LOG_DISABLED,
|
|
};
|
|
|
|
/**
|
|
* struct landlock_details - Domain's creation information
|
|
*
|
|
* Rarely accessed, mainly when logging the first domain's denial.
|
|
*
|
|
* The contained pointers are initialized at the domain creation time and never
|
|
* changed again. Contrary to most other Landlock object types, this one is
|
|
* not allocated with GFP_KERNEL_ACCOUNT because its size may not be under the
|
|
* caller's control (e.g. unknown exe_path) and the data is not explicitly
|
|
* requested nor used by tasks.
|
|
*/
|
|
struct landlock_details {
|
|
/**
|
|
* @pid: PID of the task that initially restricted itself. It still
|
|
* identifies the same task. Keeping a reference to this PID ensures that
|
|
* it will not be recycled.
|
|
*/
|
|
struct pid *pid;
|
|
/**
|
|
* @uid: UID of the task that initially restricted itself, at creation time.
|
|
*/
|
|
uid_t uid;
|
|
/**
|
|
* @comm: Command line of the task that initially restricted itself, at
|
|
* creation time. Always NULL terminated.
|
|
*/
|
|
char comm[TASK_COMM_LEN];
|
|
/**
|
|
* @exe_path: Executable path of the task that initially restricted
|
|
* itself, at creation time. Always NULL terminated, and never greater
|
|
* than LANDLOCK_PATH_MAX_SIZE.
|
|
*/
|
|
char exe_path[];
|
|
};
|
|
|
|
/* Adds 11 extra characters for the potential " (deleted)" suffix. */
|
|
#define LANDLOCK_PATH_MAX_SIZE (PATH_MAX + 11)
|
|
|
|
/* Makes sure the greatest landlock_details can be allocated. */
|
|
static_assert(struct_size_t(struct landlock_details, exe_path,
|
|
LANDLOCK_PATH_MAX_SIZE) <= KMALLOC_MAX_SIZE);
|
|
|
|
/**
|
|
* struct landlock_hierarchy - Node in a domain hierarchy
|
|
*/
|
|
struct landlock_hierarchy {
|
|
/**
|
|
* @parent: Pointer to the parent node, or NULL if it is a root
|
|
* Landlock domain.
|
|
*/
|
|
struct landlock_hierarchy *parent;
|
|
/**
|
|
* @usage: Number of potential children domains plus their parent
|
|
* domain.
|
|
*/
|
|
refcount_t usage;
|
|
|
|
#ifdef CONFIG_AUDIT
|
|
/**
|
|
* @log_status: Whether this domain should be logged or not. Because
|
|
* concurrent log entries may be created at the same time, it is still
|
|
* possible to have several domain records of the same domain.
|
|
*/
|
|
enum landlock_log_status log_status;
|
|
/**
|
|
* @num_denials: Number of access requests denied by this domain.
|
|
* Masked (i.e. never logged) denials are still counted.
|
|
*/
|
|
atomic64_t num_denials;
|
|
/**
|
|
* @id: Landlock domain ID, sets once at domain creation time.
|
|
*/
|
|
u64 id;
|
|
/**
|
|
* @details: Information about the related domain.
|
|
*/
|
|
const struct landlock_details *details;
|
|
/**
|
|
* @log_same_exec: Set if the domain is *not* configured with
|
|
* %LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF. Set to true by default.
|
|
*/
|
|
u32 log_same_exec : 1,
|
|
/**
|
|
* @log_new_exec: Set if the domain is configured with
|
|
* %LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON. Set to false by default.
|
|
*/
|
|
log_new_exec : 1;
|
|
#endif /* CONFIG_AUDIT */
|
|
};
|
|
|
|
#ifdef CONFIG_AUDIT
|
|
|
|
deny_masks_t
|
|
landlock_get_deny_masks(const access_mask_t all_existing_optional_access,
|
|
const access_mask_t optional_access,
|
|
const layer_mask_t (*const layer_masks)[],
|
|
size_t layer_masks_size);
|
|
|
|
int landlock_init_hierarchy_log(struct landlock_hierarchy *const hierarchy);
|
|
|
|
static inline void
|
|
landlock_free_hierarchy_details(struct landlock_hierarchy *const hierarchy)
|
|
{
|
|
if (!hierarchy || !hierarchy->details)
|
|
return;
|
|
|
|
put_pid(hierarchy->details->pid);
|
|
kfree(hierarchy->details);
|
|
}
|
|
|
|
#else /* CONFIG_AUDIT */
|
|
|
|
static inline int
|
|
landlock_init_hierarchy_log(struct landlock_hierarchy *const hierarchy)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static inline void
|
|
landlock_free_hierarchy_details(struct landlock_hierarchy *const hierarchy)
|
|
{
|
|
}
|
|
|
|
#endif /* CONFIG_AUDIT */
|
|
|
|
static inline void
|
|
landlock_get_hierarchy(struct landlock_hierarchy *const hierarchy)
|
|
{
|
|
if (hierarchy)
|
|
refcount_inc(&hierarchy->usage);
|
|
}
|
|
|
|
static inline void landlock_put_hierarchy(struct landlock_hierarchy *hierarchy)
|
|
{
|
|
while (hierarchy && refcount_dec_and_test(&hierarchy->usage)) {
|
|
const struct landlock_hierarchy *const freeme = hierarchy;
|
|
|
|
landlock_log_drop_domain(hierarchy);
|
|
landlock_free_hierarchy_details(hierarchy);
|
|
hierarchy = hierarchy->parent;
|
|
kfree(freeme);
|
|
}
|
|
}
|
|
|
|
#endif /* _SECURITY_LANDLOCK_DOMAIN_H */
|