Skip to content

kernel: make sepolicy manipulation follows rcu#37

Draft
5ec1cff wants to merge 10 commits intomainfrom
rcupolicydb
Draft

kernel: make sepolicy manipulation follows rcu#37
5ec1cff wants to merge 10 commits intomainfrom
rcupolicydb

Conversation

@5ec1cff
Copy link
Owner

@5ec1cff 5ec1cff commented Mar 10, 2026

No description provided.

@5ec1cff 5ec1cff force-pushed the main branch 2 times, most recently from f203c12 to 67e782c Compare March 10, 2026 15:49
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates KernelSU’s SELinux policy manipulation to follow an RCU-style “duplicate → swap pointer → wait grace period → free old” model, aiming to avoid in-place mutation of the active policy and make policy updates safer under concurrent readers.

Changes:

  • Adds ksu_dup_sepolicy() / ksu_destroy_sepolicy() helpers to duplicate and partially free a struct selinux_policy.
  • Updates rule application and sepolicy handling paths to lock selinux_state.policy_mutex, swap selinux_state.policy via rcu_assign_pointer(), and synchronize_rcu() before freeing the old policy.
  • Keeps AVC cache reset after policy modifications so updated rules take effect immediately.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 8 comments.

File Description
kernel/selinux/sepolicy.h Exposes new policy duplication/destruction APIs.
kernel/selinux/sepolicy.c Implements partial policy duplication and teardown helpers.
kernel/selinux/rules.c Switches policy update paths to mutex + RCU pointer swap + old-policy destruction, and centralizes AVC reset.
Comments suppressed due to low confidence (1)

kernel/selinux/rules.c:198

  • copy_from_user(&data, ...) failure returns immediately while selinux_state.policy_mutex is held and after a new policy may have been allocated. This can deadlock future callers and leak pol. Set ret, free/destroy pol if allocated, and goto out_unlock instead of returning here.
    struct sepol_data data;
    if (copy_from_user(&data, arg4, sizeof(struct sepol_data))) {
        pr_err("sepol: copy sepol_data failed.\n");
        return -EINVAL;
    }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +44 to 45
struct selinux_policy *pol, *old_pol = selinux_state.policy;
struct policydb *db;
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

old_pol is read from selinux_state.policy before policy_mutex is taken. If the policy pointer can change concurrently (e.g., policy reload), this cached pointer can become stale before the later rcu_dereference_protected(old_pol, ...) and ksu_destroy_sepolicy(old_pol) calls. Consider reading selinux_state.policy only after acquiring selinux_state.policy_mutex (via rcu_dereference_protected(selinux_state.policy, ...)) and keep old_pol scoped to the locked section.

Copilot uses AI. Check for mistakes.
Comment on lines +1301 to +1304

out:
kfree(new_pol);
return NULL;
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ksu_dup_sepolicy error path (out:) only kfree(new_pol). If any copy step fails after earlier ones succeeded, those earlier allocations are leaked. Consider unwinding via ksu_destroy_sepolicy(new_pol) (or a stepwise cleanup) before returning NULL.

Copilot uses AI. Check for mistakes.
Comment on lines +1218 to +1221
static void free_filename_trans(struct policydb *db)
{
hashtab_destroy(&db->filename_trans);
}
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

free_filename_trans() only calls hashtab_destroy(&db->filename_trans), but add_filename_trans() allocates filename_trans_key/filename_trans_datum (plus kstrdup name) and inserts them into this table. Without a hashtab_map() + free callback (or equivalent), these per-rule allocations will leak on each policy replacement.

Copilot uses AI. Check for mistakes.
Comment on lines +1132 to +1136
kvfree(db->sym_val_to_name[SYM_TYPES]);
}

hashtab_destroy(&db->p_types.table);
}
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

free_type_datum_partially() destroys db->p_types.table via hashtab_destroy() but never frees per-entry key/datum. Since KSU can allocate new types/attrs at runtime (see add_type() using kzalloc + kstrdup + symtab_insert()), those allocations will leak when a duplicated policy is destroyed. Consider iterating the table with a free callback for entries owned by this policy (or avoid allocating new type entries in a policy that uses shallow-copied symtabs).

Copilot uses AI. Check for mistakes.
Comment on lines +120 to +123
rcu_assign_pointer(selinux_state.policy, pol);
synchronize_rcu();
ksu_destroy_sepolicy(old_pol);

Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

apply_kernelsu_rules() replaces selinux_state.policy and then calls ksu_destroy_sepolicy(old_pol). ksu_destroy_sepolicy() is a partial free (it doesn’t release many policydb-owned allocations / symtabs), so if old_pol is the original SELinux-loaded policy, this will leak a large amount of memory. Consider only calling ksu_destroy_sepolicy() for policies created by ksu_dup_sepolicy(), and use the proper SELinux policy free path (or keep the original policy alive) for the initial policy object.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants