linux-stable/include/linux/evm.h
Christian Brauner e61b135f7b
integrity: implement get and set acl hook
The current way of setting and getting posix acls through the generic
xattr interface is error prone and type unsafe. The vfs needs to
interpret and fixup posix acls before storing or reporting it to
userspace. Various hacks exist to make this work. The code is hard to
understand and difficult to maintain in it's current form. Instead of
making this work by hacking posix acls through xattr handlers we are
building a dedicated posix acl api around the get and set inode
operations. This removes a lot of hackiness and makes the codepaths
easier to maintain. A lot of background can be found in [1].

So far posix acls were passed as a void blob to the security and
integrity modules. Some of them like evm then proceed to interpret the
void pointer and convert it into the kernel internal struct posix acl
representation to perform their integrity checking magic. This is
obviously pretty problematic as that requires knowledge that only the
vfs is guaranteed to have and has lead to various bugs. Add a proper
security hook for setting posix acls and pass down the posix acls in
their appropriate vfs format instead of hacking it through a void
pointer stored in the uapi format.

I spent considerate time in the security module and integrity
infrastructure and audited all codepaths. EVM is the only part that
really has restrictions based on the actual posix acl values passed
through it (e.g., i_mode). Before this dedicated hook EVM used to translate
from the uapi posix acl format sent to it in the form of a void pointer
into the vfs format. This is not a good thing. Instead of hacking around in
the uapi struct give EVM the posix acls in the appropriate vfs format and
perform sane permissions checks that mirror what it used to to in the
generic xattr hook.

IMA doesn't have any restrictions on posix acls. When posix acls are
changed it just wants to update its appraisal status to trigger an EVM
revalidation.

The removal of posix acls is equivalent to passing NULL to the posix set
acl hooks. This is the same as before through the generic xattr api.

Link: https://lore.kernel.org/all/20220801145520.1532837-1-brauner@kernel.org [1]
Acked-by: Paul Moore <paul@paul-moore.com> (LSM)
Signed-off-by: Christian Brauner (Microsoft) <brauner@kernel.org>
2022-10-20 10:13:29 +02:00

159 lines
4.2 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
/*
* evm.h
*
* Copyright (c) 2009 IBM Corporation
* Author: Mimi Zohar <zohar@us.ibm.com>
*/
#ifndef _LINUX_EVM_H
#define _LINUX_EVM_H
#include <linux/integrity.h>
#include <linux/xattr.h>
struct integrity_iint_cache;
#ifdef CONFIG_EVM
extern int evm_set_key(void *key, size_t keylen);
extern enum integrity_status evm_verifyxattr(struct dentry *dentry,
const char *xattr_name,
void *xattr_value,
size_t xattr_value_len,
struct integrity_iint_cache *iint);
extern int evm_inode_setattr(struct user_namespace *mnt_userns,
struct dentry *dentry, struct iattr *attr);
extern void evm_inode_post_setattr(struct dentry *dentry, int ia_valid);
extern int evm_inode_setxattr(struct user_namespace *mnt_userns,
struct dentry *dentry, const char *name,
const void *value, size_t size);
extern void evm_inode_post_setxattr(struct dentry *dentry,
const char *xattr_name,
const void *xattr_value,
size_t xattr_value_len);
extern int evm_inode_removexattr(struct user_namespace *mnt_userns,
struct dentry *dentry, const char *xattr_name);
extern void evm_inode_post_removexattr(struct dentry *dentry,
const char *xattr_name);
extern int evm_inode_set_acl(struct user_namespace *mnt_userns,
struct dentry *dentry, const char *acl_name,
struct posix_acl *kacl);
static inline int evm_inode_remove_acl(struct user_namespace *mnt_userns,
struct dentry *dentry,
const char *acl_name)
{
return evm_inode_set_acl(mnt_userns, dentry, acl_name, NULL);
}
extern int evm_inode_init_security(struct inode *inode,
const struct xattr *xattr_array,
struct xattr *evm);
extern bool evm_revalidate_status(const char *xattr_name);
extern int evm_protected_xattr_if_enabled(const char *req_xattr_name);
extern int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
int buffer_size, char type,
bool canonical_fmt);
#ifdef CONFIG_FS_POSIX_ACL
extern int posix_xattr_acl(const char *xattrname);
#else
static inline int posix_xattr_acl(const char *xattrname)
{
return 0;
}
#endif
#else
static inline int evm_set_key(void *key, size_t keylen)
{
return -EOPNOTSUPP;
}
#ifdef CONFIG_INTEGRITY
static inline enum integrity_status evm_verifyxattr(struct dentry *dentry,
const char *xattr_name,
void *xattr_value,
size_t xattr_value_len,
struct integrity_iint_cache *iint)
{
return INTEGRITY_UNKNOWN;
}
#endif
static inline int evm_inode_setattr(struct user_namespace *mnt_userns,
struct dentry *dentry, struct iattr *attr)
{
return 0;
}
static inline void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
{
return;
}
static inline int evm_inode_setxattr(struct user_namespace *mnt_userns,
struct dentry *dentry, const char *name,
const void *value, size_t size)
{
return 0;
}
static inline void evm_inode_post_setxattr(struct dentry *dentry,
const char *xattr_name,
const void *xattr_value,
size_t xattr_value_len)
{
return;
}
static inline int evm_inode_removexattr(struct user_namespace *mnt_userns,
struct dentry *dentry,
const char *xattr_name)
{
return 0;
}
static inline void evm_inode_post_removexattr(struct dentry *dentry,
const char *xattr_name)
{
return;
}
static inline int evm_inode_set_acl(struct user_namespace *mnt_userns,
struct dentry *dentry, const char *acl_name,
struct posix_acl *kacl)
{
return 0;
}
static inline int evm_inode_remove_acl(struct user_namespace *mnt_userns,
struct dentry *dentry,
const char *acl_name)
{
return 0;
}
static inline int evm_inode_init_security(struct inode *inode,
const struct xattr *xattr_array,
struct xattr *evm)
{
return 0;
}
static inline bool evm_revalidate_status(const char *xattr_name)
{
return false;
}
static inline int evm_protected_xattr_if_enabled(const char *req_xattr_name)
{
return false;
}
static inline int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
int buffer_size, char type,
bool canonical_fmt)
{
return -EOPNOTSUPP;
}
#endif /* CONFIG_EVM */
#endif /* LINUX_EVM_H */