xref: /openbmc/linux/security/apparmor/procattr.c (revision 1f2bc06a)
1b886d83cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
263e2b423SJohn Johansen /*
363e2b423SJohn Johansen  * AppArmor security module
463e2b423SJohn Johansen  *
563e2b423SJohn Johansen  * This file contains AppArmor /proc/<pid>/attr/ interface functions
663e2b423SJohn Johansen  *
763e2b423SJohn Johansen  * Copyright (C) 1998-2008 Novell/SUSE
863e2b423SJohn Johansen  * Copyright 2009-2010 Canonical Ltd.
963e2b423SJohn Johansen  */
1063e2b423SJohn Johansen 
1163e2b423SJohn Johansen #include "include/apparmor.h"
12d8889d49SJohn Johansen #include "include/cred.h"
1363e2b423SJohn Johansen #include "include/policy.h"
14cff281f6SJohn Johansen #include "include/policy_ns.h"
1563e2b423SJohn Johansen #include "include/domain.h"
16cc7db099SJames Morris #include "include/procattr.h"
1763e2b423SJohn Johansen 
1863e2b423SJohn Johansen 
1963e2b423SJohn Johansen /**
20*1f2bc06aSGaosheng Cui  * aa_getprocattr - Return the label information for @label
21*1f2bc06aSGaosheng Cui  * @label: the label to print label info about  (NOT NULL)
22*1f2bc06aSGaosheng Cui  * @string: Returns - string containing the label info (NOT NULL)
2363e2b423SJohn Johansen  *
24*1f2bc06aSGaosheng Cui  * Requires: label != NULL && string != NULL
2563e2b423SJohn Johansen  *
26*1f2bc06aSGaosheng Cui  * Creates a string containing the label information for @label.
2763e2b423SJohn Johansen  *
2863e2b423SJohn Johansen  * Returns: size of string placed in @string else error code on failure
2963e2b423SJohn Johansen  */
aa_getprocattr(struct aa_label * label,char ** string)3076a1d263SJohn Johansen int aa_getprocattr(struct aa_label *label, char **string)
3163e2b423SJohn Johansen {
3276a1d263SJohn Johansen 	struct aa_ns *ns = labels_ns(label);
33cf797c0eSJohn Johansen 	struct aa_ns *current_ns = aa_get_current_ns();
3476a1d263SJohn Johansen 	int len;
3563e2b423SJohn Johansen 
3676a1d263SJohn Johansen 	if (!aa_ns_visible(current_ns, ns, true)) {
37cf797c0eSJohn Johansen 		aa_put_ns(current_ns);
3876a1d263SJohn Johansen 		return -EACCES;
3976a1d263SJohn Johansen 	}
4063e2b423SJohn Johansen 
4176a1d263SJohn Johansen 	len = aa_label_snxprint(NULL, 0, current_ns, label,
4276a1d263SJohn Johansen 				FLAG_SHOW_MODE | FLAG_VIEW_SUBNS |
4376a1d263SJohn Johansen 				FLAG_HIDDEN_UNCONFINED);
4476a1d263SJohn Johansen 	AA_BUG(len < 0);
4576a1d263SJohn Johansen 
4676a1d263SJohn Johansen 	*string = kmalloc(len + 2, GFP_KERNEL);
4776a1d263SJohn Johansen 	if (!*string) {
4876a1d263SJohn Johansen 		aa_put_ns(current_ns);
4976a1d263SJohn Johansen 		return -ENOMEM;
5076a1d263SJohn Johansen 	}
5176a1d263SJohn Johansen 
5276a1d263SJohn Johansen 	len = aa_label_snxprint(*string, len + 2, current_ns, label,
5376a1d263SJohn Johansen 				FLAG_SHOW_MODE | FLAG_VIEW_SUBNS |
5476a1d263SJohn Johansen 				FLAG_HIDDEN_UNCONFINED);
5576a1d263SJohn Johansen 	if (len < 0) {
5676a1d263SJohn Johansen 		aa_put_ns(current_ns);
5763e2b423SJohn Johansen 		return len;
5863e2b423SJohn Johansen 	}
5963e2b423SJohn Johansen 
6076a1d263SJohn Johansen 	(*string)[len] = '\n';
6176a1d263SJohn Johansen 	(*string)[len + 1] = 0;
6276a1d263SJohn Johansen 
6376a1d263SJohn Johansen 	aa_put_ns(current_ns);
6476a1d263SJohn Johansen 	return len + 1;
6576a1d263SJohn Johansen }
6676a1d263SJohn Johansen 
6763e2b423SJohn Johansen /**
6863e2b423SJohn Johansen  * split_token_from_name - separate a string of form  <token>^<name>
6963e2b423SJohn Johansen  * @op: operation being checked
7063e2b423SJohn Johansen  * @args: string to parse  (NOT NULL)
7163e2b423SJohn Johansen  * @token: stores returned parsed token value  (NOT NULL)
7263e2b423SJohn Johansen  *
7363e2b423SJohn Johansen  * Returns: start position of name after token else NULL on failure
7463e2b423SJohn Johansen  */
split_token_from_name(const char * op,char * args,u64 * token)7547f6e5ccSJohn Johansen static char *split_token_from_name(const char *op, char *args, u64 *token)
7663e2b423SJohn Johansen {
7763e2b423SJohn Johansen 	char *name;
7863e2b423SJohn Johansen 
7963e2b423SJohn Johansen 	*token = simple_strtoull(args, &name, 16);
8063e2b423SJohn Johansen 	if ((name == args) || *name != '^') {
8147f6e5ccSJohn Johansen 		AA_ERROR("%s: Invalid input '%s'", op, args);
8263e2b423SJohn Johansen 		return ERR_PTR(-EINVAL);
8363e2b423SJohn Johansen 	}
8463e2b423SJohn Johansen 
8563e2b423SJohn Johansen 	name++;			/* skip ^ */
8663e2b423SJohn Johansen 	if (!*name)
8763e2b423SJohn Johansen 		name = NULL;
8863e2b423SJohn Johansen 	return name;
8963e2b423SJohn Johansen }
9063e2b423SJohn Johansen 
9163e2b423SJohn Johansen /**
92240516dfSYang Li  * aa_setprocattr_changehat - handle procattr interface to change_hat
9363e2b423SJohn Johansen  * @args: args received from writing to /proc/<pid>/attr/current (NOT NULL)
9463e2b423SJohn Johansen  * @size: size of the args
95df8073c6SJohn Johansen  * @flags: set of flags governing behavior
9663e2b423SJohn Johansen  *
9763e2b423SJohn Johansen  * Returns: %0 or error code if change_hat fails
9863e2b423SJohn Johansen  */
aa_setprocattr_changehat(char * args,size_t size,int flags)99df8073c6SJohn Johansen int aa_setprocattr_changehat(char *args, size_t size, int flags)
10063e2b423SJohn Johansen {
10163e2b423SJohn Johansen 	char *hat;
10263e2b423SJohn Johansen 	u64 token;
10363e2b423SJohn Johansen 	const char *hats[16];		/* current hard limit on # of names */
10463e2b423SJohn Johansen 	int count = 0;
10563e2b423SJohn Johansen 
10663e2b423SJohn Johansen 	hat = split_token_from_name(OP_CHANGE_HAT, args, &token);
10763e2b423SJohn Johansen 	if (IS_ERR(hat))
10863e2b423SJohn Johansen 		return PTR_ERR(hat);
10963e2b423SJohn Johansen 
11063e2b423SJohn Johansen 	if (!hat && !token) {
11163e2b423SJohn Johansen 		AA_ERROR("change_hat: Invalid input, NULL hat and NULL magic");
11263e2b423SJohn Johansen 		return -EINVAL;
11363e2b423SJohn Johansen 	}
11463e2b423SJohn Johansen 
11563e2b423SJohn Johansen 	if (hat) {
11663e2b423SJohn Johansen 		/* set up hat name vector, args guaranteed null terminated
11763e2b423SJohn Johansen 		 * at args[size] by setprocattr.
11863e2b423SJohn Johansen 		 *
11963e2b423SJohn Johansen 		 * If there are multiple hat names in the buffer each is
12063e2b423SJohn Johansen 		 * separated by a \0.  Ie. userspace writes them pre tokenized
12163e2b423SJohn Johansen 		 */
12263e2b423SJohn Johansen 		char *end = args + size;
12363e2b423SJohn Johansen 		for (count = 0; (hat < end) && count < 16; ++count) {
12463e2b423SJohn Johansen 			char *next = hat + strlen(hat) + 1;
12563e2b423SJohn Johansen 			hats[count] = hat;
126c3e1e584SJohn Johansen 			AA_DEBUG("%s: (pid %d) Magic 0x%llx count %d hat '%s'\n"
127c3e1e584SJohn Johansen 				 , __func__, current->pid, token, count, hat);
12863e2b423SJohn Johansen 			hat = next;
12963e2b423SJohn Johansen 		}
130c3e1e584SJohn Johansen 	} else
131c3e1e584SJohn Johansen 		AA_DEBUG("%s: (pid %d) Magic 0x%llx count %d Hat '%s'\n",
132c3e1e584SJohn Johansen 			 __func__, current->pid, token, count, "<NULL>");
13363e2b423SJohn Johansen 
134df8073c6SJohn Johansen 	return aa_change_hat(hats, count, token, flags);
13563e2b423SJohn Johansen }
136