Merge "msm: adsprpc: detect privileged processes based on group ID"

This commit is contained in:
qctecmdr 2020-02-04 15:25:03 -08:00 • committed by Gerrit - the friendly Code Review server
commit 0d234d7b41

View file

@ -33,6 +33,7 @@
#include <linux/cma.h>
#include <linux/iommu.h>
#include <linux/sort.h>
#include <linux/cred.h>
#include <linux/msm_dma_iommu_mapping.h>
#include "adsprpc_compat.h"
#include "adsprpc_shared.h"
@ -135,6 +136,9 @@
#define INIT_MEMLEN_MAX (8*1024*1024)
#define MAX_CACHE_BUF_SIZE (8*1024*1024)
/* Position of privilege bit in remote process attribute */
#define FASTRPC_MODE_PRIVILEGED (1 << 6)
#define PERF_END (void)0
#define PERF(enb, cnt, ff) \
@ -211,6 +215,11 @@ struct secure_vm {
int vmcount;
};
struct gid_list {
unsigned int *gids;
unsigned int gidcount;
};
struct fastrpc_file;
struct fastrpc_buf {
@ -360,6 +369,7 @@ struct fastrpc_apps {
struct wakeup_source *wake_source_secure;
/* Non-secure subsystem like CDSP will use regular client */
struct wakeup_source *wake_source;
struct gid_list gidlist;
};
struct fastrpc_mmap {
@ -443,6 +453,7 @@ struct fastrpc_file {
char *debug_buf;
/* Flag to enable PM wake/relax voting for every remote invoke */
int wake_enable;
struct gid_list gidlist;
};
static struct fastrpc_apps gfa;
@ -1193,7 +1204,32 @@ static int context_restore_interrupted(struct fastrpc_file *fl,
return err;
}
static unsigned int sorted_lists_intersection(unsigned int *listA,
unsigned int lenA, unsigned int *listB, unsigned int lenB)
{
unsigned int i = 0, j = 0;
while (i < lenA && j < lenB) {
if (listA[i] < listB[j])
i++;
else if (listA[i] > listB[j])
j++;
else
return listA[i];
}
return 0;
}
#define CMP(aa, bb) ((aa) == (bb) ? 0 : (aa) < (bb) ? -1 : 1)
static int uint_cmp_func(const void *p1, const void *p2)
{
unsigned int a1 = *((unsigned int *)p1);
unsigned int a2 = *((unsigned int *)p2);
return CMP(a1, a2);
}
static int overlap_ptr_cmp(const void *a, const void *b)
{
struct overlap *pa = *((struct overlap **)a);
@ -2356,6 +2392,22 @@ bail:
static int fastrpc_mmap_remove_pdr(struct fastrpc_file *fl);
static int fastrpc_channel_open(struct fastrpc_file *fl);
static int fastrpc_mmap_remove_ssr(struct fastrpc_file *fl);
static void fastrpc_check_privileged_process(struct fastrpc_file *fl,
struct fastrpc_ioctl_init_attrs *uproc)
{
unsigned int gid = sorted_lists_intersection(fl->gidlist.gids,
fl->gidlist.gidcount, gfa.gidlist.gids, gfa.gidlist.gidcount);
/* disregard any privilege bits from userspace */
uproc->attrs &= (~FASTRPC_MODE_PRIVILEGED);
if (gid) {
pr_info("adsprpc: %s: %s (PID %d, GID %u) is a privileged process\n",
__func__, current->comm, fl->tgid, gid);
uproc->attrs |= FASTRPC_MODE_PRIVILEGED;
}
}
static int fastrpc_init_process(struct fastrpc_file *fl,
struct fastrpc_ioctl_init_attrs *uproc)
{
@ -2434,6 +2486,8 @@ static int fastrpc_init_process(struct fastrpc_file *fl,
}
inbuf.pageslen = 1;
fastrpc_check_privileged_process(fl, uproc);
VERIFY(err, !init->mem);
if (err) {
err = -EINVAL;
@ -3492,6 +3546,7 @@ static int fastrpc_file_free(struct fastrpc_file *fl)
hlist_del_init(&fl->hn);
spin_unlock(&fl->apps->hlock);
kfree(fl->debug_buf);
kfree(fl->gidlist.gids);
if (!fl->sctx) {
kfree(fl);
@ -3896,6 +3951,34 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp)
return 0;
}
static int fastrpc_get_process_gids(struct gid_list *gidlist)
{
struct group_info *group_info = get_current_groups();
int i = 0, err = 0, num_gids = group_info->ngroups + 1;
unsigned int *gids = NULL;
gids = kcalloc(num_gids, sizeof(unsigned int), GFP_KERNEL);
if (!gids) {
err = -ENOMEM;
goto bail;
}
/* Get the real GID */
gids[0] = __kgid_val(current_gid());
/* Get the supplemental GIDs */
for (i = 1; i < num_gids; i++)
gids[i] = __kgid_val(group_info->gid[i - 1]);
sort(gids, num_gids, sizeof(*gids), uint_cmp_func, NULL);
gidlist->gids = gids;
gidlist->gidcount = num_gids;
bail:
if (err)
kfree(gids);
return err;
}
static int fastrpc_get_info(struct fastrpc_file *fl, uint32_t *info)
{
int err = 0;
@ -3904,6 +3987,7 @@ static int fastrpc_get_info(struct fastrpc_file *fl, uint32_t *info)
VERIFY(err, fl != NULL);
if (err)
goto bail;
fastrpc_get_process_gids(&fl->gidlist);
if (fl->cid == -1) {
cid = *info;
VERIFY(err, cid < NUM_CHANNELS);
@ -4578,6 +4662,41 @@ bail:
}
}
static void fastrpc_init_privileged_gids(struct device *dev, char *prop_name,
struct gid_list *gidlist)
{
int err = 0;
u32 len = 0, i = 0;
u32 *gids = NULL;
if (!of_find_property(dev->of_node, prop_name, &len))
goto bail;
if (len == 0)
goto bail;
len /= sizeof(u32);
gids = kcalloc(len, sizeof(u32), GFP_KERNEL);
if (!gids) {
err = ENOMEM;
goto bail;
}
for (i = 0; i < len; i++) {
err = of_property_read_u32_index(dev->of_node, prop_name,
i, &gids[i]);
if (err) {
pr_err("Error: adsprpc: %s: failed to read GID %u\n",
__func__, i);
goto bail;
}
pr_info("adsprpc: %s: privileged GID: %u\n", __func__, gids[i]);
}
sort(gids, len, sizeof(*gids), uint_cmp_func, NULL);
gidlist->gids = gids;
gidlist->gidcount = len;
bail:
if (err)
kfree(gids);
}
static void configure_secure_channels(uint32_t secure_domains)
{
struct fastrpc_apps *me = &gfa;
@ -4610,7 +4729,8 @@ static int fastrpc_probe(struct platform_device *pdev)
"qcom,msm-fastrpc-compute")) {
init_secure_vmid_list(dev, "qcom,adsp-remoteheap-vmid",
&gcinfo[0].rhvm);
fastrpc_init_privileged_gids(dev, "qcom,fastrpc-gids",
&me->gidlist);
of_property_read_u32(dev->of_node, "qcom,rpc-latency-us",
&me->latency);
@ -4907,6 +5027,7 @@ static void __exit fastrpc_device_exit(void)
wakeup_source_unregister(me->wake_source);
if (me->wake_source_secure)
wakeup_source_unregister(me->wake_source_secure);
kfree(me->gidlist.gids);
debugfs_remove_recursive(debugfs_root);
}