Similar to how security_dma_buf_charge_task adds an access-control point for pidfd for the charge_fd of a DMA_HEAP_IOCTL_ALLOC ioctl, we need a new access-control point for the case where charge_fd represents a cgroupfd.
Add security_dma_buf_charge_cgroup(), called in mem_cgroup_get_from_fd() when charge_fd refers to a cgroup. The hook receives the credentials of the requesting process (cred) and the target cgroup to charge (cgrp), giving security modules a controlled enforcement point for cross-cgroup dma-buf attribution policy.
When CONFIG_SECURITY is not set the hook compiles to an inline returning 0, adding no overhead to the fast path.
Signed-off-by: Albert Esteve aesteve@redhat.com --- include/linux/lsm_hook_defs.h | 3 +++ include/linux/security.h | 11 +++++++++++ mm/memcontrol.c | 6 ++++++ security/security.c | 18 ++++++++++++++++++ 4 files changed, 38 insertions(+)
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index 0f1138e16dbe..fbf7f17127db 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -44,6 +44,9 @@ LSM_HOOK(int, 0, capset, struct cred *new, const struct cred *old, LSM_HOOK(int, 0, capable, const struct cred *cred, struct user_namespace *ns, int cap, unsigned int opts) LSM_HOOK(int, 0, dma_buf_charge_task, const struct cred *from, const struct cred *to) +#ifdef CONFIG_CGROUPS +LSM_HOOK(int, 0, dma_buf_charge_cgroup, const struct cred *cred, struct cgroup *cgrp) +#endif LSM_HOOK(int, 0, quotactl, int cmds, int type, int id, const struct super_block *sb) LSM_HOOK(int, 0, quota_on, struct dentry *dentry) LSM_HOOK(int, 0, syslog, int type) diff --git a/include/linux/security.h b/include/linux/security.h index 89a35eb07b8c..8fb1539156b5 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -351,6 +351,9 @@ int security_capable(const struct cred *cred, int cap, unsigned int opts); int security_dma_buf_charge_task(const struct cred *from, const struct cred *to); +#ifdef CONFIG_CGROUPS +int security_dma_buf_charge_cgroup(const struct cred *cred, struct cgroup *cgrp); +#endif int security_quotactl(int cmds, int type, int id, const struct super_block *sb); int security_quota_on(struct dentry *dentry); int security_syslog(int type); @@ -708,6 +711,14 @@ static inline int security_dma_buf_charge_task(const struct cred *from, return 0; }
+#ifdef CONFIG_CGROUPS +static inline int security_dma_buf_charge_cgroup(const struct cred *cred, + struct cgroup *cgrp) +{ + return 0; +} +#endif + static inline int security_quotactl(int cmds, int type, int id, const struct super_block *sb) { diff --git a/mm/memcontrol.c b/mm/memcontrol.c index ad195cfd1b5f..7b841b905759 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -5693,7 +5693,13 @@ struct mem_cgroup *mem_cgroup_get_from_fd(int fd)
memcg = mem_cgroup_from_css(css); rcu_read_unlock(); + + ret = security_dma_buf_charge_cgroup(current_cred(), cgrp); cgroup_put(cgrp); + if (ret) { + mem_cgroup_put(memcg); + return ERR_PTR(ret); + } return memcg; }
diff --git a/security/security.c b/security/security.c index 4a16e4076aab..a5dcf9dc4963 100644 --- a/security/security.c +++ b/security/security.c @@ -676,6 +676,24 @@ int security_dma_buf_charge_task(const struct cred *from, const struct cred *to) return call_int_hook(dma_buf_charge_task, from, to); }
+#ifdef CONFIG_CGROUPS +/** + * security_dma_buf_charge_cgroup() - Check if charging dma-buf memory to a cgroup is allowed + * @cred: credentials of the process requesting the charge + * @cgrp: target cgroup to charge + * + * Check whether the process with credentials @cred is allowed to charge + * dma-buf memory to @cgrp. Called when userspace passes a cgroupfd to + * identify the charge target instead of a pidfd. + * + * Return: Returns 0 if permission is granted. + */ +int security_dma_buf_charge_cgroup(const struct cred *cred, struct cgroup *cgrp) +{ + return call_int_hook(dma_buf_charge_cgroup, cred, cgrp); +} +#endif + /** * security_quotactl() - Check if a quotactl() syscall is allowed for this fs * @cmds: commands