Skip to content

Commit aa569fa

Browse files
committed
Merge branch 'serge-next-2' of git://git.kernel.org/pub/scm/linux/kernel/git/sergeh/linux-security
Pull more security layer updates from Serge Hallyn: "A few more commits had previously failed to make it through security-next into linux-next but this week made it into linux-next. At least commit "ima: introduce ima_kernel_read()" was deemed critical by Mimi to make this merge window. This is a temporary tree just for this request. Mimi has pointed me to some previous threads about keeping maintainer trees at the previous release, which I'll certainly do for anything long-term, after talking with James" * 'serge-next-2' of git://git.kernel.org/pub/scm/linux/kernel/git/sergeh/linux-security: ima: introduce ima_kernel_read() evm: prohibit userspace writing 'security.evm' HMAC value ima: check inode integrity cache in violation check ima: prevent unnecessary policy checking evm: provide option to protect additional SMACK xattrs evm: replace HMAC version with attribute mask ima: prevent new digsig xattr from being replaced
2 parents 6d87c22 + 0430e49 commit aa569fa

File tree

7 files changed

+114
-28
lines changed

7 files changed

+114
-28
lines changed

security/integrity/evm/Kconfig

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,41 @@ config EVM
1212

1313
If you are unsure how to answer this question, answer N.
1414

15-
config EVM_HMAC_VERSION
16-
int "EVM HMAC version"
15+
if EVM
16+
17+
menu "EVM options"
18+
19+
config EVM_ATTR_FSUUID
20+
bool "FSUUID (version 2)"
21+
default y
1722
depends on EVM
18-
default 2
1923
help
20-
This options adds EVM HMAC version support.
21-
1 - original version
22-
2 - add per filesystem unique identifier (UUID) (default)
24+
Include filesystem UUID for HMAC calculation.
25+
26+
Default value is 'selected', which is former version 2.
27+
if 'not selected', it is former version 1
2328

24-
WARNING: changing the HMAC calculation method or adding
29+
WARNING: changing the HMAC calculation method or adding
2530
additional info to the calculation, requires existing EVM
26-
labeled file systems to be relabeled.
31+
labeled file systems to be relabeled.
32+
33+
config EVM_EXTRA_SMACK_XATTRS
34+
bool "Additional SMACK xattrs"
35+
depends on EVM && SECURITY_SMACK
36+
default n
37+
help
38+
Include additional SMACK xattrs for HMAC calculation.
39+
40+
In addition to the original security xattrs (eg. security.selinux,
41+
security.SMACK64, security.capability, and security.ima) included
42+
in the HMAC calculation, enabling this option includes newly defined
43+
Smack xattrs: security.SMACK64EXEC, security.SMACK64TRANSMUTE and
44+
security.SMACK64MMAP.
45+
46+
WARNING: changing the HMAC calculation method or adding
47+
additional info to the calculation, requires existing EVM
48+
labeled file systems to be relabeled.
49+
50+
endmenu
51+
52+
endif

security/integrity/evm/evm.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@
2424
extern int evm_initialized;
2525
extern char *evm_hmac;
2626
extern char *evm_hash;
27-
extern int evm_hmac_version;
27+
28+
#define EVM_ATTR_FSUUID 0x0001
29+
30+
extern int evm_hmac_attrs;
2831

2932
extern struct crypto_shash *hmac_tfm;
3033
extern struct crypto_shash *hash_tfm;

security/integrity/evm/evm_crypto.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
112112
hmac_misc.gid = from_kgid(&init_user_ns, inode->i_gid);
113113
hmac_misc.mode = inode->i_mode;
114114
crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof(hmac_misc));
115-
if (evm_hmac_version > 1)
115+
if (evm_hmac_attrs & EVM_ATTR_FSUUID)
116116
crypto_shash_update(desc, inode->i_sb->s_uuid,
117117
sizeof(inode->i_sb->s_uuid));
118118
crypto_shash_final(desc, digest);

security/integrity/evm/evm_main.c

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,19 @@ static char *integrity_status_msg[] = {
3232
};
3333
char *evm_hmac = "hmac(sha1)";
3434
char *evm_hash = "sha1";
35-
int evm_hmac_version = CONFIG_EVM_HMAC_VERSION;
35+
int evm_hmac_attrs;
3636

3737
char *evm_config_xattrnames[] = {
3838
#ifdef CONFIG_SECURITY_SELINUX
3939
XATTR_NAME_SELINUX,
4040
#endif
4141
#ifdef CONFIG_SECURITY_SMACK
4242
XATTR_NAME_SMACK,
43+
#ifdef CONFIG_EVM_EXTRA_SMACK_XATTRS
44+
XATTR_NAME_SMACKEXEC,
45+
XATTR_NAME_SMACKTRANSMUTE,
46+
XATTR_NAME_SMACKMMAP,
47+
#endif
4348
#endif
4449
#ifdef CONFIG_IMA_APPRAISE
4550
XATTR_NAME_IMA,
@@ -57,6 +62,14 @@ static int __init evm_set_fixmode(char *str)
5762
}
5863
__setup("evm=", evm_set_fixmode);
5964

65+
static void __init evm_init_config(void)
66+
{
67+
#ifdef CONFIG_EVM_ATTR_FSUUID
68+
evm_hmac_attrs |= EVM_ATTR_FSUUID;
69+
#endif
70+
pr_info("HMAC attrs: 0x%x\n", evm_hmac_attrs);
71+
}
72+
6073
static int evm_find_protected_xattrs(struct dentry *dentry)
6174
{
6275
struct inode *inode = dentry->d_inode;
@@ -287,12 +300,20 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
287300
* @xattr_value: pointer to the new extended attribute value
288301
* @xattr_value_len: pointer to the new extended attribute value length
289302
*
290-
* Updating 'security.evm' requires CAP_SYS_ADMIN privileges and that
291-
* the current value is valid.
303+
* Before allowing the 'security.evm' protected xattr to be updated,
304+
* verify the existing value is valid. As only the kernel should have
305+
* access to the EVM encrypted key needed to calculate the HMAC, prevent
306+
* userspace from writing HMAC value. Writing 'security.evm' requires
307+
* requires CAP_SYS_ADMIN privileges.
292308
*/
293309
int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name,
294310
const void *xattr_value, size_t xattr_value_len)
295311
{
312+
const struct evm_ima_xattr_data *xattr_data = xattr_value;
313+
314+
if ((strcmp(xattr_name, XATTR_NAME_EVM) == 0)
315+
&& (xattr_data->type == EVM_XATTR_HMAC))
316+
return -EPERM;
296317
return evm_protect_xattr(dentry, xattr_name, xattr_value,
297318
xattr_value_len);
298319
}
@@ -432,6 +453,8 @@ static int __init init_evm(void)
432453
{
433454
int error;
434455

456+
evm_init_config();
457+
435458
error = evm_init_secfs();
436459
if (error < 0) {
437460
pr_info("Error registering secfs\n");

security/integrity/ima/ima_appraise.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ static int ima_protect_xattr(struct dentry *dentry, const char *xattr_name,
341341
return 0;
342342
}
343343

344-
static void ima_reset_appraise_flags(struct inode *inode)
344+
static void ima_reset_appraise_flags(struct inode *inode, int digsig)
345345
{
346346
struct integrity_iint_cache *iint;
347347

@@ -353,18 +353,22 @@ static void ima_reset_appraise_flags(struct inode *inode)
353353
return;
354354

355355
iint->flags &= ~IMA_DONE_MASK;
356+
if (digsig)
357+
iint->flags |= IMA_DIGSIG;
356358
return;
357359
}
358360

359361
int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
360362
const void *xattr_value, size_t xattr_value_len)
361363
{
364+
const struct evm_ima_xattr_data *xvalue = xattr_value;
362365
int result;
363366

364367
result = ima_protect_xattr(dentry, xattr_name, xattr_value,
365368
xattr_value_len);
366369
if (result == 1) {
367-
ima_reset_appraise_flags(dentry->d_inode);
370+
ima_reset_appraise_flags(dentry->d_inode,
371+
(xvalue->type == EVM_IMA_XATTR_DIGSIG) ? 1 : 0);
368372
result = 0;
369373
}
370374
return result;
@@ -376,7 +380,7 @@ int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name)
376380

377381
result = ima_protect_xattr(dentry, xattr_name, NULL, 0);
378382
if (result == 1) {
379-
ima_reset_appraise_flags(dentry->d_inode);
383+
ima_reset_appraise_flags(dentry->d_inode, 0);
380384
result = 0;
381385
}
382386
return result;

security/integrity/ima/ima_crypto.c

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,36 @@
2727

2828
static struct crypto_shash *ima_shash_tfm;
2929

30+
/**
31+
* ima_kernel_read - read file content
32+
*
33+
* This is a function for reading file content instead of kernel_read().
34+
* It does not perform locking checks to ensure it cannot be blocked.
35+
* It does not perform security checks because it is irrelevant for IMA.
36+
*
37+
*/
38+
static int ima_kernel_read(struct file *file, loff_t offset,
39+
char *addr, unsigned long count)
40+
{
41+
mm_segment_t old_fs;
42+
char __user *buf = addr;
43+
ssize_t ret;
44+
45+
if (!(file->f_mode & FMODE_READ))
46+
return -EBADF;
47+
if (!file->f_op->read && !file->f_op->aio_read)
48+
return -EINVAL;
49+
50+
old_fs = get_fs();
51+
set_fs(get_ds());
52+
if (file->f_op->read)
53+
ret = file->f_op->read(file, buf, count, &offset);
54+
else
55+
ret = do_sync_read(file, buf, count, &offset);
56+
set_fs(old_fs);
57+
return ret;
58+
}
59+
3060
int ima_init_crypto(void)
3161
{
3262
long rc;
@@ -104,7 +134,7 @@ static int ima_calc_file_hash_tfm(struct file *file,
104134
while (offset < i_size) {
105135
int rbuf_len;
106136

107-
rbuf_len = kernel_read(file, offset, rbuf, PAGE_SIZE);
137+
rbuf_len = ima_kernel_read(file, offset, rbuf, PAGE_SIZE);
108138
if (rbuf_len < 0) {
109139
rc = rbuf_len;
110140
break;

security/integrity/ima/ima_main.c

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ static void ima_rdwr_violation_check(struct file *file)
8181
{
8282
struct inode *inode = file_inode(file);
8383
fmode_t mode = file->f_mode;
84-
int must_measure;
8584
bool send_tomtou = false, send_writers = false;
8685
char *pathbuf = NULL;
8786
const char *pathname;
@@ -92,18 +91,19 @@ static void ima_rdwr_violation_check(struct file *file)
9291
mutex_lock(&inode->i_mutex); /* file metadata: permissions, xattr */
9392

9493
if (mode & FMODE_WRITE) {
95-
if (atomic_read(&inode->i_readcount) && IS_IMA(inode))
96-
send_tomtou = true;
97-
goto out;
94+
if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) {
95+
struct integrity_iint_cache *iint;
96+
iint = integrity_iint_find(inode);
97+
/* IMA_MEASURE is set from reader side */
98+
if (iint && (iint->flags & IMA_MEASURE))
99+
send_tomtou = true;
100+
}
101+
} else {
102+
if ((atomic_read(&inode->i_writecount) > 0) &&
103+
ima_must_measure(inode, MAY_READ, FILE_CHECK))
104+
send_writers = true;
98105
}
99106

100-
must_measure = ima_must_measure(inode, MAY_READ, FILE_CHECK);
101-
if (!must_measure)
102-
goto out;
103-
104-
if (atomic_read(&inode->i_writecount) > 0)
105-
send_writers = true;
106-
out:
107107
mutex_unlock(&inode->i_mutex);
108108

109109
if (!send_tomtou && !send_writers)

0 commit comments

Comments
 (0)