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