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