From 726e817aae1e70391b8719a47ee786462f48a261 Mon Sep 17 00:00:00 2001 From: Edgar Flores Date: Fri, 24 Jan 2020 14:14:39 -0800 Subject: [PATCH] msm: adsprpc: detect privileged processes based on group ID Detect if the process is privileged by comparing its group ID with an internal list obtained from the device-tree. Update the process attributes sent to the remote subsystem accordingly. Change-Id: I8d7b6824762b934ca6bd9a5d2420dc0dd49b7e6d Acked-by: Thyagarajan Venkatanarayanan Signed-off-by: Edgar Flores --- drivers/char/adsprpc.c | 123 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 122 insertions(+), 1 deletion(-) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 54f137a3f78a..5b11f99c087b 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #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 { @@ -359,6 +368,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 { @@ -442,6 +452,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; @@ -1192,7 +1203,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); @@ -2333,6 +2369,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) { @@ -2411,6 +2463,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; @@ -3469,6 +3523,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); @@ -3873,6 +3928,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; @@ -3881,6 +3964,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); @@ -4555,6 +4639,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; @@ -4587,7 +4706,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); @@ -4884,6 +5004,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); }