18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * AppArmor security module 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This file contains AppArmor /proc/<pid>/attr/ interface functions 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 1998-2008 Novell/SUSE 88c2ecf20Sopenharmony_ci * Copyright 2009-2010 Canonical Ltd. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "include/apparmor.h" 128c2ecf20Sopenharmony_ci#include "include/cred.h" 138c2ecf20Sopenharmony_ci#include "include/policy.h" 148c2ecf20Sopenharmony_ci#include "include/policy_ns.h" 158c2ecf20Sopenharmony_ci#include "include/domain.h" 168c2ecf20Sopenharmony_ci#include "include/procattr.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/** 208c2ecf20Sopenharmony_ci * aa_getprocattr - Return the profile information for @profile 218c2ecf20Sopenharmony_ci * @profile: the profile to print profile info about (NOT NULL) 228c2ecf20Sopenharmony_ci * @string: Returns - string containing the profile info (NOT NULL) 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * Returns: length of @string on success else error on failure 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * Requires: profile != NULL 278c2ecf20Sopenharmony_ci * 288c2ecf20Sopenharmony_ci * Creates a string containing the namespace_name://profile_name for 298c2ecf20Sopenharmony_ci * @profile. 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * Returns: size of string placed in @string else error code on failure 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_ciint aa_getprocattr(struct aa_label *label, char **string) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci struct aa_ns *ns = labels_ns(label); 368c2ecf20Sopenharmony_ci struct aa_ns *current_ns = aa_get_current_ns(); 378c2ecf20Sopenharmony_ci int len; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci if (!aa_ns_visible(current_ns, ns, true)) { 408c2ecf20Sopenharmony_ci aa_put_ns(current_ns); 418c2ecf20Sopenharmony_ci return -EACCES; 428c2ecf20Sopenharmony_ci } 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci len = aa_label_snxprint(NULL, 0, current_ns, label, 458c2ecf20Sopenharmony_ci FLAG_SHOW_MODE | FLAG_VIEW_SUBNS | 468c2ecf20Sopenharmony_ci FLAG_HIDDEN_UNCONFINED); 478c2ecf20Sopenharmony_ci AA_BUG(len < 0); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci *string = kmalloc(len + 2, GFP_KERNEL); 508c2ecf20Sopenharmony_ci if (!*string) { 518c2ecf20Sopenharmony_ci aa_put_ns(current_ns); 528c2ecf20Sopenharmony_ci return -ENOMEM; 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci len = aa_label_snxprint(*string, len + 2, current_ns, label, 568c2ecf20Sopenharmony_ci FLAG_SHOW_MODE | FLAG_VIEW_SUBNS | 578c2ecf20Sopenharmony_ci FLAG_HIDDEN_UNCONFINED); 588c2ecf20Sopenharmony_ci if (len < 0) { 598c2ecf20Sopenharmony_ci aa_put_ns(current_ns); 608c2ecf20Sopenharmony_ci return len; 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci (*string)[len] = '\n'; 648c2ecf20Sopenharmony_ci (*string)[len + 1] = 0; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci aa_put_ns(current_ns); 678c2ecf20Sopenharmony_ci return len + 1; 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/** 718c2ecf20Sopenharmony_ci * split_token_from_name - separate a string of form <token>^<name> 728c2ecf20Sopenharmony_ci * @op: operation being checked 738c2ecf20Sopenharmony_ci * @args: string to parse (NOT NULL) 748c2ecf20Sopenharmony_ci * @token: stores returned parsed token value (NOT NULL) 758c2ecf20Sopenharmony_ci * 768c2ecf20Sopenharmony_ci * Returns: start position of name after token else NULL on failure 778c2ecf20Sopenharmony_ci */ 788c2ecf20Sopenharmony_cistatic char *split_token_from_name(const char *op, char *args, u64 *token) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci char *name; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci *token = simple_strtoull(args, &name, 16); 838c2ecf20Sopenharmony_ci if ((name == args) || *name != '^') { 848c2ecf20Sopenharmony_ci AA_ERROR("%s: Invalid input '%s'", op, args); 858c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci name++; /* skip ^ */ 898c2ecf20Sopenharmony_ci if (!*name) 908c2ecf20Sopenharmony_ci name = NULL; 918c2ecf20Sopenharmony_ci return name; 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci/** 958c2ecf20Sopenharmony_ci * aa_setprocattr_chagnehat - handle procattr interface to change_hat 968c2ecf20Sopenharmony_ci * @args: args received from writing to /proc/<pid>/attr/current (NOT NULL) 978c2ecf20Sopenharmony_ci * @size: size of the args 988c2ecf20Sopenharmony_ci * @flags: set of flags governing behavior 998c2ecf20Sopenharmony_ci * 1008c2ecf20Sopenharmony_ci * Returns: %0 or error code if change_hat fails 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_ciint aa_setprocattr_changehat(char *args, size_t size, int flags) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci char *hat; 1058c2ecf20Sopenharmony_ci u64 token; 1068c2ecf20Sopenharmony_ci const char *hats[16]; /* current hard limit on # of names */ 1078c2ecf20Sopenharmony_ci int count = 0; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci hat = split_token_from_name(OP_CHANGE_HAT, args, &token); 1108c2ecf20Sopenharmony_ci if (IS_ERR(hat)) 1118c2ecf20Sopenharmony_ci return PTR_ERR(hat); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci if (!hat && !token) { 1148c2ecf20Sopenharmony_ci AA_ERROR("change_hat: Invalid input, NULL hat and NULL magic"); 1158c2ecf20Sopenharmony_ci return -EINVAL; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci if (hat) { 1198c2ecf20Sopenharmony_ci /* set up hat name vector, args guaranteed null terminated 1208c2ecf20Sopenharmony_ci * at args[size] by setprocattr. 1218c2ecf20Sopenharmony_ci * 1228c2ecf20Sopenharmony_ci * If there are multiple hat names in the buffer each is 1238c2ecf20Sopenharmony_ci * separated by a \0. Ie. userspace writes them pre tokenized 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_ci char *end = args + size; 1268c2ecf20Sopenharmony_ci for (count = 0; (hat < end) && count < 16; ++count) { 1278c2ecf20Sopenharmony_ci char *next = hat + strlen(hat) + 1; 1288c2ecf20Sopenharmony_ci hats[count] = hat; 1298c2ecf20Sopenharmony_ci AA_DEBUG("%s: (pid %d) Magic 0x%llx count %d hat '%s'\n" 1308c2ecf20Sopenharmony_ci , __func__, current->pid, token, count, hat); 1318c2ecf20Sopenharmony_ci hat = next; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci } else 1348c2ecf20Sopenharmony_ci AA_DEBUG("%s: (pid %d) Magic 0x%llx count %d Hat '%s'\n", 1358c2ecf20Sopenharmony_ci __func__, current->pid, token, count, "<NULL>"); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci return aa_change_hat(hats, count, token, flags); 1388c2ecf20Sopenharmony_ci} 139