Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0d234d7b authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

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

parents ff2b18c9 726e817a
Loading
Loading
Loading
Loading
+122 −1
Original line number Diff line number Diff line
@@ -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 @@ static int fastrpc_get_spd_session(char *name, int *session, int *cid)
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 @@ static void init_secure_vmid_list(struct device *dev, char *prop_name,
	}
}

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);
}