Kernel
Threads by month
- ----- 2025 -----
- 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
September 2023
- 56 participants
- 248 discussions

[PATCH OLK-5.10 0/3] scsi: scsi_device_gets returns failure when the module is NULL
by Zhong Jinghua 06 Sep '23
by Zhong Jinghua 06 Sep '23
06 Sep '23
scsi: scsi_device_gets returns failure when the module is NULL
Li Lingfeng (2):
scsi: don't fail if hostt->module is NULL
scsi: fix kabi broken in struct Scsi_Host
Zhong Jinghua (1):
scsi: scsi_device_gets returns failure when the module is NULL.
drivers/scsi/hosts.c | 3 +++
drivers/scsi/scsi.c | 6 +++++-
include/scsi/scsi_host.h | 2 +-
3 files changed, 9 insertions(+), 2 deletions(-)
--
2.31.1
2
4

06 Sep '23
hulk inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I7YS6M
-------------------------------
Expand qos_level from {-1,0} to [-2, 2], to distinguish the tasks expected
to be with extremely high or low priority level. Using qos_level_weight
to reweight the shares when calculating group's weight. Meanwhile,
set offline task's schedule policy to SCHED_IDLE so that it can be
preempted at check_preempt_wakeup.
Signed-off-by: Zhao Wenhui <zhaowenhui8(a)huawei.com>
---
arch/arm64/configs/openeuler_defconfig | 1 +
arch/x86/configs/openeuler_defconfig | 1 +
include/linux/sched/sysctl.h | 4 ++
init/Kconfig | 9 ++++
kernel/sched/core.c | 24 ++++++----
kernel/sched/fair.c | 64 ++++++++++++++++++++++++--
kernel/sched/sched.h | 26 ++++++++++-
kernel/sysctl.c | 9 ++++
8 files changed, 125 insertions(+), 13 deletions(-)
diff --git a/arch/arm64/configs/openeuler_defconfig b/arch/arm64/configs/openeuler_defconfig
index a64923c8f1c9..1b591206471b 100644
--- a/arch/arm64/configs/openeuler_defconfig
+++ b/arch/arm64/configs/openeuler_defconfig
@@ -181,6 +181,7 @@ CONFIG_CGROUP_PERF=y
CONFIG_CGROUP_BPF=y
# CONFIG_CGROUP_MISC is not set
CONFIG_QOS_SCHED=y
+CONFIG_QOS_SCHED_MULTILEVEL=y
# CONFIG_CGROUP_DEBUG is not set
CONFIG_SOCK_CGROUP_DATA=y
CONFIG_CGROUP_FILES=y
diff --git a/arch/x86/configs/openeuler_defconfig b/arch/x86/configs/openeuler_defconfig
index a0669731cef4..73d87040d650 100644
--- a/arch/x86/configs/openeuler_defconfig
+++ b/arch/x86/configs/openeuler_defconfig
@@ -190,6 +190,7 @@ CONFIG_FAIR_GROUP_SCHED=y
CONFIG_QOS_SCHED_SMT_EXPELLER=y
CONFIG_CFS_BANDWIDTH=y
CONFIG_QOS_SCHED=y
+CONFIG_QOS_SCHED_MULTILEVEL=y
CONFIG_RT_GROUP_SCHED=y
CONFIG_SCHED_MM_CID=y
CONFIG_QOS_SCHED_DYNAMIC_AFFINITY=y
diff --git a/include/linux/sched/sysctl.h b/include/linux/sched/sysctl.h
index 28d9be8e4614..3a02a76b08ca 100644
--- a/include/linux/sched/sysctl.h
+++ b/include/linux/sched/sysctl.h
@@ -37,4 +37,8 @@ extern unsigned int sysctl_overload_detect_period;
extern unsigned int sysctl_offline_wait_interval;
#endif
+#ifdef CONFIG_QOS_SCHED_MULTILEVEL
+extern unsigned int sysctl_qos_level_weights[];
+#endif
+
#endif /* _LINUX_SCHED_SYSCTL_H */
diff --git a/init/Kconfig b/init/Kconfig
index a12109fe4385..12a5ffbb5252 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1015,6 +1015,15 @@ config QOS_SCHED_SMT_EXPELLER
This feature enable online tasks to expel offline tasks
on the smt sibling cpus, and exclusively occupy CPU resources.
+config QOS_SCHED_MULTILEVEL
+ bool "Multiple qos level task scheduling"
+ depends on QOS_SCHED
+ default n
+ help
+ This feature enable multiple qos level on task scheduling.
+ Expand the qos_level to [-2,2] to distinguish the tasks expected
+ to be with extremely high or low priority level.
+
config FAIR_GROUP_SCHED
bool "Group scheduling for SCHED_OTHER"
depends on CGROUP_SCHED
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 652c06bd546d..238b5b55c38a 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -7689,7 +7689,7 @@ static int __sched_setscheduler(struct task_struct *p,
* other than SCHED_IDLE, the online task preemption and cpu resource
* isolation will be invalid, so return -EINVAL in this case.
*/
- if (unlikely(task_group(p)->qos_level == -1 && !idle_policy(policy))) {
+ if (unlikely(is_offline_level(task_group(p)->qos_level) && !idle_policy(policy))) {
retval = -EINVAL;
goto unlock;
}
@@ -10356,7 +10356,7 @@ static void sched_change_qos_group(struct task_struct *tsk, struct task_group *t
*/
if (!(tsk->flags & PF_EXITING) &&
!task_group_is_autogroup(tg) &&
- (tg->qos_level == -1)) {
+ (is_offline_level(tg->qos_level))) {
attr.sched_priority = 0;
attr.sched_policy = SCHED_IDLE;
attr.sched_nice = PRIO_TO_NICE(tsk->static_prio);
@@ -10385,7 +10385,7 @@ void sched_move_offline_task(struct task_struct *p)
{
struct offline_args *args;
- if (unlikely(task_group(p)->qos_level != -1))
+ if (unlikely(!is_offline_level(task_group(p)->qos_level)))
return;
args = kmalloc(sizeof(struct offline_args), GFP_ATOMIC);
@@ -11275,7 +11275,7 @@ static int tg_change_scheduler(struct task_group *tg, void *data)
struct cgroup_subsys_state *css = &tg->css;
tg->qos_level = qos_level;
- if (qos_level == -1)
+ if (is_offline_level(qos_level))
policy = SCHED_IDLE;
else
policy = SCHED_NORMAL;
@@ -11297,19 +11297,27 @@ static int cpu_qos_write(struct cgroup_subsys_state *css,
if (!tg->se[0])
return -EINVAL;
- if (qos_level != -1 && qos_level != 0)
+#ifdef CONFIG_QOS_SCHED_MULTILEVEL
+ if (qos_level > QOS_LEVEL_HIGH_EX || qos_level < QOS_LEVEL_OFFLINE_EX)
+#else
+ if (qos_level != QOS_LEVEL_OFFLINE && qos_level != QOS_LEVEL_ONLINE)
+#endif
return -EINVAL;
if (tg->qos_level == qos_level)
goto done;
- if (tg->qos_level == -1 && qos_level == 0)
+#ifdef CONFIG_QOS_SCHED_MULTILEVEL
+ if (!is_normal_level(tg->qos_level))
+#else
+ if (tg->qos_level == QOS_LEVEL_OFFLINE && qos_level == QOS_LEVEL_ONLINE)
+#endif
return -EINVAL;
cpus_read_lock();
- if (qos_level == -1)
+ if (is_offline_level(qos_level))
cfs_bandwidth_usage_inc();
- else
+ else if (is_offline_level(tg->qos_level) && !is_offline_level(qos_level))
cfs_bandwidth_usage_dec();
cpus_read_unlock();
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index ec2be284d185..bd833504f741 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -199,6 +199,23 @@ static bool qos_smt_expelled(int this_cpu);
static DEFINE_PER_CPU(int, qos_smt_status);
#endif
+#ifdef CONFIG_QOS_SCHED_MULTILEVEL
+#define QOS_LEVEL_WEIGHT_OFFLINE_EX 1
+#define QOS_LEVEL_WEIGHT_OFFLINE 10
+#define QOS_LEVEL_WEIGHT_ONLINE 100
+#define QOS_LEVEL_WEIGHT_HIGH 1000
+#define QOS_LEVEL_WEIGHT_HIGH_EX 10000
+
+unsigned int sysctl_qos_level_weights[5] = {
+ QOS_LEVEL_WEIGHT_OFFLINE_EX,
+ QOS_LEVEL_WEIGHT_OFFLINE,
+ QOS_LEVEL_WEIGHT_ONLINE,
+ QOS_LEVEL_WEIGHT_HIGH,
+ QOS_LEVEL_WEIGHT_HIGH_EX,
+};
+static long qos_reweight(long shares, struct task_group *tg);
+#endif
+
#ifdef CONFIG_CFS_BANDWIDTH
/*
* Amount of runtime to allocate from global (tg) to local (per-cfs_rq) pool
@@ -3537,6 +3554,9 @@ static long calc_group_shares(struct cfs_rq *cfs_rq)
struct task_group *tg = cfs_rq->tg;
tg_shares = READ_ONCE(tg->shares);
+#ifdef CONFIG_QOS_SCHED_MULTILEVEL
+ tg_shares = qos_reweight(tg_shares, tg);
+#endif
load = max(scale_load_down(cfs_rq->load.weight), cfs_rq->avg.load_avg);
@@ -3583,6 +3603,9 @@ static void update_cfs_group(struct sched_entity *se)
#ifndef CONFIG_SMP
shares = READ_ONCE(gcfs_rq->tg->shares);
+#ifdef CONFIG_QOS_SCHED_MULTILEVEL
+ shares = qos_reweight(shares, gcfs_rq->tg);
+#endif
if (likely(se->load.weight == shares))
return;
@@ -8317,7 +8340,7 @@ static inline void cancel_qos_timer(int cpu)
static inline bool is_offline_task(struct task_struct *p)
{
- return task_group(p)->qos_level == -1;
+ return task_group(p)->qos_level < QOS_LEVEL_ONLINE;
}
static void start_qos_hrtimer(int cpu);
@@ -8510,7 +8533,7 @@ static bool check_qos_cfs_rq(struct cfs_rq *cfs_rq)
if (unlikely(__this_cpu_read(qos_cpu_overload)))
return false;
- if (unlikely(cfs_rq && cfs_rq->tg->qos_level < 0 &&
+ if (unlikely(cfs_rq && is_offline_level(cfs_rq->tg->qos_level) &&
!sched_idle_cpu(smp_processor_id()) &&
cfs_rq->h_nr_running == cfs_rq->idle_h_nr_running)) {
throttle_qos_cfs_rq(cfs_rq);
@@ -8526,7 +8549,7 @@ static inline void unthrottle_qos_sched_group(struct cfs_rq *cfs_rq)
struct rq_flags rf;
rq_lock_irqsave(rq, &rf);
- if (cfs_rq->tg->qos_level == -1 && cfs_rq_throttled(cfs_rq))
+ if (is_offline_level(cfs_rq->tg->qos_level) && cfs_rq_throttled(cfs_rq))
unthrottle_qos_cfs_rq(cfs_rq);
rq_unlock_irqrestore(rq, &rf);
}
@@ -8539,7 +8562,7 @@ void sched_qos_offline_wait(void)
rcu_read_lock();
qos_level = task_group(current)->qos_level;
rcu_read_unlock();
- if (qos_level != -1 || fatal_signal_pending(current))
+ if (!is_offline_level(qos_level) || fatal_signal_pending(current))
break;
schedule_timeout_killable(msecs_to_jiffies(sysctl_offline_wait_interval));
@@ -8569,6 +8592,39 @@ static enum hrtimer_restart qos_overload_timer_handler(struct hrtimer *timer)
return HRTIMER_NORESTART;
}
+#ifdef CONFIG_QOS_SCHED_MULTILEVEL
+static long qos_reweight(long shares, struct task_group *tg)
+{
+ long qos_weight = 100;
+ long div = 100;
+ long scale_shares;
+
+ switch (tg->qos_level) {
+ case QOS_LEVEL_OFFLINE_EX:
+ qos_weight = sysctl_qos_level_weights[0];
+ break;
+ case QOS_LEVEL_OFFLINE:
+ qos_weight = sysctl_qos_level_weights[1];
+ break;
+ case QOS_LEVEL_ONLINE:
+ qos_weight = sysctl_qos_level_weights[2];
+ break;
+ case QOS_LEVEL_HIGH:
+ qos_weight = sysctl_qos_level_weights[3];
+ break;
+ case QOS_LEVEL_HIGH_EX:
+ qos_weight = sysctl_qos_level_weights[4];
+ break;
+ }
+ if (qos_weight > LONG_MAX / shares)
+ scale_shares = LONG_MAX / div;
+ else
+ scale_shares = shares * qos_weight / div;
+ scale_shares = clamp_t(long, scale_shares, scale_load(MIN_SHARES), scale_load(MAX_SHARES));
+ return scale_shares;
+}
+#endif
+
static void start_qos_hrtimer(int cpu)
{
ktime_t time;
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 0d981063bf48..5782b770e120 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -1420,11 +1420,20 @@ do { \
} while (0)
#ifdef CONFIG_QOS_SCHED
+#ifdef CONFIG_QOS_SCHED_MULTILEVEL
enum task_qos_level {
+ QOS_LEVEL_OFFLINE_EX = -2,
QOS_LEVEL_OFFLINE = -1,
QOS_LEVEL_ONLINE = 0,
- QOS_LEVEL_MAX
+ QOS_LEVEL_HIGH = 1,
+ QOS_LEVEL_HIGH_EX = 2
};
+#else
+enum task_qos_level {
+ QOS_LEVEL_OFFLINE = -1,
+ QOS_LEVEL_ONLINE = 0,
+};
+#endif
void init_qos_hrtimer(int cpu);
#endif
@@ -3269,6 +3278,21 @@ static inline int qos_idle_policy(int policy)
{
return policy == QOS_LEVEL_OFFLINE;
}
+
+static inline int is_high_level(long qos_level)
+{
+ return qos_level > QOS_LEVEL_ONLINE;
+}
+
+static inline int is_normal_level(long qos_level)
+{
+ return qos_level == QOS_LEVEL_ONLINE;
+}
+
+static inline int is_offline_level(long qos_level)
+{
+ return qos_level < QOS_LEVEL_ONLINE;
+}
#endif
#ifdef CONFIG_QOS_SCHED_SMT_EXPELLER
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index e9af234bf882..1714abd73f23 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -2068,6 +2068,15 @@ static struct ctl_table kern_table[] = {
.extra1 = SYSCTL_ONE_HUNDRED,
.extra2 = &one_thousand,
},
+#endif
+#ifdef CONFIG_QOS_SCHED_MULTILEVEL
+ {
+ .procname = "qos_level_weights",
+ .data = &sysctl_qos_level_weights,
+ .maxlen = 5*sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
#endif
{
.procname = "max_rcu_stall_to_panic",
--
2.34.1
2
1

06 Sep '23
hulk inclusion
category: bugfix
bugzilla: 189183, https://gitee.com/openeuler/kernel/issues/I7Z1ZU
CVE: NA
----------------------------------------
The following panic with RedHat 7.5 kernel was reported by UVP:
CPU: 28 PID: 56610 Comm: kworker/u160:6 Kdump: loaded Tainted: G OE K----V------- 3.10.0-862.14.1.6_152.x86_64 #1
Hardware name: ZTE R5300 G4/R5300G4, BIOS 03.20.0200_8717837 06/07/2021
Workqueue: events_aync_free recharge_parent
task: ffff97fc84cc0fe0 ti: ffff97d3840c8000 task.ti: ffff97d3840c8000
RIP: 0010:[<ffffffffa0d1ea7d>] [<ffffffffa0d1ea7d>] cgroup_is_descendant+0x1d/0x40
RSP: 0018:ffff97d3840cbd10 EFLAGS: 00010296
RAX: 0000000000000000 RBX: ffffffffa1943ba0 RCX: 0000000000000007
RDX: ffff97fd12043800 RSI: ffff982d3faa5c00 RDI: 3930343331356364
RBP: ffff97d3840cbd10 R08: ffffffffa1943ba0 R09: 0000000000000007
R10: 0000000000000000 R11: 0000000000000001 R12: 0000000000016100
R13: ffff97fe809d6100 R14: 0000000000000007 R15: 0000000000000007
FS: 0000000000000000(0000) GS:ffff982e7be00000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00005633394b1c10 CR3: 00000059d900e000 CR4: 00000000003627e0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
Call Trace:
[<ffffffffa0e1840c>] __mem_cgroup_same_or_subtree+0x2c/0x40
[<ffffffffc0937291>] drain_all_stock+0xc1/0xe30 [klp_HP0038]
[<ffffffffa0e185f1>] mem_cgroup_reparent_charges+0x51/0x3b0
[<ffffffffa0cce718>] ? finish_task_switch+0xf8/0x170
[<ffffffffa0e18b14>] recharge_parent+0x54/0x80
[<ffffffffa0cb7a32>] process_one_work+0x182/0x450
[<ffffffffa0cb8996>] worker_thread+0x126/0x3c0
[<ffffffffa0cb8870>] ? manage_workers.isra.24+0x2a0/0x2a0
[<ffffffffa0cbfab1>] kthread+0xd1/0xe0
[<ffffffffa0cbf9e0>] ? insert_kthread_work+0x40/0x40
[<ffffffffa133b5dd>] ret_from_fork_nospec_begin+0x7/0x21
[<ffffffffa0cbf9e0>] ? insert_kthread_work+0x40/0x40
It is found that in case stock->nr_pages is decreased to 0, a memcg that
is going to be freed would skip the drain_local_stock() process and
therefore be left on stock->cached after being freed, which could cause
UAF problems in drain_all_stock().
Now it is believed that the same problem exists on 4.19 as well,
confirmed by successful reproduction. The problem causes panic with
similar call trace, and its triggering process is demonstrated as
follows:
stock->cached = mB
CPU2 CPU3 CPU4
consume_stock
local_irq_save
stock->nr_pages -= xxx -> 0
drain_all_stock
rcu_read_lock()
memcg = cpu2's stock->cached
cpu2's stock->nr_page==0
rcu_read_unlock()
(skip)
====================================== (mB freed) =======================================
drain_all_stock(mD)
rcu_read_lock()
memcg = cpu2's stock->cached
(interrupted)
refill_stock(mC)
local_irq_save
drain_stock(mB)
stock->cached = mC
stock->nr_pages += xxx (> 0)
stock->nr_pages > 0
mem_cgroup_is_descendant(memcg, root_memcg) [UAF]
rcu_read_unlock()
Fix this problem by removing `stock->nr_pages` from the preconditions of
`flush = true` in drain_all_stock(), so as to drain the stock even if
its nr_pages is 0.
Signed-off-by: GONG, Ruiqi <gongruiqi1(a)huawei.com>
---
mm/memcontrol.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 1b11bc13e1aa..032bb52cd2ed 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -2226,8 +2226,7 @@ static void drain_all_stock(struct mem_cgroup *root_memcg)
rcu_read_lock();
memcg = stock->cached;
- if (memcg && stock->nr_pages &&
- mem_cgroup_is_descendant(memcg, root_memcg))
+ if (memcg && mem_cgroup_is_descendant(memcg, root_memcg))
flush = true;
rcu_read_unlock();
--
2.25.1
2
1

06 Sep '23
hulk inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I7YS6M
-------------------------------
Expand qos_level from {-1,0} to [-2, 2], to distinguish the tasks expected
to be with extremely high or low priority level. Using qos_level_weight
to reweight the shares when calculating group's weight. Meanwhile,
set offline task's schedule policy to SCHED_IDLE so that it can be
preempted at check_preempt_wakeup.
Signed-off-by: Zhao Wenhui <zhaowenhui8(a)huawei.com>
---
arch/arm64/configs/openeuler_defconfig | 1 +
arch/x86/configs/openeuler_defconfig | 1 +
include/linux/sched/sysctl.h | 4 ++
init/Kconfig | 9 ++++
kernel/sched/core.c | 24 ++++++----
kernel/sched/fair.c | 64 ++++++++++++++++++++++++--
kernel/sched/sched.h | 26 ++++++++++-
kernel/sysctl.c | 9 ++++
8 files changed, 125 insertions(+), 13 deletions(-)
diff --git a/arch/arm64/configs/openeuler_defconfig b/arch/arm64/configs/openeuler_defconfig
index c89f8a7ec669..7020bad802cc 100644
--- a/arch/arm64/configs/openeuler_defconfig
+++ b/arch/arm64/configs/openeuler_defconfig
@@ -178,6 +178,7 @@ CONFIG_CGROUP_PERF=y
CONFIG_CGROUP_BPF=y
# CONFIG_CGROUP_MISC is not set
CONFIG_QOS_SCHED=y
+CONFIG_QOS_SCHED_MULTILEVEL=y
# CONFIG_CGROUP_DEBUG is not set
CONFIG_SOCK_CGROUP_DATA=y
CONFIG_NAMESPACES=y
diff --git a/arch/x86/configs/openeuler_defconfig b/arch/x86/configs/openeuler_defconfig
index d72097778f4b..d1afc82733e5 100644
--- a/arch/x86/configs/openeuler_defconfig
+++ b/arch/x86/configs/openeuler_defconfig
@@ -187,6 +187,7 @@ CONFIG_FAIR_GROUP_SCHED=y
CONFIG_QOS_SCHED_SMT_EXPELLER=y
CONFIG_CFS_BANDWIDTH=y
CONFIG_QOS_SCHED=y
+CONFIG_QOS_SCHED_MULTILEVEL=y
CONFIG_RT_GROUP_SCHED=y
CONFIG_SCHED_MM_CID=y
CONFIG_QOS_SCHED_DYNAMIC_AFFINITY=y
diff --git a/include/linux/sched/sysctl.h b/include/linux/sched/sysctl.h
index 28d9be8e4614..3a02a76b08ca 100644
--- a/include/linux/sched/sysctl.h
+++ b/include/linux/sched/sysctl.h
@@ -37,4 +37,8 @@ extern unsigned int sysctl_overload_detect_period;
extern unsigned int sysctl_offline_wait_interval;
#endif
+#ifdef CONFIG_QOS_SCHED_MULTILEVEL
+extern unsigned int sysctl_qos_level_weights[];
+#endif
+
#endif /* _LINUX_SCHED_SYSCTL_H */
diff --git a/init/Kconfig b/init/Kconfig
index c189d4d5d91b..3b4576d04117 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1005,6 +1005,15 @@ config QOS_SCHED_SMT_EXPELLER
This feature enable online tasks to expel offline tasks
on the smt sibling cpus, and exclusively occupy CPU resources.
+config QOS_SCHED_MULTILEVEL
+ bool "Multiple qos level task scheduling"
+ depends on QOS_SCHED
+ default n
+ help
+ This feature enable multiple qos level on task scheduling.
+ Expand the qos_level to [-2,2] to distinguish the tasks expected
+ to be with extremely high or low priority level.
+
config FAIR_GROUP_SCHED
bool "Group scheduling for SCHED_OTHER"
depends on CGROUP_SCHED
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 08ce8aada0b0..8a69840b82ed 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -7686,7 +7686,7 @@ static int __sched_setscheduler(struct task_struct *p,
* other than SCHED_IDLE, the online task preemption and cpu resource
* isolation will be invalid, so return -EINVAL in this case.
*/
- if (unlikely(task_group(p)->qos_level == -1 && !idle_policy(policy))) {
+ if (unlikely(is_offline_level(task_group(p)->qos_level) && !idle_policy(policy))) {
retval = -EINVAL;
goto unlock;
}
@@ -10342,7 +10342,7 @@ static void sched_change_qos_group(struct task_struct *tsk, struct task_group *t
*/
if (!(tsk->flags & PF_EXITING) &&
!task_group_is_autogroup(tg) &&
- (tg->qos_level == -1)) {
+ (is_offline_level(tg->qos_level))) {
attr.sched_priority = 0;
attr.sched_policy = SCHED_IDLE;
attr.sched_nice = PRIO_TO_NICE(tsk->static_prio);
@@ -10371,7 +10371,7 @@ void sched_move_offline_task(struct task_struct *p)
{
struct offline_args *args;
- if (unlikely(task_group(p)->qos_level != -1))
+ if (unlikely(!is_offline_level(task_group(p)->qos_level)))
return;
args = kmalloc(sizeof(struct offline_args), GFP_ATOMIC);
@@ -11242,7 +11242,7 @@ static int tg_change_scheduler(struct task_group *tg, void *data)
struct cgroup_subsys_state *css = &tg->css;
tg->qos_level = qos_level;
- if (qos_level == -1)
+ if (is_offline_level(qos_level))
policy = SCHED_IDLE;
else
policy = SCHED_NORMAL;
@@ -11264,19 +11264,27 @@ static int cpu_qos_write(struct cgroup_subsys_state *css,
if (!tg->se[0])
return -EINVAL;
- if (qos_level != -1 && qos_level != 0)
+#ifdef CONFIG_QOS_SCHED_MULTILEVEL
+ if (qos_level > QOS_LEVEL_HIGH_EX || qos_level < QOS_LEVEL_OFFLINE_EX)
+#else
+ if (qos_level != QOS_LEVEL_OFFLINE && qos_level != QOS_LEVEL_ONLINE)
+#endif
return -EINVAL;
if (tg->qos_level == qos_level)
goto done;
- if (tg->qos_level == -1 && qos_level == 0)
+#ifdef CONFIG_QOS_SCHED_MULTILEVEL
+ if (!is_normal_level(tg->qos_level))
+#else
+ if (tg->qos_level == QOS_LEVEL_OFFLINE && qos_level == QOS_LEVEL_ONLINE)
+#endif
return -EINVAL;
cpus_read_lock();
- if (qos_level == -1)
+ if (is_offline_level(qos_level))
cfs_bandwidth_usage_inc();
- else
+ else if (is_offline_level(tg->qos_level) && !is_offline_level(qos_level))
cfs_bandwidth_usage_dec();
cpus_read_unlock();
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 51e550ba66b8..04795fd25703 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -194,6 +194,23 @@ static bool qos_smt_expelled(int this_cpu);
static DEFINE_PER_CPU(int, qos_smt_status);
#endif
+#ifdef CONFIG_QOS_SCHED_MULTILEVEL
+#define QOS_LEVEL_WEIGHT_OFFLINE_EX 1
+#define QOS_LEVEL_WEIGHT_OFFLINE 10
+#define QOS_LEVEL_WEIGHT_ONLINE 100
+#define QOS_LEVEL_WEIGHT_HIGH 1000
+#define QOS_LEVEL_WEIGHT_HIGH_EX 10000
+
+unsigned int sysctl_qos_level_weights[5] = {
+ QOS_LEVEL_WEIGHT_OFFLINE_EX,
+ QOS_LEVEL_WEIGHT_OFFLINE,
+ QOS_LEVEL_WEIGHT_ONLINE,
+ QOS_LEVEL_WEIGHT_HIGH,
+ QOS_LEVEL_WEIGHT_HIGH_EX,
+};
+static long qos_reweight(long shares, struct task_group *tg);
+#endif
+
#ifdef CONFIG_CFS_BANDWIDTH
/*
* Amount of runtime to allocate from global (tg) to local (per-cfs_rq) pool
@@ -3523,6 +3540,9 @@ static long calc_group_shares(struct cfs_rq *cfs_rq)
struct task_group *tg = cfs_rq->tg;
tg_shares = READ_ONCE(tg->shares);
+#ifdef CONFIG_QOS_SCHED_MULTILEVEL
+ tg_shares = qos_reweight(tg_shares, tg);
+#endif
load = max(scale_load_down(cfs_rq->load.weight), cfs_rq->avg.load_avg);
@@ -3569,6 +3589,9 @@ static void update_cfs_group(struct sched_entity *se)
#ifndef CONFIG_SMP
shares = READ_ONCE(gcfs_rq->tg->shares);
+#ifdef CONFIG_QOS_SCHED_MULTILEVEL
+ shares = qos_reweight(shares, gcfs_rq->tg);
+#endif
if (likely(se->load.weight == shares))
return;
@@ -8196,7 +8219,7 @@ static inline void cancel_qos_timer(int cpu)
static inline bool is_offline_task(struct task_struct *p)
{
- return task_group(p)->qos_level == -1;
+ return task_group(p)->qos_level < QOS_LEVEL_ONLINE;
}
static void start_qos_hrtimer(int cpu);
@@ -8389,7 +8412,7 @@ static bool check_qos_cfs_rq(struct cfs_rq *cfs_rq)
if (unlikely(__this_cpu_read(qos_cpu_overload)))
return false;
- if (unlikely(cfs_rq && cfs_rq->tg->qos_level < 0 &&
+ if (unlikely(cfs_rq && is_offline_level(cfs_rq->tg->qos_level) &&
!sched_idle_cpu(smp_processor_id()) &&
cfs_rq->h_nr_running == cfs_rq->idle_h_nr_running)) {
throttle_qos_cfs_rq(cfs_rq);
@@ -8405,7 +8428,7 @@ static inline void unthrottle_qos_sched_group(struct cfs_rq *cfs_rq)
struct rq_flags rf;
rq_lock_irqsave(rq, &rf);
- if (cfs_rq->tg->qos_level == -1 && cfs_rq_throttled(cfs_rq))
+ if (is_offline_level(cfs_rq->tg->qos_level) && cfs_rq_throttled(cfs_rq))
unthrottle_qos_cfs_rq(cfs_rq);
rq_unlock_irqrestore(rq, &rf);
}
@@ -8418,7 +8441,7 @@ void sched_qos_offline_wait(void)
rcu_read_lock();
qos_level = task_group(current)->qos_level;
rcu_read_unlock();
- if (qos_level != -1 || fatal_signal_pending(current))
+ if (!is_offline_level(qos_level) || fatal_signal_pending(current))
break;
schedule_timeout_killable(msecs_to_jiffies(sysctl_offline_wait_interval));
@@ -8448,6 +8471,39 @@ static enum hrtimer_restart qos_overload_timer_handler(struct hrtimer *timer)
return HRTIMER_NORESTART;
}
+#ifdef CONFIG_QOS_SCHED_MULTILEVEL
+static long qos_reweight(long shares, struct task_group *tg)
+{
+ long qos_weight = 100;
+ long div = 100;
+ long scale_shares;
+
+ switch (tg->qos_level) {
+ case QOS_LEVEL_OFFLINE_EX:
+ qos_weight = sysctl_qos_level_weights[0];
+ break;
+ case QOS_LEVEL_OFFLINE:
+ qos_weight = sysctl_qos_level_weights[1];
+ break;
+ case QOS_LEVEL_ONLINE:
+ qos_weight = sysctl_qos_level_weights[2];
+ break;
+ case QOS_LEVEL_HIGH:
+ qos_weight = sysctl_qos_level_weights[3];
+ break;
+ case QOS_LEVEL_HIGH_EX:
+ qos_weight = sysctl_qos_level_weights[4];
+ break;
+ }
+ if (qos_weight > LONG_MAX / shares)
+ scale_shares = LONG_MAX / div;
+ else
+ scale_shares = shares * qos_weight / div;
+ scale_shares = clamp_t(long, scale_shares, scale_load(MIN_SHARES), scale_load(MAX_SHARES));
+ return scale_shares;
+}
+#endif
+
static void start_qos_hrtimer(int cpu)
{
ktime_t time;
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index c1f69a3ce166..271a5633f1da 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -1414,11 +1414,20 @@ do { \
} while (0)
#ifdef CONFIG_QOS_SCHED
+#ifdef CONFIG_QOS_SCHED_MULTILEVEL
enum task_qos_level {
+ QOS_LEVEL_OFFLINE_EX = -2,
QOS_LEVEL_OFFLINE = -1,
QOS_LEVEL_ONLINE = 0,
- QOS_LEVEL_MAX
+ QOS_LEVEL_HIGH = 1,
+ QOS_LEVEL_HIGH_EX = 2
};
+#else
+enum task_qos_level {
+ QOS_LEVEL_OFFLINE = -1,
+ QOS_LEVEL_ONLINE = 0,
+};
+#endif
void init_qos_hrtimer(int cpu);
#endif
@@ -3263,6 +3272,21 @@ static inline int qos_idle_policy(int policy)
{
return policy == QOS_LEVEL_OFFLINE;
}
+
+static inline int is_high_level(long qos_level)
+{
+ return qos_level > QOS_LEVEL_ONLINE;
+}
+
+static inline int is_normal_level(long qos_level)
+{
+ return qos_level == QOS_LEVEL_ONLINE;
+}
+
+static inline int is_offline_level(long qos_level)
+{
+ return qos_level < QOS_LEVEL_ONLINE;
+}
#endif
#ifdef CONFIG_QOS_SCHED_SMT_EXPELLER
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index e9af234bf882..1714abd73f23 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -2068,6 +2068,15 @@ static struct ctl_table kern_table[] = {
.extra1 = SYSCTL_ONE_HUNDRED,
.extra2 = &one_thousand,
},
+#endif
+#ifdef CONFIG_QOS_SCHED_MULTILEVEL
+ {
+ .procname = "qos_level_weights",
+ .data = &sysctl_qos_level_weights,
+ .maxlen = 5*sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
#endif
{
.procname = "max_rcu_stall_to_panic",
--
2.34.1
2
1
Changes in v2:
- define __generic_start/end_io_acct() as static
- remove input parameters sectors of generic_start_precise_io_acct()
Li Nan (2):
block: add precise io accouting apis
dm: switch to precise io accounting
include/linux/bio.h | 6 ++++++
block/bio.c | 49 +++++++++++++++++++++++++++++++++++++++------
drivers/md/dm.c | 8 ++++----
3 files changed, 53 insertions(+), 10 deletions(-)
--
2.39.2
2
3

06 Sep '23
euleros inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I7YT6U
--------------------------------
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
v4:
merge some duplicate code and add macro comments
v5:
format the code and update the issue number
v6:
merge duplicate code instead of isolating the entire function
Signed-off-by: Zhou Shuiqing <zhoushuiqing2(a)huawei.com>
---
fs/xattr.c | 4 +
include/linux/evm.h | 5 +-
include/linux/ima.h | 8 +
include/linux/integrity.h | 2 +
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 | 117 ++++++++++++++
security/integrity/iint.c | 4 +
security/integrity/ima/ima.h | 62 ++++++-
security/integrity/ima/ima_api.c | 39 +++++
security/integrity/ima/ima_appraise.c | 125 ++++++++++++++-
security/integrity/ima/ima_fs.c | 187 +++++++++++++++++++++-
security/integrity/ima/ima_init.c | 6 +
security/integrity/ima/ima_main.c | 33 ++++
security/integrity/ima/ima_policy.c | 80 +++++++++
security/integrity/ima/ima_template.c | 2 +
security/integrity/ima/ima_template_lib.c | 8 +
security/integrity/ima/ima_template_lib.h | 2 +
security/integrity/integrity.h | 32 ++--
security/security.c | 2 +
21 files changed, 736 insertions(+), 26 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..fbaebb01b8a6 100644
--- a/include/linux/evm.h
+++ b/include/linux/evm.h
@@ -35,7 +35,9 @@ 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);
+#ifdef CONFIG_IMA_DIGEST_LIST
extern bool evm_status_revalidate(const char *xattr_name);
+#endif
#ifdef CONFIG_FS_POSIX_ACL
extern int posix_xattr_acl(const char *xattrname);
#else
@@ -105,10 +107,11 @@ static inline int evm_inode_init_security(struct inode *inode,
return 0;
}
+#ifdef CONFIG_IMA_DIGEST_LIST
static inline bool evm_status_revalidate(const char *xattr_name)
{
return false;
}
-
+#endif /* CONFIG_IMA_DIGEST_LIST */
#endif /* CONFIG_EVM */
#endif /* LINUX_EVM_H */
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/include/linux/integrity.h b/include/linux/integrity.h
index 2ea0f2f65ab6..b3e403f214f0 100644
--- a/include/linux/integrity.h
+++ b/include/linux/integrity.h
@@ -13,7 +13,9 @@ enum integrity_status {
INTEGRITY_PASS = 0,
INTEGRITY_PASS_IMMUTABLE,
INTEGRITY_FAIL,
+#ifdef CONFIG_IMA_DIGEST_LIST
INTEGRITY_FAIL_IMMUTABLE,
+#endif
INTEGRITY_NOLABEL,
INTEGRITY_NOXATTRS,
INTEGRITY_UNKNOWN,
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..8632b05145a7 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_IMA_XATTR_DIGEST_LIST)
+#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..c67271c45e50 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -18,7 +18,9 @@
#include <linux/integrity.h>
#include <linux/evm.h>
#include <linux/magic.h>
+#ifdef CONFIG_IMA_DIGEST_LIST
#include <linux/posix_acl_xattr.h>
+#endif
#include <crypto/hash.h>
#include <crypto/hash_info.h>
@@ -27,10 +29,17 @@
int evm_initialized;
+#ifdef CONFIG_IMA_DIGEST_LIST
static const char * const integrity_status_msg[] = {
"pass", "pass_immutable", "fail", "fail_immutable", "no_label",
"no_xattrs", "unknown"
};
+#else
+static const char * const integrity_status_msg[] = {
+ "pass", "pass_immutable", "fail", "no_label", "no_xattrs", "unknown"
+};
+#endif
+
int evm_hmac_attrs;
static struct xattr_list evm_config_default_xattrnames[] = {
@@ -57,22 +66,32 @@ 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)
+#else
+static int __init evm_set_fixmode(char *str)
+#endif
{
if (strncmp(str, "fix", 3) == 0)
evm_fixmode = 1;
+#ifdef CONFIG_IMA_DIGEST_LIST
else if (strncmp(str, "x509", 4) == 0)
evm_initialized |= EVM_INIT_X509;
else if (strncmp(str, "allow_metadata_writes", 21) == 0)
evm_initialized |= EVM_ALLOW_METADATA_WRITES;
else if (strncmp(str, "complete", 8) == 0)
evm_initialized |= EVM_SETUP_COMPLETE;
+#endif
else
pr_err("invalid \"%s\" mode", str);
return 1;
}
+#ifdef CONFIG_IMA_DIGEST_LIST
__setup("evm=", evm_set_param);
+#else
+__setup("evm=", evm_set_fixmode);
+#endif
static void __init evm_init_config(void)
{
@@ -98,6 +117,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 +135,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 +158,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 +190,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 +200,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;
+#endif
+
if (iint && (iint->evm_status == INTEGRITY_PASS ||
iint->evm_status == INTEGRITY_PASS_IMMUTABLE))
return iint->evm_status;
@@ -184,7 +218,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 +230,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 +245,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;
@@ -213,23 +255,37 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
/* check value type */
switch (xattr_data->type) {
case EVM_XATTR_HMAC:
+#ifdef CONFIG_IMA_DIGEST_LIST
if (xattr_len != hash_digest_size[evm_hash_algo] + 1) {
+#else
+ if (xattr_len != sizeof(struct evm_xattr)) {
+#endif
evm_status = INTEGRITY_FAIL;
goto out;
}
+#ifdef CONFIG_IMA_DIGEST_LIST
digest.hdr.algo = evm_hash_algo;
+#else
+ digest.hdr.algo = HASH_ALGO_SHA1;
+#endif
rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
xattr_value_len, &digest);
if (rc)
break;
rc = crypto_memneq(xattr_data->data, digest.digest,
+#ifdef CONFIG_IMA_DIGEST_LIST
hash_digest_size[evm_hash_algo]);
+#else
+ SHA1_DIGEST_SIZE);
+#endif
if (rc)
rc = -EINVAL;
break;
case EVM_XATTR_PORTABLE_DIGSIG:
+#ifdef CONFIG_IMA_DIGEST_LIST
evm_immutable = 1;
fallthrough;
+#endif
case EVM_IMA_XATTR_DIGSIG:
/* accept xattr with non-empty signature field */
if (xattr_len <= sizeof(struct signature_v2_hdr)) {
@@ -262,6 +318,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 +359,13 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
evm_status = INTEGRITY_PASS;
}
break;
+#endif /* CONFIG_IMA_DIGEST_LIST */
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 +374,17 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
evm_status = evm_immutable ?
INTEGRITY_FAIL_IMMUTABLE : INTEGRITY_FAIL;
}
+#else
+ if (rc)
+ evm_status = (rc == -ENODATA) ?
+ INTEGRITY_NOXATTRS : 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;
}
@@ -397,6 +463,7 @@ static enum integrity_status evm_verify_current_integrity(struct dentry *dentry)
return evm_verify_hmac(dentry, NULL, NULL, 0, NULL);
}
+#ifdef CONFIG_IMA_DIGEST_LIST
/*
* evm_xattr_acl_change - check if passed ACL changes the inode mode
* @dentry: pointer to the affected dentry
@@ -468,6 +535,7 @@ static int evm_xattr_change(struct dentry *dentry, const char *xattr_name,
kfree(xattr_data);
return rc;
}
+#endif
/*
* evm_protect_xattr - protect the EVM extended attribute
@@ -519,6 +587,7 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
-EPERM, 0);
}
out:
+#ifdef CONFIG_IMA_DIGEST_LIST
if (evm_ignore_error_safe(evm_status))
return 0;
@@ -532,6 +601,7 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
if (evm_status == INTEGRITY_PASS_IMMUTABLE &&
!evm_xattr_change(dentry, xattr_name, xattr_value, xattr_value_len))
return 0;
+#endif
if (evm_status != INTEGRITY_PASS)
integrity_audit_msg(AUDIT_INTEGRITY_METADATA, d_backing_inode(dentry),
@@ -569,8 +639,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,
@@ -605,6 +679,7 @@ static void evm_reset_status(struct inode *inode)
iint->evm_status = INTEGRITY_UNKNOWN;
}
+#ifdef CONFIG_IMA_DIGEST_LIST
/**
* evm_status_revalidate - report whether EVM status re-validation is necessary
* @xattr_name: pointer to the affected extended attribute name
@@ -629,6 +704,7 @@ bool evm_status_revalidate(const char *xattr_name)
return true;
}
+#endif
/**
* evm_inode_post_setxattr - update 'security.evm' to reflect the changes
@@ -646,13 +722,20 @@ 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)
{
+#ifdef CONFIG_IMA_DIGEST_LIST
if (!evm_status_revalidate(xattr_name))
+#else
+ if (!evm_key_loaded() || (!evm_protected_xattr(xattr_name)
+ && !posix_xattr_acl(xattr_name)))
+#endif
return;
evm_reset_status(dentry->d_inode);
+#ifdef CONFIG_IMA_DIGEST_LIST
if (!strcmp(xattr_name, XATTR_NAME_EVM))
return;
+#endif
evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len);
}
@@ -669,17 +752,24 @@ void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
*/
void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
{
+#ifdef CONFIG_IMA_DIGEST_LIST
if (!evm_status_revalidate(xattr_name))
+#else
+ if (!evm_key_loaded() || !evm_protected_xattr(xattr_name))
+#endif
return;
evm_reset_status(dentry->d_inode);
+#ifdef CONFIG_IMA_DIGEST_LIST
if (!strcmp(xattr_name, XATTR_NAME_EVM))
return;
+#endif
evm_update_evmxattr(dentry, xattr_name, NULL, 0);
}
+#ifdef CONFIG_IMA_DIGEST_LIST
static int evm_attr_change(struct dentry *dentry, struct iattr *attr)
{
struct inode *inode = d_backing_inode(dentry);
@@ -692,6 +782,7 @@ static int evm_attr_change(struct dentry *dentry, struct iattr *attr)
return 1;
}
+#endif
/**
* evm_inode_setattr - prevent updating an invalid EVM extended attribute
@@ -714,19 +805,26 @@ 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);
+
/*
* Writing attrs is safe for portable signatures, as portable signatures
* are immutable and can never be updated.
*/
if ((evm_status == INTEGRITY_PASS) ||
+#ifdef CONFIG_IMA_DIGEST_LIST
(evm_status == INTEGRITY_NOXATTRS) ||
(evm_status == INTEGRITY_FAIL_IMMUTABLE) ||
(evm_ignore_error_safe(evm_status)))
+#else
+ (evm_status == INTEGRITY_NOXATTRS))
+#endif
return 0;
+#ifdef CONFIG_IMA_DIGEST_LIST
if (evm_status == INTEGRITY_PASS_IMMUTABLE &&
!evm_attr_change(dentry, attr))
return 0;
+#endif
integrity_audit_msg(AUDIT_INTEGRITY_METADATA, d_backing_inode(dentry),
dentry->d_name.name, "appraise_metadata",
@@ -747,10 +845,16 @@ int evm_inode_setattr(struct dentry *dentry, struct iattr *attr)
*/
void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
{
+#ifdef CONFIG_IMA_DIGEST_LIST
if (!evm_status_revalidate(NULL))
+#else
+ if (!evm_key_loaded())
+#endif
return;
+#ifdef CONFIG_IMA_DIGEST_LIST
evm_reset_status(dentry->d_inode);
+#endif
if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
evm_update_evmxattr(dentry, NULL, NULL, 0);
@@ -766,8 +870,12 @@ int evm_inode_init_security(struct inode *inode,
struct evm_xattr *xattr_data;
int rc;
+#ifdef CONFIG_IMA_DIGEST_LIST
if (!(evm_initialized & EVM_INIT_HMAC) ||
!evm_protected_xattr(lsm_xattr->name))
+#else
+ if (!evm_key_loaded() || !evm_protected_xattr(lsm_xattr->name))
+#endif
return 0;
xattr_data = kzalloc(sizeof(*xattr_data), GFP_NOFS);
@@ -780,7 +888,11 @@ 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;
+#else
+ evm_xattr->value_len = sizeof(*xattr_data);
+#endif
evm_xattr->name = XATTR_EVM_SUFFIX;
return 0;
out:
@@ -802,6 +914,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 +922,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..bd66cadc4a3a 100644
--- a/security/integrity/iint.c
+++ b/security/integrity/iint.c
@@ -209,10 +209,14 @@ void __init integrity_load_keys(void)
{
ima_load_x509();
+#ifdef CONFIG_IMA_DIGEST_LIST
if (!IS_ENABLED(CONFIG_IMA_LOAD_X509))
+#endif
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..2145eb0c76e0 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 /* CONFIG_IMA_DIGEST_LIST */
#define __ima_hook_enumify(ENUM, str) ENUM,
#define __ima_stringify(arg) (#arg)
@@ -268,8 +286,12 @@ 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,
+#ifdef CONFIG_IMA_DIGEST_LIST
struct ima_template_desc *template_desc,
struct ima_digest *digest);
+#else
+ 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);
@@ -280,7 +302,11 @@ int ima_alloc_init_template(struct ima_event_data *event_data,
struct ima_template_desc *template_desc);
int ima_store_template(struct ima_template_entry *entry, int violation,
struct inode *inode, const unsigned char *filename,
+#ifdef CONFIG_IMA_DIGEST_LIST
int pcr, struct ima_digest *digest);
+#else
+ 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,7 +334,9 @@ 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,
@@ -317,12 +345,24 @@ 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,
+#ifdef CONFIG_IMA_DIGEST_LIST
int xattr_len, const struct modsig *modsig,
struct ima_digest *found_digest);
+#else
+ 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)
@@ -336,8 +376,12 @@ static inline int ima_appraise_measurement(enum ima_hooks func,
const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
int xattr_len,
+#ifndef CONFIG_IMA_DIGEST_LIST
const struct modsig *modsig,
struct ima_digest *found_digest)
+#else
+ const struct modsig *modsig)
+#endif
{
return INTEGRITY_UNKNOWN;
}
@@ -360,6 +404,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..3c59049e58ad 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 /* CONFIG_IMA_DIGEST_LIST */
+
/*
* 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,21 +286,28 @@ 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;
break;
}
+#ifdef CONFIG_IMA_DIGEST_LIST
clear_bit(IMA_DIGSIG, &iint->atomic_flags);
} else {
set_bit(IMA_DIGSIG, &iint->atomic_flags);
+#endif
}
if (xattr_len - sizeof(xattr_value->type) - hash_start >=
iint->ima_hash->length)
@@ -352,26 +428,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 +483,7 @@ int ima_appraise_measurement(enum ima_hooks func,
rc = xattr_len;
}
}
+#endif /* CONFIG_IMA_DIGEST_LIST */
/* If reading the xattr failed and there's no modsig, error out. */
if (rc <= 0 && !try_modsig) {
@@ -417,11 +507,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 +523,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,11 +541,14 @@ int ima_appraise_measurement(enum ima_hooks func,
ima_digest_is_immutable(found_digest))
break;
}
+#endif
cause = "missing-HMAC";
goto out;
+#ifdef CONFIG_IMA_DIGEST_LIST
case INTEGRITY_FAIL_IMMUTABLE:
set_bit(IMA_DIGSIG, &iint->atomic_flags);
fallthrough;
+#endif
case INTEGRITY_FAIL: /* Invalid HMAC/signature. */
cause = "invalid-HMAC";
goto out;
@@ -458,6 +556,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 +565,15 @@ int ima_appraise_measurement(enum ima_hooks func,
filename, op, cause, rc, 0);
goto out;
}
+#endif
if (xattr_value)
rc = xattr_verify(func, iint, xattr_value, xattr_len, &status,
+#ifdef CONFIG_IMA_DIGEST_LIST
&cause, found_digest);
+#else
+ &cause);
+#endif
/*
* If we have a modsig and either no imasig or the imasig's key isn't
@@ -508,7 +612,11 @@ int ima_appraise_measurement(enum ima_hooks func,
* without data.
*/
if (inode->i_size == 0 && iint->flags & IMA_NEW_FILE &&
+#ifdef CONFIG_IMA_DIGEST_LIST
test_bit(IMA_DIGSIG, &iint->atomic_flags)) {
+#else
+ xattr_value && xattr_value->type == EVM_IMA_XATTR_DIGSIG) {
+#endif
status = INTEGRITY_PASS;
}
@@ -567,6 +675,10 @@ void ima_inode_post_setattr(struct dentry *dentry)
return;
action = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR);
+#ifndef CONFIG_IMA_DIGEST_LIST
+ if (!action)
+ __vfs_removexattr(dentry, XATTR_NAME_IMA);
+#endif
iint = integrity_iint_find(inode);
if (iint) {
set_bit(IMA_CHANGE_ATTR, &iint->atomic_flags);
@@ -620,11 +732,16 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
if (result == 1) {
if (!xattr_value_len || (xvalue->type >= IMA_XATTR_LAST))
return -EINVAL;
+#ifndef CONFIG_IMA_DIGEST_LIST
+ ima_reset_appraise_flags(d_backing_inode(dentry),
+ xvalue->type == EVM_IMA_XATTR_DIGSIG);
+#endif
result = 0;
}
return result;
}
+#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)
{
@@ -641,6 +758,7 @@ void ima_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
if (result == 1 || evm_status_revalidate(xattr_name))
ima_reset_appraise_flags(d_backing_inode(dentry), digsig);
}
+#endif
int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name)
{
@@ -648,11 +766,15 @@ int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name)
result = ima_protect_xattr(dentry, xattr_name, NULL, 0);
if (result == 1) {
+#ifndef CONFIG_IMA_DIGEST_LIST
+ ima_reset_appraise_flags(d_backing_inode(dentry), 0);
+#endif
result = 0;
}
return result;
}
+#ifdef CONFIG_IMA_DIGEST_LIST
void ima_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
{
int result;
@@ -661,3 +783,4 @@ void ima_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
if (result == 1 || evm_status_revalidate(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..dd577ae68381 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,18 +58,24 @@ __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)
{
atomic_long_t *val = NULL;
+#else
+static ssize_t ima_show_htable_value(char __user *buf, size_t count,
+ loff_t *ppos, atomic_long_t *val)
+{
+#endif
char tmpbuf[32]; /* greater than largest 'long' string value */
ssize_t len;
+#ifdef CONFIG_IMA_DIGEST_LIST
if (filp->f_path.dentry == violations)
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
@@ -72,10 +84,37 @@ static ssize_t ima_show_htable_value(struct file *filp, char __user *buf,
return simple_read_from_buffer(buf, count, ppos, tmpbuf, len);
}
+#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 /* CONFIG_IMA_DIGEST_LIST */
/* returns pointer to hlist_node */
static void *ima_measurements_start(struct seq_file *m, loff_t *pos)
@@ -275,14 +314,20 @@ 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)
+#else
+static ssize_t ima_read_policy(char *path)
+#endif
{
void *data = NULL;
char *datap;
size_t size;
+#ifdef CONFIG_IMA_DIGEST_LIST
struct file *file;
enum kernel_read_file_id file_id = READING_POLICY;
int op = DIGEST_LIST_OP_ADD;
+#endif
int rc, pathlen = strlen(path);
char *p;
@@ -291,6 +336,7 @@ static ssize_t ima_read_file(char *path, struct dentry *dentry)
datap = path;
strsep(&datap, "\n");
+#ifdef CONFIG_IMA_DIGEST_LIST
if (dentry == digest_list_data || dentry == digest_list_data_del)
file_id = READING_DIGEST_LIST;
@@ -301,26 +347,38 @@ static ssize_t ima_read_file(char *path, struct dentry *dentry)
}
rc = kernel_read_file(file, 0, &data, INT_MAX, NULL, file_id);
+#else
+ rc = kernel_read_file_from_path(path, 0, &data, INT_MAX, NULL,
+ READING_POLICY);
+#endif
if (rc < 0) {
+#ifdef CONFIG_IMA_DIGEST_LIST
pr_err("Unable to read file: %s (%d)", path, rc);
fput(file);
+#else
+ pr_err("Unable to open file: %s (%d)", path, rc);
+#endif
return rc;
}
size = rc;
rc = 0;
datap = data;
+#ifdef CONFIG_IMA_DIGEST_LIST
while (size > 0) {
if (dentry == ima_policy) {
p = strsep(&datap, "\n");
if (p == NULL)
break;
+#else
+ while (size > 0 && (p = strsep(&datap, "\n"))) {
+#endif
pr_debug("rule: %s\n", p);
rc = ima_parse_add_rule(p);
+#ifdef CONFIG_IMA_DIGEST_LIST
} 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 +386,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.
@@ -340,7 +397,7 @@ static ssize_t ima_read_file(char *path, struct dentry *dentry)
rc = ima_parse_compact_list(size, data, op);
}
-
+#endif
if (rc < 0)
break;
#ifdef CONFIG_IMA_DIGEST_LIST
@@ -353,7 +410,9 @@ static ssize_t ima_read_file(char *path, struct dentry *dentry)
}
vfree(data);
+#ifdef CONFIG_IMA_DIGEST_LIST
fput(file);
+#endif
if (rc < 0)
return rc;
else if (size)
@@ -362,19 +421,31 @@ static ssize_t ima_read_file(char *path, struct dentry *dentry)
return pathlen;
}
+#ifdef CONFIG_IMA_DIGEST_LIST
static ssize_t ima_write_data(struct file *file, const char __user *buf,
size_t datalen, loff_t *ppos)
+#else
+static ssize_t ima_write_policy(struct file *file, const char __user *buf,
+ size_t datalen, loff_t *ppos)
+#endif
{
char *data;
ssize_t result;
+#ifdef CONFIG_IMA_DIGEST_LIST
struct dentry *dentry = file_dentry(file);
int i;
+#else
+
+ if (datalen >= PAGE_SIZE)
+ datalen = PAGE_SIZE - 1;
+#endif
/* No partial writes. */
result = -EINVAL;
if (*ppos != 0)
goto out;
+#ifdef CONFIG_IMA_DIGEST_LIST
result = -EFBIG;
if (datalen > 64 * 1024 * 1024 - 1)
goto out;
@@ -389,12 +460,20 @@ static ssize_t ima_write_data(struct file *file, const char __user *buf,
goto out_free;
data[datalen] = '\0';
+#else
+ data = memdup_user_nul(buf, datalen);
+ if (IS_ERR(data)) {
+ result = PTR_ERR(data);
+ goto out;
+ }
+#endif
result = mutex_lock_interruptible(&ima_write_mutex);
if (result < 0)
goto out_free;
if (data[0] == '/') {
+#ifdef CONFIG_IMA_DIGEST_LIST
for (i = 0; data[i] != '\n' && data[i] != '\0'; i++) {
if (iscntrl(data[i])) {
pr_err_once("invalid path (control characters are not allowed)\n");
@@ -434,22 +513,45 @@ static ssize_t ima_write_data(struct file *file, const char __user *buf,
pr_err("Unknown data type\n");
result = -EINVAL;
}
+#else
+ 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);
+ }
+#endif
mutex_unlock(&ima_write_mutex);
out_free:
+#ifdef CONFIG_IMA_DIGEST_LIST
vfree(data);
+#else
+ kfree(data);
+#endif
out:
+#ifdef CONFIG_IMA_DIGEST_LIST
if (dentry == ima_policy && result < 0)
+#else
+ if (result < 0)
+#endif
valid_policy = 0;
return result;
}
enum ima_fs_flags {
+#ifdef CONFIG_IMA_DIGEST_LIST
IMA_POLICY_BUSY,
IMA_DIGEST_LIST_DATA_BUSY,
+#endif
IMA_FS_BUSY,
};
+#ifdef CONFIG_IMA_DIGEST_LIST
static enum ima_fs_flags ima_get_dentry_flag(struct dentry *dentry)
{
enum ima_fs_flags flag = IMA_FS_BUSY;
@@ -461,6 +563,7 @@ static enum ima_fs_flags ima_get_dentry_flag(struct dentry *dentry)
return flag;
}
+#endif
static unsigned long ima_fs_flags;
@@ -473,11 +576,19 @@ 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
*/
static int ima_open_data_upload(struct inode *inode, struct file *filp)
+#else
+/*
+ * ima_open_policy: sequentialize access to the policy file
+ */
+static int ima_open_policy(struct inode *inode, struct file *filp)
+#endif
{
+#ifdef CONFIG_IMA_DIGEST_LIST
struct dentry *dentry = file_dentry(filp);
const struct seq_operations *seq_ops = NULL;
enum ima_fs_flags flag = ima_get_dentry_flag(dentry);
@@ -489,8 +600,10 @@ static int ima_open_data_upload(struct inode *inode, struct file *filp)
seq_ops = &ima_policy_seqops;
#endif
}
+#endif
if (!(filp->f_flags & O_WRONLY)) {
+#ifdef CONFIG_IMA_DIGEST_LIST
if (!read_allowed)
return -EACCES;
if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
@@ -498,17 +611,35 @@ static int ima_open_data_upload(struct inode *inode, struct file *filp)
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
return seq_open(filp, seq_ops);
+#else
+#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 /*CONFIG_IMA_READ_POLICY*/
+#endif /* CONFIG_IMA_DIGEST_LIST */
}
+#ifdef CONFIG_IMA_DIGEST_LIST
if (test_and_set_bit(flag, &ima_fs_flags))
+#else
+ if (test_and_set_bit(IMA_FS_BUSY, &ima_fs_flags))
+#endif
return -EBUSY;
+#ifdef CONFIG_IMA_DIGEST_LIST
if (dentry == digest_list_data || dentry == digest_list_data_del)
if (ima_check_current_is_parser())
ima_set_parser();
+#endif
return 0;
}
+#ifdef CONFIG_IMA_DIGEST_LIST
/*
* ima_release_data_upload - start using the new measure policy rules.
*
@@ -517,14 +648,29 @@ static int ima_open_data_upload(struct inode *inode, struct file *filp)
* assuming a valid policy.
*/
static int ima_release_data_upload(struct inode *inode, struct file *file)
+#else
+/*
+ * 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)
+#endif
{
+#ifdef CONFIG_IMA_DIGEST_LIST
struct dentry *dentry = file_dentry(file);
+#endif
const char *cause = valid_policy ? "completed" : "failed";
+#ifdef CONFIG_IMA_DIGEST_LIST
enum ima_fs_flags flag = ima_get_dentry_flag(dentry);
+#endif
if ((file->f_flags & O_ACCMODE) == O_RDONLY)
return seq_release(inode, file);
+#ifdef CONFIG_IMA_DIGEST_LIST
if (dentry == digest_list_data || dentry == digest_list_data_del)
ima_unset_parser();
@@ -532,6 +678,7 @@ static int ima_release_data_upload(struct inode *inode, struct file *file)
clear_bit(flag, &ima_fs_flags);
return 0;
}
+#endif
if (valid_policy && ima_check_policy() < 0) {
cause = "failed";
@@ -545,7 +692,11 @@ static int ima_release_data_upload(struct inode *inode, struct file *file)
if (!valid_policy) {
ima_delete_rules();
valid_policy = 1;
+#ifdef CONFIG_IMA_DIGEST_LIST
clear_bit(flag, &ima_fs_flags);
+#else
+ clear_bit(IMA_FS_BUSY, &ima_fs_flags);
+#endif
return 0;
}
@@ -554,18 +705,32 @@ static int ima_release_data_upload(struct inode *inode, struct file *file)
securityfs_remove(ima_policy);
ima_policy = NULL;
#elif defined(CONFIG_IMA_WRITE_POLICY)
+#ifdef CONFIG_IMA_DIGEST_LIST
clear_bit(flag, &ima_fs_flags);
+#else
+ clear_bit(IMA_FS_BUSY, &ima_fs_flags);
+#endif
#elif defined(CONFIG_IMA_READ_POLICY)
inode->i_mode &= ~S_IWUSR;
#endif
return 0;
}
+#ifdef CONFIG_IMA_DIGEST_LIST
static const struct file_operations ima_data_upload_ops = {
.open = ima_open_data_upload,
.write = ima_write_data,
+#else
+static const struct file_operations ima_measure_policy_ops = {
+ .open = ima_open_policy,
+ .write = ima_write_policy,
+#endif
.read = seq_read,
+#ifdef CONFIG_IMA_DIGEST_LIST
.release = ima_release_data_upload,
+#else
+ .release = ima_release_policy,
+#endif
.llseek = generic_file_llseek,
};
@@ -597,19 +762,31 @@ int __init ima_fs_init(void)
runtime_measurements_count =
securityfs_create_file("runtime_measurements_count",
S_IRUSR | S_IRGRP, ima_dir, NULL,
+#ifdef CONFIG_IMA_DIGEST_LIST
&ima_htable_value_ops);
+#else
+ &ima_measurements_count_ops);
+#endif
if (IS_ERR(runtime_measurements_count))
goto out;
violations =
securityfs_create_file("violations", S_IRUSR | S_IRGRP,
+#ifdef CONFIG_IMA_DIGEST_LIST
ima_dir, NULL, &ima_htable_value_ops);
+#else
+ ima_dir, NULL, &ima_htable_violations_ops);
+#endif
if (IS_ERR(violations))
goto out;
ima_policy = securityfs_create_file("policy", POLICY_FILE_FLAGS,
ima_dir, NULL,
+#ifdef CONFIG_IMA_DIGEST_LIST
&ima_data_upload_ops);
+#else
+ &ima_measure_policy_ops);
+#endif
if (IS_ERR(ima_policy))
goto out;
@@ -634,9 +811,11 @@ int __init ima_fs_init(void)
#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..7ab87713a2e4 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -86,7 +86,11 @@ static int __init ima_add_boot_aggregate(void)
result = ima_store_template(entry, violation, NULL,
boot_aggregate_name,
+#ifdef CONFIG_IMA_DIGEST_LIST
CONFIG_IMA_MEASURE_PCR_IDX, NULL);
+#else
+ CONFIG_IMA_MEASURE_PCR_IDX);
+#endif
if (result < 0) {
ima_free_template_entry(entry);
audit_cause = "store_entry";
@@ -107,8 +111,10 @@ void __init ima_load_x509(void)
ima_policy_flag &= ~unset_flags;
integrity_load_x509(INTEGRITY_KEYRING_IMA, CONFIG_IMA_X509_PATH);
+#ifdef CONFIG_IMA_DIGEST_LIST
/* load also EVM key to avoid appraisal */
evm_load_x509();
+#endif
ima_policy_flag |= unset_flags;
}
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 999d5904cce0..0afcbd5dd196 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 /* CONFIG_IMA_DIGEST_LIST */
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,39 @@ 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)
ima_store_measurement(iint, file, pathname,
xattr_value, xattr_len, modsig, pcr,
+#ifdef CONFIG_IMA_DIGEST_LIST
template_desc,
ima_digest_allow(found_digest,
IMA_MEASURE));
+#else
+ template_desc);
+#endif
if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) {
rc = ima_check_blacklist(iint, modsig, pcr);
if (rc != -EPERM) {
inode_lock(inode);
+
rc = ima_appraise_measurement(func, iint, file,
pathname, xattr_value,
+#ifdef CONFIG_IMA_DIGEST_LIST
xattr_len, modsig,
ima_digest_allow(found_digest,
IMA_APPRAISE));
+#else
+ xattr_len, modsig);
+#endif
inode_unlock(inode);
}
if (!rc)
@@ -568,15 +587,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 +766,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 +970,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..84528e1413ad 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 /* CONFIG_IMA_DIGEST_LIST */
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/ima/ima_template.c b/security/integrity/ima/ima_template.c
index 6f126dbd2b39..4a7b5df58863 100644
--- a/security/integrity/ima/ima_template.c
+++ b/security/integrity/ima/ima_template.c
@@ -46,8 +46,10 @@ static const struct ima_template_field supported_fields[] = {
.field_show = ima_show_template_digest_ng},
{.field_id = "modsig", .field_init = ima_eventmodsig_init,
.field_show = ima_show_template_sig},
+#ifdef CONFIG_IMA_DIGEST_LIST
{.field_id = "evmsig", .field_init = ima_eventevmsig_init,
.field_show = ima_show_template_sig},
+#endif
};
/*
diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c
index 90040fac150b..7308ee587314 100644
--- a/security/integrity/ima/ima_template_lib.c
+++ b/security/integrity/ima/ima_template_lib.c
@@ -10,7 +10,9 @@
*/
#include "ima_template_lib.h"
+#ifdef CONFIG_IMA_DIGEST_LIST
#include <linux/xattr.h>
+#endif
static bool ima_template_hash_algo_allowed(u8 algo)
{
@@ -439,7 +441,11 @@ int ima_eventsig_init(struct ima_event_data *event_data,
struct evm_ima_xattr_data *xattr_value = event_data->xattr_value;
if ((!xattr_value) || (xattr_value->type != EVM_IMA_XATTR_DIGSIG))
+#ifdef CONFIG_IMA_DIGEST_LIST
return ima_eventevmsig_init(event_data, field_data);
+#else
+ return 0;
+#endif
return ima_write_template_field_data(xattr_value, event_data->xattr_len,
DATA_FMT_HEX, field_data);
@@ -486,6 +492,7 @@ int ima_eventmodsig_init(struct ima_event_data *event_data,
field_data);
}
+#ifdef CONFIG_IMA_DIGEST_LIST
/*
* ima_eventevmsig_init - include the EVM portable signature as part of the
* template data
@@ -514,3 +521,4 @@ int ima_eventevmsig_init(struct ima_event_data *event_data,
kfree(xattr_data);
return rc;
}
+#endif
diff --git a/security/integrity/ima/ima_template_lib.h b/security/integrity/ima/ima_template_lib.h
index f4b2a2056d1d..7d0d5be28908 100644
--- a/security/integrity/ima/ima_template_lib.h
+++ b/security/integrity/ima/ima_template_lib.h
@@ -46,6 +46,8 @@ int ima_eventbuf_init(struct ima_event_data *event_data,
struct ima_field_data *field_data);
int ima_eventmodsig_init(struct ima_event_data *event_data,
struct ima_field_data *field_data);
+#ifdef CONFIG_IMA_DIGEST_LIST
int ima_eventevmsig_init(struct ima_event_data *event_data,
struct ima_field_data *field_data);
+#endif /* CONFIG_IMA_DIGEST_LIST */
#endif /* __LINUX_IMA_TEMPLATE_LIB_H */
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 77e6819e8db8..cb1c178f8ac4 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,27 +176,11 @@ 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);
void __init ima_load_digest_lists(void);
-#else
-static inline struct ima_digest *ima_lookup_digest(u8 *digest,
- enum hash_algo algo,
- enum compact_types type)
-{
- return NULL;
-}
-static inline struct ima_digest *ima_digest_allow(struct ima_digest *digest,
- int action)
-{
- return NULL;
-}
-static inline void ima_load_digest_lists(void)
-{
-}
-#endif
+#endif /* CONFIG_IMA_DIGEST_LIST */
/* rbtree tree calls to lookup, insert, delete
* integrity data associated with an inode.
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

06 Sep '23
hulk inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I7YS6M
-------------------------------
Expand qos_level from {-1,0} to [-2, 2], to distinguish the tasks expected
to be with extremely high or low priority level. Using qos_level_weight
to reweight the shares when calculating group's weight. Meanwhile,
set offline task's schedule policy to SCHED_IDLE so that it can be
preempted at check_preempt_wakeup.
Signed-off-by: Zhao Wenhui <zhaowenhui8(a)huawei.com>
---
arch/arm64/configs/openeuler_defconfig | 1 +
arch/x86/configs/openeuler_defconfig | 1 +
include/linux/sched/sysctl.h | 4 ++
init/Kconfig | 9 ++++
kernel/sched/core.c | 24 ++++++----
kernel/sched/fair.c | 64 ++++++++++++++++++++++++--
kernel/sched/sched.h | 29 +++++++++++-
kernel/sysctl.c | 9 ++++
8 files changed, 128 insertions(+), 13 deletions(-)
diff --git a/arch/arm64/configs/openeuler_defconfig b/arch/arm64/configs/openeuler_defconfig
index c89f8a7ec669..7020bad802cc 100644
--- a/arch/arm64/configs/openeuler_defconfig
+++ b/arch/arm64/configs/openeuler_defconfig
@@ -178,6 +178,7 @@ CONFIG_CGROUP_PERF=y
CONFIG_CGROUP_BPF=y
# CONFIG_CGROUP_MISC is not set
CONFIG_QOS_SCHED=y
+CONFIG_QOS_SCHED_MULTILEVEL=y
# CONFIG_CGROUP_DEBUG is not set
CONFIG_SOCK_CGROUP_DATA=y
CONFIG_NAMESPACES=y
diff --git a/arch/x86/configs/openeuler_defconfig b/arch/x86/configs/openeuler_defconfig
index d72097778f4b..d1afc82733e5 100644
--- a/arch/x86/configs/openeuler_defconfig
+++ b/arch/x86/configs/openeuler_defconfig
@@ -187,6 +187,7 @@ CONFIG_FAIR_GROUP_SCHED=y
CONFIG_QOS_SCHED_SMT_EXPELLER=y
CONFIG_CFS_BANDWIDTH=y
CONFIG_QOS_SCHED=y
+CONFIG_QOS_SCHED_MULTILEVEL=y
CONFIG_RT_GROUP_SCHED=y
CONFIG_SCHED_MM_CID=y
CONFIG_QOS_SCHED_DYNAMIC_AFFINITY=y
diff --git a/include/linux/sched/sysctl.h b/include/linux/sched/sysctl.h
index 28d9be8e4614..3a02a76b08ca 100644
--- a/include/linux/sched/sysctl.h
+++ b/include/linux/sched/sysctl.h
@@ -37,4 +37,8 @@ extern unsigned int sysctl_overload_detect_period;
extern unsigned int sysctl_offline_wait_interval;
#endif
+#ifdef CONFIG_QOS_SCHED_MULTILEVEL
+extern unsigned int sysctl_qos_level_weights[];
+#endif
+
#endif /* _LINUX_SCHED_SYSCTL_H */
diff --git a/init/Kconfig b/init/Kconfig
index c189d4d5d91b..3b4576d04117 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1005,6 +1005,15 @@ config QOS_SCHED_SMT_EXPELLER
This feature enable online tasks to expel offline tasks
on the smt sibling cpus, and exclusively occupy CPU resources.
+config QOS_SCHED_MULTILEVEL
+ bool "Multiple qos level task scheduling"
+ depends on QOS_SCHED
+ default n
+ help
+ This feature enable multiple qos level on task scheduling.
+ Expand the qos_level to [-2,2] to distinguish the tasks expected
+ to be with extremely high or low priority level.
+
config FAIR_GROUP_SCHED
bool "Group scheduling for SCHED_OTHER"
depends on CGROUP_SCHED
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 08ce8aada0b0..8a69840b82ed 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -7686,7 +7686,7 @@ static int __sched_setscheduler(struct task_struct *p,
* other than SCHED_IDLE, the online task preemption and cpu resource
* isolation will be invalid, so return -EINVAL in this case.
*/
- if (unlikely(task_group(p)->qos_level == -1 && !idle_policy(policy))) {
+ if (unlikely(is_offline_level(task_group(p)->qos_level) && !idle_policy(policy))) {
retval = -EINVAL;
goto unlock;
}
@@ -10342,7 +10342,7 @@ static void sched_change_qos_group(struct task_struct *tsk, struct task_group *t
*/
if (!(tsk->flags & PF_EXITING) &&
!task_group_is_autogroup(tg) &&
- (tg->qos_level == -1)) {
+ (is_offline_level(tg->qos_level))) {
attr.sched_priority = 0;
attr.sched_policy = SCHED_IDLE;
attr.sched_nice = PRIO_TO_NICE(tsk->static_prio);
@@ -10371,7 +10371,7 @@ void sched_move_offline_task(struct task_struct *p)
{
struct offline_args *args;
- if (unlikely(task_group(p)->qos_level != -1))
+ if (unlikely(!is_offline_level(task_group(p)->qos_level)))
return;
args = kmalloc(sizeof(struct offline_args), GFP_ATOMIC);
@@ -11242,7 +11242,7 @@ static int tg_change_scheduler(struct task_group *tg, void *data)
struct cgroup_subsys_state *css = &tg->css;
tg->qos_level = qos_level;
- if (qos_level == -1)
+ if (is_offline_level(qos_level))
policy = SCHED_IDLE;
else
policy = SCHED_NORMAL;
@@ -11264,19 +11264,27 @@ static int cpu_qos_write(struct cgroup_subsys_state *css,
if (!tg->se[0])
return -EINVAL;
- if (qos_level != -1 && qos_level != 0)
+#ifdef CONFIG_QOS_SCHED_MULTILEVEL
+ if (qos_level > QOS_LEVEL_HIGH_EX || qos_level < QOS_LEVEL_OFFLINE_EX)
+#else
+ if (qos_level != QOS_LEVEL_OFFLINE && qos_level != QOS_LEVEL_ONLINE)
+#endif
return -EINVAL;
if (tg->qos_level == qos_level)
goto done;
- if (tg->qos_level == -1 && qos_level == 0)
+#ifdef CONFIG_QOS_SCHED_MULTILEVEL
+ if (!is_normal_level(tg->qos_level))
+#else
+ if (tg->qos_level == QOS_LEVEL_OFFLINE && qos_level == QOS_LEVEL_ONLINE)
+#endif
return -EINVAL;
cpus_read_lock();
- if (qos_level == -1)
+ if (is_offline_level(qos_level))
cfs_bandwidth_usage_inc();
- else
+ else if (is_offline_level(tg->qos_level) && !is_offline_level(qos_level))
cfs_bandwidth_usage_dec();
cpus_read_unlock();
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 51e550ba66b8..04795fd25703 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -194,6 +194,23 @@ static bool qos_smt_expelled(int this_cpu);
static DEFINE_PER_CPU(int, qos_smt_status);
#endif
+#ifdef CONFIG_QOS_SCHED_MULTILEVEL
+#define QOS_LEVEL_WEIGHT_OFFLINE_EX 1
+#define QOS_LEVEL_WEIGHT_OFFLINE 10
+#define QOS_LEVEL_WEIGHT_ONLINE 100
+#define QOS_LEVEL_WEIGHT_HIGH 1000
+#define QOS_LEVEL_WEIGHT_HIGH_EX 10000
+
+unsigned int sysctl_qos_level_weights[5] = {
+ QOS_LEVEL_WEIGHT_OFFLINE_EX,
+ QOS_LEVEL_WEIGHT_OFFLINE,
+ QOS_LEVEL_WEIGHT_ONLINE,
+ QOS_LEVEL_WEIGHT_HIGH,
+ QOS_LEVEL_WEIGHT_HIGH_EX,
+};
+static long qos_reweight(long shares, struct task_group *tg);
+#endif
+
#ifdef CONFIG_CFS_BANDWIDTH
/*
* Amount of runtime to allocate from global (tg) to local (per-cfs_rq) pool
@@ -3523,6 +3540,9 @@ static long calc_group_shares(struct cfs_rq *cfs_rq)
struct task_group *tg = cfs_rq->tg;
tg_shares = READ_ONCE(tg->shares);
+#ifdef CONFIG_QOS_SCHED_MULTILEVEL
+ tg_shares = qos_reweight(tg_shares, tg);
+#endif
load = max(scale_load_down(cfs_rq->load.weight), cfs_rq->avg.load_avg);
@@ -3569,6 +3589,9 @@ static void update_cfs_group(struct sched_entity *se)
#ifndef CONFIG_SMP
shares = READ_ONCE(gcfs_rq->tg->shares);
+#ifdef CONFIG_QOS_SCHED_MULTILEVEL
+ shares = qos_reweight(shares, gcfs_rq->tg);
+#endif
if (likely(se->load.weight == shares))
return;
@@ -8196,7 +8219,7 @@ static inline void cancel_qos_timer(int cpu)
static inline bool is_offline_task(struct task_struct *p)
{
- return task_group(p)->qos_level == -1;
+ return task_group(p)->qos_level < QOS_LEVEL_ONLINE;
}
static void start_qos_hrtimer(int cpu);
@@ -8389,7 +8412,7 @@ static bool check_qos_cfs_rq(struct cfs_rq *cfs_rq)
if (unlikely(__this_cpu_read(qos_cpu_overload)))
return false;
- if (unlikely(cfs_rq && cfs_rq->tg->qos_level < 0 &&
+ if (unlikely(cfs_rq && is_offline_level(cfs_rq->tg->qos_level) &&
!sched_idle_cpu(smp_processor_id()) &&
cfs_rq->h_nr_running == cfs_rq->idle_h_nr_running)) {
throttle_qos_cfs_rq(cfs_rq);
@@ -8405,7 +8428,7 @@ static inline void unthrottle_qos_sched_group(struct cfs_rq *cfs_rq)
struct rq_flags rf;
rq_lock_irqsave(rq, &rf);
- if (cfs_rq->tg->qos_level == -1 && cfs_rq_throttled(cfs_rq))
+ if (is_offline_level(cfs_rq->tg->qos_level) && cfs_rq_throttled(cfs_rq))
unthrottle_qos_cfs_rq(cfs_rq);
rq_unlock_irqrestore(rq, &rf);
}
@@ -8418,7 +8441,7 @@ void sched_qos_offline_wait(void)
rcu_read_lock();
qos_level = task_group(current)->qos_level;
rcu_read_unlock();
- if (qos_level != -1 || fatal_signal_pending(current))
+ if (!is_offline_level(qos_level) || fatal_signal_pending(current))
break;
schedule_timeout_killable(msecs_to_jiffies(sysctl_offline_wait_interval));
@@ -8448,6 +8471,39 @@ static enum hrtimer_restart qos_overload_timer_handler(struct hrtimer *timer)
return HRTIMER_NORESTART;
}
+#ifdef CONFIG_QOS_SCHED_MULTILEVEL
+static long qos_reweight(long shares, struct task_group *tg)
+{
+ long qos_weight = 100;
+ long div = 100;
+ long scale_shares;
+
+ switch (tg->qos_level) {
+ case QOS_LEVEL_OFFLINE_EX:
+ qos_weight = sysctl_qos_level_weights[0];
+ break;
+ case QOS_LEVEL_OFFLINE:
+ qos_weight = sysctl_qos_level_weights[1];
+ break;
+ case QOS_LEVEL_ONLINE:
+ qos_weight = sysctl_qos_level_weights[2];
+ break;
+ case QOS_LEVEL_HIGH:
+ qos_weight = sysctl_qos_level_weights[3];
+ break;
+ case QOS_LEVEL_HIGH_EX:
+ qos_weight = sysctl_qos_level_weights[4];
+ break;
+ }
+ if (qos_weight > LONG_MAX / shares)
+ scale_shares = LONG_MAX / div;
+ else
+ scale_shares = shares * qos_weight / div;
+ scale_shares = clamp_t(long, scale_shares, scale_load(MIN_SHARES), scale_load(MAX_SHARES));
+ return scale_shares;
+}
+#endif
+
static void start_qos_hrtimer(int cpu)
{
ktime_t time;
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index c1f69a3ce166..91c24b380169 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -1215,6 +1215,24 @@ static inline bool is_migration_disabled(struct task_struct *p)
#endif
}
+#ifdef CONFIG_QOS_SCHED
+
+static inline int is_high_level(long qos_level)
+{
+ return qos_level > QOS_LEVEL_ONLINE;
+}
+
+static inline int is_normal_level(long qos_level)
+{
+ return qos_level == QOS_LEVEL_ONLINE;
+}
+
+static inline int is_offline_level(long qos_level)
+{
+ return qos_level < QOS_LEVEL_ONLINE;
+}
+#endif
+
DECLARE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues);
#define cpu_rq(cpu) (&per_cpu(runqueues, (cpu)))
@@ -1414,11 +1432,20 @@ do { \
} while (0)
#ifdef CONFIG_QOS_SCHED
+#ifdef CONFIG_QOS_SCHED_MULTILEVEL
enum task_qos_level {
+ QOS_LEVEL_OFFLINE_EX = -2,
QOS_LEVEL_OFFLINE = -1,
QOS_LEVEL_ONLINE = 0,
- QOS_LEVEL_MAX
+ QOS_LEVEL_HIGH = 1,
+ QOS_LEVEL_HIGH_EX = 2
};
+#else
+enum task_qos_level {
+ QOS_LEVEL_OFFLINE = -1,
+ QOS_LEVEL_ONLINE = 0,
+};
+#endif
void init_qos_hrtimer(int cpu);
#endif
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index e9af234bf882..1714abd73f23 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -2068,6 +2068,15 @@ static struct ctl_table kern_table[] = {
.extra1 = SYSCTL_ONE_HUNDRED,
.extra2 = &one_thousand,
},
+#endif
+#ifdef CONFIG_QOS_SCHED_MULTILEVEL
+ {
+ .procname = "qos_level_weights",
+ .data = &sysctl_qos_level_weights,
+ .maxlen = 5*sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
#endif
{
.procname = "max_rcu_stall_to_panic",
--
2.34.1
2
1

[PATCH OLK-5.10 0/2] iommu/arm-smmu-v3: Fix ECMDQ initialization error and add arm_smmu_v3.disable_ecmdq
by Zhen Lei 05 Sep '23
by Zhen Lei 05 Sep '23
05 Sep '23
1. Make ECMDQs to be evenly allocated based on the number of cores
2. Allow disabling ECMDQs at boot time
Zhen Lei (2):
iommu/arm-smmu-v3: Make ECMDQs to be evenly allocated based on the
number of cores
iommu/arm-smmu-v3: Allow disabling ECMDQs at boot time
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 105 ++++----------------
1 file changed, 17 insertions(+), 88 deletions(-)
--
2.34.1
2
3

05 Sep '23
euleros inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I7YT6U
--------------------------------
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
v4:
merge some duplicate code and add macro comments
v5:
format the code and update the issue number
Signed-off-by: Zhou Shuiqing <zhoushuiqing2(a)huawei.com>
---
fs/xattr.c | 4 +
include/linux/evm.h | 5 +-
include/linux/ima.h | 8 +
include/linux/integrity.h | 2 +
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 | 117 +++++++++++++
security/integrity/iint.c | 4 +
security/integrity/ima/ima.h | 62 ++++++-
security/integrity/ima/ima_api.c | 39 +++++
security/integrity/ima/ima_appraise.c | 125 +++++++++++++-
security/integrity/ima/ima_fs.c | 192 +++++++++++++++++++++-
security/integrity/ima/ima_init.c | 6 +
security/integrity/ima/ima_main.c | 33 ++++
security/integrity/ima/ima_policy.c | 80 +++++++++
security/integrity/ima/ima_template.c | 2 +
security/integrity/ima/ima_template_lib.c | 8 +
security/integrity/ima/ima_template_lib.h | 2 +
security/integrity/integrity.h | 32 ++--
security/security.c | 2 +
21 files changed, 740 insertions(+), 27 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..fbaebb01b8a6 100644
--- a/include/linux/evm.h
+++ b/include/linux/evm.h
@@ -35,7 +35,9 @@ 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);
+#ifdef CONFIG_IMA_DIGEST_LIST
extern bool evm_status_revalidate(const char *xattr_name);
+#endif
#ifdef CONFIG_FS_POSIX_ACL
extern int posix_xattr_acl(const char *xattrname);
#else
@@ -105,10 +107,11 @@ static inline int evm_inode_init_security(struct inode *inode,
return 0;
}
+#ifdef CONFIG_IMA_DIGEST_LIST
static inline bool evm_status_revalidate(const char *xattr_name)
{
return false;
}
-
+#endif /* CONFIG_IMA_DIGEST_LIST */
#endif /* CONFIG_EVM */
#endif /* LINUX_EVM_H */
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/include/linux/integrity.h b/include/linux/integrity.h
index 2ea0f2f65ab6..b3e403f214f0 100644
--- a/include/linux/integrity.h
+++ b/include/linux/integrity.h
@@ -13,7 +13,9 @@ enum integrity_status {
INTEGRITY_PASS = 0,
INTEGRITY_PASS_IMMUTABLE,
INTEGRITY_FAIL,
+#ifdef CONFIG_IMA_DIGEST_LIST
INTEGRITY_FAIL_IMMUTABLE,
+#endif
INTEGRITY_NOLABEL,
INTEGRITY_NOXATTRS,
INTEGRITY_UNKNOWN,
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..8632b05145a7 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_IMA_XATTR_DIGEST_LIST)
+#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..c67271c45e50 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -18,7 +18,9 @@
#include <linux/integrity.h>
#include <linux/evm.h>
#include <linux/magic.h>
+#ifdef CONFIG_IMA_DIGEST_LIST
#include <linux/posix_acl_xattr.h>
+#endif
#include <crypto/hash.h>
#include <crypto/hash_info.h>
@@ -27,10 +29,17 @@
int evm_initialized;
+#ifdef CONFIG_IMA_DIGEST_LIST
static const char * const integrity_status_msg[] = {
"pass", "pass_immutable", "fail", "fail_immutable", "no_label",
"no_xattrs", "unknown"
};
+#else
+static const char * const integrity_status_msg[] = {
+ "pass", "pass_immutable", "fail", "no_label", "no_xattrs", "unknown"
+};
+#endif
+
int evm_hmac_attrs;
static struct xattr_list evm_config_default_xattrnames[] = {
@@ -57,22 +66,32 @@ 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)
+#else
+static int __init evm_set_fixmode(char *str)
+#endif
{
if (strncmp(str, "fix", 3) == 0)
evm_fixmode = 1;
+#ifdef CONFIG_IMA_DIGEST_LIST
else if (strncmp(str, "x509", 4) == 0)
evm_initialized |= EVM_INIT_X509;
else if (strncmp(str, "allow_metadata_writes", 21) == 0)
evm_initialized |= EVM_ALLOW_METADATA_WRITES;
else if (strncmp(str, "complete", 8) == 0)
evm_initialized |= EVM_SETUP_COMPLETE;
+#endif
else
pr_err("invalid \"%s\" mode", str);
return 1;
}
+#ifdef CONFIG_IMA_DIGEST_LIST
__setup("evm=", evm_set_param);
+#else
+__setup("evm=", evm_set_fixmode);
+#endif
static void __init evm_init_config(void)
{
@@ -98,6 +117,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 +135,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 +158,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 +190,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 +200,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;
+#endif
+
if (iint && (iint->evm_status == INTEGRITY_PASS ||
iint->evm_status == INTEGRITY_PASS_IMMUTABLE))
return iint->evm_status;
@@ -184,7 +218,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 +230,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 +245,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;
@@ -213,23 +255,37 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
/* check value type */
switch (xattr_data->type) {
case EVM_XATTR_HMAC:
+#ifdef CONFIG_IMA_DIGEST_LIST
if (xattr_len != hash_digest_size[evm_hash_algo] + 1) {
+#else
+ if (xattr_len != sizeof(struct evm_xattr)) {
+#endif
evm_status = INTEGRITY_FAIL;
goto out;
}
+#ifdef CONFIG_IMA_DIGEST_LIST
digest.hdr.algo = evm_hash_algo;
+#else
+ digest.hdr.algo = HASH_ALGO_SHA1;
+#endif
rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
xattr_value_len, &digest);
if (rc)
break;
rc = crypto_memneq(xattr_data->data, digest.digest,
+#ifdef CONFIG_IMA_DIGEST_LIST
hash_digest_size[evm_hash_algo]);
+#else
+ SHA1_DIGEST_SIZE);
+#endif
if (rc)
rc = -EINVAL;
break;
case EVM_XATTR_PORTABLE_DIGSIG:
+#ifdef CONFIG_IMA_DIGEST_LIST
evm_immutable = 1;
fallthrough;
+#endif
case EVM_IMA_XATTR_DIGSIG:
/* accept xattr with non-empty signature field */
if (xattr_len <= sizeof(struct signature_v2_hdr)) {
@@ -262,6 +318,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 +359,13 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
evm_status = INTEGRITY_PASS;
}
break;
+#endif /* CONFIG_IMA_DIGEST_LIST */
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 +374,17 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
evm_status = evm_immutable ?
INTEGRITY_FAIL_IMMUTABLE : INTEGRITY_FAIL;
}
+#else
+ if (rc)
+ evm_status = (rc == -ENODATA) ?
+ INTEGRITY_NOXATTRS : 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;
}
@@ -397,6 +463,7 @@ static enum integrity_status evm_verify_current_integrity(struct dentry *dentry)
return evm_verify_hmac(dentry, NULL, NULL, 0, NULL);
}
+#ifdef CONFIG_IMA_DIGEST_LIST
/*
* evm_xattr_acl_change - check if passed ACL changes the inode mode
* @dentry: pointer to the affected dentry
@@ -468,6 +535,7 @@ static int evm_xattr_change(struct dentry *dentry, const char *xattr_name,
kfree(xattr_data);
return rc;
}
+#endif
/*
* evm_protect_xattr - protect the EVM extended attribute
@@ -519,6 +587,7 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
-EPERM, 0);
}
out:
+#ifdef CONFIG_IMA_DIGEST_LIST
if (evm_ignore_error_safe(evm_status))
return 0;
@@ -532,6 +601,7 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
if (evm_status == INTEGRITY_PASS_IMMUTABLE &&
!evm_xattr_change(dentry, xattr_name, xattr_value, xattr_value_len))
return 0;
+#endif
if (evm_status != INTEGRITY_PASS)
integrity_audit_msg(AUDIT_INTEGRITY_METADATA, d_backing_inode(dentry),
@@ -569,8 +639,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,
@@ -605,6 +679,7 @@ static void evm_reset_status(struct inode *inode)
iint->evm_status = INTEGRITY_UNKNOWN;
}
+#ifdef CONFIG_IMA_DIGEST_LIST
/**
* evm_status_revalidate - report whether EVM status re-validation is necessary
* @xattr_name: pointer to the affected extended attribute name
@@ -629,6 +704,7 @@ bool evm_status_revalidate(const char *xattr_name)
return true;
}
+#endif
/**
* evm_inode_post_setxattr - update 'security.evm' to reflect the changes
@@ -646,13 +722,20 @@ 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)
{
+#ifdef CONFIG_IMA_DIGEST_LIST
if (!evm_status_revalidate(xattr_name))
+#else
+ if (!evm_key_loaded() || (!evm_protected_xattr(xattr_name)
+ && !posix_xattr_acl(xattr_name)))
+#endif
return;
evm_reset_status(dentry->d_inode);
+#ifdef CONFIG_IMA_DIGEST_LIST
if (!strcmp(xattr_name, XATTR_NAME_EVM))
return;
+#endif
evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len);
}
@@ -669,17 +752,24 @@ void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
*/
void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
{
+#ifdef CONFIG_IMA_DIGEST_LIST
if (!evm_status_revalidate(xattr_name))
+#else
+ if (!evm_key_loaded() || !evm_protected_xattr(xattr_name))
+#endif
return;
evm_reset_status(dentry->d_inode);
+#ifdef CONFIG_IMA_DIGEST_LIST
if (!strcmp(xattr_name, XATTR_NAME_EVM))
return;
+#endif
evm_update_evmxattr(dentry, xattr_name, NULL, 0);
}
+#ifdef CONFIG_IMA_DIGEST_LIST
static int evm_attr_change(struct dentry *dentry, struct iattr *attr)
{
struct inode *inode = d_backing_inode(dentry);
@@ -692,6 +782,7 @@ static int evm_attr_change(struct dentry *dentry, struct iattr *attr)
return 1;
}
+#endif
/**
* evm_inode_setattr - prevent updating an invalid EVM extended attribute
@@ -714,19 +805,26 @@ 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);
+
/*
* Writing attrs is safe for portable signatures, as portable signatures
* are immutable and can never be updated.
*/
if ((evm_status == INTEGRITY_PASS) ||
+#ifdef CONFIG_IMA_DIGEST_LIST
(evm_status == INTEGRITY_NOXATTRS) ||
(evm_status == INTEGRITY_FAIL_IMMUTABLE) ||
(evm_ignore_error_safe(evm_status)))
+#else
+ (evm_status == INTEGRITY_NOXATTRS))
+#endif
return 0;
+#ifdef CONFIG_IMA_DIGEST_LIST
if (evm_status == INTEGRITY_PASS_IMMUTABLE &&
!evm_attr_change(dentry, attr))
return 0;
+#endif
integrity_audit_msg(AUDIT_INTEGRITY_METADATA, d_backing_inode(dentry),
dentry->d_name.name, "appraise_metadata",
@@ -747,10 +845,16 @@ int evm_inode_setattr(struct dentry *dentry, struct iattr *attr)
*/
void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
{
+#ifdef CONFIG_IMA_DIGEST_LIST
if (!evm_status_revalidate(NULL))
+#else
+ if (!evm_key_loaded())
+#endif
return;
+#ifdef CONFIG_IMA_DIGEST_LIST
evm_reset_status(dentry->d_inode);
+#endif
if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
evm_update_evmxattr(dentry, NULL, NULL, 0);
@@ -766,8 +870,12 @@ int evm_inode_init_security(struct inode *inode,
struct evm_xattr *xattr_data;
int rc;
+#ifdef CONFIG_IMA_DIGEST_LIST
if (!(evm_initialized & EVM_INIT_HMAC) ||
!evm_protected_xattr(lsm_xattr->name))
+#else
+ if (!evm_key_loaded() || !evm_protected_xattr(lsm_xattr->name))
+#endif
return 0;
xattr_data = kzalloc(sizeof(*xattr_data), GFP_NOFS);
@@ -780,7 +888,11 @@ 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;
+#else
+ evm_xattr->value_len = sizeof(*xattr_data);
+#endif
evm_xattr->name = XATTR_EVM_SUFFIX;
return 0;
out:
@@ -802,6 +914,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 +922,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..bd66cadc4a3a 100644
--- a/security/integrity/iint.c
+++ b/security/integrity/iint.c
@@ -209,10 +209,14 @@ void __init integrity_load_keys(void)
{
ima_load_x509();
+#ifdef CONFIG_IMA_DIGEST_LIST
if (!IS_ENABLED(CONFIG_IMA_LOAD_X509))
+#endif
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..2145eb0c76e0 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 /* CONFIG_IMA_DIGEST_LIST */
#define __ima_hook_enumify(ENUM, str) ENUM,
#define __ima_stringify(arg) (#arg)
@@ -268,8 +286,12 @@ 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,
+#ifdef CONFIG_IMA_DIGEST_LIST
struct ima_template_desc *template_desc,
struct ima_digest *digest);
+#else
+ 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);
@@ -280,7 +302,11 @@ int ima_alloc_init_template(struct ima_event_data *event_data,
struct ima_template_desc *template_desc);
int ima_store_template(struct ima_template_entry *entry, int violation,
struct inode *inode, const unsigned char *filename,
+#ifdef CONFIG_IMA_DIGEST_LIST
int pcr, struct ima_digest *digest);
+#else
+ 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,7 +334,9 @@ 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,
@@ -317,12 +345,24 @@ 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,
+#ifdef CONFIG_IMA_DIGEST_LIST
int xattr_len, const struct modsig *modsig,
struct ima_digest *found_digest);
+#else
+ 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)
@@ -336,8 +376,12 @@ static inline int ima_appraise_measurement(enum ima_hooks func,
const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
int xattr_len,
+#ifndef CONFIG_IMA_DIGEST_LIST
const struct modsig *modsig,
struct ima_digest *found_digest)
+#else
+ const struct modsig *modsig)
+#endif
{
return INTEGRITY_UNKNOWN;
}
@@ -360,6 +404,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..3c59049e58ad 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 /* CONFIG_IMA_DIGEST_LIST */
+
/*
* 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,21 +286,28 @@ 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;
break;
}
+#ifdef CONFIG_IMA_DIGEST_LIST
clear_bit(IMA_DIGSIG, &iint->atomic_flags);
} else {
set_bit(IMA_DIGSIG, &iint->atomic_flags);
+#endif
}
if (xattr_len - sizeof(xattr_value->type) - hash_start >=
iint->ima_hash->length)
@@ -352,26 +428,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 +483,7 @@ int ima_appraise_measurement(enum ima_hooks func,
rc = xattr_len;
}
}
+#endif /* CONFIG_IMA_DIGEST_LIST */
/* If reading the xattr failed and there's no modsig, error out. */
if (rc <= 0 && !try_modsig) {
@@ -417,11 +507,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 +523,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,11 +541,14 @@ int ima_appraise_measurement(enum ima_hooks func,
ima_digest_is_immutable(found_digest))
break;
}
+#endif
cause = "missing-HMAC";
goto out;
+#ifdef CONFIG_IMA_DIGEST_LIST
case INTEGRITY_FAIL_IMMUTABLE:
set_bit(IMA_DIGSIG, &iint->atomic_flags);
fallthrough;
+#endif
case INTEGRITY_FAIL: /* Invalid HMAC/signature. */
cause = "invalid-HMAC";
goto out;
@@ -458,6 +556,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 +565,15 @@ int ima_appraise_measurement(enum ima_hooks func,
filename, op, cause, rc, 0);
goto out;
}
+#endif
if (xattr_value)
rc = xattr_verify(func, iint, xattr_value, xattr_len, &status,
+#ifdef CONFIG_IMA_DIGEST_LIST
&cause, found_digest);
+#else
+ &cause);
+#endif
/*
* If we have a modsig and either no imasig or the imasig's key isn't
@@ -508,7 +612,11 @@ int ima_appraise_measurement(enum ima_hooks func,
* without data.
*/
if (inode->i_size == 0 && iint->flags & IMA_NEW_FILE &&
+#ifdef CONFIG_IMA_DIGEST_LIST
test_bit(IMA_DIGSIG, &iint->atomic_flags)) {
+#else
+ xattr_value && xattr_value->type == EVM_IMA_XATTR_DIGSIG) {
+#endif
status = INTEGRITY_PASS;
}
@@ -567,6 +675,10 @@ void ima_inode_post_setattr(struct dentry *dentry)
return;
action = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR);
+#ifndef CONFIG_IMA_DIGEST_LIST
+ if (!action)
+ __vfs_removexattr(dentry, XATTR_NAME_IMA);
+#endif
iint = integrity_iint_find(inode);
if (iint) {
set_bit(IMA_CHANGE_ATTR, &iint->atomic_flags);
@@ -620,11 +732,16 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
if (result == 1) {
if (!xattr_value_len || (xvalue->type >= IMA_XATTR_LAST))
return -EINVAL;
+#ifndef CONFIG_IMA_DIGEST_LIST
+ ima_reset_appraise_flags(d_backing_inode(dentry),
+ xvalue->type == EVM_IMA_XATTR_DIGSIG);
+#endif
result = 0;
}
return result;
}
+#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)
{
@@ -641,6 +758,7 @@ void ima_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
if (result == 1 || evm_status_revalidate(xattr_name))
ima_reset_appraise_flags(d_backing_inode(dentry), digsig);
}
+#endif
int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name)
{
@@ -648,11 +766,15 @@ int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name)
result = ima_protect_xattr(dentry, xattr_name, NULL, 0);
if (result == 1) {
+#ifndef CONFIG_IMA_DIGEST_LIST
+ ima_reset_appraise_flags(d_backing_inode(dentry), 0);
+#endif
result = 0;
}
return result;
}
+#ifdef CONFIG_IMA_DIGEST_LIST
void ima_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
{
int result;
@@ -661,3 +783,4 @@ void ima_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
if (result == 1 || evm_status_revalidate(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..45f6024c47b7 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 /* CONFIG_IMA_DIGEST_LIST */
+
+#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 /* CONFIG_IMA_DIGEST_LIST */
/* returns pointer to hlist_node */
static void *ima_measurements_start(struct seq_file *m, loff_t *pos)
@@ -275,14 +318,20 @@ 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)
+#else
+static ssize_t ima_read_policy(char *path)
+#endif
{
void *data = NULL;
char *datap;
size_t size;
+#ifdef CONFIG_IMA_DIGEST_LIST
struct file *file;
enum kernel_read_file_id file_id = READING_POLICY;
int op = DIGEST_LIST_OP_ADD;
+#endif
int rc, pathlen = strlen(path);
char *p;
@@ -291,6 +340,7 @@ static ssize_t ima_read_file(char *path, struct dentry *dentry)
datap = path;
strsep(&datap, "\n");
+#ifdef CONFIG_IMA_DIGEST_LIST
if (dentry == digest_list_data || dentry == digest_list_data_del)
file_id = READING_DIGEST_LIST;
@@ -301,26 +351,38 @@ static ssize_t ima_read_file(char *path, struct dentry *dentry)
}
rc = kernel_read_file(file, 0, &data, INT_MAX, NULL, file_id);
+#else
+ rc = kernel_read_file_from_path(path, 0, &data, INT_MAX, NULL,
+ READING_POLICY);
+#endif
if (rc < 0) {
+#ifdef CONFIG_IMA_DIGEST_LIST
pr_err("Unable to read file: %s (%d)", path, rc);
fput(file);
+#else
+ pr_err("Unable to open file: %s (%d)", path, rc);
+#endif
return rc;
}
size = rc;
rc = 0;
datap = data;
+#ifdef CONFIG_IMA_DIGEST_LIST
while (size > 0) {
if (dentry == ima_policy) {
p = strsep(&datap, "\n");
if (p == NULL)
break;
+#else
+ while (size > 0 && (p = strsep(&datap, "\n"))) {
+#endif
pr_debug("rule: %s\n", p);
rc = ima_parse_add_rule(p);
+#ifdef CONFIG_IMA_DIGEST_LIST
} 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 +390,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.
@@ -340,7 +401,7 @@ static ssize_t ima_read_file(char *path, struct dentry *dentry)
rc = ima_parse_compact_list(size, data, op);
}
-
+#endif
if (rc < 0)
break;
#ifdef CONFIG_IMA_DIGEST_LIST
@@ -353,7 +414,9 @@ static ssize_t ima_read_file(char *path, struct dentry *dentry)
}
vfree(data);
+#ifdef CONFIG_IMA_DIGEST_LIST
fput(file);
+#endif
if (rc < 0)
return rc;
else if (size)
@@ -362,19 +425,31 @@ static ssize_t ima_read_file(char *path, struct dentry *dentry)
return pathlen;
}
+#ifdef CONFIG_IMA_DIGEST_LIST
static ssize_t ima_write_data(struct file *file, const char __user *buf,
size_t datalen, loff_t *ppos)
+#else
+static ssize_t ima_write_policy(struct file *file, const char __user *buf,
+ size_t datalen, loff_t *ppos)
+#endif
{
char *data;
ssize_t result;
+#ifdef CONFIG_IMA_DIGEST_LIST
struct dentry *dentry = file_dentry(file);
int i;
+#else
+
+ if (datalen >= PAGE_SIZE)
+ datalen = PAGE_SIZE - 1;
+#endif
/* No partial writes. */
result = -EINVAL;
if (*ppos != 0)
goto out;
+#ifdef CONFIG_IMA_DIGEST_LIST
result = -EFBIG;
if (datalen > 64 * 1024 * 1024 - 1)
goto out;
@@ -389,12 +464,20 @@ static ssize_t ima_write_data(struct file *file, const char __user *buf,
goto out_free;
data[datalen] = '\0';
+#else
+ data = memdup_user_nul(buf, datalen);
+ if (IS_ERR(data)) {
+ result = PTR_ERR(data);
+ goto out;
+ }
+#endif
result = mutex_lock_interruptible(&ima_write_mutex);
if (result < 0)
goto out_free;
if (data[0] == '/') {
+#ifdef CONFIG_IMA_DIGEST_LIST
for (i = 0; data[i] != '\n' && data[i] != '\0'; i++) {
if (iscntrl(data[i])) {
pr_err_once("invalid path (control characters are not allowed)\n");
@@ -434,22 +517,44 @@ static ssize_t ima_write_data(struct file *file, const char __user *buf,
pr_err("Unknown data type\n");
result = -EINVAL;
}
+#else
+ 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);
+#endif
mutex_unlock(&ima_write_mutex);
out_free:
+#ifdef CONFIG_IMA_DIGEST_LIST
vfree(data);
+#else
+ kfree(data);
+#endif
out:
+#ifdef CONFIG_IMA_DIGEST_LIST
if (dentry == ima_policy && result < 0)
+#else
+ if (result < 0)
+#endif
valid_policy = 0;
return result;
}
enum ima_fs_flags {
+#ifdef CONFIG_IMA_DIGEST_LIST
IMA_POLICY_BUSY,
IMA_DIGEST_LIST_DATA_BUSY,
+#endif
IMA_FS_BUSY,
};
+#ifdef CONFIG_IMA_DIGEST_LIST
static enum ima_fs_flags ima_get_dentry_flag(struct dentry *dentry)
{
enum ima_fs_flags flag = IMA_FS_BUSY;
@@ -461,6 +566,7 @@ static enum ima_fs_flags ima_get_dentry_flag(struct dentry *dentry)
return flag;
}
+#endif
static unsigned long ima_fs_flags;
@@ -473,11 +579,19 @@ 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
*/
static int ima_open_data_upload(struct inode *inode, struct file *filp)
+#else
+/*
+ * ima_open_policy: sequentialize access to the policy file
+ */
+static int ima_open_policy(struct inode *inode, struct file *filp)
+#endif
{
+#ifdef CONFIG_IMA_DIGEST_LIST
struct dentry *dentry = file_dentry(filp);
const struct seq_operations *seq_ops = NULL;
enum ima_fs_flags flag = ima_get_dentry_flag(dentry);
@@ -489,8 +603,10 @@ static int ima_open_data_upload(struct inode *inode, struct file *filp)
seq_ops = &ima_policy_seqops;
#endif
}
+#endif
if (!(filp->f_flags & O_WRONLY)) {
+#ifdef CONFIG_IMA_DIGEST_LIST
if (!read_allowed)
return -EACCES;
if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
@@ -498,17 +614,35 @@ static int ima_open_data_upload(struct inode *inode, struct file *filp)
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
return seq_open(filp, seq_ops);
+#else
+#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 /*CONFIG_IMA_READ_POLICY*/
+#endif /* CONFIG_IMA_DIGEST_LIST */
}
+#ifdef CONFIG_IMA_DIGEST_LIST
if (test_and_set_bit(flag, &ima_fs_flags))
+#else
+ if (test_and_set_bit(IMA_FS_BUSY, &ima_fs_flags))
+#endif
return -EBUSY;
+#ifdef CONFIG_IMA_DIGEST_LIST
if (dentry == digest_list_data || dentry == digest_list_data_del)
if (ima_check_current_is_parser())
ima_set_parser();
+#endif
return 0;
}
+#ifdef CONFIG_IMA_DIGEST_LIST
/*
* ima_release_data_upload - start using the new measure policy rules.
*
@@ -517,14 +651,29 @@ static int ima_open_data_upload(struct inode *inode, struct file *filp)
* assuming a valid policy.
*/
static int ima_release_data_upload(struct inode *inode, struct file *file)
+#else
+/*
+ * 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)
+#endif
{
+#ifdef CONFIG_IMA_DIGEST_LIST
struct dentry *dentry = file_dentry(file);
+#endif
const char *cause = valid_policy ? "completed" : "failed";
+#ifdef CONFIG_IMA_DIGEST_LIST
enum ima_fs_flags flag = ima_get_dentry_flag(dentry);
+#endif
if ((file->f_flags & O_ACCMODE) == O_RDONLY)
return seq_release(inode, file);
+#ifdef CONFIG_IMA_DIGEST_LIST
if (dentry == digest_list_data || dentry == digest_list_data_del)
ima_unset_parser();
@@ -532,6 +681,7 @@ static int ima_release_data_upload(struct inode *inode, struct file *file)
clear_bit(flag, &ima_fs_flags);
return 0;
}
+#endif
if (valid_policy && ima_check_policy() < 0) {
cause = "failed";
@@ -545,7 +695,11 @@ static int ima_release_data_upload(struct inode *inode, struct file *file)
if (!valid_policy) {
ima_delete_rules();
valid_policy = 1;
+#ifdef CONFIG_IMA_DIGEST_LIST
clear_bit(flag, &ima_fs_flags);
+#else
+ clear_bit(IMA_FS_BUSY, &ima_fs_flags);
+#endif
return 0;
}
@@ -554,18 +708,32 @@ static int ima_release_data_upload(struct inode *inode, struct file *file)
securityfs_remove(ima_policy);
ima_policy = NULL;
#elif defined(CONFIG_IMA_WRITE_POLICY)
+#ifdef CONFIG_IMA_DIGEST_LIST
clear_bit(flag, &ima_fs_flags);
+#else
+ clear_bit(IMA_FS_BUSY, &ima_fs_flags);
+#endif
#elif defined(CONFIG_IMA_READ_POLICY)
inode->i_mode &= ~S_IWUSR;
#endif
return 0;
}
+#ifdef CONFIG_IMA_DIGEST_LIST
static const struct file_operations ima_data_upload_ops = {
.open = ima_open_data_upload,
.write = ima_write_data,
+#else
+static const struct file_operations ima_measure_policy_ops = {
+ .open = ima_open_policy,
+ .write = ima_write_policy,
+#endif
.read = seq_read,
+#ifdef CONFIG_IMA_DIGEST_LIST
.release = ima_release_data_upload,
+#else
+ .release = ima_release_policy,
+#endif
.llseek = generic_file_llseek,
};
@@ -597,19 +765,31 @@ int __init ima_fs_init(void)
runtime_measurements_count =
securityfs_create_file("runtime_measurements_count",
S_IRUSR | S_IRGRP, ima_dir, NULL,
+#ifdef CONFIG_IMA_DIGEST_LIST
&ima_htable_value_ops);
+#else
+ &ima_measurements_count_ops);
+#endif
if (IS_ERR(runtime_measurements_count))
goto out;
violations =
securityfs_create_file("violations", S_IRUSR | S_IRGRP,
+#ifdef CONFIG_IMA_DIGEST_LIST
ima_dir, NULL, &ima_htable_value_ops);
+#else
+ ima_dir, NULL, &ima_htable_violations_ops);
+#endif
if (IS_ERR(violations))
goto out;
ima_policy = securityfs_create_file("policy", POLICY_FILE_FLAGS,
ima_dir, NULL,
+#ifdef CONFIG_IMA_DIGEST_LIST
&ima_data_upload_ops);
+#else
+ &ima_measure_policy_ops);
+#endif
if (IS_ERR(ima_policy))
goto out;
@@ -634,9 +814,11 @@ int __init ima_fs_init(void)
#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..7ab87713a2e4 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -86,7 +86,11 @@ static int __init ima_add_boot_aggregate(void)
result = ima_store_template(entry, violation, NULL,
boot_aggregate_name,
+#ifdef CONFIG_IMA_DIGEST_LIST
CONFIG_IMA_MEASURE_PCR_IDX, NULL);
+#else
+ CONFIG_IMA_MEASURE_PCR_IDX);
+#endif
if (result < 0) {
ima_free_template_entry(entry);
audit_cause = "store_entry";
@@ -107,8 +111,10 @@ void __init ima_load_x509(void)
ima_policy_flag &= ~unset_flags;
integrity_load_x509(INTEGRITY_KEYRING_IMA, CONFIG_IMA_X509_PATH);
+#ifdef CONFIG_IMA_DIGEST_LIST
/* load also EVM key to avoid appraisal */
evm_load_x509();
+#endif
ima_policy_flag |= unset_flags;
}
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 999d5904cce0..0afcbd5dd196 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 /* CONFIG_IMA_DIGEST_LIST */
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,39 @@ 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)
ima_store_measurement(iint, file, pathname,
xattr_value, xattr_len, modsig, pcr,
+#ifdef CONFIG_IMA_DIGEST_LIST
template_desc,
ima_digest_allow(found_digest,
IMA_MEASURE));
+#else
+ template_desc);
+#endif
if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) {
rc = ima_check_blacklist(iint, modsig, pcr);
if (rc != -EPERM) {
inode_lock(inode);
+
rc = ima_appraise_measurement(func, iint, file,
pathname, xattr_value,
+#ifdef CONFIG_IMA_DIGEST_LIST
xattr_len, modsig,
ima_digest_allow(found_digest,
IMA_APPRAISE));
+#else
+ xattr_len, modsig);
+#endif
inode_unlock(inode);
}
if (!rc)
@@ -568,15 +587,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 +766,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 +970,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..84528e1413ad 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 /* CONFIG_IMA_DIGEST_LIST */
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/ima/ima_template.c b/security/integrity/ima/ima_template.c
index 6f126dbd2b39..4a7b5df58863 100644
--- a/security/integrity/ima/ima_template.c
+++ b/security/integrity/ima/ima_template.c
@@ -46,8 +46,10 @@ static const struct ima_template_field supported_fields[] = {
.field_show = ima_show_template_digest_ng},
{.field_id = "modsig", .field_init = ima_eventmodsig_init,
.field_show = ima_show_template_sig},
+#ifdef CONFIG_IMA_DIGEST_LIST
{.field_id = "evmsig", .field_init = ima_eventevmsig_init,
.field_show = ima_show_template_sig},
+#endif
};
/*
diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c
index 90040fac150b..7308ee587314 100644
--- a/security/integrity/ima/ima_template_lib.c
+++ b/security/integrity/ima/ima_template_lib.c
@@ -10,7 +10,9 @@
*/
#include "ima_template_lib.h"
+#ifdef CONFIG_IMA_DIGEST_LIST
#include <linux/xattr.h>
+#endif
static bool ima_template_hash_algo_allowed(u8 algo)
{
@@ -439,7 +441,11 @@ int ima_eventsig_init(struct ima_event_data *event_data,
struct evm_ima_xattr_data *xattr_value = event_data->xattr_value;
if ((!xattr_value) || (xattr_value->type != EVM_IMA_XATTR_DIGSIG))
+#ifdef CONFIG_IMA_DIGEST_LIST
return ima_eventevmsig_init(event_data, field_data);
+#else
+ return 0;
+#endif
return ima_write_template_field_data(xattr_value, event_data->xattr_len,
DATA_FMT_HEX, field_data);
@@ -486,6 +492,7 @@ int ima_eventmodsig_init(struct ima_event_data *event_data,
field_data);
}
+#ifdef CONFIG_IMA_DIGEST_LIST
/*
* ima_eventevmsig_init - include the EVM portable signature as part of the
* template data
@@ -514,3 +521,4 @@ int ima_eventevmsig_init(struct ima_event_data *event_data,
kfree(xattr_data);
return rc;
}
+#endif
diff --git a/security/integrity/ima/ima_template_lib.h b/security/integrity/ima/ima_template_lib.h
index f4b2a2056d1d..7d0d5be28908 100644
--- a/security/integrity/ima/ima_template_lib.h
+++ b/security/integrity/ima/ima_template_lib.h
@@ -46,6 +46,8 @@ int ima_eventbuf_init(struct ima_event_data *event_data,
struct ima_field_data *field_data);
int ima_eventmodsig_init(struct ima_event_data *event_data,
struct ima_field_data *field_data);
+#ifdef CONFIG_IMA_DIGEST_LIST
int ima_eventevmsig_init(struct ima_event_data *event_data,
struct ima_field_data *field_data);
+#endif /* CONFIG_IMA_DIGEST_LIST */
#endif /* __LINUX_IMA_TEMPLATE_LIB_H */
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 77e6819e8db8..cb1c178f8ac4 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,27 +176,11 @@ 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);
void __init ima_load_digest_lists(void);
-#else
-static inline struct ima_digest *ima_lookup_digest(u8 *digest,
- enum hash_algo algo,
- enum compact_types type)
-{
- return NULL;
-}
-static inline struct ima_digest *ima_digest_allow(struct ima_digest *digest,
- int action)
-{
- return NULL;
-}
-static inline void ima_load_digest_lists(void)
-{
-}
-#endif
+#endif /* CONFIG_IMA_DIGEST_LIST */
/* rbtree tree calls to lookup, insert, delete
* integrity data associated with an inode.
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

[PATCH openEuler-1.0-LTS 0/2] blk-mq: Improve performance of non-mq IO schedulers with multiple HW queues
by Lei Chen 05 Sep '23
by Lei Chen 05 Sep '23
05 Sep '23
Jan Kara (1):
blk-mq: Improve performance of non-mq IO schedulers with multiple HW
queues
Lei Chen (1):
Fix kabi breakage in struct elevator_type.
block/blk-mq.c | 63 +++++++++++++++++++++++++++++++++++++---
block/kyber-iosched.c | 1 +
include/linux/elevator.h | 7 +++++
3 files changed, 67 insertions(+), 4 deletions(-)
--
2.34.1
2
3