procattr.c 4.2 KB
Newer Older
J
John Johansen 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * AppArmor security module
 *
 * This file contains AppArmor /proc/<pid>/attr/ interface functions
 *
 * Copyright (C) 1998-2008 Novell/SUSE
 * Copyright 2009-2010 Canonical Ltd.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, version 2 of the
 * License.
 */

#include "include/apparmor.h"
#include "include/context.h"
#include "include/policy.h"
18
#include "include/policy_ns.h"
J
John Johansen 已提交
19
#include "include/domain.h"
20
#include "include/procattr.h"
J
John Johansen 已提交
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40


/**
 * aa_getprocattr - Return the profile information for @profile
 * @profile: the profile to print profile info about  (NOT NULL)
 * @string: Returns - string containing the profile info (NOT NULL)
 *
 * Returns: length of @string on success else error on failure
 *
 * Requires: profile != NULL
 *
 * Creates a string containing the namespace_name://profile_name for
 * @profile.
 *
 * Returns: size of string placed in @string else error code on failure
 */
int aa_getprocattr(struct aa_profile *profile, char **string)
{
	char *str;
	int len = 0, mode_len = 0, ns_len = 0, name_len;
41
	const char *mode_str = aa_profile_mode_names[profile->mode];
J
John Johansen 已提交
42
	const char *ns_name = NULL;
43 44
	struct aa_ns *ns = profile->ns;
	struct aa_ns *current_ns = __aa_current_profile()->ns;
J
John Johansen 已提交
45 46
	char *s;

47
	if (!aa_ns_visible(current_ns, ns, true))
J
John Johansen 已提交
48 49
		return -EACCES;

50
	ns_name = aa_ns_name(current_ns, ns, true);
J
John Johansen 已提交
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
	ns_len = strlen(ns_name);

	/* if the visible ns_name is > 0 increase size for : :// seperator */
	if (ns_len)
		ns_len += 4;

	/* unconfined profiles don't have a mode string appended */
	if (!unconfined(profile))
		mode_len = strlen(mode_str) + 3;	/* + 3 for _() */

	name_len = strlen(profile->base.hname);
	len = mode_len + ns_len + name_len + 1;	    /* + 1 for \n */
	s = str = kmalloc(len + 1, GFP_KERNEL);	    /* + 1 \0 */
	if (!str)
		return -ENOMEM;

	if (ns_len) {
		/* skip over prefix current_ns->base.hname and separating // */
		sprintf(s, ":%s://", ns_name);
		s += ns_len;
	}
	if (unconfined(profile))
		/* mode string not being appended */
		sprintf(s, "%s\n", profile->base.hname);
	else
		sprintf(s, "%s (%s)\n", profile->base.hname, mode_str);
	*string = str;

	/* NOTE: len does not include \0 of string, not saved as part of file */
	return len;
}

/**
 * split_token_from_name - separate a string of form  <token>^<name>
 * @op: operation being checked
 * @args: string to parse  (NOT NULL)
 * @token: stores returned parsed token value  (NOT NULL)
 *
 * Returns: start position of name after token else NULL on failure
 */
91
static char *split_token_from_name(const char *op, char *args, u64 *token)
J
John Johansen 已提交
92 93 94 95 96
{
	char *name;

	*token = simple_strtoull(args, &name, 16);
	if ((name == args) || *name != '^') {
97
		AA_ERROR("%s: Invalid input '%s'", op, args);
J
John Johansen 已提交
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
		return ERR_PTR(-EINVAL);
	}

	name++;			/* skip ^ */
	if (!*name)
		name = NULL;
	return name;
}

/**
 * aa_setprocattr_chagnehat - handle procattr interface to change_hat
 * @args: args received from writing to /proc/<pid>/attr/current (NOT NULL)
 * @size: size of the args
 * @test: true if this is a test of change_hat permissions
 *
 * Returns: %0 or error code if change_hat fails
 */
int aa_setprocattr_changehat(char *args, size_t size, int test)
{
	char *hat;
	u64 token;
	const char *hats[16];		/* current hard limit on # of names */
	int count = 0;

	hat = split_token_from_name(OP_CHANGE_HAT, args, &token);
	if (IS_ERR(hat))
		return PTR_ERR(hat);

	if (!hat && !token) {
		AA_ERROR("change_hat: Invalid input, NULL hat and NULL magic");
		return -EINVAL;
	}

	if (hat) {
		/* set up hat name vector, args guaranteed null terminated
		 * at args[size] by setprocattr.
		 *
		 * If there are multiple hat names in the buffer each is
		 * separated by a \0.  Ie. userspace writes them pre tokenized
		 */
		char *end = args + size;
		for (count = 0; (hat < end) && count < 16; ++count) {
			char *next = hat + strlen(hat) + 1;
			hats[count] = hat;
142 143
			AA_DEBUG("%s: (pid %d) Magic 0x%llx count %d hat '%s'\n"
				 , __func__, current->pid, token, count, hat);
J
John Johansen 已提交
144 145
			hat = next;
		}
146 147 148
	} else
		AA_DEBUG("%s: (pid %d) Magic 0x%llx count %d Hat '%s'\n",
			 __func__, current->pid, token, count, "<NULL>");
J
John Johansen 已提交
149 150 151

	return aa_change_hat(hats, count, token, test);
}