/*1* AppArmor security module2*3* This file contains AppArmor /proc/<pid>/attr/ interface functions4*5* Copyright (C) 1998-2008 Novell/SUSE6* Copyright 2009-2010 Canonical Ltd.7*8* This program is free software; you can redistribute it and/or9* modify it under the terms of the GNU General Public License as10* published by the Free Software Foundation, version 2 of the11* License.12*/1314#include "include/apparmor.h"15#include "include/context.h"16#include "include/policy.h"17#include "include/domain.h"181920/**21* aa_getprocattr - Return the profile information for @profile22* @profile: the profile to print profile info about (NOT NULL)23* @string: Returns - string containing the profile info (NOT NULL)24*25* Returns: length of @string on success else error on failure26*27* Requires: profile != NULL28*29* Creates a string containing the namespace_name://profile_name for30* @profile.31*32* Returns: size of string placed in @string else error code on failure33*/34int aa_getprocattr(struct aa_profile *profile, char **string)35{36char *str;37int len = 0, mode_len = 0, ns_len = 0, name_len;38const char *mode_str = profile_mode_names[profile->mode];39const char *ns_name = NULL;40struct aa_namespace *ns = profile->ns;41struct aa_namespace *current_ns = __aa_current_profile()->ns;42char *s;4344if (!aa_ns_visible(current_ns, ns))45return -EACCES;4647ns_name = aa_ns_name(current_ns, ns);48ns_len = strlen(ns_name);4950/* if the visible ns_name is > 0 increase size for : :// seperator */51if (ns_len)52ns_len += 4;5354/* unconfined profiles don't have a mode string appended */55if (!unconfined(profile))56mode_len = strlen(mode_str) + 3; /* + 3 for _() */5758name_len = strlen(profile->base.hname);59len = mode_len + ns_len + name_len + 1; /* + 1 for \n */60s = str = kmalloc(len + 1, GFP_KERNEL); /* + 1 \0 */61if (!str)62return -ENOMEM;6364if (ns_len) {65/* skip over prefix current_ns->base.hname and separating // */66sprintf(s, ":%s://", ns_name);67s += ns_len;68}69if (unconfined(profile))70/* mode string not being appended */71sprintf(s, "%s\n", profile->base.hname);72else73sprintf(s, "%s (%s)\n", profile->base.hname, mode_str);74*string = str;7576/* NOTE: len does not include \0 of string, not saved as part of file */77return len;78}7980/**81* split_token_from_name - separate a string of form <token>^<name>82* @op: operation being checked83* @args: string to parse (NOT NULL)84* @token: stores returned parsed token value (NOT NULL)85*86* Returns: start position of name after token else NULL on failure87*/88static char *split_token_from_name(int op, char *args, u64 * token)89{90char *name;9192*token = simple_strtoull(args, &name, 16);93if ((name == args) || *name != '^') {94AA_ERROR("%s: Invalid input '%s'", op_table[op], args);95return ERR_PTR(-EINVAL);96}9798name++; /* skip ^ */99if (!*name)100name = NULL;101return name;102}103104/**105* aa_setprocattr_chagnehat - handle procattr interface to change_hat106* @args: args received from writing to /proc/<pid>/attr/current (NOT NULL)107* @size: size of the args108* @test: true if this is a test of change_hat permissions109*110* Returns: %0 or error code if change_hat fails111*/112int aa_setprocattr_changehat(char *args, size_t size, int test)113{114char *hat;115u64 token;116const char *hats[16]; /* current hard limit on # of names */117int count = 0;118119hat = split_token_from_name(OP_CHANGE_HAT, args, &token);120if (IS_ERR(hat))121return PTR_ERR(hat);122123if (!hat && !token) {124AA_ERROR("change_hat: Invalid input, NULL hat and NULL magic");125return -EINVAL;126}127128if (hat) {129/* set up hat name vector, args guaranteed null terminated130* at args[size] by setprocattr.131*132* If there are multiple hat names in the buffer each is133* separated by a \0. Ie. userspace writes them pre tokenized134*/135char *end = args + size;136for (count = 0; (hat < end) && count < 16; ++count) {137char *next = hat + strlen(hat) + 1;138hats[count] = hat;139hat = next;140}141}142143AA_DEBUG("%s: Magic 0x%llx Hat '%s'\n",144__func__, token, hat ? hat : NULL);145146return aa_change_hat(hats, count, token, test);147}148149/**150* aa_setprocattr_changeprofile - handle procattr interface to changeprofile151* @fqname: args received from writting to /proc/<pid>/attr/current (NOT NULL)152* @onexec: true if change_profile should be delayed until exec153* @test: true if this is a test of change_profile permissions154*155* Returns: %0 or error code if change_profile fails156*/157int aa_setprocattr_changeprofile(char *fqname, bool onexec, int test)158{159char *name, *ns_name;160161name = aa_split_fqname(fqname, &ns_name);162return aa_change_profile(ns_name, name, onexec, test);163}164165int aa_setprocattr_permipc(char *fqname)166{167/* TODO: add ipc permission querying */168return -ENOTSUPP;169}170171172