Skip to content

Commit 353ad6c

Browse files
committed
Merge tag 'integrity-v6.10' of ssh://ra.kernel.org/pub/scm/linux/kernel/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
2 parents ccae19c + 9fa8e76 commit 353ad6c

24 files changed

+374
-96
lines changed

fs/overlayfs/copy_up.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ int ovl_copy_xattr(struct super_block *sb, const struct path *oldpath, struct de
114114
if (ovl_is_private_xattr(sb, name))
115115
continue;
116116

117-
error = security_inode_copy_up_xattr(name);
117+
error = security_inode_copy_up_xattr(old, name);
118118
if (error < 0 && error != -EOPNOTSUPP)
119119
break;
120120
if (error == 1) {

fs/overlayfs/super.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1460,7 +1460,7 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc)
14601460
* lead to unexpected results.
14611461
*/
14621462
sb->s_iflags |= SB_I_NOUMASK;
1463-
sb->s_iflags |= SB_I_EVM_UNSUPPORTED;
1463+
sb->s_iflags |= SB_I_EVM_HMAC_UNSUPPORTED;
14641464

14651465
err = -ENOMEM;
14661466
root_dentry = ovl_get_root(sb, ctx->upper.dentry, oe);

include/linux/evm.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ extern int evm_protected_xattr_if_enabled(const char *req_xattr_name);
2626
extern int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
2727
int buffer_size, char type,
2828
bool canonical_fmt);
29+
extern bool evm_metadata_changed(struct inode *inode,
30+
struct inode *metadata_inode);
2931
#ifdef CONFIG_FS_POSIX_ACL
3032
extern int posix_xattr_acl(const char *xattrname);
3133
#else
@@ -76,5 +78,11 @@ static inline int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
7678
return -EOPNOTSUPP;
7779
}
7880

81+
static inline bool evm_metadata_changed(struct inode *inode,
82+
struct inode *metadata_inode)
83+
{
84+
return false;
85+
}
86+
7987
#endif /* CONFIG_EVM */
8088
#endif /* LINUX_EVM_H */

include/linux/fs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1174,7 +1174,7 @@ extern int send_sigurg(struct fown_struct *fown);
11741174
#define SB_I_USERNS_VISIBLE 0x00000010 /* fstype already mounted */
11751175
#define SB_I_IMA_UNVERIFIABLE_SIGNATURE 0x00000020
11761176
#define SB_I_UNTRUSTED_MOUNTER 0x00000040
1177-
#define SB_I_EVM_UNSUPPORTED 0x00000080
1177+
#define SB_I_EVM_HMAC_UNSUPPORTED 0x00000080
11781178

11791179
#define SB_I_SKIP_SYNC 0x00000100 /* Skip superblock at global sync */
11801180
#define SB_I_PERSB_BDI 0x00000200 /* has a per-sb bdi */

include/linux/integrity.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#define _LINUX_INTEGRITY_H
99

1010
#include <linux/fs.h>
11+
#include <linux/iversion.h>
1112

1213
enum integrity_status {
1314
INTEGRITY_PASS = 0,
@@ -28,4 +29,37 @@ static inline void integrity_load_keys(void)
2829
}
2930
#endif /* CONFIG_INTEGRITY */
3031

32+
/* An inode's attributes for detection of changes */
33+
struct integrity_inode_attributes {
34+
u64 version; /* track inode changes */
35+
unsigned long ino;
36+
dev_t dev;
37+
};
38+
39+
/*
40+
* On stacked filesystems the i_version alone is not enough to detect file data
41+
* or metadata change. Additional metadata is required.
42+
*/
43+
static inline void
44+
integrity_inode_attrs_store(struct integrity_inode_attributes *attrs,
45+
u64 i_version, const struct inode *inode)
46+
{
47+
attrs->version = i_version;
48+
attrs->dev = inode->i_sb->s_dev;
49+
attrs->ino = inode->i_ino;
50+
}
51+
52+
/*
53+
* On stacked filesystems detect whether the inode or its content has changed.
54+
*/
55+
static inline bool
56+
integrity_inode_attrs_changed(const struct integrity_inode_attributes *attrs,
57+
const struct inode *inode)
58+
{
59+
return (inode->i_sb->s_dev != attrs->dev ||
60+
inode->i_ino != attrs->ino ||
61+
!inode_eq_iversion(inode, attrs->version));
62+
}
63+
64+
3165
#endif /* _LINUX_INTEGRITY_H */

include/linux/lsm_hook_defs.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,8 @@ LSM_HOOK(int, 0, inode_listsecurity, struct inode *inode, char *buffer,
176176
size_t buffer_size)
177177
LSM_HOOK(void, LSM_RET_VOID, inode_getsecid, struct inode *inode, u32 *secid)
178178
LSM_HOOK(int, 0, inode_copy_up, struct dentry *src, struct cred **new)
179-
LSM_HOOK(int, -EOPNOTSUPP, inode_copy_up_xattr, const char *name)
179+
LSM_HOOK(int, -EOPNOTSUPP, inode_copy_up_xattr, struct dentry *src,
180+
const char *name)
180181
LSM_HOOK(int, 0, kernfs_init_security, struct kernfs_node *kn_dir,
181182
struct kernfs_node *kn)
182183
LSM_HOOK(int, 0, file_permission, struct file *file, int mask)

include/linux/security.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ int security_inode_setsecurity(struct inode *inode, const char *name, const void
398398
int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size);
399399
void security_inode_getsecid(struct inode *inode, u32 *secid);
400400
int security_inode_copy_up(struct dentry *src, struct cred **new);
401-
int security_inode_copy_up_xattr(const char *name);
401+
int security_inode_copy_up_xattr(struct dentry *src, const char *name);
402402
int security_kernfs_init_security(struct kernfs_node *kn_dir,
403403
struct kernfs_node *kn);
404404
int security_file_permission(struct file *file, int mask);
@@ -1016,7 +1016,7 @@ static inline int security_kernfs_init_security(struct kernfs_node *kn_dir,
10161016
return 0;
10171017
}
10181018

1019-
static inline int security_inode_copy_up_xattr(const char *name)
1019+
static inline int security_inode_copy_up_xattr(struct dentry *src, const char *name)
10201020
{
10211021
return -EOPNOTSUPP;
10221022
}

security/integrity/evm/evm.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ struct xattr_list {
3939
struct evm_iint_cache {
4040
unsigned long flags;
4141
enum integrity_status evm_status:4;
42+
struct integrity_inode_attributes metadata_inode;
4243
};
4344

4445
extern struct lsm_blob_sizes evm_blob_sizes;
@@ -61,7 +62,7 @@ extern int evm_hmac_attrs;
6162
extern struct list_head evm_config_xattrnames;
6263

6364
struct evm_digest {
64-
struct ima_digest_data hdr;
65+
struct ima_digest_data_hdr hdr;
6566
char digest[IMA_MAX_DIGEST_SIZE];
6667
} __packed;
6768

@@ -74,11 +75,12 @@ int evm_update_evmxattr(struct dentry *dentry,
7475
size_t req_xattr_value_len);
7576
int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
7677
const char *req_xattr_value,
77-
size_t req_xattr_value_len, struct evm_digest *data);
78+
size_t req_xattr_value_len, struct evm_digest *data,
79+
struct evm_iint_cache *iint);
7880
int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name,
7981
const char *req_xattr_value,
8082
size_t req_xattr_value_len, char type,
81-
struct evm_digest *data);
83+
struct evm_digest *data, struct evm_iint_cache *iint);
8284
int evm_init_hmac(struct inode *inode, const struct xattr *xattrs,
8385
char *hmac_val);
8486
int evm_init_secfs(void);

security/integrity/evm/evm_crypto.c

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -221,16 +221,18 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
221221
const char *req_xattr_name,
222222
const char *req_xattr_value,
223223
size_t req_xattr_value_len,
224-
uint8_t type, struct evm_digest *data)
224+
uint8_t type, struct evm_digest *data,
225+
struct evm_iint_cache *iint)
225226
{
226-
struct inode *inode = d_backing_inode(dentry);
227+
struct inode *inode = d_inode(d_real(dentry, D_REAL_METADATA));
227228
struct xattr_list *xattr;
228229
struct shash_desc *desc;
229230
size_t xattr_size = 0;
230231
char *xattr_value = NULL;
231232
int error;
232233
int size, user_space_size;
233234
bool ima_present = false;
235+
u64 i_version = 0;
234236

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

299+
if (inode != d_backing_inode(dentry) && iint) {
300+
if (IS_I_VERSION(inode))
301+
i_version = inode_query_iversion(inode);
302+
integrity_inode_attrs_store(&iint->metadata_inode, i_version,
303+
inode);
304+
}
305+
297306
/* Portable EVM signatures must include an IMA hash */
298307
if (type == EVM_XATTR_PORTABLE_DIGSIG && !ima_present)
299308
error = -EPERM;
@@ -305,18 +314,19 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
305314

306315
int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
307316
const char *req_xattr_value, size_t req_xattr_value_len,
308-
struct evm_digest *data)
317+
struct evm_digest *data, struct evm_iint_cache *iint)
309318
{
310319
return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value,
311-
req_xattr_value_len, EVM_XATTR_HMAC, data);
320+
req_xattr_value_len, EVM_XATTR_HMAC, data,
321+
iint);
312322
}
313323

314324
int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name,
315325
const char *req_xattr_value, size_t req_xattr_value_len,
316-
char type, struct evm_digest *data)
326+
char type, struct evm_digest *data, struct evm_iint_cache *iint)
317327
{
318328
return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value,
319-
req_xattr_value_len, type, data);
329+
req_xattr_value_len, type, data, iint);
320330
}
321331

322332
static int evm_is_immutable(struct dentry *dentry, struct inode *inode)
@@ -357,6 +367,7 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name,
357367
const char *xattr_value, size_t xattr_value_len)
358368
{
359369
struct inode *inode = d_backing_inode(dentry);
370+
struct evm_iint_cache *iint = evm_iint_inode(inode);
360371
struct evm_digest data;
361372
int rc = 0;
362373

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

373384
data.hdr.algo = HASH_ALGO_SHA1;
374385
rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
375-
xattr_value_len, &data);
386+
xattr_value_len, &data, iint);
376387
if (rc == 0) {
377388
data.hdr.xattr.sha1.type = EVM_XATTR_HMAC;
378389
rc = __vfs_setxattr_noperm(&nop_mnt_idmap, dentry,

0 commit comments

Comments
 (0)