162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Landlock LSM - Object management 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright © 2016-2020 Mickaël Salaün <mic@digikod.net> 662306a36Sopenharmony_ci * Copyright © 2018-2020 ANSSI 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/bug.h> 1062306a36Sopenharmony_ci#include <linux/compiler_types.h> 1162306a36Sopenharmony_ci#include <linux/err.h> 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/rcupdate.h> 1462306a36Sopenharmony_ci#include <linux/refcount.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci#include <linux/spinlock.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "object.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistruct landlock_object * 2162306a36Sopenharmony_cilandlock_create_object(const struct landlock_object_underops *const underops, 2262306a36Sopenharmony_ci void *const underobj) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci struct landlock_object *new_object; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci if (WARN_ON_ONCE(!underops || !underobj)) 2762306a36Sopenharmony_ci return ERR_PTR(-ENOENT); 2862306a36Sopenharmony_ci new_object = kzalloc(sizeof(*new_object), GFP_KERNEL_ACCOUNT); 2962306a36Sopenharmony_ci if (!new_object) 3062306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 3162306a36Sopenharmony_ci refcount_set(&new_object->usage, 1); 3262306a36Sopenharmony_ci spin_lock_init(&new_object->lock); 3362306a36Sopenharmony_ci new_object->underops = underops; 3462306a36Sopenharmony_ci new_object->underobj = underobj; 3562306a36Sopenharmony_ci return new_object; 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* 3962306a36Sopenharmony_ci * The caller must own the object (i.e. thanks to object->usage) to safely put 4062306a36Sopenharmony_ci * it. 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_civoid landlock_put_object(struct landlock_object *const object) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci /* 4562306a36Sopenharmony_ci * The call to @object->underops->release(object) might sleep, e.g. 4662306a36Sopenharmony_ci * because of iput(). 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_ci might_sleep(); 4962306a36Sopenharmony_ci if (!object) 5062306a36Sopenharmony_ci return; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci /* 5362306a36Sopenharmony_ci * If the @object's refcount cannot drop to zero, we can just decrement 5462306a36Sopenharmony_ci * the refcount without holding a lock. Otherwise, the decrement must 5562306a36Sopenharmony_ci * happen under @object->lock for synchronization with things like 5662306a36Sopenharmony_ci * get_inode_object(). 5762306a36Sopenharmony_ci */ 5862306a36Sopenharmony_ci if (refcount_dec_and_lock(&object->usage, &object->lock)) { 5962306a36Sopenharmony_ci __acquire(&object->lock); 6062306a36Sopenharmony_ci /* 6162306a36Sopenharmony_ci * With @object->lock initially held, remove the reference from 6262306a36Sopenharmony_ci * @object->underobj to @object (if it still exists). 6362306a36Sopenharmony_ci */ 6462306a36Sopenharmony_ci object->underops->release(object); 6562306a36Sopenharmony_ci kfree_rcu(object, rcu_free); 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci} 68