security/landlock/fs.c

Source file repositories/reference/linux-study-clean/security/landlock/fs.c

File Facts

System
Linux kernel
Corpus path
security/landlock/fs.c
Extension
.c
Size
65329 bytes
Lines
2038
Domain
Core OS
Bucket
Security And Isolation
Inferred role
Core OS: implementation source
Status
source implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

if (likely(refcount_inc_not_zero(&object->usage))) {
			rcu_read_unlock();
			return object;
		}
		/*
		 * We are racing with release_inode(), the object is going
		 * away.  Wait for release_inode(), then retry.
		 */
		spin_lock(&object->lock);
		spin_unlock(&object->lock);
		goto retry;
	}
	rcu_read_unlock();

	/*
	 * If there is no object tied to @inode, then create a new one (without
	 * holding any locks).
	 */
	new_object = landlock_create_object(&landlock_fs_underops, inode);
	if (IS_ERR(new_object))
		return new_object;

	/*
	 * Protects against concurrent calls to get_inode_object() or
	 * hook_sb_delete().
	 */
	spin_lock(&inode->i_lock);
	if (unlikely(rcu_access_pointer(inode_sec->object))) {
		/* Someone else just created the object, bail out and retry. */
		spin_unlock(&inode->i_lock);
		kfree(new_object);

		rcu_read_lock();
		goto retry;
	}

	/*
	 * @inode will be released by hook_sb_delete() on its superblock
	 * shutdown, or by release_inode() when no more ruleset references the
	 * related object.
	 */
	ihold(inode);
	rcu_assign_pointer(inode_sec->object, new_object);
	spin_unlock(&inode->i_lock);
	return new_object;
}

/* All access rights that can be tied to files. */
/* clang-format off */
#define ACCESS_FILE ( \
	LANDLOCK_ACCESS_FS_EXECUTE | \
	LANDLOCK_ACCESS_FS_WRITE_FILE | \
	LANDLOCK_ACCESS_FS_READ_FILE | \
	LANDLOCK_ACCESS_FS_TRUNCATE | \
	LANDLOCK_ACCESS_FS_IOCTL_DEV | \
	LANDLOCK_ACCESS_FS_RESOLVE_UNIX)
/* clang-format on */

/*
 * @path: Should have been checked by get_path_from_fd().
 */
int landlock_append_fs_rule(struct landlock_ruleset *const ruleset,
			    const struct path *const path,
			    access_mask_t access_rights, const u32 flags)
{
	int err;
	struct landlock_id id = {
		.type = LANDLOCK_KEY_INODE,
	};

	/* Files only get access rights that make sense. */
	if (!d_is_dir(path->dentry) &&
	    !access_mask_subset(access_rights, ACCESS_FILE))
		return -EINVAL;
	if (WARN_ON_ONCE(ruleset->num_layers != 1))
		return -EINVAL;

	/* Transforms relative access rights to absolute ones. */
	access_rights |= LANDLOCK_MASK_ACCESS_FS &
			 ~landlock_get_fs_access_mask(ruleset, 0);
	id.key.object = get_inode_object(d_backing_inode(path->dentry));
	if (IS_ERR(id.key.object))
		return PTR_ERR(id.key.object);
	mutex_lock(&ruleset->lock);
	err = landlock_insert_rule(ruleset, id, access_rights, flags);
	mutex_unlock(&ruleset->lock);
	/*
	 * No need to check for an error because landlock_insert_rule()
	 * increments the refcount for the new object if needed.
	 */

Annotation

Implementation Notes