summaryrefslogtreecommitdiff
path: root/security
diff options
context:
space:
mode:
Diffstat (limited to 'security')
-rw-r--r--security/safesetid/lsm.c39
-rw-r--r--security/security.c5
2 files changed, 35 insertions, 9 deletions
diff --git a/security/safesetid/lsm.c b/security/safesetid/lsm.c
index 963f4ad9cb66..e806739f7868 100644
--- a/security/safesetid/lsm.c
+++ b/security/safesetid/lsm.c
@@ -97,15 +97,9 @@ static int safesetid_security_capable(const struct cred *cred,
return 0;
/*
- * If CAP_SET{U/G}ID is currently used for a setid() syscall, we want to
- * let it go through here; the real security check happens later, in the
- * task_fix_set{u/g}id hook.
- *
- * NOTE:
- * Until we add support for restricting setgroups() calls, GID security
- * policies offer no meaningful security since we always return 0 here
- * when called from within the setgroups() syscall and there is no
- * additional hook later on to enforce security policies for setgroups().
+ * If CAP_SET{U/G}ID is currently used for a setid or setgroups syscall, we
+ * want to let it go through here; the real security check happens later, in
+ * the task_fix_set{u/g}id or task_fix_setgroups hooks.
*/
if ((opts & CAP_OPT_INSETID) != 0)
return 0;
@@ -241,9 +235,36 @@ static int safesetid_task_fix_setgid(struct cred *new,
return -EACCES;
}
+static int safesetid_task_fix_setgroups(struct cred *new, const struct cred *old)
+{
+ int i;
+
+ /* Do nothing if there are no setgid restrictions for our old RGID. */
+ if (setid_policy_lookup((kid_t){.gid = old->gid}, INVALID_ID, GID) == SIDPOL_DEFAULT)
+ return 0;
+
+ get_group_info(new->group_info);
+ for (i = 0; i < new->group_info->ngroups; i++) {
+ if (!id_permitted_for_cred(old, (kid_t){.gid = new->group_info->gid[i]}, GID)) {
+ put_group_info(new->group_info);
+ /*
+ * Kill this process to avoid potential security vulnerabilities
+ * that could arise from a missing allowlist entry preventing a
+ * privileged process from dropping to a lesser-privileged one.
+ */
+ force_sig(SIGKILL);
+ return -EACCES;
+ }
+ }
+
+ put_group_info(new->group_info);
+ return 0;
+}
+
static struct security_hook_list safesetid_security_hooks[] = {
LSM_HOOK_INIT(task_fix_setuid, safesetid_task_fix_setuid),
LSM_HOOK_INIT(task_fix_setgid, safesetid_task_fix_setgid),
+ LSM_HOOK_INIT(task_fix_setgroups, safesetid_task_fix_setgroups),
LSM_HOOK_INIT(capable, safesetid_security_capable)
};
diff --git a/security/security.c b/security/security.c
index f85afb02ea1c..14d30fec8a00 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1804,6 +1804,11 @@ int security_task_fix_setgid(struct cred *new, const struct cred *old,
return call_int_hook(task_fix_setgid, 0, new, old, flags);
}
+int security_task_fix_setgroups(struct cred *new, const struct cred *old)
+{
+ return call_int_hook(task_fix_setgroups, 0, new, old);
+}
+
int security_task_setpgid(struct task_struct *p, pid_t pgid)
{
return call_int_hook(task_setpgid, 0, p, pgid);