Skip to content

Commit

Permalink
Merge tag 'integrity-v6.10' of ssh://ra.kernel.org/pub/scm/linux/kern…
Browse files Browse the repository at this point in the history
…el/git/zohar/linux-integrity

Pull integrity updates from Mimi Zohar:
 "Two IMA changes, one EVM change, a use after free bug fix, and a code
  cleanup to address "-Wflex-array-member-not-at-end" warnings:

   - The existing IMA {ascii, binary}_runtime_measurements lists include
     a hard coded SHA1 hash. To address this limitation, define per TPM
     enabled hash algorithm {ascii, binary}_runtime_measurements lists

   - Close an IMA integrity init_module syscall measurement gap by
     defining a new critical-data record

   - Enable (partial) EVM support on stacked filesystems (overlayfs).
     Only EVM portable & immutable file signatures are copied up, since
     they do not contain filesystem specific metadata"

* tag 'integrity-v6.10' of ssh://ra.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity:
  ima: add crypto agility support for template-hash algorithm
  evm: Rename is_unsupported_fs to is_unsupported_hmac_fs
  fs: Rename SB_I_EVM_UNSUPPORTED to SB_I_EVM_HMAC_UNSUPPORTED
  evm: Enforce signatures on unsupported filesystem for EVM_INIT_X509
  ima: re-evaluate file integrity on file metadata change
  evm: Store and detect metadata inode attributes changes
  ima: Move file-change detection variables into new structure
  evm: Use the metadata inode to calculate metadata hash
  evm: Implement per signature type decision in security_inode_copy_up_xattr
  security: allow finer granularity in permitting copy-up of security xattrs
  ima: Rename backing_inode to real_inode
  integrity: Avoid -Wflex-array-member-not-at-end warnings
  ima: define an init_module critical data record
  ima: Fix use-after-free on a dentry's dname.name
  • Loading branch information
torvalds committed May 15, 2024
2 parents ccae19c + 9fa8e76 commit 353ad6c
Show file tree
Hide file tree
Showing 24 changed files with 374 additions and 96 deletions.
2 changes: 1 addition & 1 deletion fs/overlayfs/copy_up.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ int ovl_copy_xattr(struct super_block *sb, const struct path *oldpath, struct de
if (ovl_is_private_xattr(sb, name))
continue;

error = security_inode_copy_up_xattr(name);
error = security_inode_copy_up_xattr(old, name);
if (error < 0 && error != -EOPNOTSUPP)
break;
if (error == 1) {
Expand Down
2 changes: 1 addition & 1 deletion fs/overlayfs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -1460,7 +1460,7 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc)
* lead to unexpected results.
*/
sb->s_iflags |= SB_I_NOUMASK;
sb->s_iflags |= SB_I_EVM_UNSUPPORTED;
sb->s_iflags |= SB_I_EVM_HMAC_UNSUPPORTED;

err = -ENOMEM;
root_dentry = ovl_get_root(sb, ctx->upper.dentry, oe);
Expand Down
8 changes: 8 additions & 0 deletions include/linux/evm.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ 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);
extern bool evm_metadata_changed(struct inode *inode,
struct inode *metadata_inode);
#ifdef CONFIG_FS_POSIX_ACL
extern int posix_xattr_acl(const char *xattrname);
#else
Expand Down Expand Up @@ -76,5 +78,11 @@ static inline int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
return -EOPNOTSUPP;
}

static inline bool evm_metadata_changed(struct inode *inode,
struct inode *metadata_inode)
{
return false;
}

#endif /* CONFIG_EVM */
#endif /* LINUX_EVM_H */
2 changes: 1 addition & 1 deletion include/linux/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1174,7 +1174,7 @@ extern int send_sigurg(struct fown_struct *fown);
#define SB_I_USERNS_VISIBLE 0x00000010 /* fstype already mounted */
#define SB_I_IMA_UNVERIFIABLE_SIGNATURE 0x00000020
#define SB_I_UNTRUSTED_MOUNTER 0x00000040
#define SB_I_EVM_UNSUPPORTED 0x00000080
#define SB_I_EVM_HMAC_UNSUPPORTED 0x00000080

#define SB_I_SKIP_SYNC 0x00000100 /* Skip superblock at global sync */
#define SB_I_PERSB_BDI 0x00000200 /* has a per-sb bdi */
Expand Down
34 changes: 34 additions & 0 deletions include/linux/integrity.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#define _LINUX_INTEGRITY_H

#include <linux/fs.h>
#include <linux/iversion.h>

enum integrity_status {
INTEGRITY_PASS = 0,
Expand All @@ -28,4 +29,37 @@ static inline void integrity_load_keys(void)
}
#endif /* CONFIG_INTEGRITY */

/* An inode's attributes for detection of changes */
struct integrity_inode_attributes {
u64 version; /* track inode changes */
unsigned long ino;
dev_t dev;
};

/*
* On stacked filesystems the i_version alone is not enough to detect file data
* or metadata change. Additional metadata is required.
*/
static inline void
integrity_inode_attrs_store(struct integrity_inode_attributes *attrs,
u64 i_version, const struct inode *inode)
{
attrs->version = i_version;
attrs->dev = inode->i_sb->s_dev;
attrs->ino = inode->i_ino;
}

/*
* On stacked filesystems detect whether the inode or its content has changed.
*/
static inline bool
integrity_inode_attrs_changed(const struct integrity_inode_attributes *attrs,
const struct inode *inode)
{
return (inode->i_sb->s_dev != attrs->dev ||
inode->i_ino != attrs->ino ||
!inode_eq_iversion(inode, attrs->version));
}


#endif /* _LINUX_INTEGRITY_H */
3 changes: 2 additions & 1 deletion include/linux/lsm_hook_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,8 @@ LSM_HOOK(int, 0, inode_listsecurity, struct inode *inode, char *buffer,
size_t buffer_size)
LSM_HOOK(void, LSM_RET_VOID, inode_getsecid, struct inode *inode, u32 *secid)
LSM_HOOK(int, 0, inode_copy_up, struct dentry *src, struct cred **new)
LSM_HOOK(int, -EOPNOTSUPP, inode_copy_up_xattr, const char *name)
LSM_HOOK(int, -EOPNOTSUPP, inode_copy_up_xattr, struct dentry *src,
const char *name)
LSM_HOOK(int, 0, kernfs_init_security, struct kernfs_node *kn_dir,
struct kernfs_node *kn)
LSM_HOOK(int, 0, file_permission, struct file *file, int mask)
Expand Down
4 changes: 2 additions & 2 deletions include/linux/security.h
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ int security_inode_setsecurity(struct inode *inode, const char *name, const void
int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size);
void security_inode_getsecid(struct inode *inode, u32 *secid);
int security_inode_copy_up(struct dentry *src, struct cred **new);
int security_inode_copy_up_xattr(const char *name);
int security_inode_copy_up_xattr(struct dentry *src, const char *name);
int security_kernfs_init_security(struct kernfs_node *kn_dir,
struct kernfs_node *kn);
int security_file_permission(struct file *file, int mask);
Expand Down Expand Up @@ -1016,7 +1016,7 @@ static inline int security_kernfs_init_security(struct kernfs_node *kn_dir,
return 0;
}

static inline int security_inode_copy_up_xattr(const char *name)
static inline int security_inode_copy_up_xattr(struct dentry *src, const char *name)
{
return -EOPNOTSUPP;
}
Expand Down
8 changes: 5 additions & 3 deletions security/integrity/evm/evm.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ struct xattr_list {
struct evm_iint_cache {
unsigned long flags;
enum integrity_status evm_status:4;
struct integrity_inode_attributes metadata_inode;
};

extern struct lsm_blob_sizes evm_blob_sizes;
Expand All @@ -61,7 +62,7 @@ extern int evm_hmac_attrs;
extern struct list_head evm_config_xattrnames;

struct evm_digest {
struct ima_digest_data hdr;
struct ima_digest_data_hdr hdr;
char digest[IMA_MAX_DIGEST_SIZE];
} __packed;

Expand All @@ -74,11 +75,12 @@ int evm_update_evmxattr(struct dentry *dentry,
size_t req_xattr_value_len);
int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
const char *req_xattr_value,
size_t req_xattr_value_len, struct evm_digest *data);
size_t req_xattr_value_len, struct evm_digest *data,
struct evm_iint_cache *iint);
int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name,
const char *req_xattr_value,
size_t req_xattr_value_len, char type,
struct evm_digest *data);
struct evm_digest *data, struct evm_iint_cache *iint);
int evm_init_hmac(struct inode *inode, const struct xattr *xattrs,
char *hmac_val);
int evm_init_secfs(void);
Expand Down
25 changes: 18 additions & 7 deletions security/integrity/evm/evm_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -221,16 +221,18 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
const char *req_xattr_name,
const char *req_xattr_value,
size_t req_xattr_value_len,
uint8_t type, struct evm_digest *data)
uint8_t type, struct evm_digest *data,
struct evm_iint_cache *iint)
{
struct inode *inode = d_backing_inode(dentry);
struct inode *inode = d_inode(d_real(dentry, D_REAL_METADATA));
struct xattr_list *xattr;
struct shash_desc *desc;
size_t xattr_size = 0;
char *xattr_value = NULL;
int error;
int size, user_space_size;
bool ima_present = false;
u64 i_version = 0;

if (!(inode->i_opflags & IOP_XATTR) ||
inode->i_sb->s_user_ns != &init_user_ns)
Expand Down Expand Up @@ -294,6 +296,13 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
}
hmac_add_misc(desc, inode, type, data->digest);

if (inode != d_backing_inode(dentry) && iint) {
if (IS_I_VERSION(inode))
i_version = inode_query_iversion(inode);
integrity_inode_attrs_store(&iint->metadata_inode, i_version,
inode);
}

/* Portable EVM signatures must include an IMA hash */
if (type == EVM_XATTR_PORTABLE_DIGSIG && !ima_present)
error = -EPERM;
Expand All @@ -305,18 +314,19 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,

int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
const char *req_xattr_value, size_t req_xattr_value_len,
struct evm_digest *data)
struct evm_digest *data, struct evm_iint_cache *iint)
{
return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value,
req_xattr_value_len, EVM_XATTR_HMAC, data);
req_xattr_value_len, EVM_XATTR_HMAC, data,
iint);
}

int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name,
const char *req_xattr_value, size_t req_xattr_value_len,
char type, struct evm_digest *data)
char type, struct evm_digest *data, struct evm_iint_cache *iint)
{
return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value,
req_xattr_value_len, type, data);
req_xattr_value_len, type, data, iint);
}

static int evm_is_immutable(struct dentry *dentry, struct inode *inode)
Expand Down Expand Up @@ -357,6 +367,7 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name,
const char *xattr_value, size_t xattr_value_len)
{
struct inode *inode = d_backing_inode(dentry);
struct evm_iint_cache *iint = evm_iint_inode(inode);
struct evm_digest data;
int rc = 0;

Expand All @@ -372,7 +383,7 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name,

data.hdr.algo = HASH_ALGO_SHA1;
rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
xattr_value_len, &data);
xattr_value_len, &data, iint);
if (rc == 0) {
data.hdr.xattr.sha1.type = EVM_XATTR_HMAC;
rc = __vfs_setxattr_noperm(&nop_mnt_idmap, dentry,
Expand Down
Loading

0 comments on commit 353ad6c

Please sign in to comment.