1419b0af8Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
2419b0af8Sopenharmony_ci/*
3419b0af8Sopenharmony_ci * drivers/auth_ctl/auth_ctrl.c
4419b0af8Sopenharmony_ci *
5419b0af8Sopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd.
6419b0af8Sopenharmony_ci *
7419b0af8Sopenharmony_ci */
8419b0af8Sopenharmony_ci
9419b0af8Sopenharmony_ci#include <linux/cred.h>
10419b0af8Sopenharmony_ci#include <linux/mutex.h>
11419b0af8Sopenharmony_ci#include <linux/errno.h>
12419b0af8Sopenharmony_ci#include <linux/fs.h>
13419b0af8Sopenharmony_ci#include <linux/miscdevice.h>
14419b0af8Sopenharmony_ci#include <linux/module.h>
15419b0af8Sopenharmony_ci#include <linux/sched.h>
16419b0af8Sopenharmony_ci#include <linux/kernel.h>
17419b0af8Sopenharmony_ci#include <linux/slab.h>
18419b0af8Sopenharmony_ci#include <linux/proc_fs.h>
19419b0af8Sopenharmony_ci#include <linux/seq_file.h>
20419b0af8Sopenharmony_ci#include <linux/sched/auth_ctrl.h>
21419b0af8Sopenharmony_ci#include <linux/sched/rtg_auth.h>
22419b0af8Sopenharmony_ci#include <linux/sched/qos_ctrl.h>
23419b0af8Sopenharmony_ci#include <linux/sched/qos_auth.h>
24419b0af8Sopenharmony_ci
25419b0af8Sopenharmony_ci#include "auth_ctrl.h"
26419b0af8Sopenharmony_ci#ifdef CONFIG_QOS_CTRL
27419b0af8Sopenharmony_ci#include "qos_ctrl.h"
28419b0af8Sopenharmony_ci#endif
29419b0af8Sopenharmony_ci
30419b0af8Sopenharmony_citypedef long (*auth_ctrl_func)(int abi, void __user *arg);
31419b0af8Sopenharmony_ci
32419b0af8Sopenharmony_cistatic long ctrl_auth_basic_operation(int abi, void __user *uarg);
33419b0af8Sopenharmony_ci
34419b0af8Sopenharmony_cistatic auth_ctrl_func g_func_array[AUTH_CTRL_MAX_NR] = {
35419b0af8Sopenharmony_ci	NULL, /* reserved */
36419b0af8Sopenharmony_ci	ctrl_auth_basic_operation,
37419b0af8Sopenharmony_ci};
38419b0af8Sopenharmony_ci
39419b0af8Sopenharmony_ci/*
40419b0af8Sopenharmony_ci * uid-based authority idr table
41419b0af8Sopenharmony_ci */
42419b0af8Sopenharmony_cistatic struct idr *ua_idr;
43419b0af8Sopenharmony_ci
44419b0af8Sopenharmony_cistruct idr *get_auth_ctrl_idr(void)
45419b0af8Sopenharmony_ci{
46419b0af8Sopenharmony_ci	return ua_idr;
47419b0af8Sopenharmony_ci}
48419b0af8Sopenharmony_ci
49419b0af8Sopenharmony_cistatic DEFINE_MUTEX(ua_idr_mutex);
50419b0af8Sopenharmony_ci
51419b0af8Sopenharmony_cistruct mutex *get_auth_idr_mutex(void)
52419b0af8Sopenharmony_ci{
53419b0af8Sopenharmony_ci	return &ua_idr_mutex;
54419b0af8Sopenharmony_ci}
55419b0af8Sopenharmony_ci
56419b0af8Sopenharmony_ci/*
57419b0af8Sopenharmony_ci * change auth's status to SYSTEM and enable all feature access
58419b0af8Sopenharmony_ci */
59419b0af8Sopenharmony_cistatic void change_to_super(struct auth_struct *auth)
60419b0af8Sopenharmony_ci{
61419b0af8Sopenharmony_ci#ifdef CONFIG_RTG_AUTHORITY
62419b0af8Sopenharmony_ci	auth->rtg_auth_flag = AF_RTG_ALL;
63419b0af8Sopenharmony_ci#endif
64419b0af8Sopenharmony_ci#ifdef CONFIG_QOS_AUTHORITY
65419b0af8Sopenharmony_ci	auth->qos_auth_flag = AF_QOS_ALL;
66419b0af8Sopenharmony_ci#endif
67419b0af8Sopenharmony_ci	auth->status = AUTH_STATUS_SYSTEM_SERVER;
68419b0af8Sopenharmony_ci}
69419b0af8Sopenharmony_ci
70419b0af8Sopenharmony_cistatic void init_authority_record(struct auth_struct *auth)
71419b0af8Sopenharmony_ci{
72419b0af8Sopenharmony_ci#ifdef CONFIG_QOS_AUTHORITY
73419b0af8Sopenharmony_ci	int i;
74419b0af8Sopenharmony_ci#endif
75419b0af8Sopenharmony_ci
76419b0af8Sopenharmony_ci#ifdef CONFIG_RTG_AUTHORITY
77419b0af8Sopenharmony_ci	auth->rtg_auth_flag = 0;
78419b0af8Sopenharmony_ci#endif
79419b0af8Sopenharmony_ci#ifdef CONFIG_QOS_AUTHORITY
80419b0af8Sopenharmony_ci	auth->qos_auth_flag = 0;
81419b0af8Sopenharmony_ci#endif
82419b0af8Sopenharmony_ci	auth->status = AUTH_STATUS_DISABLED;
83419b0af8Sopenharmony_ci	mutex_init(&auth->mutex);
84419b0af8Sopenharmony_ci	refcount_set(&auth->usage, 1);
85419b0af8Sopenharmony_ci#ifdef CONFIG_QOS_CTRL
86419b0af8Sopenharmony_ci	for (i = QOS_POLICY_MIN_LEVEL; i < NR_QOS; ++i) {
87419b0af8Sopenharmony_ci		INIT_LIST_HEAD(&auth->tasks[i]);
88419b0af8Sopenharmony_ci		auth->num[i] = 0;
89419b0af8Sopenharmony_ci	}
90419b0af8Sopenharmony_ci#endif
91419b0af8Sopenharmony_ci}
92419b0af8Sopenharmony_ci
93419b0af8Sopenharmony_civoid get_auth_struct(struct auth_struct *auth)
94419b0af8Sopenharmony_ci{
95419b0af8Sopenharmony_ci	refcount_inc(&auth->usage);
96419b0af8Sopenharmony_ci}
97419b0af8Sopenharmony_ci
98419b0af8Sopenharmony_cistatic void __put_auth_struct(struct auth_struct *auth)
99419b0af8Sopenharmony_ci
100419b0af8Sopenharmony_ci{
101419b0af8Sopenharmony_ci	WARN_ON(auth->status != AUTH_STATUS_DEAD);
102419b0af8Sopenharmony_ci	WARN_ON(refcount_read(&auth->usage));
103419b0af8Sopenharmony_ci
104419b0af8Sopenharmony_ci#ifdef CONFIG_QOS_CTRL
105419b0af8Sopenharmony_ci	/* refcount is zero here, no contend, no lock. */
106419b0af8Sopenharmony_ci	remove_qos_tasks(auth);
107419b0af8Sopenharmony_ci#endif
108419b0af8Sopenharmony_ci	kfree(auth);
109419b0af8Sopenharmony_ci}
110419b0af8Sopenharmony_ci
111419b0af8Sopenharmony_civoid put_auth_struct(struct auth_struct *auth)
112419b0af8Sopenharmony_ci{
113419b0af8Sopenharmony_ci	if (refcount_dec_and_test(&auth->usage))
114419b0af8Sopenharmony_ci		__put_auth_struct(auth);
115419b0af8Sopenharmony_ci}
116419b0af8Sopenharmony_ci
117419b0af8Sopenharmony_cistatic int init_ua_idr(void)
118419b0af8Sopenharmony_ci{
119419b0af8Sopenharmony_ci	ua_idr = kzalloc(sizeof(*ua_idr), GFP_ATOMIC);
120419b0af8Sopenharmony_ci	if (ua_idr == NULL) {
121419b0af8Sopenharmony_ci		pr_err("[AUTH_CTRL] auth idr init failed, no memory!\n");
122419b0af8Sopenharmony_ci		return -ENOMEM;
123419b0af8Sopenharmony_ci	}
124419b0af8Sopenharmony_ci
125419b0af8Sopenharmony_ci	idr_init(ua_idr);
126419b0af8Sopenharmony_ci
127419b0af8Sopenharmony_ci	return 0;
128419b0af8Sopenharmony_ci}
129419b0af8Sopenharmony_ci
130419b0af8Sopenharmony_cistatic int init_super_authority(unsigned int auth_tgid)
131419b0af8Sopenharmony_ci{
132419b0af8Sopenharmony_ci	int ret;
133419b0af8Sopenharmony_ci	struct auth_struct *auth_super;
134419b0af8Sopenharmony_ci
135419b0af8Sopenharmony_ci	auth_super = kzalloc(sizeof(*auth_super), GFP_ATOMIC);
136419b0af8Sopenharmony_ci	if(auth_super == NULL) {
137419b0af8Sopenharmony_ci		pr_err("[AUTH_CTRL] auth struct alloc failed\n");
138419b0af8Sopenharmony_ci		return -ENOMEM;
139419b0af8Sopenharmony_ci	}
140419b0af8Sopenharmony_ci	init_authority_record(auth_super);
141419b0af8Sopenharmony_ci	change_to_super(auth_super);
142419b0af8Sopenharmony_ci
143419b0af8Sopenharmony_ci	ret = idr_alloc(ua_idr, auth_super, auth_tgid, auth_tgid + 1, GFP_ATOMIC);
144419b0af8Sopenharmony_ci	if(ret != auth_tgid) {
145419b0af8Sopenharmony_ci		pr_err("[AUTH_CTRL] authority for super init failed! ret=%d\n", ret);
146419b0af8Sopenharmony_ci		kfree(auth_super);
147419b0af8Sopenharmony_ci		return ret;
148419b0af8Sopenharmony_ci	}
149419b0af8Sopenharmony_ci
150419b0af8Sopenharmony_ci	return 0;
151419b0af8Sopenharmony_ci}
152419b0af8Sopenharmony_ci
153419b0af8Sopenharmony_ciint authority_remove_handler(int id, void *p, void *para)
154419b0af8Sopenharmony_ci{
155419b0af8Sopenharmony_ci	struct auth_struct *auth = (struct auth_struct *)p;
156419b0af8Sopenharmony_ci
157419b0af8Sopenharmony_ci	mutex_lock(&auth->mutex);
158419b0af8Sopenharmony_ci#ifdef CONFIG_QOS_CTRL
159419b0af8Sopenharmony_ci	qos_switch(auth, AUTH_STATUS_DISABLED);
160419b0af8Sopenharmony_ci#endif
161419b0af8Sopenharmony_ci	auth->status = AUTH_STATUS_DEAD;
162419b0af8Sopenharmony_ci	mutex_unlock(&auth->mutex);
163419b0af8Sopenharmony_ci	put_auth_struct(auth);
164419b0af8Sopenharmony_ci
165419b0af8Sopenharmony_ci	return 0;
166419b0af8Sopenharmony_ci}
167419b0af8Sopenharmony_ci
168419b0af8Sopenharmony_civoid remove_authority_control(void)
169419b0af8Sopenharmony_ci{
170419b0af8Sopenharmony_ci	int ret;
171419b0af8Sopenharmony_ci
172419b0af8Sopenharmony_ci	mutex_lock(&ua_idr_mutex);
173419b0af8Sopenharmony_ci	ret = idr_for_each(ua_idr, authority_remove_handler, NULL);
174419b0af8Sopenharmony_ci	if (ret < 0)
175419b0af8Sopenharmony_ci		pr_err("[AUTH_CTRL] authority item remove failed\n");
176419b0af8Sopenharmony_ci
177419b0af8Sopenharmony_ci	idr_destroy(ua_idr);
178419b0af8Sopenharmony_ci	kfree(ua_idr);
179419b0af8Sopenharmony_ci
180419b0af8Sopenharmony_ci	mutex_unlock(&ua_idr_mutex);
181419b0af8Sopenharmony_ci}
182419b0af8Sopenharmony_ci
183419b0af8Sopenharmony_ci/*
184419b0af8Sopenharmony_ci * constrain user assigned auth_flag to kernel accepted auth_flag
185419b0af8Sopenharmony_ci */
186419b0af8Sopenharmony_cistatic int generic_auth_trim(unsigned int orig_flag, unsigned int constrain)
187419b0af8Sopenharmony_ci{
188419b0af8Sopenharmony_ci	return orig_flag & constrain;
189419b0af8Sopenharmony_ci}
190419b0af8Sopenharmony_ci
191419b0af8Sopenharmony_cistatic inline void set_auth_flag(struct auth_ctrl_data *data, struct auth_struct *auth_to_enable)
192419b0af8Sopenharmony_ci{
193419b0af8Sopenharmony_ci#ifdef CONFIG_RTG_AUTHORITY
194419b0af8Sopenharmony_ci	auth_to_enable->rtg_auth_flag = generic_auth_trim(data->rtg_ua_flag, AF_RTG_DELEGATED);
195419b0af8Sopenharmony_ci#endif
196419b0af8Sopenharmony_ci#ifdef CONFIG_QOS_AUTHORITY
197419b0af8Sopenharmony_ci	auth_to_enable->qos_auth_flag = generic_auth_trim(data->qos_ua_flag, AF_QOS_ALL);
198419b0af8Sopenharmony_ci#endif
199419b0af8Sopenharmony_ci}
200419b0af8Sopenharmony_ci
201419b0af8Sopenharmony_cistatic int auth_enable(struct auth_ctrl_data *data)
202419b0af8Sopenharmony_ci{
203419b0af8Sopenharmony_ci	struct auth_struct *auth_to_enable;
204419b0af8Sopenharmony_ci	unsigned int tgid = data->pid;
205419b0af8Sopenharmony_ci	int status = data->status;
206419b0af8Sopenharmony_ci	int ret;
207419b0af8Sopenharmony_ci
208419b0af8Sopenharmony_ci	mutex_lock(&ua_idr_mutex);
209419b0af8Sopenharmony_ci	auth_to_enable = idr_find(ua_idr, tgid);
210419b0af8Sopenharmony_ci	/* auth exist, just resume the task's qos request */
211419b0af8Sopenharmony_ci	if (auth_to_enable) {
212419b0af8Sopenharmony_ci		get_auth_struct(auth_to_enable);
213419b0af8Sopenharmony_ci		mutex_unlock(&ua_idr_mutex);
214419b0af8Sopenharmony_ci
215419b0af8Sopenharmony_ci		mutex_lock(&auth_to_enable->mutex);
216419b0af8Sopenharmony_ci		if (auth_to_enable->status == AUTH_STATUS_DEAD) {
217419b0af8Sopenharmony_ci			mutex_unlock(&auth_to_enable->mutex);
218419b0af8Sopenharmony_ci			put_auth_struct(auth_to_enable);
219419b0af8Sopenharmony_ci			return -INVALID_AUTH;
220419b0af8Sopenharmony_ci		}
221419b0af8Sopenharmony_ci
222419b0af8Sopenharmony_ci		set_auth_flag(data, auth_to_enable);
223419b0af8Sopenharmony_ci#ifdef CONFIG_QOS_CTRL
224419b0af8Sopenharmony_ci		qos_switch(auth_to_enable, status);
225419b0af8Sopenharmony_ci#endif
226419b0af8Sopenharmony_ci		auth_to_enable->status = status;
227419b0af8Sopenharmony_ci		mutex_unlock(&auth_to_enable->mutex);
228419b0af8Sopenharmony_ci		ret = 0;
229419b0af8Sopenharmony_ci		put_auth_struct(auth_to_enable);
230419b0af8Sopenharmony_ci		goto out;
231419b0af8Sopenharmony_ci	}
232419b0af8Sopenharmony_ci
233419b0af8Sopenharmony_ci	/* auth not exist, build a new auth, then insert to idr */
234419b0af8Sopenharmony_ci	auth_to_enable = kzalloc(sizeof(*auth_to_enable), GFP_ATOMIC);
235419b0af8Sopenharmony_ci	if (!auth_to_enable) {
236419b0af8Sopenharmony_ci		mutex_unlock(&ua_idr_mutex);
237419b0af8Sopenharmony_ci		pr_err("[AUTH_CTRL] alloc auth data failed, no memory!\n");
238419b0af8Sopenharmony_ci		ret = -ENOMEM;
239419b0af8Sopenharmony_ci		goto out;
240419b0af8Sopenharmony_ci	}
241419b0af8Sopenharmony_ci
242419b0af8Sopenharmony_ci	init_authority_record(auth_to_enable);
243419b0af8Sopenharmony_ci
244419b0af8Sopenharmony_ci	/* no one could get the auth from idr now, no need to lock */
245419b0af8Sopenharmony_ci	set_auth_flag(data, auth_to_enable);
246419b0af8Sopenharmony_ci	auth_to_enable->status = status;
247419b0af8Sopenharmony_ci
248419b0af8Sopenharmony_ci	ret = idr_alloc(ua_idr, auth_to_enable, tgid, tgid + 1, GFP_ATOMIC);
249419b0af8Sopenharmony_ci	if (ret < 0) {
250419b0af8Sopenharmony_ci		pr_err("[AUTH_CTRL] add auth to idr failed, no memory!\n");
251419b0af8Sopenharmony_ci		kfree(auth_to_enable);
252419b0af8Sopenharmony_ci	}
253419b0af8Sopenharmony_ci
254419b0af8Sopenharmony_ci	mutex_unlock(&ua_idr_mutex);
255419b0af8Sopenharmony_ci
256419b0af8Sopenharmony_ciout:
257419b0af8Sopenharmony_ci	return ret;
258419b0af8Sopenharmony_ci}
259419b0af8Sopenharmony_ci
260419b0af8Sopenharmony_cistatic int auth_delete(struct auth_ctrl_data *data)
261419b0af8Sopenharmony_ci{
262419b0af8Sopenharmony_ci	struct auth_struct *auth_to_delete;
263419b0af8Sopenharmony_ci	unsigned int tgid = data->pid;
264419b0af8Sopenharmony_ci
265419b0af8Sopenharmony_ci	mutex_lock(&ua_idr_mutex);
266419b0af8Sopenharmony_ci	auth_to_delete = (struct auth_struct *)idr_remove(ua_idr, tgid);
267419b0af8Sopenharmony_ci	if (!auth_to_delete) {
268419b0af8Sopenharmony_ci		mutex_unlock(&ua_idr_mutex);
269419b0af8Sopenharmony_ci		pr_err("[AUTH_CTRL] no auth data for this pid=%d, delete failed\n", tgid);
270419b0af8Sopenharmony_ci		return -PID_NOT_FOUND;
271419b0af8Sopenharmony_ci	}
272419b0af8Sopenharmony_ci	mutex_unlock(&ua_idr_mutex);
273419b0af8Sopenharmony_ci
274419b0af8Sopenharmony_ci	mutex_lock(&auth_to_delete->mutex);
275419b0af8Sopenharmony_ci#ifdef CONFIG_QOS_CTRL
276419b0af8Sopenharmony_ci	qos_switch(auth_to_delete, AUTH_STATUS_DISABLED);
277419b0af8Sopenharmony_ci#endif
278419b0af8Sopenharmony_ci	auth_to_delete->status = AUTH_STATUS_DEAD;
279419b0af8Sopenharmony_ci	mutex_unlock(&auth_to_delete->mutex);
280419b0af8Sopenharmony_ci
281419b0af8Sopenharmony_ci	put_auth_struct(auth_to_delete);
282419b0af8Sopenharmony_ci
283419b0af8Sopenharmony_ci	return 0;
284419b0af8Sopenharmony_ci}
285419b0af8Sopenharmony_ci
286419b0af8Sopenharmony_cistatic int auth_get(struct auth_ctrl_data *data)
287419b0af8Sopenharmony_ci{
288419b0af8Sopenharmony_ci	struct auth_struct *auth_to_get;
289419b0af8Sopenharmony_ci	unsigned int tgid = data->pid;
290419b0af8Sopenharmony_ci
291419b0af8Sopenharmony_ci	mutex_lock(&ua_idr_mutex);
292419b0af8Sopenharmony_ci	auth_to_get = idr_find(ua_idr, tgid);
293419b0af8Sopenharmony_ci	if (!auth_to_get) {
294419b0af8Sopenharmony_ci		mutex_unlock(&ua_idr_mutex);
295419b0af8Sopenharmony_ci		pr_err("[AUTH_CTRL] no auth data for this pid=%d to get\n", tgid);
296419b0af8Sopenharmony_ci		return -PID_NOT_FOUND;
297419b0af8Sopenharmony_ci	}
298419b0af8Sopenharmony_ci	get_auth_struct(auth_to_get);
299419b0af8Sopenharmony_ci	mutex_unlock(&ua_idr_mutex);
300419b0af8Sopenharmony_ci
301419b0af8Sopenharmony_ci	mutex_lock(&auth_to_get->mutex);
302419b0af8Sopenharmony_ci	if (auth_to_get->status == AUTH_STATUS_DEAD) {
303419b0af8Sopenharmony_ci		mutex_unlock(&auth_to_get->mutex);
304419b0af8Sopenharmony_ci		put_auth_struct(auth_to_get);
305419b0af8Sopenharmony_ci		return -INVALID_AUTH;
306419b0af8Sopenharmony_ci	}
307419b0af8Sopenharmony_ci#ifdef CONFIG_RTG_AUTHORITY
308419b0af8Sopenharmony_ci	data->rtg_ua_flag = auth_to_get->rtg_auth_flag;
309419b0af8Sopenharmony_ci#endif
310419b0af8Sopenharmony_ci#ifdef CONFIG_QOS_AUTHORITY
311419b0af8Sopenharmony_ci	data->qos_ua_flag = auth_to_get->qos_auth_flag;
312419b0af8Sopenharmony_ci#endif
313419b0af8Sopenharmony_ci	data->status = auth_to_get->status;
314419b0af8Sopenharmony_ci	mutex_unlock(&auth_to_get->mutex);
315419b0af8Sopenharmony_ci
316419b0af8Sopenharmony_ci	put_auth_struct(auth_to_get);
317419b0af8Sopenharmony_ci
318419b0af8Sopenharmony_ci	return 0;
319419b0af8Sopenharmony_ci}
320419b0af8Sopenharmony_ci
321419b0af8Sopenharmony_cistatic int auth_switch(struct auth_ctrl_data *data)
322419b0af8Sopenharmony_ci{
323419b0af8Sopenharmony_ci	struct auth_struct *auth;
324419b0af8Sopenharmony_ci	unsigned int tgid = data->pid;
325419b0af8Sopenharmony_ci	unsigned int status = data->status;
326419b0af8Sopenharmony_ci
327419b0af8Sopenharmony_ci	if (status == 0 || status >= AUTH_STATUS_MAX_NR) {
328419b0af8Sopenharmony_ci		pr_err("[AUTH_CTRL] not valied status %d\n", status);
329419b0af8Sopenharmony_ci		return -ARG_INVALID;
330419b0af8Sopenharmony_ci	}
331419b0af8Sopenharmony_ci
332419b0af8Sopenharmony_ci	mutex_lock(&ua_idr_mutex);
333419b0af8Sopenharmony_ci	auth = idr_find(ua_idr, tgid);
334419b0af8Sopenharmony_ci	if (!auth) {
335419b0af8Sopenharmony_ci		mutex_unlock(&ua_idr_mutex);
336419b0af8Sopenharmony_ci		pr_err("[AUTH_CTRL] no auth data for this pid=%d to switch\n", tgid);
337419b0af8Sopenharmony_ci		return -PID_NOT_FOUND;
338419b0af8Sopenharmony_ci	}
339419b0af8Sopenharmony_ci	get_auth_struct(auth);
340419b0af8Sopenharmony_ci	mutex_unlock(&ua_idr_mutex);
341419b0af8Sopenharmony_ci
342419b0af8Sopenharmony_ci	mutex_lock(&auth->mutex);
343419b0af8Sopenharmony_ci	if (auth->status == AUTH_STATUS_DEAD) {
344419b0af8Sopenharmony_ci		mutex_unlock(&auth->mutex);
345419b0af8Sopenharmony_ci		put_auth_struct(auth);
346419b0af8Sopenharmony_ci		return -INVALID_AUTH;
347419b0af8Sopenharmony_ci	}
348419b0af8Sopenharmony_ci
349419b0af8Sopenharmony_ci	set_auth_flag(data, auth);
350419b0af8Sopenharmony_ci#ifdef CONFIG_QOS_CTRL
351419b0af8Sopenharmony_ci	qos_switch(auth, status);
352419b0af8Sopenharmony_ci#endif
353419b0af8Sopenharmony_ci	auth->status = status;
354419b0af8Sopenharmony_ci	mutex_unlock(&auth->mutex);
355419b0af8Sopenharmony_ci
356419b0af8Sopenharmony_ci	put_auth_struct(auth);
357419b0af8Sopenharmony_ci
358419b0af8Sopenharmony_ci	return 0;
359419b0af8Sopenharmony_ci}
360419b0af8Sopenharmony_ci
361419b0af8Sopenharmony_citypedef int (*auth_manipulate_func)(struct auth_ctrl_data *data);
362419b0af8Sopenharmony_ci
363419b0af8Sopenharmony_cistatic auth_manipulate_func auth_func_array[AUTH_MAX_NR] = {
364419b0af8Sopenharmony_ci	/*
365419b0af8Sopenharmony_ci	 * auth_enable: Start authority control for specific tgid.
366419b0af8Sopenharmony_ci	 * auth_delte:  End authroity control, remove statistic datas.
367419b0af8Sopenharmony_ci	 * auth_get:    Get auth info, deprecated.
368419b0af8Sopenharmony_ci	 * auth_switch: Change authority flag and status for specific tgid.
369419b0af8Sopenharmony_ci	 */
370419b0af8Sopenharmony_ci	NULL,
371419b0af8Sopenharmony_ci	auth_enable,
372419b0af8Sopenharmony_ci	auth_delete,
373419b0af8Sopenharmony_ci	auth_get,
374419b0af8Sopenharmony_ci	auth_switch,
375419b0af8Sopenharmony_ci};
376419b0af8Sopenharmony_ci
377419b0af8Sopenharmony_cistatic long do_auth_manipulate(struct auth_ctrl_data *data)
378419b0af8Sopenharmony_ci{
379419b0af8Sopenharmony_ci	long ret = 0;
380419b0af8Sopenharmony_ci	unsigned int type = data->type;
381419b0af8Sopenharmony_ci
382419b0af8Sopenharmony_ci	if (type >= AUTH_MAX_NR) {
383419b0af8Sopenharmony_ci		pr_err("[AUTH_CTRL] BASIC_AUTH_CTRL_OPERATION type not valid\n");
384419b0af8Sopenharmony_ci		return -ARG_INVALID;
385419b0af8Sopenharmony_ci	}
386419b0af8Sopenharmony_ci
387419b0af8Sopenharmony_ci	if (auth_func_array[type])
388419b0af8Sopenharmony_ci		ret = (long)(*auth_func_array[type])(data);
389419b0af8Sopenharmony_ci
390419b0af8Sopenharmony_ci	return ret;
391419b0af8Sopenharmony_ci}
392419b0af8Sopenharmony_ci
393419b0af8Sopenharmony_cistatic long ctrl_auth_basic_operation(int abi, void __user *uarg)
394419b0af8Sopenharmony_ci{
395419b0af8Sopenharmony_ci	struct auth_ctrl_data auth_data;
396419b0af8Sopenharmony_ci	long ret = -1;
397419b0af8Sopenharmony_ci
398419b0af8Sopenharmony_ci#pragma GCC diagnostic push
399419b0af8Sopenharmony_ci#pragma GCC diagnostic ignored "-Wpointer-to-int-cast"
400419b0af8Sopenharmony_ci
401419b0af8Sopenharmony_ci	switch (abi) {
402419b0af8Sopenharmony_ci	case AUTH_IOCTL_ABI_ARM32:
403419b0af8Sopenharmony_ci		ret = copy_from_user(&auth_data,
404419b0af8Sopenharmony_ci				(void __user *)compat_ptr((compat_uptr_t)uarg),
405419b0af8Sopenharmony_ci				sizeof(struct auth_ctrl_data));
406419b0af8Sopenharmony_ci		break;
407419b0af8Sopenharmony_ci	case AUTH_IOCTL_ABI_AARCH64:
408419b0af8Sopenharmony_ci		ret = copy_from_user(&auth_data, uarg, sizeof(struct auth_ctrl_data));
409419b0af8Sopenharmony_ci		break;
410419b0af8Sopenharmony_ci	default:
411419b0af8Sopenharmony_ci		pr_err("[AUTH_CTRL] abi format error\n");
412419b0af8Sopenharmony_ci		break;
413419b0af8Sopenharmony_ci	}
414419b0af8Sopenharmony_ci
415419b0af8Sopenharmony_ci#pragma GCC diagnostic pop
416419b0af8Sopenharmony_ci
417419b0af8Sopenharmony_ci	if (ret) {
418419b0af8Sopenharmony_ci		pr_err("[AUTH_RTG] %s copy user data failed\n", __func__);
419419b0af8Sopenharmony_ci		return ret;
420419b0af8Sopenharmony_ci	}
421419b0af8Sopenharmony_ci
422419b0af8Sopenharmony_ci	ret = do_auth_manipulate(&auth_data);
423419b0af8Sopenharmony_ci	if (ret < 0) {
424419b0af8Sopenharmony_ci		pr_err("[AUTH_CTRL] BASIC_AUTH_CTRL_OPERATION failed\n");
425419b0af8Sopenharmony_ci		return ret;
426419b0af8Sopenharmony_ci	}
427419b0af8Sopenharmony_ci
428419b0af8Sopenharmony_ci#pragma GCC diagnostic push
429419b0af8Sopenharmony_ci#pragma GCC diagnostic ignored "-Wpointer-to-int-cast"
430419b0af8Sopenharmony_ci
431419b0af8Sopenharmony_ci	switch (abi) {
432419b0af8Sopenharmony_ci	case AUTH_IOCTL_ABI_ARM32:
433419b0af8Sopenharmony_ci		ret = copy_to_user((void __user *)compat_ptr((compat_uptr_t)uarg),
434419b0af8Sopenharmony_ci				&auth_data,
435419b0af8Sopenharmony_ci				sizeof(struct auth_ctrl_data));
436419b0af8Sopenharmony_ci		break;
437419b0af8Sopenharmony_ci	case AUTH_IOCTL_ABI_AARCH64:
438419b0af8Sopenharmony_ci		ret = copy_to_user(uarg, &auth_data, sizeof(struct auth_ctrl_data));
439419b0af8Sopenharmony_ci		break;
440419b0af8Sopenharmony_ci	default:
441419b0af8Sopenharmony_ci		pr_err("[AUTH_CTRL] abi format error\n");
442419b0af8Sopenharmony_ci		break;
443419b0af8Sopenharmony_ci	}
444419b0af8Sopenharmony_ci
445419b0af8Sopenharmony_ci#pragma GCC diagnostic pop
446419b0af8Sopenharmony_ci
447419b0af8Sopenharmony_ci	if (ret) {
448419b0af8Sopenharmony_ci		pr_err("[AUTH_RTG] %s copy user data failed\n", __func__);
449419b0af8Sopenharmony_ci		return ret;
450419b0af8Sopenharmony_ci	}
451419b0af8Sopenharmony_ci
452419b0af8Sopenharmony_ci	return 0;
453419b0af8Sopenharmony_ci}
454419b0af8Sopenharmony_ci
455419b0af8Sopenharmony_cilong do_auth_ctrl_ioctl(int abi, struct file *file, unsigned int cmd, unsigned long arg)
456419b0af8Sopenharmony_ci{
457419b0af8Sopenharmony_ci	void __user *uarg = (void __user *)arg;
458419b0af8Sopenharmony_ci	unsigned int func_cmd = _IOC_NR(cmd);
459419b0af8Sopenharmony_ci
460419b0af8Sopenharmony_ci	if (uarg == NULL) {
461419b0af8Sopenharmony_ci		pr_err("%s: invalid user uarg\n", __func__);
462419b0af8Sopenharmony_ci		return -EINVAL;
463419b0af8Sopenharmony_ci	}
464419b0af8Sopenharmony_ci
465419b0af8Sopenharmony_ci	if (_IOC_TYPE(cmd) != AUTH_CTRL_IPC_MAGIG) {
466419b0af8Sopenharmony_ci		pr_err("%s: authority ctrl magic fail, TYPE=%d\n",
467419b0af8Sopenharmony_ci		       __func__, _IOC_TYPE(cmd));
468419b0af8Sopenharmony_ci		return -EINVAL;
469419b0af8Sopenharmony_ci	}
470419b0af8Sopenharmony_ci
471419b0af8Sopenharmony_ci	if (func_cmd >= AUTH_CTRL_MAX_NR) {
472419b0af8Sopenharmony_ci		pr_err("%s: authority ctrl cmd error, cmd:%d\n",
473419b0af8Sopenharmony_ci		       __func__, _IOC_TYPE(cmd));
474419b0af8Sopenharmony_ci		return -EINVAL;
475419b0af8Sopenharmony_ci	}
476419b0af8Sopenharmony_ci
477419b0af8Sopenharmony_ci	if (g_func_array[func_cmd])
478419b0af8Sopenharmony_ci		return (*g_func_array[func_cmd])(abi, uarg);
479419b0af8Sopenharmony_ci
480419b0af8Sopenharmony_ci	return -EINVAL;
481419b0af8Sopenharmony_ci}
482419b0af8Sopenharmony_ci
483419b0af8Sopenharmony_ci#define get_authority_flag(func_id)	(1 << (func_id - 1))
484419b0af8Sopenharmony_ci
485419b0af8Sopenharmony_cistatic inline unsigned int get_true_uid(struct task_struct *p)
486419b0af8Sopenharmony_ci{
487419b0af8Sopenharmony_ci	if (!p)
488419b0af8Sopenharmony_ci		return get_uid(current_user())->uid.val;
489419b0af8Sopenharmony_ci
490419b0af8Sopenharmony_ci	return task_uid(p).val;
491419b0af8Sopenharmony_ci}
492419b0af8Sopenharmony_ci
493419b0af8Sopenharmony_ci/*
494419b0af8Sopenharmony_ci * Return 1000 for both SYSTEM and ROOT
495419b0af8Sopenharmony_ci * Return current's uid if p is NULL
496419b0af8Sopenharmony_ci */
497419b0af8Sopenharmony_cistatic inline unsigned int get_authority_uid(struct task_struct *p)
498419b0af8Sopenharmony_ci{
499419b0af8Sopenharmony_ci	unsigned int uid = get_true_uid(p);
500419b0af8Sopenharmony_ci
501419b0af8Sopenharmony_ci	if (super_uid(uid))
502419b0af8Sopenharmony_ci		uid = SUPER_UID;
503419b0af8Sopenharmony_ci
504419b0af8Sopenharmony_ci	return uid;
505419b0af8Sopenharmony_ci}
506419b0af8Sopenharmony_ci
507419b0af8Sopenharmony_cistatic unsigned int auth_flag(struct auth_struct *auth, unsigned int type)
508419b0af8Sopenharmony_ci{
509419b0af8Sopenharmony_ci	switch (type) {
510419b0af8Sopenharmony_ci#ifdef CONFIG_RTG_AUTHORITY
511419b0af8Sopenharmony_ci	case RTG_AUTH_FLAG:
512419b0af8Sopenharmony_ci		return auth->rtg_auth_flag;
513419b0af8Sopenharmony_ci#endif
514419b0af8Sopenharmony_ci#ifdef CONFIG_QOS_AUTHORITY
515419b0af8Sopenharmony_ci	case QOS_AUTH_FLAG:
516419b0af8Sopenharmony_ci		return auth->qos_auth_flag;
517419b0af8Sopenharmony_ci#endif
518419b0af8Sopenharmony_ci	default:
519419b0af8Sopenharmony_ci		pr_err("[AUTH_CTRL] not valid auth type\n");
520419b0af8Sopenharmony_ci		return INVALIED_AUTH_FLAG;
521419b0af8Sopenharmony_ci	}
522419b0af8Sopenharmony_ci}
523419b0af8Sopenharmony_ci
524419b0af8Sopenharmony_cibool check_authorized(unsigned int func_id, unsigned int type)
525419b0af8Sopenharmony_ci{
526419b0af8Sopenharmony_ci	bool authorized = false;
527419b0af8Sopenharmony_ci	struct auth_struct *auth;
528419b0af8Sopenharmony_ci	unsigned int af = get_authority_flag(func_id);
529419b0af8Sopenharmony_ci	unsigned int uid = get_authority_uid(NULL);
530419b0af8Sopenharmony_ci	unsigned int tgid = task_tgid_nr(current);
531419b0af8Sopenharmony_ci
532419b0af8Sopenharmony_ci	mutex_lock(&ua_idr_mutex);
533419b0af8Sopenharmony_ci	if (!ua_idr) {
534419b0af8Sopenharmony_ci		mutex_unlock(&ua_idr_mutex);
535419b0af8Sopenharmony_ci		pr_err("[AUTH_CTRL] authority idr table missed, auth failed\n");
536419b0af8Sopenharmony_ci		return authorized;
537419b0af8Sopenharmony_ci	}
538419b0af8Sopenharmony_ci
539419b0af8Sopenharmony_ci	auth = (struct auth_struct *)idr_find(ua_idr, tgid);
540419b0af8Sopenharmony_ci	if (!auth) {
541419b0af8Sopenharmony_ci		if (uid != SUPER_UID) {
542419b0af8Sopenharmony_ci			mutex_unlock(&ua_idr_mutex);
543419b0af8Sopenharmony_ci			pr_err("[AUTH_CTRL] no auth data for this pid = %d\n, tgid");
544419b0af8Sopenharmony_ci			return authorized;
545419b0af8Sopenharmony_ci		} else if (init_super_authority(tgid)) {
546419b0af8Sopenharmony_ci			mutex_unlock(&ua_idr_mutex);
547419b0af8Sopenharmony_ci			pr_err("[AUTH_CTRL] init super authority failed\n");
548419b0af8Sopenharmony_ci			return authorized;
549419b0af8Sopenharmony_ci		}
550419b0af8Sopenharmony_ci
551419b0af8Sopenharmony_ci		//the auth must exist
552419b0af8Sopenharmony_ci		auth = (struct auth_struct *)idr_find(ua_idr, tgid);
553419b0af8Sopenharmony_ci		if (!auth)
554419b0af8Sopenharmony_ci			return authorized;
555419b0af8Sopenharmony_ci	}
556419b0af8Sopenharmony_ci
557419b0af8Sopenharmony_ci	get_auth_struct(auth);
558419b0af8Sopenharmony_ci	mutex_unlock(&ua_idr_mutex);
559419b0af8Sopenharmony_ci
560419b0af8Sopenharmony_ci	mutex_lock(&auth->mutex);
561419b0af8Sopenharmony_ci	if (auth->status == AUTH_STATUS_DEAD) {
562419b0af8Sopenharmony_ci		mutex_unlock(&auth->mutex);
563419b0af8Sopenharmony_ci		pr_info("[AUTH_CTRL] not valid auth for pid %d\n", tgid);
564419b0af8Sopenharmony_ci		put_auth_struct(auth);
565419b0af8Sopenharmony_ci		return authorized;
566419b0af8Sopenharmony_ci	}
567419b0af8Sopenharmony_ci	if (auth && (auth_flag(auth, type) & af))
568419b0af8Sopenharmony_ci		authorized = true;
569419b0af8Sopenharmony_ci
570419b0af8Sopenharmony_ci	mutex_unlock(&auth->mutex);
571419b0af8Sopenharmony_ci
572419b0af8Sopenharmony_ci	put_auth_struct(auth);
573419b0af8Sopenharmony_ci
574419b0af8Sopenharmony_ci	return authorized;
575419b0af8Sopenharmony_ci}
576419b0af8Sopenharmony_ci
577419b0af8Sopenharmony_ci/*
578419b0af8Sopenharmony_ci * Return authority info for given task
579419b0af8Sopenharmony_ci * return current's auth if p is NULL
580419b0af8Sopenharmony_ci * refcount will inc if this call return the valid auth
581419b0af8Sopenharmony_ci * make sure to call put_auth_struct before the calling end
582419b0af8Sopenharmony_ci */
583419b0af8Sopenharmony_cistruct auth_struct *get_authority(struct task_struct *p)
584419b0af8Sopenharmony_ci{
585419b0af8Sopenharmony_ci	unsigned int tgid;
586419b0af8Sopenharmony_ci	struct auth_struct *auth;
587419b0af8Sopenharmony_ci
588419b0af8Sopenharmony_ci	tgid = (p == NULL ? current->tgid : p->tgid);
589419b0af8Sopenharmony_ci
590419b0af8Sopenharmony_ci	mutex_lock(&ua_idr_mutex);
591419b0af8Sopenharmony_ci	auth = idr_find(ua_idr, tgid);
592419b0af8Sopenharmony_ci	if (auth)
593419b0af8Sopenharmony_ci		get_auth_struct(auth);
594419b0af8Sopenharmony_ci
595419b0af8Sopenharmony_ci	mutex_unlock(&ua_idr_mutex);
596419b0af8Sopenharmony_ci
597419b0af8Sopenharmony_ci	return auth;
598419b0af8Sopenharmony_ci}
599419b0af8Sopenharmony_ci
600419b0af8Sopenharmony_cilong proc_auth_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
601419b0af8Sopenharmony_ci{
602419b0af8Sopenharmony_ci	return do_auth_ctrl_ioctl(AUTH_IOCTL_ABI_AARCH64, file, cmd, arg);
603419b0af8Sopenharmony_ci}
604419b0af8Sopenharmony_ci
605419b0af8Sopenharmony_ci#ifdef CONFIG_COMPAT
606419b0af8Sopenharmony_cilong proc_auth_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
607419b0af8Sopenharmony_ci{
608419b0af8Sopenharmony_ci	return do_auth_ctrl_ioctl(AUTH_IOCTL_ABI_ARM32, file, cmd,
609419b0af8Sopenharmony_ci				(unsigned long)(compat_ptr((compat_uptr_t)arg)));
610419b0af8Sopenharmony_ci}
611419b0af8Sopenharmony_ci#endif
612419b0af8Sopenharmony_ci
613419b0af8Sopenharmony_cistatic const struct file_operations auth_ctrl_fops = {
614419b0af8Sopenharmony_ci	.owner		= THIS_MODULE,
615419b0af8Sopenharmony_ci	.unlocked_ioctl = proc_auth_ioctl,
616419b0af8Sopenharmony_ci#ifdef CONFIG_COMPAT
617419b0af8Sopenharmony_ci	.compat_ioctl   = proc_auth_compat_ioctl,
618419b0af8Sopenharmony_ci#endif
619419b0af8Sopenharmony_ci};
620419b0af8Sopenharmony_ci
621419b0af8Sopenharmony_cistatic struct miscdevice auth_ctrl_device = {
622419b0af8Sopenharmony_ci	.minor		= MISC_DYNAMIC_MINOR,
623419b0af8Sopenharmony_ci	.name		= "auth_ctrl",
624419b0af8Sopenharmony_ci	.fops		= &auth_ctrl_fops,
625419b0af8Sopenharmony_ci};
626419b0af8Sopenharmony_ci
627419b0af8Sopenharmony_cistatic __init int auth_ctrl_init_module(void)
628419b0af8Sopenharmony_ci{
629419b0af8Sopenharmony_ci	int err;
630419b0af8Sopenharmony_ci
631419b0af8Sopenharmony_ci	err = misc_register(&auth_ctrl_device);
632419b0af8Sopenharmony_ci	if (err < 0) {
633419b0af8Sopenharmony_ci		pr_err("auth_ctrl register failed\n");
634419b0af8Sopenharmony_ci		return err;
635419b0af8Sopenharmony_ci	}
636419b0af8Sopenharmony_ci
637419b0af8Sopenharmony_ci	pr_info("auth_ctrl init success\n");
638419b0af8Sopenharmony_ci
639419b0af8Sopenharmony_ci	BUG_ON(init_ua_idr());
640419b0af8Sopenharmony_ci
641419b0af8Sopenharmony_ci#ifdef CONFIG_QOS_CTRL
642419b0af8Sopenharmony_ci	init_qos_ctrl();
643419b0af8Sopenharmony_ci#endif
644419b0af8Sopenharmony_ci
645419b0af8Sopenharmony_ci	init_sched_auth_debug_procfs();
646419b0af8Sopenharmony_ci
647419b0af8Sopenharmony_ci	return 0;
648419b0af8Sopenharmony_ci}
649419b0af8Sopenharmony_ci
650419b0af8Sopenharmony_cistatic void auth_ctrl_exit_module(void)
651419b0af8Sopenharmony_ci{
652419b0af8Sopenharmony_ci	remove_authority_control();
653419b0af8Sopenharmony_ci	misc_deregister(&auth_ctrl_device);
654419b0af8Sopenharmony_ci}
655419b0af8Sopenharmony_ci
656419b0af8Sopenharmony_ci/* module entry points */
657419b0af8Sopenharmony_cimodule_init(auth_ctrl_init_module);
658419b0af8Sopenharmony_cimodule_exit(auth_ctrl_exit_module);
659419b0af8Sopenharmony_ci
660419b0af8Sopenharmony_ciMODULE_LICENSE("GPL v2");
661419b0af8Sopenharmony_ci
662