The criu key caps the raw policy blobs a namespace retains for checkpoint/restore.
Expose the retained bytes as .criu_size. Signed-off-by: Maxime Bélair <[email protected]> --- security/apparmor/apparmorfs.c | 4 ++- security/apparmor/include/apparmorfs.h | 1 + security/apparmor/include/policy_ns.h | 4 +++ security/apparmor/policy_ns.c | 44 +++++++++++++++++++------- 4 files changed, 40 insertions(+), 13 deletions(-) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 3ed00f5b30c4..235edbe33dcb 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -1503,6 +1503,7 @@ SEQ_NS_ACCT(acct_max_profile, ns->acct.caps.limits.max_profile); SEQ_NS_ACCT(acct_namespaces, ns->acct.caps.limits.namespaces); SEQ_NS_ACCT(acct_depth, ns->acct.caps.limits.depth); SEQ_NS_ACCT(acct_criu, ns->acct.caps.limits.criu); +SEQ_NS_ACCT(acct_criu_size, atomic_long_read(&ns->acct.criu_resident)); /* policy/raw_data/ * file ops */ @@ -2273,6 +2274,7 @@ static const struct aa_ns_acct_file { { ".namespaces", &seq_ns_acct_namespaces_fops, AAFS_NS_NAMESPACES }, { ".depth", &seq_ns_acct_depth_fops, AAFS_NS_DEPTH }, { ".criu", &seq_ns_acct_criu_fops, AAFS_NS_CRIU }, + { ".criu_size", &seq_ns_acct_criu_size_fops, AAFS_NS_CRIU_SIZE }, }; static int __aafs_ns_mkdir_entries(struct aa_ns *ns, struct dentry *dir) @@ -2697,7 +2699,7 @@ static struct aa_sfs_entry aa_sfs_entry_ns_quota[] = { * (subtree, criu, load_rate, descendants, root, name, mediation). */ AA_SFS_FILE_STRING("mask", - "self children percent local subtree mediation"), + "self children percent local subtree criu mediation"), { } }; diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h index b8e198b529b4..4b7cd92fe350 100644 --- a/security/apparmor/include/apparmorfs.h +++ b/security/apparmor/include/apparmorfs.h @@ -83,6 +83,7 @@ enum aafs_ns_type { AAFS_NS_NAMESPACES, AAFS_NS_DEPTH, AAFS_NS_CRIU, + AAFS_NS_CRIU_SIZE, AAFS_NS_SUBTREE_COUNT, AAFS_NS_SUBTREE_SIZE, AAFS_NS_SIZEOF, diff --git a/security/apparmor/include/policy_ns.h b/security/apparmor/include/policy_ns.h index 9c5af84ea023..ed6be9f9b3fa 100644 --- a/security/apparmor/include/policy_ns.h +++ b/security/apparmor/include/policy_ns.h @@ -62,6 +62,8 @@ static inline void aa_ns_capset_init_unset(struct aa_ns_capset *caps) * @ns_count: current number of direct child namespaces * @subtree_resident: resident policy bytes of this ns plus all descendants * @subtree_profile_count: non-null profiles of this ns plus all descendants + * @criu_resident: retained raw policy bytes charged to this ns (local) + * @subtree_criu: retained raw policy bytes of this ns plus all descendants * @ratelimit: bounds OP_NS_QUOTA audit emission */ struct aa_ns_acct { @@ -71,6 +73,8 @@ struct aa_ns_acct { atomic_long_t ns_count; atomic_long_t subtree_resident; atomic_long_t subtree_profile_count; + atomic_long_t criu_resident; + atomic_long_t subtree_criu; struct ratelimit_state ratelimit; }; diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c index 225384273209..0643c8319627 100644 --- a/security/apparmor/policy_ns.c +++ b/security/apparmor/policy_ns.c @@ -218,6 +218,8 @@ void aa_ns_acct_init(struct aa_ns *ns) atomic_long_set(&acct->ns_count, 0); atomic_long_set(&acct->subtree_resident, 0); atomic_long_set(&acct->subtree_profile_count, 0); + atomic_long_set(&acct->criu_resident, 0); + atomic_long_set(&acct->subtree_criu, 0); ratelimit_state_init(&acct->ratelimit, AA_NS_QUOTA_RATELIMIT_INTERVAL, AA_NS_QUOTA_RATELIMIT_BURST); @@ -409,7 +411,7 @@ static long effective_max_profile(struct aa_ns *ns, struct aa_ns_capset *pend, * of these caps is set. */ static int admit_subtree_agg(struct aa_ns *ns, struct aa_ns_capset *pend, - long bytes, long profiles) + long bytes, long profiles, long criu) { struct aa_ns *a; int error; @@ -429,6 +431,10 @@ static int admit_subtree_agg(struct aa_ns *ns, struct aa_ns_capset *pend, profiles, -EDQUOT); if (error) return error; + error = cap_admit_delta(a, AA_POLICYNS_KEY_CRIU, sc->criu, + &a->acct.subtree_criu, criu, -ENOSPC); + if (error) + return error; } return 0; } @@ -489,6 +495,7 @@ int aa_ns_admit_load_set(struct aa_ns *ns, struct list_head *lh, { long new_bytes = 0, old_bytes = 0; long new_count = 0, old_count = 0; + long raw_bytes = 0; struct aa_load_ent *ent; struct aa_ns *mp_owner; long mp_limit; @@ -527,10 +534,13 @@ int aa_ns_admit_load_set(struct aa_ns *ns, struct list_head *lh, } } /* a newly retained rawdata blob is charged too (same condition as - * the __aa_fs_create_rawdata call in aa_replace_profiles) + * the __aa_fs_create_rawdata call in aa_replace_profiles); it is + * also what the criu reserve caps */ - if (!udata->dents[AAFS_LOADDATA_DIR] && aa_g_export_binary) - new_bytes += aa_loaddata_resident_size(udata); + if (!udata->dents[AAFS_LOADDATA_DIR] && aa_g_export_binary) { + raw_bytes = aa_loaddata_resident_size(udata); + new_bytes += raw_bytes; + } error = aa_ns_admit_resident(ns, &pend->limits, new_bytes - old_bytes); if (error) { @@ -544,8 +554,15 @@ int aa_ns_admit_load_set(struct aa_ns *ns, struct list_head *lh, *info = "namespace profile cap exceeded"; return error; } + error = cap_admit_delta(ns, AA_POLICYNS_KEY_CRIU, pend->limits.criu, + &ns->acct.criu_resident, raw_bytes, -ENOSPC); + if (error) { + *fail_ent = NULL; + *info = "namespace criu reserve exceeded"; + return error; + } error = admit_subtree_agg(ns, pend, new_bytes - old_bytes, - new_count - old_count); + new_count - old_count, raw_bytes); if (error) { *fail_ent = NULL; *info = "subtree cap exceeded"; @@ -559,14 +576,16 @@ int aa_ns_admit_load_set(struct aa_ns *ns, struct list_head *lh, * @ns: the namespace the delta was charged to (NOT NULL) * @bytes: resident byte delta (may be negative) * @profiles: non-null profile count delta (may be negative) + * @criu: retained raw policy byte delta (may be negative) * * The parent chain is stable for the life of @ns. */ -static void acct_rollup(struct aa_ns *ns, long bytes, long profiles) +static void acct_rollup(struct aa_ns *ns, long bytes, long profiles, long criu) { for (; ns; ns = ns->parent) { atomic_long_add(bytes, &ns->acct.subtree_resident); atomic_long_add(profiles, &ns->acct.subtree_profile_count); + atomic_long_add(criu, &ns->acct.subtree_criu); } } @@ -591,7 +610,7 @@ void aa_ns_charge_profile(struct aa_profile *profile) atomic_long_add(bytes, &ns->acct.resident); if (counted) atomic_long_inc(&ns->acct.profile_count); - acct_rollup(ns, bytes, counted ? 1 : 0); + acct_rollup(ns, bytes, counted ? 1 : 0, 0); } /** @@ -606,7 +625,8 @@ void aa_ns_charge_rawdata(struct aa_ns *ns, struct aa_loaddata *data) long bytes = aa_loaddata_resident_size(data); atomic_long_add(bytes, &ns->acct.resident); - acct_rollup(ns, bytes, 0); + atomic_long_add(bytes, &ns->acct.criu_resident); + acct_rollup(ns, bytes, 0, bytes); } /** @@ -621,7 +641,8 @@ void aa_ns_uncharge_rawdata(struct aa_ns *ns, struct aa_loaddata *data) long bytes = aa_loaddata_resident_size(data); atomic_long_sub(bytes, &ns->acct.resident); - acct_rollup(ns, -bytes, 0); + atomic_long_sub(bytes, &ns->acct.criu_resident); + acct_rollup(ns, -bytes, 0, -bytes); } /** @@ -642,7 +663,7 @@ void aa_ns_uncharge_profile(struct aa_profile *profile) atomic_long_sub(profile->acct_resident, &ns->acct.resident); if (counted) atomic_long_dec(&ns->acct.profile_count); - acct_rollup(ns, -profile->acct_resident, counted ? -1 : 0); + acct_rollup(ns, -profile->acct_resident, counted ? -1 : 0, 0); profile->acct_resident = 0; } @@ -681,8 +702,7 @@ int aa_ns_apply_budget(struct aa_ns_capset *caps, struct aa_ns_budget *b) bool subtree = b->scope == AA_POLICYNS_SCOPE_SUBTREE; /* Some features remains to be implemented and are rejected with -EOPNOTSUPP. */ - if (b->specified & ((1u << AA_POLICYNS_KEY_CRIU) | - (1u << AA_POLICYNS_KEY_LOAD_RATE))) + if (b->specified & (1u << AA_POLICYNS_KEY_LOAD_RATE)) return -EOPNOTSUPP; /* the parser rejects subtree scope on the other keys at parse time */ if (subtree && (b->specified & ~AA_POLICYNS_SUBTREE_KEYS)) -- 2.51.0
