mailweb.openeuler.org
Manage this list

Keyboard Shortcuts

Thread View

  • j: Next unread message
  • k: Previous unread message
  • j a: Jump to all threads
  • j l: Jump to MailingList overview

Kernel

Threads by month
  • ----- 2025 -----
  • May
  • April
  • March
  • February
  • January
  • ----- 2024 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2023 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2022 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2021 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2020 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2019 -----
  • December
kernel@openeuler.org

  • 52 participants
  • 18285 discussions
[openEuler-1.0-LTS] tcp: Reduce chance of collisions in inet6_hashfn().
by Wang Yufen 22 Aug '23

22 Aug '23
From: Stewart Smith <trawets(a)amazon.com> stable inclusion from stable-v4.19.291 commit d11b0df7ddf1831f3e170972f43186dad520bfcc category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/I7FUFX CVE: CVE-2023-1206 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id… -------------------------------- [ Upstream commit d11b0df7ddf1831f3e170972f43186dad520bfcc ] For both IPv4 and IPv6 incoming TCP connections are tracked in a hash table with a hash over the source & destination addresses and ports. However, the IPv6 hash is insufficient and can lead to a high rate of collisions. The IPv6 hash used an XOR to fit everything into the 96 bits for the fast jenkins hash, meaning it is possible for an external entity to ensure the hash collides, thus falling back to a linear search in the bucket, which is slow. We take the approach of hash the full length of IPv6 address in __ipv6_addr_jhash() so that all users can benefit from a more secure version. While this may look like it adds overhead, the reality of modern CPUs means that this is unmeasurable in real world scenarios. In simulating with llvm-mca, the increase in cycles for the hashing code was ~16 cycles on Skylake (from a base of ~155), and an extra ~9 on Nehalem (base of ~173). In commit dd6d2910c5e0 ("netfilter: conntrack: switch to siphash") netfilter switched from a jenkins hash to a siphash, but even the faster hsiphash is a more significant overhead (~20-30%) in some preliminary testing. So, in this patch, we keep to the more conservative approach to ensure we don't add much overhead per SYN. In testing, this results in a consistently even spread across the connection buckets. In both testing and real-world scenarios, we have not found any measurable performance impact. Fixes: 08dcdbf6a7b9 ("ipv6: use a stronger hash for tcp") Signed-off-by: Stewart Smith <trawets(a)amazon.com> Signed-off-by: Samuel Mendoza-Jonas <samjonas(a)amazon.com> Suggested-by: Eric Dumazet <edumazet(a)google.com> Signed-off-by: Kuniyuki Iwashima <kuniyu(a)amazon.com> Reviewed-by: Eric Dumazet <edumazet(a)google.com> Link: https://lore.kernel.org/r/20230721222410.17914-1-kuniyu@amazon.com Signed-off-by: Jakub Kicinski <kuba(a)kernel.org> Signed-off-by: Sasha Levin <sashal(a)kernel.org> Signed-off-by: Wang Yufen <wangyufen(a)huawei.com> --- include/net/ipv6.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 0c88324..3a55a093 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -602,12 +602,8 @@ static inline u32 ipv6_addr_hash(const struct in6_addr *a) /* more secured version of ipv6_addr_hash() */ static inline u32 __ipv6_addr_jhash(const struct in6_addr *a, const u32 initval) { - u32 v = (__force u32)a->s6_addr32[0] ^ (__force u32)a->s6_addr32[1]; - - return jhash_3words(v, - (__force u32)a->s6_addr32[2], - (__force u32)a->s6_addr32[3], - initval); + return jhash2((__force const u32 *)a->s6_addr32, + ARRAY_SIZE(a->s6_addr32), initval); } static inline bool ipv6_addr_loopback(const struct in6_addr *a) -- 1.8.3.1
1 0
0 0
[PATCH OLK-5.10] fs: jfs: fix possible NULL pointer dereference in dbFree()
by Li Nan 22 Aug '23

22 Aug '23
From: Zixuan Fu <r33s3n6(a)gmail.com> mainline inclusion from mainline-v5.19-rc1 commit 0d4837fdb796f99369cf7691d33de1b856bcaf1f category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/I7TT9F CVE: CVE-2023-4385 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?… -------------------------------- In our fault-injection testing, the variable "nblocks" in dbFree() can be zero when kmalloc_array() fails in dtSearch(). In this case, the variable "mp" in dbFree() would be NULL and then it is dereferenced in "write_metapage(mp)". The failure log is listed as follows: [ 13.824137] BUG: kernel NULL pointer dereference, address: 0000000000000020 ... [ 13.827416] RIP: 0010:dbFree+0x5f7/0x910 [jfs] [ 13.834341] Call Trace: [ 13.834540] <TASK> [ 13.834713] txFreeMap+0x7b4/0xb10 [jfs] [ 13.835038] txUpdateMap+0x311/0x650 [jfs] [ 13.835375] jfs_lazycommit+0x5f2/0xc70 [jfs] [ 13.835726] ? sched_dynamic_update+0x1b0/0x1b0 [ 13.836092] kthread+0x3c2/0x4a0 [ 13.836355] ? txLockFree+0x160/0x160 [jfs] [ 13.836763] ? kthread_unuse_mm+0x160/0x160 [ 13.837106] ret_from_fork+0x1f/0x30 [ 13.837402] </TASK> ... This patch adds a NULL check of "mp" before "write_metapage(mp)" is called. Reported-by: TOTE Robot <oslab(a)tsinghua.edu.cn> Signed-off-by: Zixuan Fu <r33s3n6(a)gmail.com> Signed-off-by: Dave Kleikamp <dave.kleikamp(a)oracle.com> Signed-off-by: Li Nan <linan122(a)huawei.com> --- fs/jfs/jfs_dmap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c index 2c9493011aec..7b2c9e60dabc 100644 --- a/fs/jfs/jfs_dmap.c +++ b/fs/jfs/jfs_dmap.c @@ -3262,7 +3262,8 @@ int dbAllocBottomUp(struct inode *ip, s64 blkno, s64 nblocks) } /* write the last buffer. */ - write_metapage(mp); + if (mp) + write_metapage(mp); IREAD_UNLOCK(ipbmap); -- 2.39.2
2 1
0 0
[PATCH openEuler-1.0-LTS v3 0/3] fix NULL pointer dereference in __nf_nat_mangle_tcp_packet
by Zhengchao Shao 22 Aug '23

22 Aug '23
When nf_nat_ipv4.ko is not loaded, l3proto is NULL pointer. If the csum_recalc function of l3proto is called, it will cause NULL pointer access issue. --- v3: add space after return type for Patch 3/3 v2: modify commit message for Patch 3/3 --- Florian Westphal (2): netfilter: nat: remove csum_recalc hook netfilter: nat: fix udp checksum corruption Zhengchao Shao (1): netfilter: nat: fix kabi change include/net/netfilter/nf_nat_l3proto.h | 4 ++ net/ipv4/netfilter/nf_nat_l3proto_ipv4.c | 19 ------ net/ipv6/netfilter/nf_nat_l3proto_ipv6.c | 19 ------ net/netfilter/Makefile | 2 +- net/netfilter/nf_nat_helper.c | 12 ++-- net/netfilter/nf_nat_proto.c | 74 ++++++++++++++++++++++++ 6 files changed, 83 insertions(+), 47 deletions(-) create mode 100644 net/netfilter/nf_nat_proto.c -- 2.34.1
2 4
0 0
[PATCH openEuler-1.0-LTS v2 0/3] fix NULL pointer dereference in __nf_nat_mangle_tcp_packet
by Zhengchao Shao 22 Aug '23

22 Aug '23
When nf_nat_ipv4.ko is not loaded, l3proto is NULL pointer. If the csum_recalc function of l3proto is called, it will cause NULL pointer access issue. --- v2: modify commit message for Patch 3/3 --- Florian Westphal (2): netfilter: nat: remove csum_recalc hook netfilter: nat: fix udp checksum corruption Zhengchao Shao (1): netfilter: nat: fix kabi change include/net/netfilter/nf_nat_l3proto.h | 10 +++- net/ipv4/netfilter/nf_nat_l3proto_ipv4.c | 19 ------ net/ipv6/netfilter/nf_nat_l3proto_ipv6.c | 19 ------ net/netfilter/Makefile | 2 +- net/netfilter/nf_nat_helper.c | 12 ++-- net/netfilter/nf_nat_proto.c | 74 ++++++++++++++++++++++++ 6 files changed, 86 insertions(+), 50 deletions(-) create mode 100644 net/netfilter/nf_nat_proto.c -- 2.34.1
2 4
0 0
[PATCH OLK-5.10 0/2] x86/speculation: Add Gather Data Sampling mitigation
by Zeng Heng 21 Aug '23

21 Aug '23
Arnd Bergmann (1): [Backport] x86/speculation: Add cpu_show_gds() prototype Daniel Sneddon (1): [Backport] x86/speculation: Add Gather Data Sampling mitigation .../ABI/testing/sysfs-devices-system-cpu | 13 +- .../hw-vuln/gather_data_sampling.rst | 99 ++++++++++++++ Documentation/admin-guide/hw-vuln/index.rst | 1 + .../admin-guide/kernel-parameters.txt | 39 ++++-- arch/x86/include/asm/cpufeatures.h | 1 + arch/x86/include/asm/msr-index.h | 11 ++ arch/x86/kernel/cpu/bugs.c | 129 ++++++++++++++++++ arch/x86/kernel/cpu/common.c | 34 +++-- arch/x86/kernel/cpu/cpu.h | 1 + drivers/base/cpu.c | 8 ++ include/linux/cpu.h | 8 +- 11 files changed, 315 insertions(+), 29 deletions(-) create mode 100644 Documentation/admin-guide/hw-vuln/gather_data_sampling.rst -- 2.25.1
2 3
0 0
[PATCH openEuler-1.0-LTS,v2 0/3] fix NULL pointer dereference in __nf_nat_mangle_tcp_packet
by Zhengchao Shao 21 Aug '23

21 Aug '23
When nf_nat_ipv4.ko is not loaded, l3proto is NULL pointer. If the csum_recalc function of l3proto is called, it will cause NULL pointer access issue. --- v2: modify commit message for Patch 3/3 --- Florian Westphal (2): netfilter: nat: remove csum_recalc hook netfilter: nat: fix udp checksum corruption Zhengchao Shao (1): netfilter: nat: fix kabi change include/net/netfilter/nf_nat_l3proto.h | 10 +++- net/ipv4/netfilter/nf_nat_l3proto_ipv4.c | 19 ------ net/ipv6/netfilter/nf_nat_l3proto_ipv6.c | 19 ------ net/netfilter/Makefile | 2 +- net/netfilter/nf_nat_helper.c | 12 ++-- net/netfilter/nf_nat_proto.c | 74 ++++++++++++++++++++++++ 6 files changed, 86 insertions(+), 50 deletions(-) create mode 100644 net/netfilter/nf_nat_proto.c -- 2.34.1
1 3
0 0
[PATCH v5 OLK-5.10 0/4] arm64: support batched/deferred tlb shootdown during page reclamation/migration
by Jinjiang Tu 21 Aug '23

21 Aug '23
Support batched/deferred tlb shootdown during page reclamation/migration for arm64. Changelog: v5: - adjust tab num for macro DEFINE_TLB_UBC v4 - define macro DEFINE_TLB_UBC v3: - fix kabi breakage for task_struct->tlb_ubc v2: - fix kabi breakage for mm_struct->tlb_flush_batched Anshuman Khandual (1): mm/tlbbatch: introduce arch_tlbbatch_should_defer() Barry Song (2): mm/tlbbatch: rename and extend some functions arm64: support batched/deferred tlb shootdown during page reclamation/migration Yicong Yang (1): mm/tlbbatch: introduce arch_flush_tlb_batched_pending() .../features/vm/TLB/arch-support.txt | 2 +- arch/arm64/Kconfig | 1 + arch/arm64/include/asm/tlbbatch.h | 12 +++++ arch/arm64/include/asm/tlbflush.h | 44 +++++++++++++++++-- arch/x86/include/asm/tlbflush.h | 22 +++++++++- include/linux/mm_types.h | 4 +- include/linux/mm_types_task.h | 29 ++++++++++-- include/linux/sched.h | 3 ++ mm/rmap.c | 35 ++++++++------- 9 files changed, 126 insertions(+), 26 deletions(-) create mode 100644 arch/arm64/include/asm/tlbbatch.h -- 2.25.1
2 5
0 0
[PATCH openEuler-1.0-LTS 0/3] fix NULL pointer dereference in __nf_nat_mangle_tcp_packet
by Zhengchao Shao 21 Aug '23

21 Aug '23
When nf_nat_ipv4.ko is not loaded, l3proto is NULL pointer. If the csum_recalc function of l3proto is called, it will cause NULL pointer access issue. Florian Westphal (2): netfilter: nat: remove csum_recalc hook netfilter: nat: fix udp checksum corruption Zhengchao Shao (1): netfilter: nat: fix kabi change include/net/netfilter/nf_nat_l3proto.h | 10 +++- net/ipv4/netfilter/nf_nat_l3proto_ipv4.c | 19 ------ net/ipv6/netfilter/nf_nat_l3proto_ipv6.c | 19 ------ net/netfilter/Makefile | 2 +- net/netfilter/nf_nat_helper.c | 12 ++-- net/netfilter/nf_nat_proto.c | 74 ++++++++++++++++++++++++ 6 files changed, 86 insertions(+), 50 deletions(-) create mode 100644 net/netfilter/nf_nat_proto.c -- 2.34.1
2 4
0 0
[PATCH OLK-5.10] nbd: pass nbd_sock to nbd_read_reply() instead of index
by Li Nan 21 Aug '23

21 Aug '23
hulk inclusion category: bugfix bugzilla: 189113, https://gitee.com/openeuler/kernel/issues/I7T755 CVE: NA -------------------------------- If a socket is processing ioctl 'NBD_SET_SOCK', config->socks might be krealloc in nbd_add_socket(), and a garbage request is received now, a UAF may occurs. T1 nbd_ioctl __nbd_ioctl nbd_add_socket blk_mq_freeze_queue T2 recv_work nbd_read_reply sock_xmit krealloc config->socks def config->socks Pass nbd_sock to nbd_read_reply(). And introduce a new function sock_xmit_recv(), which differs from sock_xmit only in the way it get socket. ================================================================== BUG: KASAN: use-after-free in sock_xmit+0x525/0x550 Read of size 8 at addr ffff8880188ec428 by task kworker/u12:1/18779 Workqueue: knbd4-recv recv_work Call Trace: __dump_stack dump_stack+0xbe/0xfd print_address_description.constprop.0+0x19/0x170 __kasan_report.cold+0x6c/0x84 kasan_report+0x3a/0x50 sock_xmit+0x525/0x550 nbd_read_reply+0xfe/0x2c0 recv_work+0x1c2/0x750 process_one_work+0x6b6/0xf10 worker_thread+0xdd/0xd80 kthread+0x30a/0x410 ret_from_fork+0x22/0x30 Allocated by task 18784: kasan_save_stack+0x1b/0x40 kasan_set_track set_alloc_info __kasan_kmalloc __kasan_kmalloc.constprop.0+0xf0/0x130 slab_post_alloc_hook slab_alloc_node slab_alloc __kmalloc_track_caller+0x157/0x550 __do_krealloc krealloc+0x37/0xb0 nbd_add_socket +0x2d3/0x880 __nbd_ioctl nbd_ioctl+0x584/0x8e0 __blkdev_driver_ioctl blkdev_ioctl+0x2a0/0x6e0 block_ioctl+0xee/0x130 vfs_ioctl __do_sys_ioctl __se_sys_ioctl+0x138/0x190 do_syscall_64+0x33/0x40 entry_SYSCALL_64_after_hwframe+0x61/0xc6 Freed by task 18784: kasan_save_stack+0x1b/0x40 kasan_set_track+0x1c/0x30 kasan_set_free_info+0x20/0x40 __kasan_slab_free.part.0+0x13f/0x1b0 slab_free_hook slab_free_freelist_hook slab_free kfree+0xcb/0x6c0 krealloc+0x56/0xb0 nbd_add_socket+0x2d3/0x880 __nbd_ioctl nbd_ioctl+0x584/0x8e0 __blkdev_driver_ioctl blkdev_ioctl+0x2a0/0x6e0 block_ioctl+0xee/0x130 vfs_ioctl __do_sys_ioctl __se_sys_ioctl+0x138/0x190 do_syscall_64+0x33/0x40 entry_SYSCALL_64_after_hwframe+0x61/0xc6 Signed-off-by: Li Nan <linan122(a)huawei.com> --- drivers/block/nbd.c | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index e0a21169b4b8..db885f3a2f0f 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -64,6 +64,7 @@ struct nbd_sock { struct recv_thread_args { struct work_struct work; struct nbd_device *nbd; + struct nbd_sock *nsock; int index; }; @@ -500,15 +501,9 @@ static enum blk_eh_timer_return nbd_xmit_timeout(struct request *req, return BLK_EH_DONE; } -/* - * Send or receive packet. Return a positive value on success and - * negtive value on failue, and never return 0. - */ -static int sock_xmit(struct nbd_device *nbd, int index, int send, - struct iov_iter *iter, int msg_flags, int *sent) +static int __sock_xmit(struct nbd_device *nbd, struct socket *sock, int send, + struct iov_iter *iter, int msg_flags, int *sent) { - struct nbd_config *config = nbd->config; - struct socket *sock = config->socks[index]->sock; int result; struct msghdr msg; unsigned int noreclaim_flag; @@ -550,6 +545,19 @@ static int sock_xmit(struct nbd_device *nbd, int index, int send, return result; } +/* + * Send or receive packet. Return a positive value on success and + * negtive value on failure, and never return 0. + */ +static int sock_xmit(struct nbd_device *nbd, int index, int send, + struct iov_iter *iter, int msg_flags, int *sent) +{ + struct nbd_config *config = nbd->config; + struct socket *sock = config->socks[index]->sock; + + return __sock_xmit(nbd, sock, send, iter, msg_flags, sent); +} + /* * Different settings for sk->sk_sndtimeo can result in different return values * if there is a signal pending when we enter sendmsg, because reasons? @@ -706,7 +714,7 @@ static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index) return 0; } -static int nbd_read_reply(struct nbd_device *nbd, int index, +static int nbd_read_reply(struct nbd_device *nbd, struct socket *sock, struct nbd_reply *reply) { struct kvec iov = {.iov_base = reply, .iov_len = sizeof(*reply)}; @@ -715,7 +723,7 @@ static int nbd_read_reply(struct nbd_device *nbd, int index, reply->magic = 0; iov_iter_kvec(&to, READ, &iov, 1, sizeof(*reply)); - result = sock_xmit(nbd, index, 0, &to, MSG_WAITALL, NULL); + result = __sock_xmit(nbd, sock, 0, &to, MSG_WAITALL, NULL); if (result < 0) { if (!nbd_disconnected(nbd->config)) dev_err(disk_to_dev(nbd->disk), @@ -837,14 +845,14 @@ static void recv_work(struct work_struct *work) struct nbd_device *nbd = args->nbd; struct nbd_config *config = nbd->config; struct request_queue *q = nbd->disk->queue; - struct nbd_sock *nsock; + struct nbd_sock *nsock = args->nsock; struct nbd_cmd *cmd; struct request *rq; while (1) { struct nbd_reply reply; - if (nbd_read_reply(nbd, args->index, &reply)) + if (nbd_read_reply(nbd, nsock->sock, &reply)) break; /* @@ -879,7 +887,6 @@ static void recv_work(struct work_struct *work) percpu_ref_put(&q->q_usage_counter); } - nsock = config->socks[args->index]; mutex_lock(&nsock->tx_lock); nbd_mark_nsock_dead(nbd, nsock, 1); mutex_unlock(&nsock->tx_lock); @@ -1223,6 +1230,7 @@ static int nbd_reconnect_socket(struct nbd_device *nbd, unsigned long arg) INIT_WORK(&args->work, recv_work); args->index = i; args->nbd = nbd; + args->nsock = nsock; nsock->cookie++; mutex_unlock(&nsock->tx_lock); sockfd_put(old); @@ -1413,6 +1421,7 @@ static int nbd_start_device(struct nbd_device *nbd) refcount_inc(&nbd->config_refs); INIT_WORK(&args->work, recv_work); args->nbd = nbd; + args->nsock = config->socks[i]; args->index = i; queue_work(nbd->recv_workq, &args->work); } -- 2.39.2
2 1
0 0
[PATCH v3 OLK-5.10] ima: Add macros to isolate the IMA digest list
by Zhou Shuiqing 21 Aug '23

21 Aug '23
euleros inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I277UJ -------------------------------- Isolate the IMA digest list code by using macros. changelog v2: Exclude some macros for code that has already been merged into upstream kernel. v3: add patch header and fix some simple code warnings Signed-off-by: Zhou Shuiqing <zhoushuiqing2(a)huawei.com> --- fs/xattr.c | 4 + include/linux/evm.h | 4 +- include/linux/ima.h | 8 + security/integrity/digsig_asymmetric.c | 4 + security/integrity/evm/evm.h | 2 + security/integrity/evm/evm_crypto.c | 38 +++- security/integrity/evm/evm_main.c | 79 +++++++- security/integrity/iint.c | 2 + security/integrity/ima/ima.h | 80 +++++++- security/integrity/ima/ima_api.c | 39 ++++ security/integrity/ima/ima_appraise.c | 154 ++++++++++++++- security/integrity/ima/ima_fs.c | 248 ++++++++++++++++++++++++- security/integrity/ima/ima_init.c | 6 + security/integrity/ima/ima_main.c | 36 ++++ security/integrity/ima/ima_policy.c | 80 ++++++++ security/integrity/integrity.h | 15 +- security/security.c | 2 + 17 files changed, 780 insertions(+), 21 deletions(-) diff --git a/fs/xattr.c b/fs/xattr.c index 149b8cf5f99f..c31266a83391 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -16,7 +16,9 @@ #include <linux/namei.h> #include <linux/security.h> #include <linux/evm.h> +#ifdef CONFIG_IMA_DIGEST_LIST #include <linux/ima.h> +#endif #include <linux/syscalls.h> #include <linux/export.h> #include <linux/fsnotify.h> @@ -475,7 +477,9 @@ __vfs_removexattr_locked(struct dentry *dentry, const char *name, if (!error) { fsnotify_xattr(dentry); +#ifdef CONFIG_IMA_DIGEST_LIST ima_inode_post_removexattr(dentry, name); +#endif evm_inode_post_removexattr(dentry, name); } diff --git a/include/linux/evm.h b/include/linux/evm.h index e5b7bcb152b9..39bb17a8236b 100644 --- a/include/linux/evm.h +++ b/include/linux/evm.h @@ -35,7 +35,7 @@ extern void evm_inode_post_removexattr(struct dentry *dentry, extern int evm_inode_init_security(struct inode *inode, const struct xattr *xattr_array, struct xattr *evm); -extern bool evm_status_revalidate(const char *xattr_name); +extern bool evm_revalidate_status(const char *xattr_name); #ifdef CONFIG_FS_POSIX_ACL extern int posix_xattr_acl(const char *xattrname); #else @@ -105,7 +105,7 @@ static inline int evm_inode_init_security(struct inode *inode, return 0; } -static inline bool evm_status_revalidate(const char *xattr_name) +static inline bool evm_revalidate_status(const char *xattr_name) { return false; } diff --git a/include/linux/ima.h b/include/linux/ima.h index f7a088b2579e..713c6f9696cb 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h @@ -144,13 +144,17 @@ extern bool is_ima_appraise_enabled(void); extern void ima_inode_post_setattr(struct dentry *dentry); extern int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, const void *xattr_value, size_t xattr_value_len); +#ifdef CONFIG_IMA_DIGEST_LIST extern void ima_inode_post_setxattr(struct dentry *dentry, const char *xattr_name, const void *xattr_value, size_t xattr_value_len); +#endif extern int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name); +#ifdef CONFIG_IMA_DIGEST_LIST extern void ima_inode_post_removexattr(struct dentry *dentry, const char *xattr_name); +#endif #else static inline bool is_ima_appraise_enabled(void) { @@ -170,12 +174,14 @@ static inline int ima_inode_setxattr(struct dentry *dentry, return 0; } +#ifdef CONFIG_IMA_DIGEST_LIST static inline void ima_inode_post_setxattr(struct dentry *dentry, const char *xattr_name, const void *xattr_value, size_t xattr_value_len) { } +#endif static inline int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name) @@ -183,10 +189,12 @@ static inline int ima_inode_removexattr(struct dentry *dentry, return 0; } +#ifdef CONFIG_IMA_DIGEST_LIST static inline void ima_inode_post_removexattr(struct dentry *dentry, const char *xattr_name) { } +#endif #endif /* CONFIG_IMA_APPRAISE */ #if defined(CONFIG_IMA_APPRAISE) && defined(CONFIG_INTEGRITY_TRUSTED_KEYRING) diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c index 92dc64755e53..72941f9b1b99 100644 --- a/security/integrity/digsig_asymmetric.c +++ b/security/integrity/digsig_asymmetric.c @@ -9,7 +9,9 @@ #include <linux/err.h> #include <linux/ratelimit.h> #include <linux/key-type.h> +#ifdef CONFIG_IMA_DIGEST_LIST #include <linux/verification.h> +#endif #include <crypto/public_key.h> #include <crypto/hash_info.h> #include <keys/asymmetric-type.h> @@ -55,6 +57,7 @@ static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid) key = request_key(&key_type_asymmetric, name, NULL); } +#ifdef CONFIG_IMA_DIGEST_LIST if (IS_ERR(key)) { #ifdef CONFIG_IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY keyring = VERIFY_USE_SECONDARY_KEYRING; @@ -63,6 +66,7 @@ static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid) #endif key = search_trusted_key(keyring, &key_type_asymmetric, name); } +#endif if (IS_ERR(key)) { if (keyring) diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h index ca7ed2e532dc..f8b1627708a1 100644 --- a/security/integrity/evm/evm.h +++ b/security/integrity/evm/evm.h @@ -32,7 +32,9 @@ struct xattr_list { }; extern int evm_initialized; +#ifdef CONFIG_IMA_DIGEST_LIST extern enum hash_algo evm_hash_algo; +#endif #define EVM_ATTR_FSUUID 0x0001 diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c index 7c36dbb96d24..fa8147c2294e 100644 --- a/security/integrity/evm/evm_crypto.c +++ b/security/integrity/evm/evm_crypto.c @@ -33,7 +33,11 @@ static DEFINE_MUTEX(mutex); static unsigned long evm_set_key_flags; +#ifdef CONFIG_IMA_DIGEST_LIST enum hash_algo evm_hash_algo __ro_after_init = HASH_ALGO_SHA1; +#else +static const char evm_hmac[] = "hmac(sha1)"; +#endif /** * evm_set_key() - set EVM HMAC key from the kernel @@ -74,11 +78,13 @@ static struct shash_desc *init_desc(char type, uint8_t hash_algo) long rc; const char *algo; struct crypto_shash **tfm, *tmp_tfm; - char evm_hmac[CRYPTO_MAX_ALG_NAME]; struct shash_desc *desc; +#ifdef CONFIG_IMA_DIGEST_LIST + char evm_hmac[CRYPTO_MAX_ALG_NAME]; snprintf(evm_hmac, sizeof(evm_hmac), "hmac(%s)", CONFIG_EVM_DEFAULT_HASH); +#endif if (type == EVM_XATTR_HMAC) { if (!(evm_initialized & EVM_INIT_HMAC)) { @@ -156,8 +162,12 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode, /* Don't include the inode or generation number in portable * signatures */ +#ifdef CONFIG_IMA_DIGEST_LIST if (type != EVM_XATTR_PORTABLE_DIGSIG && type != EVM_IMA_XATTR_DIGEST_LIST) { +#else + if (type != EVM_XATTR_PORTABLE_DIGSIG) { +#endif hmac_misc.ino = inode->i_ino; hmac_misc.generation = inode->i_generation; } @@ -174,8 +184,12 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode, hmac_misc.mode = inode->i_mode; crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof(hmac_misc)); if ((evm_hmac_attrs & EVM_ATTR_FSUUID) && +#ifdef CONFIG_IMA_DIGEST_LIST type != EVM_XATTR_PORTABLE_DIGSIG && type != EVM_IMA_XATTR_DIGEST_LIST) +#else + type != EVM_XATTR_PORTABLE_DIGSIG) +#endif crypto_shash_update(desc, (u8 *)&inode->i_sb->s_uuid, UUID_SIZE); crypto_shash_final(desc, digest); } @@ -288,8 +302,12 @@ static int evm_is_immutable(struct dentry *dentry, struct inode *inode) return 0; return rc; } +#ifdef CONFIG_IMA_DIGEST_LIST if (xattr_data->type == EVM_XATTR_PORTABLE_DIGSIG || xattr_data->type == EVM_IMA_XATTR_DIGEST_LIST) +#else + if (xattr_data->type == EVM_XATTR_PORTABLE_DIGSIG) +#endif rc = 1; else rc = 0; @@ -321,15 +339,23 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name, if (rc) return -EPERM; +#ifdef CONFIG_IMA_DIGEST_LIST data.hdr.algo = evm_hash_algo; +#else + data.hdr.algo = HASH_ALGO_SHA1; +#endif rc = evm_calc_hmac(dentry, xattr_name, xattr_value, xattr_value_len, &data); if (rc == 0) { data.hdr.xattr.sha1.type = EVM_XATTR_HMAC; rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_EVM, &data.hdr.xattr.data[1], +#ifdef CONFIG_IMA_DIGEST_LIST hash_digest_size[evm_hash_algo] + 1, 0); +#else + SHA1_DIGEST_SIZE + 1, 0); +#endif } else if (rc == -ENODATA && (inode->i_opflags & IOP_XATTR)) { rc = __vfs_removexattr(dentry, XATTR_NAME_EVM); } @@ -341,7 +367,11 @@ int evm_init_hmac(struct inode *inode, const struct xattr *lsm_xattr, { struct shash_desc *desc; +#ifdef CONFIG_IMA_DIGEST_LIST desc = init_desc(EVM_XATTR_HMAC, evm_hash_algo); +#else + desc = init_desc(EVM_XATTR_HMAC, HASH_ALGO_SHA1); +#endif if (IS_ERR(desc)) { pr_info("init_desc failed\n"); return PTR_ERR(desc); @@ -353,9 +383,15 @@ int evm_init_hmac(struct inode *inode, const struct xattr *lsm_xattr, return 0; } +#ifdef CONFIG_IMA_DIGEST_LIST /* * Get the key from the TPM for the HMAC */ +#else +/* + * Get the key from the TPM for the SHA1-HMAC + */ +#endif int evm_init_key(void) { struct key *evm_key; diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index cddfc0e43a80..a3f6729e00ca 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c @@ -57,6 +57,7 @@ static struct xattr_list evm_config_default_xattrnames[] = { LIST_HEAD(evm_config_xattrnames); static int evm_fixmode __ro_after_init; +#ifdef CONFIG_IMA_DIGEST_LIST static int __init evm_set_param(char *str) { if (strncmp(str, "fix", 3) == 0) @@ -73,6 +74,18 @@ static int __init evm_set_param(char *str) return 1; } __setup("evm=", evm_set_param); +#else +static int __init evm_set_fixmode(char *str) +{ + if (strncmp(str, "fix", 3) == 0) + evm_fixmode = 1; + else + pr_err("invalid \"%s\" mode", str); + + return 0; +} +__setup("evm=", evm_set_fixmode); +#endif static void __init evm_init_config(void) { @@ -98,6 +111,7 @@ static bool evm_key_loaded(void) return (bool)(evm_initialized & EVM_KEY_MASK); } +#ifdef CONFIG_IMA_DIGEST_LIST /* * Ignoring INTEGRITY_NOLABEL/INTEGRITY_NOXATTRS is safe if no HMAC key * is loaded and the EVM_SETUP_COMPLETE initialization flag is set. @@ -115,8 +129,13 @@ static bool evm_ignore_error_safe(enum integrity_status evm_status) return true; } +#endif +#ifdef CONFIG_IMA_DIGEST_LIST static int evm_find_protected_xattrs(struct dentry *dentry, int *ima_present) +#else +static int evm_find_protected_xattrs(struct dentry *dentry) +#endif { struct inode *inode = d_backing_inode(dentry); struct xattr_list *xattr; @@ -133,8 +152,10 @@ static int evm_find_protected_xattrs(struct dentry *dentry, int *ima_present) continue; return error; } +#ifdef CONFIG_IMA_DIGEST_LIST if (!strcmp(xattr->name, XATTR_NAME_IMA)) *ima_present = 1; +#endif count++; } @@ -163,6 +184,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, struct evm_ima_xattr_data *xattr_data = NULL; struct signature_v2_hdr *hdr; enum integrity_status evm_status = INTEGRITY_PASS; +#ifdef CONFIG_IMA_DIGEST_LIST enum integrity_status saved_evm_status = INTEGRITY_UNKNOWN; struct evm_digest digest; struct ima_digest *found_digest; @@ -172,6 +194,12 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, .version = 2, .hash_algo = HASH_ALGO_SHA256 }; int rc, xattr_len, evm_immutable = 0, ima_present = 0; +#else + struct evm_digest digest; + struct inode *inode; + int rc, xattr_len, evm_immutable = 0; +#endif + if (iint && (iint->evm_status == INTEGRITY_PASS || iint->evm_status == INTEGRITY_PASS_IMMUTABLE)) return iint->evm_status; @@ -184,7 +212,11 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, if (rc <= 0) { evm_status = INTEGRITY_FAIL; if (rc == -ENODATA) { +#ifdef CONFIG_IMA_DIGEST_LIST rc = evm_find_protected_xattrs(dentry, &ima_present); +#else + rc = evm_find_protected_xattrs(dentry); +#endif if (rc > 0) evm_status = INTEGRITY_NOLABEL; else if (rc == 0) @@ -192,6 +224,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, } else if (rc == -EOPNOTSUPP) { evm_status = INTEGRITY_UNKNOWN; } +#ifdef CONFIG_IMA_DIGEST_LIST /* IMA added a fake xattr, set also EVM fake xattr */ if (!ima_present && xattr_name && !strcmp(xattr_name, XATTR_NAME_IMA) && @@ -206,6 +239,9 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, goto out; saved_evm_status = evm_status; +#else + goto out; +#endif } xattr_len = rc; @@ -262,6 +298,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, } } break; +#ifdef CONFIG_IMA_DIGEST_LIST case EVM_IMA_XATTR_DIGEST_LIST: /* At this point, we cannot determine whether metadata are * immutable or not. However, it is safe to return the @@ -302,11 +339,13 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, evm_status = INTEGRITY_PASS; } break; +#endif default: rc = -EINVAL; break; } +#ifdef CONFIG_IMA_DIGEST_LIST if (rc && xattr_data == (struct evm_ima_xattr_data *)&evm_fake_xattr) { evm_status = saved_evm_status; } else if (rc) { @@ -315,10 +354,22 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, evm_status = evm_immutable ? INTEGRITY_FAIL_IMMUTABLE : INTEGRITY_FAIL; } +#else + if (rc) { + if (rc == -ENODATA) + evm_status = INTEGRITY_NOXATTRS; + else if (evm_immutable) + evm_status = INTEGRITY_FAIL_IMMUTABLE; + else + evm_status = INTEGRITY_FAIL; + } +#endif out: if (iint) iint->evm_status = evm_status; +#ifdef CONFIG_IMA_DIGEST_LIST if (xattr_data != (struct evm_ima_xattr_data *)&evm_fake_xattr) +#endif kfree(xattr_data); return evm_status; } @@ -569,8 +620,12 @@ int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name, if (!xattr_value_len) return -EINVAL; if (xattr_data->type != EVM_IMA_XATTR_DIGSIG && +#ifdef CONFIG_IMA_DIGEST_LIST xattr_data->type != EVM_XATTR_PORTABLE_DIGSIG && xattr_data->type != EVM_IMA_XATTR_DIGEST_LIST) +#else + xattr_data->type != EVM_XATTR_PORTABLE_DIGSIG) +#endif return -EPERM; } return evm_protect_xattr(dentry, xattr_name, xattr_value, @@ -606,7 +661,7 @@ static void evm_reset_status(struct inode *inode) } /** - * evm_status_revalidate - report whether EVM status re-validation is necessary + * evm_revalidate_status - report whether EVM status re-validation is necessary * @xattr_name: pointer to the affected extended attribute name * * Report whether callers of evm_verifyxattr() should re-validate the @@ -614,7 +669,7 @@ static void evm_reset_status(struct inode *inode) * * Return true if re-validation is necessary, false otherwise. */ -bool evm_status_revalidate(const char *xattr_name) +bool evm_revalidate_status(const char *xattr_name) { if (!evm_key_loaded()) return false; @@ -646,7 +701,7 @@ bool evm_status_revalidate(const char *xattr_name) void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name, const void *xattr_value, size_t xattr_value_len) { - if (!evm_status_revalidate(xattr_name)) + if (!evm_revalidate_status(xattr_name)) return; evm_reset_status(dentry->d_inode); @@ -669,7 +724,7 @@ void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name, */ void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name) { - if (!evm_status_revalidate(xattr_name)) + if (!evm_revalidate_status(xattr_name)) return; evm_reset_status(dentry->d_inode); @@ -714,6 +769,7 @@ int evm_inode_setattr(struct dentry *dentry, struct iattr *attr) if (!(ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))) return 0; evm_status = evm_verify_current_integrity(dentry); +#ifdef CONFIG_IMA_DIGEST_LIST /* * Writing attrs is safe for portable signatures, as portable signatures * are immutable and can never be updated. @@ -723,6 +779,12 @@ int evm_inode_setattr(struct dentry *dentry, struct iattr *attr) (evm_status == INTEGRITY_FAIL_IMMUTABLE) || (evm_ignore_error_safe(evm_status))) return 0; +#else + if ((evm_status == INTEGRITY_PASS) || + (evm_status == INTEGRITY_NOXATTRS) || + (evm_status == INTEGRITY_FAIL_IMMUTABLE)) + return 0; +#endif if (evm_status == INTEGRITY_PASS_IMMUTABLE && !evm_attr_change(dentry, attr)) @@ -747,7 +809,7 @@ int evm_inode_setattr(struct dentry *dentry, struct iattr *attr) */ void evm_inode_post_setattr(struct dentry *dentry, int ia_valid) { - if (!evm_status_revalidate(NULL)) + if (!evm_revalidate_status(NULL)) return; evm_reset_status(dentry->d_inode); @@ -780,7 +842,9 @@ int evm_inode_init_security(struct inode *inode, goto out; evm_xattr->value = xattr_data; +#ifdef CONFIG_IMA_DIGEST_LIST evm_xattr->value_len = hash_digest_size[evm_hash_algo] + 1; +#endif evm_xattr->name = XATTR_EVM_SUFFIX; return 0; out: @@ -802,6 +866,7 @@ void __init evm_load_x509(void) static int __init init_evm(void) { +#ifdef CONFIG_IMA_DIGEST_LIST int error, i; struct list_head *pos, *q; @@ -809,6 +874,10 @@ static int __init init_evm(void) CONFIG_EVM_DEFAULT_HASH); if (i >= 0) evm_hash_algo = i; +#else + int error; + struct list_head *pos, *q; +#endif evm_init_config(); diff --git a/security/integrity/iint.c b/security/integrity/iint.c index 8953ac6412c3..22dc1eb63f78 100644 --- a/security/integrity/iint.c +++ b/security/integrity/iint.c @@ -212,7 +212,9 @@ void __init integrity_load_keys(void) if (!IS_ENABLED(CONFIG_IMA_LOAD_X509)) evm_load_x509(); +#ifdef CONFIG_IMA_DIGEST_LIST ima_load_digest_lists(); +#endif } static int __init integrity_fs_init(void) diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 46afb6bef45b..72e1843b05e1 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -53,11 +53,11 @@ extern int ima_hash_algo_idx __ro_after_init; extern int ima_extra_slots __ro_after_init; extern int ima_appraise; extern struct tpm_chip *ima_tpm_chip; +extern const char boot_aggregate_name[]; +#ifdef CONFIG_IMA_DIGEST_LIST extern int ima_digest_list_pcr; extern bool ima_plus_standard_pcr; -extern const char boot_aggregate_name[]; extern int ima_digest_list_actions; -#ifdef CONFIG_IMA_DIGEST_LIST extern int ima_digest_db_max_size __ro_after_init; extern int ima_digest_db_size; #endif @@ -189,6 +189,7 @@ static inline unsigned int ima_hash_key(u8 *digest) return (digest[0] | digest[1] << 8) % IMA_MEASURE_HTABLE_SIZE; } +#ifdef CONFIG_IMA_DIGEST_LIST #define __ima_hooks(hook) \ hook(NONE, none) \ hook(FILE_CHECK, file) \ @@ -205,6 +206,23 @@ static inline unsigned int ima_hash_key(u8 *digest) hook(KEY_CHECK, key) \ hook(DIGEST_LIST_CHECK, digest_list) \ hook(MAX_CHECK, none) +#else +#define __ima_hooks(hook) \ + (hook(NONE, none) \ + hook(FILE_CHECK, file) \ + hook(MMAP_CHECK, mmap) \ + hook(BPRM_CHECK, bprm) \ + hook(CREDS_CHECK, creds) \ + hook(POST_SETATTR, post_setattr) \ + hook(MODULE_CHECK, module) \ + hook(FIRMWARE_CHECK, firmware) \ + hook(KEXEC_KERNEL_CHECK, kexec_kernel) \ + hook(KEXEC_INITRAMFS_CHECK, kexec_initramfs) \ + hook(POLICY_CHECK, policy) \ + hook(KEXEC_CMDLINE, kexec_cmdline) \ + hook(KEY_CHECK, key) \ + hook(MAX_CHECK, none)) +#endif #define __ima_hook_enumify(ENUM, str) ENUM, #define __ima_stringify(arg) (#arg) @@ -264,12 +282,20 @@ int ima_must_measure(struct inode *inode, int mask, enum ima_hooks func); int ima_collect_measurement(struct integrity_iint_cache *iint, struct file *file, void *buf, loff_t size, enum hash_algo algo, struct modsig *modsig); +#ifdef CONFIG_IMA_DIGEST_LIST void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file, const unsigned char *filename, struct evm_ima_xattr_data *xattr_value, int xattr_len, const struct modsig *modsig, int pcr, struct ima_template_desc *template_desc, struct ima_digest *digest); +#else +void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file, + const unsigned char *filename, + struct evm_ima_xattr_data *xattr_value, + int xattr_len, const struct modsig *modsig, int pcr, + struct ima_template_desc *template_desc); +#endif void process_buffer_measurement(struct inode *inode, const void *buf, int size, const char *eventname, enum ima_hooks func, int pcr, const char *keyring); @@ -278,9 +304,15 @@ void ima_audit_measurement(struct integrity_iint_cache *iint, int ima_alloc_init_template(struct ima_event_data *event_data, struct ima_template_entry **entry, struct ima_template_desc *template_desc); +#ifdef CONFIG_IMA_DIGEST_LIST int ima_store_template(struct ima_template_entry *entry, int violation, struct inode *inode, const unsigned char *filename, int pcr, struct ima_digest *digest); +#else +int ima_store_template(struct ima_template_entry *entry, int violation, + struct inode *inode, + const unsigned char *filename, int pcr); +#endif void ima_free_template_entry(struct ima_template_entry *entry); const char *ima_d_path(const struct path *path, char **pathbuf, char *filename); @@ -308,21 +340,41 @@ int ima_policy_show(struct seq_file *m, void *v); #define IMA_APPRAISE_FIRMWARE 0x10 #define IMA_APPRAISE_POLICY 0x20 #define IMA_APPRAISE_KEXEC 0x40 +#ifdef CONFIG_IMA_DIGEST_LIST #define IMA_APPRAISE_DIGEST_LIST 0x80 +#endif #ifdef CONFIG_IMA_APPRAISE int ima_check_blacklist(struct integrity_iint_cache *iint, const struct modsig *modsig, int pcr); + +#ifdef CONFIG_IMA_DIGEST_LIST int ima_appraise_measurement(enum ima_hooks func, struct integrity_iint_cache *iint, struct file *file, const unsigned char *filename, struct evm_ima_xattr_data *xattr_value, int xattr_len, const struct modsig *modsig, struct ima_digest *found_digest); +#else +int ima_appraise_measurement(enum ima_hooks func, + struct integrity_iint_cache *iint, + struct file *file, const unsigned char *filename, + struct evm_ima_xattr_data *xattr_value, + int xattr_len, const struct modsig *modsig); +#endif + int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func); void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file); enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, enum ima_hooks func); + +#ifndef CONFIG_IMA_DIGEST_LIST +enum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, + int xattr_len); +int ima_read_xattr(struct dentry *dentry, + struct evm_ima_xattr_data **xattr_value); +#endif + #else static inline int ima_check_blacklist(struct integrity_iint_cache *iint, const struct modsig *modsig, int pcr) @@ -330,6 +382,7 @@ static inline int ima_check_blacklist(struct integrity_iint_cache *iint, return 0; } +#ifndef CONFIG_IMA_DIGEST_LIST static inline int ima_appraise_measurement(enum ima_hooks func, struct integrity_iint_cache *iint, struct file *file, @@ -338,6 +391,15 @@ static inline int ima_appraise_measurement(enum ima_hooks func, int xattr_len, const struct modsig *modsig, struct ima_digest *found_digest) +#else +static inline int ima_appraise_measurement(enum ima_hooks func, + struct integrity_iint_cache *iint, + struct file *file, + const unsigned char *filename, + struct evm_ima_xattr_data *xattr_value, + int xattr_len, + const struct modsig *modsig) +#endif { return INTEGRITY_UNKNOWN; } @@ -360,6 +422,20 @@ static inline enum integrity_status ima_get_cache_status(struct integrity_iint_c return INTEGRITY_UNKNOWN; } +#ifndef CONFIG_IMA_DIGEST_LIST +static inline enum hash_algo +ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, int xattr_len) +{ + return ima_hash_algo; +} + +static inline int ima_read_xattr(struct dentry *dentry, + struct evm_ima_xattr_data **xattr_value) +{ + return 0; +} +#endif + #endif /* CONFIG_IMA_APPRAISE */ #ifdef CONFIG_IMA_APPRAISE_MODSIG diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index 6ecaf6834844..1b8d3696d873 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -99,15 +99,23 @@ int ima_alloc_init_template(struct ima_event_data *event_data, * * Returns 0 on success, error code otherwise */ +#ifdef CONFIG_IMA_DIGEST_LIST int ima_store_template(struct ima_template_entry *entry, int violation, struct inode *inode, const unsigned char *filename, int pcr, struct ima_digest *digest) +#else +int ima_store_template(struct ima_template_entry *entry, + int violation, struct inode *inode, + const unsigned char *filename, int pcr) +#endif { static const char op[] = "add_template_measure"; static const char audit_cause[] = "hashing_error"; char *template_name = entry->template_desc->name; +#ifdef CONFIG_IMA_DIGEST_LIST struct ima_template_entry *duplicated_entry = NULL; +#endif int result; if (!violation) { @@ -121,6 +129,7 @@ int ima_store_template(struct ima_template_entry *entry, } } +#ifdef CONFIG_IMA_DIGEST_LIST if (ima_plus_standard_pcr && !digest) { duplicated_entry = kmemdup(entry, sizeof(*entry) + entry->template_desc->num_fields * @@ -130,9 +139,11 @@ int ima_store_template(struct ima_template_entry *entry, } else if (!ima_plus_standard_pcr && ima_digest_list_pcr >= 0) { pcr = ima_digest_list_pcr; } +#endif entry->pcr = pcr; result = ima_add_template_entry(entry, violation, op, inode, filename); +#ifdef CONFIG_IMA_DIGEST_LIST if (result) { kfree(duplicated_entry); } else if (duplicated_entry) { @@ -141,6 +152,7 @@ int ima_store_template(struct ima_template_entry *entry, if (result < 0) kfree(duplicated_entry); } +#endif return result; } @@ -173,8 +185,13 @@ void ima_add_violation(struct file *file, const unsigned char *filename, result = -ENOMEM; goto err_out; } +#ifdef CONFIG_IMA_DIGEST_LIST result = ima_store_template(entry, violation, inode, filename, CONFIG_IMA_MEASURE_PCR_IDX, NULL); +#else + result = ima_store_template(entry, violation, inode, + filename, CONFIG_IMA_MEASURE_PCR_IDX); +#endif if (result < 0) ima_free_template_entry(entry); err_out: @@ -315,18 +332,30 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, * * Must be called with iint->mutex held. */ +#ifdef CONFIG_IMA_DIGEST_LIST void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file, const unsigned char *filename, struct evm_ima_xattr_data *xattr_value, int xattr_len, const struct modsig *modsig, int pcr, struct ima_template_desc *template_desc, struct ima_digest *digest) +#else +void ima_store_measurement(struct integrity_iint_cache *iint, + struct file *file, const unsigned char *filename, + struct evm_ima_xattr_data *xattr_value, + int xattr_len, const struct modsig *modsig, int pcr, + struct ima_template_desc *template_desc) +#endif { static const char op[] = "add_template_measure"; static const char audit_cause[] = "ENOMEM"; int result = -ENOMEM; struct inode *inode = file_inode(file); +#ifdef CONFIG_IMA_DIGEST_LIST struct ima_template_entry *entry = NULL; +#else + struct ima_template_entry *entry; +#endif struct ima_event_data event_data = { .iint = iint, .file = file, .filename = filename, @@ -344,10 +373,12 @@ void ima_store_measurement(struct integrity_iint_cache *iint, if (iint->measured_pcrs & (0x1 << pcr) && !modsig) return; +#ifdef CONFIG_IMA_DIGEST_LIST if (digest && !ima_plus_standard_pcr && ima_digest_list_pcr >= 0) { result = -EEXIST; goto out; } +#endif result = ima_alloc_init_template(&event_data, &entry, template_desc); if (result < 0) { @@ -356,14 +387,22 @@ void ima_store_measurement(struct integrity_iint_cache *iint, return; } +#ifdef CONFIG_IMA_DIGEST_LIST result = ima_store_template(entry, violation, inode, filename, pcr, digest); out: +#else + result = ima_store_template(entry, violation, inode, filename, pcr); +#endif if ((!result || result == -EEXIST) && !(file->f_flags & O_DIRECT)) { iint->flags |= IMA_MEASURED; iint->measured_pcrs |= (0x1 << pcr); } +#ifdef CONFIG_IMA_DIGEST_LIST if (result < 0 && entry) +#else + if (result < 0) +#endif ima_free_template_entry(entry); } diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 956fb0f4c006..9dd8634b9e5a 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -15,9 +15,11 @@ #include <keys/system_keyring.h> #include "ima.h" +#ifdef CONFIG_IMA_DIGEST_LIST #include "ima_digest_list.h" static bool ima_appraise_req_evm __ro_after_init; +#endif static int __init default_appraise_setup(char *str) { #ifdef CONFIG_IMA_APPRAISE_BOOTPARAM @@ -45,16 +47,18 @@ static int __init default_appraise_setup(char *str) ima_appraise = appraisal_state; } #endif +#ifdef CONFIG_IMA_DIGEST_LIST if (strcmp(str, "enforce-evm") == 0 || strcmp(str, "log-evm") == 0) ima_appraise_req_evm = true; +#endif return 1; } __setup("ima_appraise=", default_appraise_setup); -static bool ima_appraise_no_metadata __ro_after_init; #ifdef CONFIG_IMA_DIGEST_LIST +static bool ima_appraise_no_metadata __ro_after_init; static int __init appraise_digest_list_setup(char *str) { if (!strncmp(str, "digest", 6)) { @@ -108,9 +112,11 @@ static int ima_fix_xattr(struct dentry *dentry, } else { offset = 0; iint->ima_hash->xattr.ng.type = IMA_XATTR_DIGEST_NG; +#ifdef CONFIG_IMA_DIGEST_LIST if (test_bit(IMA_DIGEST_LIST, &iint->atomic_flags)) iint->ima_hash->xattr.ng.type = EVM_IMA_XATTR_DIGEST_LIST; +#endif iint->ima_hash->xattr.ng.algo = algo; } rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA, @@ -189,6 +195,60 @@ static void ima_cache_flags(struct integrity_iint_cache *iint, } } +#ifndef CONFIG_IMA_DIGEST_LIST +enum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, + int xattr_len) +{ + struct signature_v2_hdr *sig; + enum hash_algo ret; + + if (!xattr_value || xattr_len < 2) + /* return default hash algo */ + return ima_hash_algo; + + switch (xattr_value->type) { + case EVM_IMA_XATTR_DIGSIG: + sig = (typeof(sig))xattr_value; + if (sig->version != 2 || xattr_len <= sizeof(*sig)) + return ima_hash_algo; + return sig->hash_algo; + case IMA_XATTR_DIGEST_NG: + /* first byte contains algorithm id */ + ret = xattr_value->data[0]; + if (ret < HASH_ALGO__LAST) + return ret; + break; + case IMA_XATTR_DIGEST: + /* this is for backward compatibility */ + if (xattr_len == 21) { + unsigned int zero = 0; + + if (!memcmp(&xattr_value->data[16], &zero, 4)) + return HASH_ALGO_MD5; + else + return HASH_ALGO_SHA1; + } else if (xattr_len == 17) + return HASH_ALGO_MD5; + break; + } + + /* return default hash algo */ + return ima_hash_algo; +} + +int ima_read_xattr(struct dentry *dentry, + struct evm_ima_xattr_data **xattr_value) +{ + ssize_t ret; + + ret = vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)xattr_value, + 0, GFP_NOFS); + if (ret == -EOPNOTSUPP) + ret = 0; + return ret; +} +#endif + /* * xattr_verify - verify xattr digest or signature * @@ -196,18 +256,27 @@ static void ima_cache_flags(struct integrity_iint_cache *iint, * * Return 0 on success, error code otherwise. */ +#ifdef CONFIG_IMA_DIGEST_LIST static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint, struct evm_ima_xattr_data *xattr_value, int xattr_len, enum integrity_status *status, const char **cause, struct ima_digest *found_digest) +#else +static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint, + struct evm_ima_xattr_data *xattr_value, int xattr_len, + enum integrity_status *status, const char **cause) +#endif { int rc = -EINVAL, hash_start = 0; +#ifdef CONFIG_IMA_DIGEST_LIST if (found_digest && *status != INTEGRITY_PASS && *status != INTEGRITY_PASS_IMMUTABLE) set_bit(IMA_DIGEST_LIST, &iint->atomic_flags); +#endif switch (xattr_value->type) { +#ifdef CONFIG_IMA_DIGEST_LIST case EVM_IMA_XATTR_DIGEST_LIST: set_bit(IMA_DIGEST_LIST, &iint->atomic_flags); @@ -217,13 +286,18 @@ static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint, break; } fallthrough; +#endif case IMA_XATTR_DIGEST_NG: /* first byte contains algorithm id */ hash_start = 1; fallthrough; case IMA_XATTR_DIGEST: +#ifdef CONFIG_IMA_DIGEST_LIST if (*status != INTEGRITY_PASS_IMMUTABLE && (!found_digest || !ima_digest_is_immutable(found_digest))) { +#else + if (*status != INTEGRITY_PASS_IMMUTABLE) { +#endif if (iint->flags & IMA_DIGSIG_REQUIRED) { *cause = "IMA-signature-required"; *status = INTEGRITY_FAIL; @@ -352,26 +426,39 @@ int ima_check_blacklist(struct integrity_iint_cache *iint, * * Return 0 on success, error code otherwise */ +#ifdef CONFIG_IMA_DIGEST_LIST int ima_appraise_measurement(enum ima_hooks func, struct integrity_iint_cache *iint, struct file *file, const unsigned char *filename, struct evm_ima_xattr_data *xattr_value, int xattr_len, const struct modsig *modsig, struct ima_digest *found_digest) +#else +int ima_appraise_measurement(enum ima_hooks func, + struct integrity_iint_cache *iint, + struct file *file, const unsigned char *filename, + struct evm_ima_xattr_data *xattr_value, + int xattr_len, const struct modsig *modsig) +#endif { static const char op[] = "appraise_data"; const char *cause = "unknown"; struct dentry *dentry = file_dentry(file); struct inode *inode = d_backing_inode(dentry); enum integrity_status status = INTEGRITY_UNKNOWN; +#ifdef CONFIG_IMA_DIGEST_LIST int rc = xattr_len, rc_evm; char _buf[sizeof(struct evm_ima_xattr_data) + 1 + SHA512_DIGEST_SIZE]; +#else + int rc = xattr_len; +#endif bool try_modsig = iint->flags & IMA_MODSIG_ALLOWED && modsig; /* If not appraising a modsig, we need an xattr. */ if (!(inode->i_opflags & IOP_XATTR) && !try_modsig) return INTEGRITY_UNKNOWN; +#ifdef CONFIG_IMA_DIGEST_LIST if (xattr_value && xattr_value->type == EVM_IMA_XATTR_DIGSIG && xattr_len == sizeof(struct signature_v2_hdr)) rc = -ENODATA; @@ -394,6 +481,7 @@ int ima_appraise_measurement(enum ima_hooks func, rc = xattr_len; } } +#endif /* If reading the xattr failed and there's no modsig, error out. */ if (rc <= 0 && !try_modsig) { @@ -417,11 +505,15 @@ int ima_appraise_measurement(enum ima_hooks func, switch (status) { case INTEGRITY_PASS: case INTEGRITY_PASS_IMMUTABLE: +#ifdef CONFIG_IMA_DIGEST_LIST break; case INTEGRITY_UNKNOWN: if (ima_appraise_req_evm && xattr_value->type != EVM_IMA_XATTR_DIGSIG && !found_digest) goto out; +#else + case INTEGRITY_UNKNOWN: +#endif break; case INTEGRITY_NOXATTRS: /* No EVM protected xattrs. */ /* It's fine not to have xattrs when using a modsig. */ @@ -429,6 +521,7 @@ int ima_appraise_measurement(enum ima_hooks func, break; fallthrough; case INTEGRITY_NOLABEL: /* No security.evm xattr. */ +#ifdef CONFIG_IMA_DIGEST_LIST /* * If the digest-nometadata mode is selected, allow access * without metadata check. EVM will eventually create an HMAC @@ -446,6 +539,7 @@ int ima_appraise_measurement(enum ima_hooks func, ima_digest_is_immutable(found_digest)) break; } +#endif cause = "missing-HMAC"; goto out; case INTEGRITY_FAIL_IMMUTABLE: @@ -458,6 +552,7 @@ int ima_appraise_measurement(enum ima_hooks func, WARN_ONCE(true, "Unexpected integrity status %d\n", status); } +#ifdef CONFIG_IMA_DIGEST_LIST if ((iint->flags & IMA_META_IMMUTABLE_REQUIRED) && status != INTEGRITY_PASS_IMMUTABLE) { status = INTEGRITY_FAIL; @@ -466,10 +561,16 @@ int ima_appraise_measurement(enum ima_hooks func, filename, op, cause, rc, 0); goto out; } +#endif if (xattr_value) +#ifdef CONFIG_IMA_DIGEST_LIST rc = xattr_verify(func, iint, xattr_value, xattr_len, &status, &cause, found_digest); +#else + rc = xattr_verify(func, iint, xattr_value, xattr_len, &status, + &cause); +#endif /* * If we have a modsig and either no imasig or the imasig's key isn't @@ -609,6 +710,7 @@ static void ima_reset_appraise_flags(struct inode *inode, int digsig) clear_bit(IMA_DIGSIG, &iint->atomic_flags); } +#ifdef CONFIG_IMA_DIGEST_LIST int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, const void *xattr_value, size_t xattr_value_len) { @@ -624,7 +726,35 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, } return result; } +#else +int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, + const void *xattr_value, size_t xattr_value_len) +{ + const struct evm_ima_xattr_data *xvalue = xattr_value; + int digsig = 0; + int result; + result = ima_protect_xattr(dentry, xattr_name, xattr_value, + xattr_value_len); + if (result == 1) { + if (!xattr_value_len || (xvalue->type >= IMA_XATTR_LAST)) + return -EINVAL; + digsig = (xvalue->type == EVM_IMA_XATTR_DIGSIG); +#ifndef CONFIG_IMA_DIGEST_LIST + } else if (!strcmp(xattr_name, XATTR_NAME_EVM) && xattr_value_len > 0) { + digsig = (xvalue->type == EVM_XATTR_PORTABLE_DIGSIG); +#endif + } + if (result == 1 || evm_revalidate_status(xattr_name)) { + ima_reset_appraise_flags(d_backing_inode(dentry), digsig); + if (result == 1) + result = 0; + } + return result; +} +#endif + +#ifdef CONFIG_IMA_DIGEST_LIST void ima_inode_post_setxattr(struct dentry *dentry, const char *xattr_name, const void *xattr_value, size_t xattr_value_len) { @@ -638,10 +768,12 @@ void ima_inode_post_setxattr(struct dentry *dentry, const char *xattr_name, digsig = (xvalue->type == EVM_IMA_XATTR_DIGSIG); if (!strcmp(xattr_name, XATTR_NAME_EVM) && xattr_value_len > 0) digsig = (xvalue->type == EVM_XATTR_PORTABLE_DIGSIG); - if (result == 1 || evm_status_revalidate(xattr_name)) + if (result == 1 || evm_revalidate_status(xattr_name)) ima_reset_appraise_flags(d_backing_inode(dentry), digsig); } +#endif +#ifdef CONFIG_IMA_DIGEST_LIST int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name) { int result; @@ -652,12 +784,28 @@ int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name) } return result; } +#else +int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name) +{ + int result; + result = ima_protect_xattr(dentry, xattr_name, NULL, 0); + if (result == 1 || evm_revalidate_status(xattr_name)) { + ima_reset_appraise_flags(d_backing_inode(dentry), 0); + if (result == 1) + result = 0; + } + return result; +} +#endif + +#ifdef CONFIG_IMA_DIGEST_LIST void ima_inode_post_removexattr(struct dentry *dentry, const char *xattr_name) { int result; result = ima_protect_xattr(dentry, xattr_name, NULL, 0); - if (result == 1 || evm_status_revalidate(xattr_name)) + if (result == 1 || evm_revalidate_status(xattr_name)) ima_reset_appraise_flags(d_backing_inode(dentry), 0); } +#endif diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index f1bc3e201bd8..345ca9bc5c43 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -21,11 +21,15 @@ #include <linux/rcupdate.h> #include <linux/parser.h> #include <linux/vmalloc.h> +#ifdef CONFIG_IMA_DIGEST_LIST #include <linux/file.h> +#endif #include <linux/ctype.h> #include "ima.h" +#ifdef CONFIG_IMA_DIGEST_LIST #include "ima_digest_list.h" +#endif static DEFINE_MUTEX(ima_write_mutex); @@ -36,9 +40,11 @@ static struct dentry *ascii_runtime_measurements; static struct dentry *runtime_measurements_count; static struct dentry *violations; static struct dentry *ima_policy; +#ifdef CONFIG_IMA_DIGEST_LIST static struct dentry *digests_count; static struct dentry *digest_list_data; static struct dentry *digest_list_data_del; +#endif bool ima_canonical_fmt; static int __init default_canonical_fmt_setup(char *str) @@ -52,6 +58,7 @@ __setup("ima_canonical_fmt", default_canonical_fmt_setup); static int valid_policy = 1; +#ifdef CONFIG_IMA_DIGEST_LIST static ssize_t ima_show_htable_value(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { @@ -63,19 +70,55 @@ static ssize_t ima_show_htable_value(struct file *filp, char __user *buf, val = &ima_htable.violations; else if (filp->f_path.dentry == runtime_measurements_count) val = &ima_htable.len; -#ifdef CONFIG_IMA_DIGEST_LIST else if (filp->f_path.dentry == digests_count) val = &ima_digests_htable.len; -#endif len = scnprintf(tmpbuf, sizeof(tmpbuf), "%li\n", atomic_long_read(val)); return simple_read_from_buffer(buf, count, ppos, tmpbuf, len); } +#else +static ssize_t ima_show_htable_value(char __user *buf, size_t count, + loff_t *ppos, atomic_long_t *val) +{ + char tmpbuf[32]; /* greater than largest 'long' string value */ + ssize_t len; + + len = scnprintf(tmpbuf, sizeof(tmpbuf), "%li\n", atomic_long_read(val)); + return simple_read_from_buffer(buf, count, ppos, tmpbuf, len); +} +#endif +#ifdef CONFIG_IMA_DIGEST_LIST static const struct file_operations ima_htable_value_ops = { .read = ima_show_htable_value, .llseek = generic_file_llseek, }; +#else +static ssize_t ima_show_htable_violations(struct file *filp, + char __user *buf, + size_t count, loff_t *ppos) +{ + return ima_show_htable_value(buf, count, ppos, &ima_htable.violations); +} + +static const struct file_operations ima_htable_violations_ops = { + .read = ima_show_htable_violations, + .llseek = generic_file_llseek, +}; + +static ssize_t ima_show_measurements_count(struct file *filp, + char __user *buf, + size_t count, loff_t *ppos) +{ + return ima_show_htable_value(buf, count, ppos, &ima_htable.len); + +} + +static const struct file_operations ima_measurements_count_ops = { + .read = ima_show_measurements_count, + .llseek = generic_file_llseek, +}; +#endif /* returns pointer to hlist_node */ static void *ima_measurements_start(struct seq_file *m, loff_t *pos) @@ -275,6 +318,7 @@ static const struct file_operations ima_ascii_measurements_ops = { .release = seq_release, }; +#ifdef CONFIG_IMA_DIGEST_LIST static ssize_t ima_read_file(char *path, struct dentry *dentry) { void *data = NULL; @@ -320,7 +364,6 @@ static ssize_t ima_read_file(char *path, struct dentry *dentry) rc = ima_parse_add_rule(p); } else if (dentry == digest_list_data || dentry == digest_list_data_del) { -#ifdef CONFIG_IMA_DIGEST_LIST /* Only check size when adding digest lists */ if (dentry == digest_list_data && size > ima_digest_db_max_size - ima_digest_db_size) { @@ -328,7 +371,6 @@ static ssize_t ima_read_file(char *path, struct dentry *dentry) rc = -ENOMEM; break; } -#endif /* * Disable usage of digest lists if not measured * or appraised. @@ -343,12 +385,10 @@ static ssize_t ima_read_file(char *path, struct dentry *dentry) if (rc < 0) break; -#ifdef CONFIG_IMA_DIGEST_LIST else if (dentry == digest_list_data) pr_debug("digest imported, current DB size: %d\n", ima_digest_db_size); else if (dentry == digest_list_data_del) pr_debug("digest deleted, current DB size: %d\n", ima_digest_db_size); -#endif size -= rc; } @@ -461,6 +501,104 @@ static enum ima_fs_flags ima_get_dentry_flag(struct dentry *dentry) return flag; } +#else +static ssize_t ima_read_policy(char *path) +{ + void *data = NULL; + char *datap; + size_t size; + int rc, pathlen = strlen(path); + + char *p; + + /* remove \n */ + datap = path; + strsep(&datap, "\n"); + + rc = kernel_read_file_from_path(path, 0, &data, INT_MAX, NULL, + READING_POLICY); + if (rc < 0) { + pr_err("Unable to open file: %s (%d)", path, rc); + return rc; + } + size = rc; + rc = 0; + + datap = data; + while (size > 0 && (p = strsep(&datap, "\n"))) { + pr_debug("rule: %s\n", p); + rc = ima_parse_add_rule(p); + if (rc < 0) + break; + size -= rc; + } + + vfree(data); + if (rc < 0) + return rc; + else if (size) + return -EINVAL; + else + return pathlen; +} + +static ssize_t ima_write_policy(struct file *file, const char __user *buf, + size_t datalen, loff_t *ppos) +{ + char *data; + ssize_t result; + + if (datalen >= PAGE_SIZE) + datalen = PAGE_SIZE - 1; + + /* No partial writes. */ + result = -EINVAL; + if (*ppos != 0) + goto out; + + data = memdup_user_nul(buf, datalen); + if (IS_ERR(data)) { + result = PTR_ERR(data); + goto out; + } + + result = mutex_lock_interruptible(&ima_write_mutex); + if (result < 0) + goto out_free; + + if (data[0] == '/') { + result = ima_read_policy(data); + } else if (ima_appraise & IMA_APPRAISE_POLICY) { + pr_err("signed policy file (specified as an absolute pathname) required\n"); + integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL, + "policy_update", "signed policy required", + 1, 0); + result = -EACCES; + } else { + result = ima_parse_add_rule(data); + } + mutex_unlock(&ima_write_mutex); +out_free: + kfree(data); +out: + if (result < 0) + valid_policy = 0; + + return result; +} + +static struct dentry *ima_dir; +static struct dentry *ima_symlink; +static struct dentry *binary_runtime_measurements; +static struct dentry *ascii_runtime_measurements; +static struct dentry *runtime_measurements_count; +static struct dentry *violations; +static struct dentry *ima_policy; + +enum ima_fs_flags { + IMA_FS_BUSY, +}; +#endif static unsigned long ima_fs_flags; @@ -473,6 +611,7 @@ static const struct seq_operations ima_policy_seqops = { }; #endif +#ifdef CONFIG_IMA_DIGEST_LIST /* * ima_open_data_upload: sequentialize access to the data upload interface */ @@ -568,6 +707,79 @@ static const struct file_operations ima_data_upload_ops = { .release = ima_release_data_upload, .llseek = generic_file_llseek, }; +#else +/* + * ima_open_policy: sequentialize access to the policy file + */ +static int ima_open_policy(struct inode *inode, struct file *filp) +{ + if (!(filp->f_flags & O_WRONLY)) { +#ifndef CONFIG_IMA_READ_POLICY + return -EACCES; +#else + if ((filp->f_flags & O_ACCMODE) != O_RDONLY) + return -EACCES; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + return seq_open(filp, &ima_policy_seqops); +#endif + } + if (test_and_set_bit(IMA_FS_BUSY, &ima_fs_flags)) + return -EBUSY; + return 0; +} + +/* + * ima_release_policy - start using the new measure policy rules. + * + * Initially, ima_measure points to the default policy rules, now + * point to the new policy rules, and remove the securityfs policy file, + * assuming a valid policy. + */ +static int ima_release_policy(struct inode *inode, struct file *file) +{ + const char *cause = valid_policy ? "completed" : "failed"; + + if ((file->f_flags & O_ACCMODE) == O_RDONLY) + return seq_release(inode, file); + + if (valid_policy && ima_check_policy() < 0) { + cause = "failed"; + valid_policy = 0; + } + + pr_info("policy update %s\n", cause); + integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL, + "policy_update", cause, !valid_policy, 0); + + if (!valid_policy) { + ima_delete_rules(); + valid_policy = 1; + clear_bit(IMA_FS_BUSY, &ima_fs_flags); + return 0; + } + + ima_update_policy(); +#if !defined(CONFIG_IMA_WRITE_POLICY) && !defined(CONFIG_IMA_READ_POLICY) + securityfs_remove(ima_policy); + ima_policy = NULL; +#elif defined(CONFIG_IMA_WRITE_POLICY) + clear_bit(IMA_FS_BUSY, &ima_fs_flags); +#elif defined(CONFIG_IMA_READ_POLICY) + inode->i_mode &= ~S_IWUSR; +#endif + return 0; +} + +static const struct file_operations ima_measure_policy_ops = { + .open = ima_open_policy, + .write = ima_write_policy, + .read = seq_read, + .release = ima_release_policy, + .llseek = generic_file_llseek, +}; + +#endif int __init ima_fs_init(void) { @@ -594,6 +806,7 @@ int __init ima_fs_init(void) if (IS_ERR(ascii_runtime_measurements)) goto out; +#ifdef CONFIG_IMA_DIGEST_LIST runtime_measurements_count = securityfs_create_file("runtime_measurements_count", S_IRUSR | S_IRGRP, ima_dir, NULL, @@ -613,7 +826,6 @@ int __init ima_fs_init(void) if (IS_ERR(ima_policy)) goto out; -#ifdef CONFIG_IMA_DIGEST_LIST digests_count = securityfs_create_file("digests_count", S_IRUSR | S_IRGRP, ima_dir, NULL, &ima_htable_value_ops); @@ -631,12 +843,34 @@ int __init ima_fs_init(void) &ima_data_upload_ops); if (IS_ERR(digest_list_data_del)) goto out; +#else + runtime_measurements_count = + securityfs_create_file("runtime_measurements_count", + S_IRUSR | S_IRGRP, ima_dir, NULL, + &ima_measurements_count_ops); + if (IS_ERR(runtime_measurements_count)) + goto out; + + violations = + securityfs_create_file("violations", S_IRUSR | S_IRGRP, + ima_dir, NULL, &ima_htable_violations_ops); + if (IS_ERR(violations)) + goto out; + + ima_policy = securityfs_create_file("policy", POLICY_FILE_FLAGS, + ima_dir, NULL, + &ima_measure_policy_ops); + if (IS_ERR(ima_policy)) + goto out; + #endif return 0; out: +#ifdef CONFIG_IMA_DIGEST_LIST securityfs_remove(digest_list_data_del); securityfs_remove(digest_list_data); securityfs_remove(digests_count); +#endif securityfs_remove(ima_policy); securityfs_remove(violations); securityfs_remove(runtime_measurements_count); diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index 913d6b879b0b..da47d366a98c 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c @@ -84,9 +84,15 @@ static int __init ima_add_boot_aggregate(void) goto err_out; } +#ifdef CONFIG_IMA_DIGEST_LIST result = ima_store_template(entry, violation, NULL, boot_aggregate_name, CONFIG_IMA_MEASURE_PCR_IDX, NULL); +#else + result = ima_store_template(entry, violation, NULL, + boot_aggregate_name, + CONFIG_IMA_MEASURE_PCR_IDX); +#endif if (result < 0) { ima_free_template_entry(entry); audit_cause = "store_entry"; diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 999d5904cce0..fc1af21b3ad8 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -28,7 +28,9 @@ #include <linux/fs.h> #include "ima.h" +#ifdef CONFIG_IMA_DIGEST_LIST #include "ima_digest_list.h" +#endif #ifdef CONFIG_IMA_APPRAISE int ima_appraise = IMA_APPRAISE_ENFORCE; @@ -38,12 +40,14 @@ int ima_appraise; int ima_hash_algo = HASH_ALGO_SHA1; +#ifdef CONFIG_IMA_DIGEST_LIST /* Actions (measure/appraisal) for which digest lists can be used */ int ima_digest_list_actions; /* PCR used for digest list measurements */ int ima_digest_list_pcr = -1; /* Flag to include standard measurement if digest list PCR is specified */ bool ima_plus_standard_pcr; +#endif static int hash_setup_done; @@ -156,6 +160,7 @@ static void ima_rdwr_violation_check(struct file *file, "invalid_pcr", "open_writers"); } +#ifdef CONFIG_IMA_DIGEST_LIST static enum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, int xattr_len) { @@ -209,6 +214,7 @@ static int ima_read_xattr(struct dentry *dentry, ret = 0; return ret; } +#endif static void ima_check_last_writer(struct integrity_iint_cache *iint, struct inode *inode, struct file *file) @@ -268,7 +274,9 @@ static int process_measurement(struct file *file, const struct cred *cred, const char *pathname = NULL; int rc = 0, action, must_appraise = 0; int pcr = CONFIG_IMA_MEASURE_PCR_IDX; +#ifdef CONFIG_IMA_DIGEST_LIST struct ima_digest *found_digest; +#endif struct evm_ima_xattr_data *xattr_value = NULL; struct modsig *modsig = NULL; int xattr_len = 0; @@ -398,28 +406,42 @@ static int process_measurement(struct file *file, const struct cred *cred, if (!pathbuf) /* ima_rdwr_violation possibly pre-fetched */ pathname = ima_d_path(&file->f_path, &pathbuf, filename); +#ifdef CONFIG_IMA_DIGEST_LIST if (!pathname || strlen(pathname) > IMA_EVENT_NAME_LEN_MAX) pathname = file->f_path.dentry->d_name.name; found_digest = ima_lookup_digest(iint->ima_hash->digest, hash_algo, COMPACT_FILE); +#endif if (action & IMA_MEASURE) +#ifdef CONFIG_IMA_DIGEST_LIST ima_store_measurement(iint, file, pathname, xattr_value, xattr_len, modsig, pcr, template_desc, ima_digest_allow(found_digest, IMA_MEASURE)); +#else + ima_store_measurement(iint, file, pathname, + xattr_value, xattr_len, modsig, pcr, + template_desc); +#endif if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) { rc = ima_check_blacklist(iint, modsig, pcr); if (rc != -EPERM) { inode_lock(inode); +#ifdef CONFIG_IMA_DIGEST_LIST rc = ima_appraise_measurement(func, iint, file, pathname, xattr_value, xattr_len, modsig, ima_digest_allow(found_digest, IMA_APPRAISE)); +#else + rc = ima_appraise_measurement(func, iint, file, + pathname, xattr_value, + xattr_len, modsig); +#endif inode_unlock(inode); } if (!rc) @@ -568,15 +590,23 @@ int ima_bprm_check(struct linux_binprm *bprm) int ima_file_check(struct file *file, int mask) { u32 secid; +#ifdef CONFIG_IMA_DIGEST_LIST int rc; +#endif security_task_getsecid(current, &secid); +#ifdef CONFIG_IMA_DIGEST_LIST rc = process_measurement(file, current_cred(), secid, NULL, 0, mask & (MAY_READ | MAY_WRITE | MAY_EXEC | MAY_APPEND), FILE_CHECK); if (ima_current_is_parser() && !rc) ima_check_measured_appraised(file); return rc; +#else + return process_measurement(file, current_cred(), secid, NULL, 0, + mask & (MAY_READ | MAY_WRITE | MAY_EXEC | + MAY_APPEND), FILE_CHECK); +#endif } EXPORT_SYMBOL_GPL(ima_file_check); @@ -739,7 +769,9 @@ const int read_idmap[READING_MAX_ID] = { [READING_KEXEC_IMAGE] = KEXEC_KERNEL_CHECK, [READING_KEXEC_INITRAMFS] = KEXEC_INITRAMFS_CHECK, [READING_POLICY] = POLICY_CHECK, +#ifdef CONFIG_IMA_DIGEST_LIST [READING_DIGEST_LIST] = DIGEST_LIST_CHECK +#endif }; /** @@ -941,7 +973,11 @@ void process_buffer_measurement(struct inode *inode, const void *buf, int size, goto out; } +#ifdef CONFIG_IMA_DIGEST_LIST ret = ima_store_template(entry, violation, NULL, buf, pcr, NULL); +#else + ret = ima_store_template(entry, violation, NULL, buf, pcr); +#endif if (ret < 0) { audit_cause = "store_entry"; ima_free_template_entry(entry); diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 274f4c7c99f4..3e14b55ecf0f 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -21,7 +21,9 @@ #include <linux/ima.h> #include "ima.h" +#ifdef CONFIG_IMA_DIGEST_LIST #include "ima_digest_list.h" +#endif /* flags definitions */ #define IMA_FUNC 0x0001 @@ -35,7 +37,9 @@ #define IMA_PCR 0x0100 #define IMA_FSNAME 0x0200 #define IMA_KEYRINGS 0x0400 +#ifdef CONFIG_IMA_DIGEST_LIST #define IMA_PARSER 0x0800 +#endif #define UNKNOWN 0 #define MEASURE 0x0001 /* same as IMA_MEASURE */ @@ -58,7 +62,11 @@ enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE, LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE }; +#ifdef CONFIG_IMA_DIGEST_LIST enum policy_types { ORIGINAL_TCB = 1, DEFAULT_TCB, EXEC_TCB }; +#else +enum policy_types { ORIGINAL_TCB = 1, DEFAULT_TCB }; +#endif enum policy_rule_list { IMA_DEFAULT_POLICY = 1, IMA_CUSTOM_POLICY }; @@ -145,11 +153,13 @@ static struct ima_rule_entry default_measurement_rules[] __ro_after_init = { {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC}, {.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC}, {.action = MEASURE, .func = POLICY_CHECK, .flags = IMA_FUNC}, +#ifdef CONFIG_IMA_DIGEST_LIST {.action = MEASURE, .func = DIGEST_LIST_CHECK, .flags = IMA_FUNC}, }; static struct ima_rule_entry ima_parser_measure_rule __ro_after_init = { .action = MEASURE, .flags = IMA_PARSER +#endif }; static struct ima_rule_entry default_appraise_rules[] __ro_after_init = { @@ -181,12 +191,14 @@ static struct ima_rule_entry default_appraise_rules[] __ro_after_init = { #endif }; +#ifdef CONFIG_IMA_DIGEST_LIST static struct ima_rule_entry appraise_exec_rules[] __ro_after_init = { {.action = APPRAISE, .func = BPRM_CHECK, .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, {.action = APPRAISE, .func = MMAP_CHECK, .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, }; +#endif static struct ima_rule_entry build_appraise_rules[] __ro_after_init = { #ifdef CONFIG_IMA_APPRAISE_REQUIRE_MODULE_SIGS @@ -216,6 +228,7 @@ static struct ima_rule_entry secure_boot_rules[] __ro_after_init = { .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, {.action = APPRAISE, .func = POLICY_CHECK, .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, +#ifdef CONFIG_IMA_DIGEST_LIST {.action = APPRAISE, .func = DIGEST_LIST_CHECK, .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, }; @@ -223,6 +236,7 @@ static struct ima_rule_entry secure_boot_rules[] __ro_after_init = { static struct ima_rule_entry ima_parser_appraise_rule __ro_after_init = { .action = APPRAISE, .flags = IMA_PARSER | IMA_DIGSIG_REQUIRED +#endif }; /* An array of architecture specific rules */ @@ -246,8 +260,10 @@ static int __init default_measure_policy_setup(char *str) __setup("ima_tcb", default_measure_policy_setup); static bool ima_use_appraise_tcb __initdata; +#ifdef CONFIG_IMA_DIGEST_LIST static bool ima_use_appraise_exec_tcb __initdata; static bool ima_use_appraise_exec_immutable __initdata; +#endif static bool ima_use_secure_boot __initdata; static bool ima_fail_unverifiable_sigs __ro_after_init; static int __init policy_setup(char *str) @@ -259,14 +275,18 @@ static int __init policy_setup(char *str) continue; if ((strcmp(p, "tcb") == 0) && !ima_policy) ima_policy = DEFAULT_TCB; +#ifdef CONFIG_IMA_DIGEST_LIST else if ((strcmp(p, "exec_tcb") == 0) && !ima_policy) ima_policy = EXEC_TCB; +#endif else if (strcmp(p, "appraise_tcb") == 0) ima_use_appraise_tcb = true; +#ifdef CONFIG_IMA_DIGEST_LIST else if (strcmp(p, "appraise_exec_tcb") == 0) ima_use_appraise_exec_tcb = true; else if (strcmp(p, "appraise_exec_immutable") == 0) ima_use_appraise_exec_immutable = true; +#endif else if (strcmp(p, "secure_boot") == 0) ima_use_secure_boot = true; else if (strcmp(p, "fail_securely") == 0) @@ -569,9 +589,11 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode, if ((rule->flags & IMA_FOWNER) && !rule->fowner_op(inode->i_uid, rule->fowner)) return false; +#ifdef CONFIG_IMA_DIGEST_LIST if ((rule->flags & IMA_PARSER) && !ima_current_is_parser()) return false; +#endif for (i = 0; i < MAX_LSM_RULES; i++) { int rc = 0; u32 osid; @@ -752,19 +774,27 @@ static int ima_appraise_flag(enum ima_hooks func) return IMA_APPRAISE_POLICY; else if (func == KEXEC_KERNEL_CHECK) return IMA_APPRAISE_KEXEC; +#ifdef CONFIG_IMA_DIGEST_LIST else if (func == DIGEST_LIST_CHECK) return IMA_APPRAISE_DIGEST_LIST; +#endif return 0; } +#ifdef CONFIG_IMA_DIGEST_LIST static void __init add_rules(struct ima_rule_entry *entries, int count, enum policy_rule_list policy_rule) +#else +static void add_rules(struct ima_rule_entry *entries, int count, + enum policy_rule_list policy_rule) +#endif { int i = 0; for (i = 0; i < count; i++) { struct ima_rule_entry *entry; +#ifdef CONFIG_IMA_DIGEST_LIST if (ima_policy == EXEC_TCB) { if (entries == dont_measure_rules) if ((entries[i].flags & IMA_FSMAGIC) && @@ -792,6 +822,7 @@ static void __init add_rules(struct ima_rule_entry *entries, int count, (entries[i].flags & IMA_FUNC) && entries[i].func == BPRM_CHECK) entries[i].flags |= IMA_META_IMMUTABLE_REQUIRED; +#endif if (policy_rule & IMA_DEFAULT_POLICY) list_add_tail(&entries[i].list, &ima_default_rules); @@ -879,8 +910,10 @@ void __init ima_init_policy(void) ARRAY_SIZE(original_measurement_rules), IMA_DEFAULT_POLICY); break; +#ifdef CONFIG_IMA_DIGEST_LIST case EXEC_TCB: fallthrough; +#endif case DEFAULT_TCB: add_rules(default_measurement_rules, ARRAY_SIZE(default_measurement_rules), @@ -889,8 +922,10 @@ void __init ima_init_policy(void) break; } +#ifdef CONFIG_IMA_DIGEST_LIST if (ima_policy) add_rules(&ima_parser_measure_rule, 1, IMA_DEFAULT_POLICY); +#endif /* * Based on runtime secure boot flags, insert arch specific measurement @@ -909,7 +944,11 @@ void __init ima_init_policy(void) * Insert the builtin "secure_boot" policy rules requiring file * signatures, prior to other appraise rules. */ +#ifdef CONFIG_IMA_DIGEST_LIST if (ima_use_secure_boot || ima_use_appraise_exec_tcb) +#else + if (ima_use_secure_boot) +#endif add_rules(secure_boot_rules, ARRAY_SIZE(secure_boot_rules), IMA_DEFAULT_POLICY); @@ -929,11 +968,16 @@ void __init ima_init_policy(void) IMA_DEFAULT_POLICY | IMA_CUSTOM_POLICY); } +#ifdef CONFIG_IMA_DIGEST_LIST if (ima_use_appraise_tcb || ima_use_appraise_exec_tcb) +#else + if (ima_use_appraise_tcb) +#endif add_rules(default_appraise_rules, ARRAY_SIZE(default_appraise_rules), IMA_DEFAULT_POLICY); +#ifdef CONFIG_IMA_DIGEST_LIST if (ima_use_appraise_exec_tcb) add_rules(appraise_exec_rules, ARRAY_SIZE(appraise_exec_rules), @@ -942,6 +986,7 @@ void __init ima_init_policy(void) if (ima_use_secure_boot || ima_use_appraise_tcb || ima_use_appraise_exec_tcb) add_rules(&ima_parser_appraise_rule, 1, IMA_DEFAULT_POLICY); +#endif ima_update_policy_flag(); } @@ -1002,7 +1047,11 @@ enum { Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt, Opt_appraise_type, Opt_appraise_flag, Opt_permit_directio, Opt_pcr, Opt_template, Opt_keyrings, +#ifdef CONFIG_IMA_DIGEST_LIST Opt_parser, Opt_err +#else + Opt_err +#endif }; static const match_table_t policy_tokens = { @@ -1039,7 +1088,9 @@ static const match_table_t policy_tokens = { {Opt_pcr, "pcr=%s"}, {Opt_template, "template=%s"}, {Opt_keyrings, "keyrings=%s"}, +#ifdef CONFIG_IMA_DIGEST_LIST {Opt_parser, "parser"}, +#endif {Opt_err, NULL} }; @@ -1134,9 +1185,14 @@ static bool ima_validate_rule(struct ima_rule_entry *entry) if (entry->action != MEASURE && entry->flags & IMA_PCR) return false; +#ifdef CONFIG_IMA_DIGEST_LIST if (entry->action != APPRAISE && entry->flags & (IMA_DIGSIG_REQUIRED | IMA_MODSIG_ALLOWED | IMA_CHECK_BLACKLIST | IMA_META_IMMUTABLE_REQUIRED)) +#else + if (entry->action != APPRAISE && + entry->flags & (IMA_DIGSIG_REQUIRED | IMA_MODSIG_ALLOWED | IMA_CHECK_BLACKLIST)) +#endif return false; /* @@ -1162,13 +1218,19 @@ static bool ima_validate_rule(struct ima_rule_entry *entry) case POST_SETATTR: case FIRMWARE_CHECK: case POLICY_CHECK: +#ifdef CONFIG_IMA_DIGEST_LIST case DIGEST_LIST_CHECK: +#endif if (entry->flags & ~(IMA_FUNC | IMA_MASK | IMA_FSMAGIC | IMA_UID | IMA_FOWNER | IMA_FSUUID | IMA_INMASK | IMA_EUID | IMA_PCR | IMA_FSNAME | IMA_DIGSIG_REQUIRED | +#ifdef CONFIG_IMA_DIGEST_LIST IMA_PERMIT_DIRECTIO | IMA_META_IMMUTABLE_REQUIRED | IMA_PARSER)) +#else + IMA_PERMIT_DIRECTIO)) +#endif return false; break; @@ -1180,8 +1242,12 @@ static bool ima_validate_rule(struct ima_rule_entry *entry) IMA_INMASK | IMA_EUID | IMA_PCR | IMA_FSNAME | IMA_DIGSIG_REQUIRED | IMA_PERMIT_DIRECTIO | IMA_MODSIG_ALLOWED | +#ifdef CONFIG_IMA_DIGEST_LIST IMA_CHECK_BLACKLIST | IMA_META_IMMUTABLE_REQUIRED)) +#else + IMA_CHECK_BLACKLIST)) +#endif return false; break; @@ -1338,8 +1404,10 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) else if (IS_ENABLED(CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS) && strcmp(args[0].from, "KEY_CHECK") == 0) entry->func = KEY_CHECK; +#ifdef CONFIG_IMA_DIGEST_LIST else if (strcmp(args[0].from, "DIGEST_LIST_CHECK") == 0) entry->func = DIGEST_LIST_CHECK; +#endif else result = -EINVAL; if (!result) @@ -1526,8 +1594,10 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) strcmp(args[0].from, "imasig|modsig") == 0) entry->flags |= IMA_DIGSIG_REQUIRED | IMA_MODSIG_ALLOWED; +#ifdef CONFIG_IMA_DIGEST_LIST else if (strcmp(args[0].from, "meta_immutable") == 0) entry->flags |= IMA_META_IMMUTABLE_REQUIRED; +#endif else result = -EINVAL; break; @@ -1546,8 +1616,12 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) ima_log_string(ab, "pcr", args[0].from); result = kstrtoint(args[0].from, 10, &entry->pcr); +#ifdef CONFIG_IMA_DIGEST_LIST if (result || INVALID_PCR(entry->pcr) || entry->pcr == ima_digest_list_pcr) +#else + if (result || INVALID_PCR(entry->pcr)) +#endif result = -EINVAL; else entry->flags |= IMA_PCR; @@ -1574,10 +1648,12 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) &(template_desc->fields), &(template_desc->num_fields)); entry->template = template_desc; +#ifdef CONFIG_IMA_DIGEST_LIST break; case Opt_parser: audit_log_format(ab, "parser "); entry->flags |= IMA_PARSER; +#endif break; case Opt_err: ima_log_string(ab, "UNKNOWN", p); @@ -1849,8 +1925,10 @@ int ima_policy_show(struct seq_file *m, void *v) seq_puts(m, " "); } +#ifdef CONFIG_IMA_DIGEST_LIST if (entry->flags & IMA_PARSER) seq_puts(m, "parser "); +#endif for (i = 0; i < MAX_LSM_RULES; i++) { if (entry->lsm[i].rule) { @@ -1893,8 +1971,10 @@ int ima_policy_show(struct seq_file *m, void *v) } if (entry->flags & IMA_CHECK_BLACKLIST) seq_puts(m, "appraise_flag=check_blacklist "); +#ifdef CONFIG_IMA_DIGEST_LIST if (entry->flags & IMA_META_IMMUTABLE_REQUIRED) seq_puts(m, "appraise_type=meta_immutable "); +#endif if (entry->flags & IMA_PERMIT_DIRECTIO) seq_puts(m, "permit_directio "); rcu_read_unlock(); diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 77e6819e8db8..d9cf29e286a9 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -14,10 +14,13 @@ #include <linux/types.h> #include <linux/integrity.h> +#include <crypto/sha1.h> #include <crypto/sha2.h> #include <linux/key.h> #include <linux/audit.h> +#ifdef CONFIG_IMA_DIGEST_LIST #include <linux/hash_info.h> +#endif /* iint action cache flags */ #define IMA_MEASURE 0x00000001 @@ -40,7 +43,9 @@ #define IMA_FAIL_UNVERIFIABLE_SIGS 0x10000000 #define IMA_MODSIG_ALLOWED 0x20000000 #define IMA_CHECK_BLACKLIST 0x40000000 +#ifdef CONFIG_IMA_DIGEST_LIST #define IMA_META_IMMUTABLE_REQUIRED 0x80000000 +#endif #define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \ IMA_HASH | IMA_APPRAISE_SUBMASK) @@ -72,7 +77,9 @@ #define IMA_CHANGE_ATTR 2 #define IMA_DIGSIG 3 #define IMA_MUST_MEASURE 4 +#ifdef CONFIG_IMA_DIGEST_LIST #define IMA_DIGEST_LIST 5 +#endif enum evm_ima_xattr_type { IMA_XATTR_DIGEST = 0x01, @@ -80,7 +87,9 @@ enum evm_ima_xattr_type { EVM_IMA_XATTR_DIGSIG, IMA_XATTR_DIGEST_NG, EVM_XATTR_PORTABLE_DIGSIG, +#ifdef CONFIG_IMA_DIGEST_LIST EVM_IMA_XATTR_DIGEST_LIST, +#endif IMA_XATTR_LAST }; @@ -92,7 +101,11 @@ struct evm_ima_xattr_data { /* Only used in the EVM HMAC code. */ struct evm_xattr { struct evm_ima_xattr_data data; +#ifdef CONFIG_IMA_DIGEST_LIST u8 digest[SHA512_DIGEST_SIZE]; +#else + u8 digest[SHA1_DIGEST_SIZE]; +#endif } __packed; #define IMA_MAX_DIGEST_SIZE 64 @@ -144,6 +157,7 @@ struct integrity_iint_cache { struct ima_digest_data *ima_hash; }; +#ifdef CONFIG_IMA_DIGEST_LIST enum compact_types { COMPACT_KEY, COMPACT_PARSER, COMPACT_FILE, COMPACT_METADATA, COMPACT__LAST }; enum compact_modifiers { COMPACT_MOD_IMMUTABLE, COMPACT_MOD__LAST }; @@ -162,7 +176,6 @@ static inline bool ima_digest_is_immutable(struct ima_digest *digest) return (digest->modifiers & (1 << COMPACT_MOD_IMMUTABLE)); } -#ifdef CONFIG_IMA_DIGEST_LIST struct ima_digest *ima_lookup_digest(u8 *digest, enum hash_algo algo, enum compact_types type); struct ima_digest *ima_digest_allow(struct ima_digest *digest, int action); diff --git a/security/security.c b/security/security.c index 5678d4e334fb..11c859a9b8ed 100644 --- a/security/security.c +++ b/security/security.c @@ -1362,7 +1362,9 @@ void security_inode_post_setxattr(struct dentry *dentry, const char *name, if (unlikely(IS_PRIVATE(d_backing_inode(dentry)))) return; call_void_hook(inode_post_setxattr, dentry, name, value, size, flags); +#ifdef CONFIG_IMA_DIGEST_LIST ima_inode_post_setxattr(dentry, name, value, size); +#endif evm_inode_post_setxattr(dentry, name, value, size); } -- 2.33.0
2 1
0 0
  • ← Newer
  • 1
  • ...
  • 1476
  • 1477
  • 1478
  • 1479
  • 1480
  • 1481
  • 1482
  • ...
  • 1829
  • Older →

HyperKitty Powered by HyperKitty