LCOV - code coverage report
Current view: top level - security/apparmor - domain.c (source / functions) Hit Total Coverage
Test: Real Lines: 0 421 0.0 %
Date: 2020-10-17 15:46:16 Functions: 0 20 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  * AppArmor security module
       4                 :            :  *
       5                 :            :  * This file contains AppArmor policy attachment and domain transitions
       6                 :            :  *
       7                 :            :  * Copyright (C) 2002-2008 Novell/SUSE
       8                 :            :  * Copyright 2009-2010 Canonical Ltd.
       9                 :            :  */
      10                 :            : 
      11                 :            : #include <linux/errno.h>
      12                 :            : #include <linux/fdtable.h>
      13                 :            : #include <linux/file.h>
      14                 :            : #include <linux/mount.h>
      15                 :            : #include <linux/syscalls.h>
      16                 :            : #include <linux/tracehook.h>
      17                 :            : #include <linux/personality.h>
      18                 :            : #include <linux/xattr.h>
      19                 :            : 
      20                 :            : #include "include/audit.h"
      21                 :            : #include "include/apparmorfs.h"
      22                 :            : #include "include/cred.h"
      23                 :            : #include "include/domain.h"
      24                 :            : #include "include/file.h"
      25                 :            : #include "include/ipc.h"
      26                 :            : #include "include/match.h"
      27                 :            : #include "include/path.h"
      28                 :            : #include "include/policy.h"
      29                 :            : #include "include/policy_ns.h"
      30                 :            : 
      31                 :            : /**
      32                 :            :  * aa_free_domain_entries - free entries in a domain table
      33                 :            :  * @domain: the domain table to free  (MAYBE NULL)
      34                 :            :  */
      35                 :          0 : void aa_free_domain_entries(struct aa_domain *domain)
      36                 :            : {
      37                 :            :         int i;
      38                 :          0 :         if (domain) {
      39                 :          0 :                 if (!domain->table)
      40                 :          0 :                         return;
      41                 :            : 
      42                 :          0 :                 for (i = 0; i < domain->size; i++)
      43                 :          0 :                         kzfree(domain->table[i]);
      44                 :          0 :                 kzfree(domain->table);
      45                 :          0 :                 domain->table = NULL;
      46                 :            :         }
      47                 :            : }
      48                 :            : 
      49                 :            : /**
      50                 :            :  * may_change_ptraced_domain - check if can change profile on ptraced task
      51                 :            :  * @to_label: profile to change to  (NOT NULL)
      52                 :            :  * @info: message if there is an error
      53                 :            :  *
      54                 :            :  * Check if current is ptraced and if so if the tracing task is allowed
      55                 :            :  * to trace the new domain
      56                 :            :  *
      57                 :            :  * Returns: %0 or error if change not allowed
      58                 :            :  */
      59                 :          0 : static int may_change_ptraced_domain(struct aa_label *to_label,
      60                 :            :                                      const char **info)
      61                 :            : {
      62                 :            :         struct task_struct *tracer;
      63                 :            :         struct aa_label *tracerl = NULL;
      64                 :            :         int error = 0;
      65                 :            : 
      66                 :            :         rcu_read_lock();
      67                 :          0 :         tracer = ptrace_parent(current);
      68                 :          0 :         if (tracer)
      69                 :            :                 /* released below */
      70                 :          0 :                 tracerl = aa_get_task_label(tracer);
      71                 :            : 
      72                 :            :         /* not ptraced */
      73                 :          0 :         if (!tracer || unconfined(tracerl))
      74                 :            :                 goto out;
      75                 :            : 
      76                 :          0 :         error = aa_may_ptrace(tracerl, to_label, PTRACE_MODE_ATTACH);
      77                 :            : 
      78                 :            : out:
      79                 :            :         rcu_read_unlock();
      80                 :            :         aa_put_label(tracerl);
      81                 :            : 
      82                 :          0 :         if (error)
      83                 :          0 :                 *info = "ptrace prevents transition";
      84                 :          0 :         return error;
      85                 :            : }
      86                 :            : 
      87                 :            : /**** TODO: dedup to aa_label_match - needs perm and dfa, merging
      88                 :            :  * specifically this is an exact copy of aa_label_match except
      89                 :            :  * aa_compute_perms is replaced with aa_compute_fperms
      90                 :            :  * and policy.dfa with file.dfa
      91                 :            :  ****/
      92                 :            : /* match a profile and its associated ns component if needed
      93                 :            :  * Assumes visibility test has already been done.
      94                 :            :  * If a subns profile is not to be matched should be prescreened with
      95                 :            :  * visibility test.
      96                 :            :  */
      97                 :          0 : static inline unsigned int match_component(struct aa_profile *profile,
      98                 :            :                                            struct aa_profile *tp,
      99                 :            :                                            bool stack, unsigned int state)
     100                 :            : {
     101                 :            :         const char *ns_name;
     102                 :            : 
     103                 :          0 :         if (stack)
     104                 :          0 :                 state = aa_dfa_match(profile->file.dfa, state, "&");
     105                 :          0 :         if (profile->ns == tp->ns)
     106                 :          0 :                 return aa_dfa_match(profile->file.dfa, state, tp->base.hname);
     107                 :            : 
     108                 :            :         /* try matching with namespace name and then profile */
     109                 :          0 :         ns_name = aa_ns_name(profile->ns, tp->ns, true);
     110                 :          0 :         state = aa_dfa_match_len(profile->file.dfa, state, ":", 1);
     111                 :          0 :         state = aa_dfa_match(profile->file.dfa, state, ns_name);
     112                 :          0 :         state = aa_dfa_match_len(profile->file.dfa, state, ":", 1);
     113                 :          0 :         return aa_dfa_match(profile->file.dfa, state, tp->base.hname);
     114                 :            : }
     115                 :            : 
     116                 :            : /**
     117                 :            :  * label_compound_match - find perms for full compound label
     118                 :            :  * @profile: profile to find perms for
     119                 :            :  * @label: label to check access permissions for
     120                 :            :  * @stack: whether this is a stacking request
     121                 :            :  * @start: state to start match in
     122                 :            :  * @subns: whether to do permission checks on components in a subns
     123                 :            :  * @request: permissions to request
     124                 :            :  * @perms: perms struct to set
     125                 :            :  *
     126                 :            :  * Returns: 0 on success else ERROR
     127                 :            :  *
     128                 :            :  * For the label A//&B//&C this does the perm match for A//&B//&C
     129                 :            :  * @perms should be preinitialized with allperms OR a previous permission
     130                 :            :  *        check to be stacked.
     131                 :            :  */
     132                 :          0 : static int label_compound_match(struct aa_profile *profile,
     133                 :            :                                 struct aa_label *label, bool stack,
     134                 :            :                                 unsigned int state, bool subns, u32 request,
     135                 :            :                                 struct aa_perms *perms)
     136                 :            : {
     137                 :            :         struct aa_profile *tp;
     138                 :            :         struct label_it i;
     139                 :          0 :         struct path_cond cond = { };
     140                 :            : 
     141                 :            :         /* find first subcomponent that is visible */
     142                 :          0 :         label_for_each(i, label, tp) {
     143                 :          0 :                 if (!aa_ns_visible(profile->ns, tp->ns, subns))
     144                 :          0 :                         continue;
     145                 :          0 :                 state = match_component(profile, tp, stack, state);
     146                 :          0 :                 if (!state)
     147                 :            :                         goto fail;
     148                 :            :                 goto next;
     149                 :            :         }
     150                 :            : 
     151                 :            :         /* no component visible */
     152                 :          0 :         *perms = allperms;
     153                 :          0 :         return 0;
     154                 :            : 
     155                 :            : next:
     156                 :          0 :         label_for_each_cont(i, label, tp) {
     157                 :          0 :                 if (!aa_ns_visible(profile->ns, tp->ns, subns))
     158                 :          0 :                         continue;
     159                 :          0 :                 state = aa_dfa_match(profile->file.dfa, state, "//&");
     160                 :          0 :                 state = match_component(profile, tp, false, state);
     161                 :          0 :                 if (!state)
     162                 :            :                         goto fail;
     163                 :            :         }
     164                 :          0 :         *perms = aa_compute_fperms(profile->file.dfa, state, &cond);
     165                 :          0 :         aa_apply_modes_to_perms(profile, perms);
     166                 :          0 :         if ((perms->allow & request) != request)
     167                 :            :                 return -EACCES;
     168                 :            : 
     169                 :          0 :         return 0;
     170                 :            : 
     171                 :            : fail:
     172                 :          0 :         *perms = nullperms;
     173                 :          0 :         return -EACCES;
     174                 :            : }
     175                 :            : 
     176                 :            : /**
     177                 :            :  * label_components_match - find perms for all subcomponents of a label
     178                 :            :  * @profile: profile to find perms for
     179                 :            :  * @label: label to check access permissions for
     180                 :            :  * @stack: whether this is a stacking request
     181                 :            :  * @start: state to start match in
     182                 :            :  * @subns: whether to do permission checks on components in a subns
     183                 :            :  * @request: permissions to request
     184                 :            :  * @perms: an initialized perms struct to add accumulation to
     185                 :            :  *
     186                 :            :  * Returns: 0 on success else ERROR
     187                 :            :  *
     188                 :            :  * For the label A//&B//&C this does the perm match for each of A and B and C
     189                 :            :  * @perms should be preinitialized with allperms OR a previous permission
     190                 :            :  *        check to be stacked.
     191                 :            :  */
     192                 :          0 : static int label_components_match(struct aa_profile *profile,
     193                 :            :                                   struct aa_label *label, bool stack,
     194                 :            :                                   unsigned int start, bool subns, u32 request,
     195                 :            :                                   struct aa_perms *perms)
     196                 :            : {
     197                 :            :         struct aa_profile *tp;
     198                 :            :         struct label_it i;
     199                 :            :         struct aa_perms tmp;
     200                 :          0 :         struct path_cond cond = { };
     201                 :            :         unsigned int state = 0;
     202                 :            : 
     203                 :            :         /* find first subcomponent to test */
     204                 :          0 :         label_for_each(i, label, tp) {
     205                 :          0 :                 if (!aa_ns_visible(profile->ns, tp->ns, subns))
     206                 :          0 :                         continue;
     207                 :          0 :                 state = match_component(profile, tp, stack, start);
     208                 :          0 :                 if (!state)
     209                 :            :                         goto fail;
     210                 :            :                 goto next;
     211                 :            :         }
     212                 :            : 
     213                 :            :         /* no subcomponents visible - no change in perms */
     214                 :            :         return 0;
     215                 :            : 
     216                 :            : next:
     217                 :          0 :         tmp = aa_compute_fperms(profile->file.dfa, state, &cond);
     218                 :          0 :         aa_apply_modes_to_perms(profile, &tmp);
     219                 :          0 :         aa_perms_accum(perms, &tmp);
     220                 :          0 :         label_for_each_cont(i, label, tp) {
     221                 :          0 :                 if (!aa_ns_visible(profile->ns, tp->ns, subns))
     222                 :          0 :                         continue;
     223                 :          0 :                 state = match_component(profile, tp, stack, start);
     224                 :          0 :                 if (!state)
     225                 :            :                         goto fail;
     226                 :          0 :                 tmp = aa_compute_fperms(profile->file.dfa, state, &cond);
     227                 :          0 :                 aa_apply_modes_to_perms(profile, &tmp);
     228                 :          0 :                 aa_perms_accum(perms, &tmp);
     229                 :            :         }
     230                 :            : 
     231                 :          0 :         if ((perms->allow & request) != request)
     232                 :            :                 return -EACCES;
     233                 :            : 
     234                 :          0 :         return 0;
     235                 :            : 
     236                 :            : fail:
     237                 :          0 :         *perms = nullperms;
     238                 :          0 :         return -EACCES;
     239                 :            : }
     240                 :            : 
     241                 :            : /**
     242                 :            :  * label_match - do a multi-component label match
     243                 :            :  * @profile: profile to match against (NOT NULL)
     244                 :            :  * @label: label to match (NOT NULL)
     245                 :            :  * @stack: whether this is a stacking request
     246                 :            :  * @state: state to start in
     247                 :            :  * @subns: whether to match subns components
     248                 :            :  * @request: permission request
     249                 :            :  * @perms: Returns computed perms (NOT NULL)
     250                 :            :  *
     251                 :            :  * Returns: the state the match finished in, may be the none matching state
     252                 :            :  */
     253                 :          0 : static int label_match(struct aa_profile *profile, struct aa_label *label,
     254                 :            :                        bool stack, unsigned int state, bool subns, u32 request,
     255                 :            :                        struct aa_perms *perms)
     256                 :            : {
     257                 :            :         int error;
     258                 :            : 
     259                 :          0 :         *perms = nullperms;
     260                 :          0 :         error = label_compound_match(profile, label, stack, state, subns,
     261                 :            :                                      request, perms);
     262                 :          0 :         if (!error)
     263                 :            :                 return error;
     264                 :            : 
     265                 :          0 :         *perms = allperms;
     266                 :          0 :         return label_components_match(profile, label, stack, state, subns,
     267                 :            :                                       request, perms);
     268                 :            : }
     269                 :            : 
     270                 :            : /******* end TODO: dedup *****/
     271                 :            : 
     272                 :            : /**
     273                 :            :  * change_profile_perms - find permissions for change_profile
     274                 :            :  * @profile: the current profile  (NOT NULL)
     275                 :            :  * @target: label to transition to (NOT NULL)
     276                 :            :  * @stack: whether this is a stacking request
     277                 :            :  * @request: requested perms
     278                 :            :  * @start: state to start matching in
     279                 :            :  *
     280                 :            :  *
     281                 :            :  * Returns: permission set
     282                 :            :  *
     283                 :            :  * currently only matches full label A//&B//&C or individual components A, B, C
     284                 :            :  * not arbitrary combinations. Eg. A//&B, C
     285                 :            :  */
     286                 :          0 : static int change_profile_perms(struct aa_profile *profile,
     287                 :            :                                 struct aa_label *target, bool stack,
     288                 :            :                                 u32 request, unsigned int start,
     289                 :            :                                 struct aa_perms *perms)
     290                 :            : {
     291                 :          0 :         if (profile_unconfined(profile)) {
     292                 :          0 :                 perms->allow = AA_MAY_CHANGE_PROFILE | AA_MAY_ONEXEC;
     293                 :          0 :                 perms->audit = perms->quiet = perms->kill = 0;
     294                 :          0 :                 return 0;
     295                 :            :         }
     296                 :            : 
     297                 :            :         /* TODO: add profile in ns screening */
     298                 :          0 :         return label_match(profile, target, stack, start, true, request, perms);
     299                 :            : }
     300                 :            : 
     301                 :            : /**
     302                 :            :  * aa_xattrs_match - check whether a file matches the xattrs defined in profile
     303                 :            :  * @bprm: binprm struct for the process to validate
     304                 :            :  * @profile: profile to match against (NOT NULL)
     305                 :            :  * @state: state to start match in
     306                 :            :  *
     307                 :            :  * Returns: number of extended attributes that matched, or < 0 on error
     308                 :            :  */
     309                 :          0 : static int aa_xattrs_match(const struct linux_binprm *bprm,
     310                 :            :                            struct aa_profile *profile, unsigned int state)
     311                 :            : {
     312                 :            :         int i;
     313                 :            :         ssize_t size;
     314                 :            :         struct dentry *d;
     315                 :          0 :         char *value = NULL;
     316                 :          0 :         int value_size = 0, ret = profile->xattr_count;
     317                 :            : 
     318                 :          0 :         if (!bprm || !profile->xattr_count)
     319                 :            :                 return 0;
     320                 :          0 :         might_sleep();
     321                 :            : 
     322                 :            :         /* transition from exec match to xattr set */
     323                 :          0 :         state = aa_dfa_null_transition(profile->xmatch, state);
     324                 :            : 
     325                 :          0 :         d = bprm->file->f_path.dentry;
     326                 :            : 
     327                 :          0 :         for (i = 0; i < profile->xattr_count; i++) {
     328                 :          0 :                 size = vfs_getxattr_alloc(d, profile->xattrs[i], &value,
     329                 :            :                                           value_size, GFP_KERNEL);
     330                 :          0 :                 if (size >= 0) {
     331                 :            :                         u32 perm;
     332                 :            : 
     333                 :            :                         /* Check the xattr value, not just presence */
     334                 :          0 :                         state = aa_dfa_match_len(profile->xmatch, state, value,
     335                 :            :                                                  size);
     336                 :          0 :                         perm = dfa_user_allow(profile->xmatch, state);
     337                 :          0 :                         if (!(perm & MAY_EXEC)) {
     338                 :            :                                 ret = -EINVAL;
     339                 :            :                                 goto out;
     340                 :            :                         }
     341                 :            :                 }
     342                 :            :                 /* transition to next element */
     343                 :          0 :                 state = aa_dfa_null_transition(profile->xmatch, state);
     344                 :          0 :                 if (size < 0) {
     345                 :            :                         /*
     346                 :            :                          * No xattr match, so verify if transition to
     347                 :            :                          * next element was valid. IFF so the xattr
     348                 :            :                          * was optional.
     349                 :            :                          */
     350                 :          0 :                         if (!state) {
     351                 :            :                                 ret = -EINVAL;
     352                 :            :                                 goto out;
     353                 :            :                         }
     354                 :            :                         /* don't count missing optional xattr as matched */
     355                 :          0 :                         ret--;
     356                 :            :                 }
     357                 :            :         }
     358                 :            : 
     359                 :            : out:
     360                 :          0 :         kfree(value);
     361                 :          0 :         return ret;
     362                 :            : }
     363                 :            : 
     364                 :            : /**
     365                 :            :  * find_attach - do attachment search for unconfined processes
     366                 :            :  * @bprm - binprm structure of transitioning task
     367                 :            :  * @ns: the current namespace  (NOT NULL)
     368                 :            :  * @head - profile list to walk  (NOT NULL)
     369                 :            :  * @name - to match against  (NOT NULL)
     370                 :            :  * @info - info message if there was an error (NOT NULL)
     371                 :            :  *
     372                 :            :  * Do a linear search on the profiles in the list.  There is a matching
     373                 :            :  * preference where an exact match is preferred over a name which uses
     374                 :            :  * expressions to match, and matching expressions with the greatest
     375                 :            :  * xmatch_len are preferred.
     376                 :            :  *
     377                 :            :  * Requires: @head not be shared or have appropriate locks held
     378                 :            :  *
     379                 :            :  * Returns: label or NULL if no match found
     380                 :            :  */
     381                 :          0 : static struct aa_label *find_attach(const struct linux_binprm *bprm,
     382                 :            :                                     struct aa_ns *ns, struct list_head *head,
     383                 :            :                                     const char *name, const char **info)
     384                 :            : {
     385                 :            :         int candidate_len = 0, candidate_xattrs = 0;
     386                 :            :         bool conflict = false;
     387                 :            :         struct aa_profile *profile, *candidate = NULL;
     388                 :            : 
     389                 :            :         AA_BUG(!name);
     390                 :            :         AA_BUG(!head);
     391                 :            : 
     392                 :            :         rcu_read_lock();
     393                 :            : restart:
     394                 :          0 :         list_for_each_entry_rcu(profile, head, base.list) {
     395                 :          0 :                 if (profile->label.flags & FLAG_NULL &&
     396                 :          0 :                     &profile->label == ns_unconfined(profile->ns))
     397                 :          0 :                         continue;
     398                 :            : 
     399                 :            :                 /* Find the "best" matching profile. Profiles must
     400                 :            :                  * match the path and extended attributes (if any)
     401                 :            :                  * associated with the file. A more specific path
     402                 :            :                  * match will be preferred over a less specific one,
     403                 :            :                  * and a match with more matching extended attributes
     404                 :            :                  * will be preferred over one with fewer. If the best
     405                 :            :                  * match has both the same level of path specificity
     406                 :            :                  * and the same number of matching extended attributes
     407                 :            :                  * as another profile, signal a conflict and refuse to
     408                 :            :                  * match.
     409                 :            :                  */
     410                 :          0 :                 if (profile->xmatch) {
     411                 :            :                         unsigned int state, count;
     412                 :            :                         u32 perm;
     413                 :            : 
     414                 :          0 :                         state = aa_dfa_leftmatch(profile->xmatch, DFA_START,
     415                 :            :                                                  name, &count);
     416                 :          0 :                         perm = dfa_user_allow(profile->xmatch, state);
     417                 :            :                         /* any accepting state means a valid match. */
     418                 :          0 :                         if (perm & MAY_EXEC) {
     419                 :            :                                 int ret = 0;
     420                 :            : 
     421                 :          0 :                                 if (count < candidate_len)
     422                 :          0 :                                         continue;
     423                 :            : 
     424                 :          0 :                                 if (bprm && profile->xattr_count) {
     425                 :          0 :                                         long rev = READ_ONCE(ns->revision);
     426                 :            : 
     427                 :          0 :                                         if (!aa_get_profile_not0(profile))
     428                 :            :                                                 goto restart;
     429                 :            :                                         rcu_read_unlock();
     430                 :          0 :                                         ret = aa_xattrs_match(bprm, profile,
     431                 :            :                                                               state);
     432                 :            :                                         rcu_read_lock();
     433                 :            :                                         aa_put_profile(profile);
     434                 :          0 :                                         if (rev !=
     435                 :          0 :                                             READ_ONCE(ns->revision))
     436                 :            :                                                 /* policy changed */
     437                 :            :                                                 goto restart;
     438                 :            :                                         /*
     439                 :            :                                          * Fail matching if the xattrs don't
     440                 :            :                                          * match
     441                 :            :                                          */
     442                 :          0 :                                         if (ret < 0)
     443                 :          0 :                                                 continue;
     444                 :            :                                 }
     445                 :            :                                 /*
     446                 :            :                                  * TODO: allow for more flexible best match
     447                 :            :                                  *
     448                 :            :                                  * The new match isn't more specific
     449                 :            :                                  * than the current best match
     450                 :            :                                  */
     451                 :          0 :                                 if (count == candidate_len &&
     452                 :            :                                     ret <= candidate_xattrs) {
     453                 :            :                                         /* Match is equivalent, so conflict */
     454                 :          0 :                                         if (ret == candidate_xattrs)
     455                 :            :                                                 conflict = true;
     456                 :          0 :                                         continue;
     457                 :            :                                 }
     458                 :            : 
     459                 :            :                                 /* Either the same length with more matching
     460                 :            :                                  * xattrs, or a longer match
     461                 :            :                                  */
     462                 :            :                                 candidate = profile;
     463                 :          0 :                                 candidate_len = profile->xmatch_len;
     464                 :            :                                 candidate_xattrs = ret;
     465                 :            :                                 conflict = false;
     466                 :            :                         }
     467                 :          0 :                 } else if (!strcmp(profile->base.name, name)) {
     468                 :            :                         /*
     469                 :            :                          * old exact non-re match, without conditionals such
     470                 :            :                          * as xattrs. no more searching required
     471                 :            :                          */
     472                 :          0 :                         candidate = profile;
     473                 :          0 :                         goto out;
     474                 :            :                 }
     475                 :            :         }
     476                 :            : 
     477                 :          0 :         if (!candidate || conflict) {
     478                 :          0 :                 if (conflict)
     479                 :          0 :                         *info = "conflicting profile attachments";
     480                 :            :                 rcu_read_unlock();
     481                 :          0 :                 return NULL;
     482                 :            :         }
     483                 :            : 
     484                 :            : out:
     485                 :          0 :         candidate = aa_get_newest_profile(candidate);
     486                 :            :         rcu_read_unlock();
     487                 :            : 
     488                 :          0 :         return &candidate->label;
     489                 :            : }
     490                 :            : 
     491                 :            : static const char *next_name(int xtype, const char *name)
     492                 :            : {
     493                 :            :         return NULL;
     494                 :            : }
     495                 :            : 
     496                 :            : /**
     497                 :            :  * x_table_lookup - lookup an x transition name via transition table
     498                 :            :  * @profile: current profile (NOT NULL)
     499                 :            :  * @xindex: index into x transition table
     500                 :            :  * @name: returns: name tested to find label (NOT NULL)
     501                 :            :  *
     502                 :            :  * Returns: refcounted label, or NULL on failure (MAYBE NULL)
     503                 :            :  */
     504                 :          0 : struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex,
     505                 :            :                                 const char **name)
     506                 :            : {
     507                 :            :         struct aa_label *label = NULL;
     508                 :            :         u32 xtype = xindex & AA_X_TYPE_MASK;
     509                 :          0 :         int index = xindex & AA_X_INDEX_MASK;
     510                 :            : 
     511                 :            :         AA_BUG(!name);
     512                 :            : 
     513                 :            :         /* index is guaranteed to be in range, validated at load time */
     514                 :            :         /* TODO: move lookup parsing to unpack time so this is a straight
     515                 :            :          *       index into the resultant label
     516                 :            :          */
     517                 :          0 :         for (*name = profile->file.trans.table[index]; !label && *name;
     518                 :          0 :              *name = next_name(xtype, *name)) {
     519                 :          0 :                 if (xindex & AA_X_CHILD) {
     520                 :            :                         struct aa_profile *new_profile;
     521                 :            :                         /* release by caller */
     522                 :          0 :                         new_profile = aa_find_child(profile, *name);
     523                 :          0 :                         if (new_profile)
     524                 :          0 :                                 label = &new_profile->label;
     525                 :          0 :                         continue;
     526                 :            :                 }
     527                 :          0 :                 label = aa_label_parse(&profile->label, *name, GFP_ATOMIC,
     528                 :            :                                        true, false);
     529                 :          0 :                 if (IS_ERR(label))
     530                 :            :                         label = NULL;
     531                 :            :         }
     532                 :            : 
     533                 :            :         /* released by caller */
     534                 :            : 
     535                 :          0 :         return label;
     536                 :            : }
     537                 :            : 
     538                 :            : /**
     539                 :            :  * x_to_label - get target label for a given xindex
     540                 :            :  * @profile: current profile  (NOT NULL)
     541                 :            :  * @bprm: binprm structure of transitioning task
     542                 :            :  * @name: name to lookup (NOT NULL)
     543                 :            :  * @xindex: index into x transition table
     544                 :            :  * @lookupname: returns: name used in lookup if one was specified (NOT NULL)
     545                 :            :  *
     546                 :            :  * find label for a transition index
     547                 :            :  *
     548                 :            :  * Returns: refcounted label or NULL if not found available
     549                 :            :  */
     550                 :          0 : static struct aa_label *x_to_label(struct aa_profile *profile,
     551                 :            :                                    const struct linux_binprm *bprm,
     552                 :            :                                    const char *name, u32 xindex,
     553                 :            :                                    const char **lookupname,
     554                 :            :                                    const char **info)
     555                 :            : {
     556                 :            :         struct aa_label *new = NULL;
     557                 :          0 :         struct aa_ns *ns = profile->ns;
     558                 :          0 :         u32 xtype = xindex & AA_X_TYPE_MASK;
     559                 :            :         const char *stack = NULL;
     560                 :            : 
     561                 :          0 :         switch (xtype) {
     562                 :            :         case AA_X_NONE:
     563                 :            :                 /* fail exec unless ix || ux fallback - handled by caller */
     564                 :          0 :                 *lookupname = NULL;
     565                 :          0 :                 break;
     566                 :            :         case AA_X_TABLE:
     567                 :            :                 /* TODO: fix when perm mapping done at unload */
     568                 :          0 :                 stack = profile->file.trans.table[xindex & AA_X_INDEX_MASK];
     569                 :          0 :                 if (*stack != '&') {
     570                 :            :                         /* released by caller */
     571                 :          0 :                         new = x_table_lookup(profile, xindex, lookupname);
     572                 :            :                         stack = NULL;
     573                 :          0 :                         break;
     574                 :            :                 }
     575                 :            :                 /* fall through - to X_NAME */
     576                 :            :         case AA_X_NAME:
     577                 :          0 :                 if (xindex & AA_X_CHILD)
     578                 :            :                         /* released by caller */
     579                 :          0 :                         new = find_attach(bprm, ns, &profile->base.profiles,
     580                 :            :                                           name, info);
     581                 :            :                 else
     582                 :            :                         /* released by caller */
     583                 :          0 :                         new = find_attach(bprm, ns, &ns->base.profiles,
     584                 :            :                                           name, info);
     585                 :          0 :                 *lookupname = name;
     586                 :          0 :                 break;
     587                 :            :         }
     588                 :            : 
     589                 :          0 :         if (!new) {
     590                 :          0 :                 if (xindex & AA_X_INHERIT) {
     591                 :            :                         /* (p|c|n)ix - don't change profile but do
     592                 :            :                          * use the newest version
     593                 :            :                          */
     594                 :          0 :                         *info = "ix fallback";
     595                 :            :                         /* no profile && no error */
     596                 :          0 :                         new = aa_get_newest_label(&profile->label);
     597                 :          0 :                 } else if (xindex & AA_X_UNCONFINED) {
     598                 :          0 :                         new = aa_get_newest_label(ns_unconfined(profile->ns));
     599                 :          0 :                         *info = "ux fallback";
     600                 :            :                 }
     601                 :            :         }
     602                 :            : 
     603                 :          0 :         if (new && stack) {
     604                 :            :                 /* base the stack on post domain transition */
     605                 :            :                 struct aa_label *base = new;
     606                 :            : 
     607                 :          0 :                 new = aa_label_parse(base, stack, GFP_ATOMIC, true, false);
     608                 :          0 :                 if (IS_ERR(new))
     609                 :            :                         new = NULL;
     610                 :            :                 aa_put_label(base);
     611                 :            :         }
     612                 :            : 
     613                 :            :         /* released by caller */
     614                 :          0 :         return new;
     615                 :            : }
     616                 :            : 
     617                 :          0 : static struct aa_label *profile_transition(struct aa_profile *profile,
     618                 :            :                                            const struct linux_binprm *bprm,
     619                 :            :                                            char *buffer, struct path_cond *cond,
     620                 :            :                                            bool *secure_exec)
     621                 :            : {
     622                 :            :         struct aa_label *new = NULL;
     623                 :            :         struct aa_profile *component;
     624                 :            :         struct label_it i;
     625                 :          0 :         const char *info = NULL, *name = NULL, *target = NULL;
     626                 :          0 :         unsigned int state = profile->file.start;
     627                 :          0 :         struct aa_perms perms = {};
     628                 :            :         bool nonewprivs = false;
     629                 :            :         int error = 0;
     630                 :            : 
     631                 :            :         AA_BUG(!profile);
     632                 :            :         AA_BUG(!bprm);
     633                 :            :         AA_BUG(!buffer);
     634                 :            : 
     635                 :          0 :         error = aa_path_name(&bprm->file->f_path, profile->path_flags, buffer,
     636                 :            :                              &name, &info, profile->disconnected);
     637                 :          0 :         if (error) {
     638                 :          0 :                 if (profile_unconfined(profile) ||
     639                 :          0 :                     (profile->label.flags & FLAG_IX_ON_NAME_ERROR)) {
     640                 :            :                         AA_DEBUG("name lookup ix on error");
     641                 :            :                         error = 0;
     642                 :          0 :                         new = aa_get_newest_label(&profile->label);
     643                 :            :                 }
     644                 :          0 :                 name = bprm->filename;
     645                 :          0 :                 goto audit;
     646                 :            :         }
     647                 :            : 
     648                 :          0 :         if (profile_unconfined(profile)) {
     649                 :          0 :                 new = find_attach(bprm, profile->ns,
     650                 :          0 :                                   &profile->ns->base.profiles, name, &info);
     651                 :          0 :                 if (new) {
     652                 :            :                         AA_DEBUG("unconfined attached to new label");
     653                 :            :                         return new;
     654                 :            :                 }
     655                 :            :                 AA_DEBUG("unconfined exec no attachment");
     656                 :          0 :                 return aa_get_newest_label(&profile->label);
     657                 :            :         }
     658                 :            : 
     659                 :            :         /* find exec permissions for name */
     660                 :          0 :         state = aa_str_perms(profile->file.dfa, state, name, cond, &perms);
     661                 :          0 :         if (perms.allow & MAY_EXEC) {
     662                 :            :                 /* exec permission determine how to transition */
     663                 :          0 :                 new = x_to_label(profile, bprm, name, perms.xindex, &target,
     664                 :            :                                  &info);
     665                 :          0 :                 if (new && new->proxy == profile->label.proxy && info) {
     666                 :            :                         /* hack ix fallback - improve how this is detected */
     667                 :            :                         goto audit;
     668                 :          0 :                 } else if (!new) {
     669                 :            :                         error = -EACCES;
     670                 :          0 :                         info = "profile transition not found";
     671                 :            :                         /* remove MAY_EXEC to audit as failure */
     672                 :          0 :                         perms.allow &= ~MAY_EXEC;
     673                 :            :                 } else {
     674                 :            :                         /* verify that each component's xattr requirements are
     675                 :            :                          * met, and fail execution otherwise
     676                 :            :                          */
     677                 :          0 :                         label_for_each(i, new, component) {
     678                 :          0 :                                 if (aa_xattrs_match(bprm, component, state) <
     679                 :            :                                     0) {
     680                 :            :                                         error = -EACCES;
     681                 :          0 :                                         info = "required xattrs not present";
     682                 :          0 :                                         perms.allow &= ~MAY_EXEC;
     683                 :            :                                         aa_put_label(new);
     684                 :            :                                         new = NULL;
     685                 :            :                                         goto audit;
     686                 :            :                                 }
     687                 :            :                         }
     688                 :            :                 }
     689                 :          0 :         } else if (COMPLAIN_MODE(profile)) {
     690                 :            :                 /* no exec permission - learning mode */
     691                 :            :                 struct aa_profile *new_profile = NULL;
     692                 :          0 :                 char *n = kstrdup(name, GFP_ATOMIC);
     693                 :            : 
     694                 :          0 :                 if (n) {
     695                 :            :                         /* name is ptr into buffer */
     696                 :          0 :                         long pos = name - buffer;
     697                 :            :                         /* break per cpu buffer hold */
     698                 :          0 :                         put_buffers(buffer);
     699                 :          0 :                         new_profile = aa_new_null_profile(profile, false, n,
     700                 :            :                                                           GFP_KERNEL);
     701                 :          0 :                         get_buffers(buffer);
     702                 :          0 :                         name = buffer + pos;
     703                 :          0 :                         strcpy((char *)name, n);
     704                 :          0 :                         kfree(n);
     705                 :            :                 }
     706                 :          0 :                 if (!new_profile) {
     707                 :            :                         error = -ENOMEM;
     708                 :          0 :                         info = "could not create null profile";
     709                 :            :                 } else {
     710                 :            :                         error = -EACCES;
     711                 :          0 :                         new = &new_profile->label;
     712                 :            :                 }
     713                 :          0 :                 perms.xindex |= AA_X_UNSAFE;
     714                 :            :         } else
     715                 :            :                 /* fail exec */
     716                 :            :                 error = -EACCES;
     717                 :            : 
     718                 :          0 :         if (!new)
     719                 :            :                 goto audit;
     720                 :            : 
     721                 :            : 
     722                 :          0 :         if (!(perms.xindex & AA_X_UNSAFE)) {
     723                 :          0 :                 if (DEBUG_ON) {
     724                 :            :                         dbg_printk("apparmor: scrubbing environment variables"
     725                 :            :                                    " for %s profile=", name);
     726                 :          0 :                         aa_label_printk(new, GFP_ATOMIC);
     727                 :            :                         dbg_printk("\n");
     728                 :            :                 }
     729                 :          0 :                 *secure_exec = true;
     730                 :            :         }
     731                 :            : 
     732                 :            : audit:
     733                 :          0 :         aa_audit_file(profile, &perms, OP_EXEC, MAY_EXEC, name, target, new,
     734                 :            :                       cond->uid, info, error);
     735                 :          0 :         if (!new || nonewprivs) {
     736                 :            :                 aa_put_label(new);
     737                 :          0 :                 return ERR_PTR(error);
     738                 :            :         }
     739                 :            : 
     740                 :            :         return new;
     741                 :            : }
     742                 :            : 
     743                 :          0 : static int profile_onexec(struct aa_profile *profile, struct aa_label *onexec,
     744                 :            :                           bool stack, const struct linux_binprm *bprm,
     745                 :            :                           char *buffer, struct path_cond *cond,
     746                 :            :                           bool *secure_exec)
     747                 :            : {
     748                 :          0 :         unsigned int state = profile->file.start;
     749                 :          0 :         struct aa_perms perms = {};
     750                 :          0 :         const char *xname = NULL, *info = "change_profile onexec";
     751                 :            :         int error = -EACCES;
     752                 :            : 
     753                 :            :         AA_BUG(!profile);
     754                 :            :         AA_BUG(!onexec);
     755                 :            :         AA_BUG(!bprm);
     756                 :            :         AA_BUG(!buffer);
     757                 :            : 
     758                 :          0 :         if (profile_unconfined(profile)) {
     759                 :            :                 /* change_profile on exec already granted */
     760                 :            :                 /*
     761                 :            :                  * NOTE: Domain transitions from unconfined are allowed
     762                 :            :                  * even when no_new_privs is set because this aways results
     763                 :            :                  * in a further reduction of permissions.
     764                 :            :                  */
     765                 :            :                 return 0;
     766                 :            :         }
     767                 :            : 
     768                 :          0 :         error = aa_path_name(&bprm->file->f_path, profile->path_flags, buffer,
     769                 :            :                              &xname, &info, profile->disconnected);
     770                 :          0 :         if (error) {
     771                 :          0 :                 if (profile_unconfined(profile) ||
     772                 :          0 :                     (profile->label.flags & FLAG_IX_ON_NAME_ERROR)) {
     773                 :            :                         AA_DEBUG("name lookup ix on error");
     774                 :            :                         error = 0;
     775                 :            :                 }
     776                 :          0 :                 xname = bprm->filename;
     777                 :          0 :                 goto audit;
     778                 :            :         }
     779                 :            : 
     780                 :            :         /* find exec permissions for name */
     781                 :          0 :         state = aa_str_perms(profile->file.dfa, state, xname, cond, &perms);
     782                 :          0 :         if (!(perms.allow & AA_MAY_ONEXEC)) {
     783                 :          0 :                 info = "no change_onexec valid for executable";
     784                 :          0 :                 goto audit;
     785                 :            :         }
     786                 :            :         /* test if this exec can be paired with change_profile onexec.
     787                 :            :          * onexec permission is linked to exec with a standard pairing
     788                 :            :          * exec\0change_profile
     789                 :            :          */
     790                 :          0 :         state = aa_dfa_null_transition(profile->file.dfa, state);
     791                 :          0 :         error = change_profile_perms(profile, onexec, stack, AA_MAY_ONEXEC,
     792                 :            :                                      state, &perms);
     793                 :          0 :         if (error) {
     794                 :          0 :                 perms.allow &= ~AA_MAY_ONEXEC;
     795                 :          0 :                 goto audit;
     796                 :            :         }
     797                 :            : 
     798                 :          0 :         if (!(perms.xindex & AA_X_UNSAFE)) {
     799                 :          0 :                 if (DEBUG_ON) {
     800                 :            :                         dbg_printk("apparmor: scrubbing environment "
     801                 :            :                                    "variables for %s label=", xname);
     802                 :          0 :                         aa_label_printk(onexec, GFP_ATOMIC);
     803                 :            :                         dbg_printk("\n");
     804                 :            :                 }
     805                 :          0 :                 *secure_exec = true;
     806                 :            :         }
     807                 :            : 
     808                 :            : audit:
     809                 :          0 :         return aa_audit_file(profile, &perms, OP_EXEC, AA_MAY_ONEXEC, xname,
     810                 :            :                              NULL, onexec, cond->uid, info, error);
     811                 :            : }
     812                 :            : 
     813                 :            : /* ensure none ns domain transitions are correctly applied with onexec */
     814                 :            : 
     815                 :          0 : static struct aa_label *handle_onexec(struct aa_label *label,
     816                 :            :                                       struct aa_label *onexec, bool stack,
     817                 :            :                                       const struct linux_binprm *bprm,
     818                 :            :                                       char *buffer, struct path_cond *cond,
     819                 :            :                                       bool *unsafe)
     820                 :            : {
     821                 :            :         struct aa_profile *profile;
     822                 :            :         struct aa_label *new;
     823                 :            :         int error;
     824                 :            : 
     825                 :            :         AA_BUG(!label);
     826                 :            :         AA_BUG(!onexec);
     827                 :            :         AA_BUG(!bprm);
     828                 :            :         AA_BUG(!buffer);
     829                 :            : 
     830                 :          0 :         if (!stack) {
     831                 :          0 :                 error = fn_for_each_in_ns(label, profile,
     832                 :            :                                 profile_onexec(profile, onexec, stack,
     833                 :            :                                                bprm, buffer, cond, unsafe));
     834                 :          0 :                 if (error)
     835                 :          0 :                         return ERR_PTR(error);
     836                 :          0 :                 new = fn_label_build_in_ns(label, profile, GFP_ATOMIC,
     837                 :            :                                 aa_get_newest_label(onexec),
     838                 :            :                                 profile_transition(profile, bprm, buffer,
     839                 :            :                                                    cond, unsafe));
     840                 :            : 
     841                 :            :         } else {
     842                 :            :                 /* TODO: determine how much we want to loosen this */
     843                 :          0 :                 error = fn_for_each_in_ns(label, profile,
     844                 :            :                                 profile_onexec(profile, onexec, stack, bprm,
     845                 :            :                                                buffer, cond, unsafe));
     846                 :          0 :                 if (error)
     847                 :          0 :                         return ERR_PTR(error);
     848                 :          0 :                 new = fn_label_build_in_ns(label, profile, GFP_ATOMIC,
     849                 :            :                                 aa_label_merge(&profile->label, onexec,
     850                 :            :                                                GFP_ATOMIC),
     851                 :            :                                 profile_transition(profile, bprm, buffer,
     852                 :            :                                                    cond, unsafe));
     853                 :            :         }
     854                 :            : 
     855                 :          0 :         if (new)
     856                 :            :                 return new;
     857                 :            : 
     858                 :            :         /* TODO: get rid of GLOBAL_ROOT_UID */
     859                 :          0 :         error = fn_for_each_in_ns(label, profile,
     860                 :            :                         aa_audit_file(profile, &nullperms, OP_CHANGE_ONEXEC,
     861                 :            :                                       AA_MAY_ONEXEC, bprm->filename, NULL,
     862                 :            :                                       onexec, GLOBAL_ROOT_UID,
     863                 :            :                                       "failed to build target label", -ENOMEM));
     864                 :          0 :         return ERR_PTR(error);
     865                 :            : }
     866                 :            : 
     867                 :            : /**
     868                 :            :  * apparmor_bprm_set_creds - set the new creds on the bprm struct
     869                 :            :  * @bprm: binprm for the exec  (NOT NULL)
     870                 :            :  *
     871                 :            :  * Returns: %0 or error on failure
     872                 :            :  *
     873                 :            :  * TODO: once the other paths are done see if we can't refactor into a fn
     874                 :            :  */
     875                 :          0 : int apparmor_bprm_set_creds(struct linux_binprm *bprm)
     876                 :            : {
     877                 :            :         struct aa_task_ctx *ctx;
     878                 :            :         struct aa_label *label, *new = NULL;
     879                 :            :         struct aa_profile *profile;
     880                 :            :         char *buffer = NULL;
     881                 :          0 :         const char *info = NULL;
     882                 :            :         int error = 0;
     883                 :          0 :         bool unsafe = false;
     884                 :          0 :         struct path_cond cond = {
     885                 :          0 :                 file_inode(bprm->file)->i_uid,
     886                 :          0 :                 file_inode(bprm->file)->i_mode
     887                 :            :         };
     888                 :            : 
     889                 :          0 :         if (bprm->called_set_creds)
     890                 :            :                 return 0;
     891                 :            : 
     892                 :          0 :         ctx = task_ctx(current);
     893                 :            :         AA_BUG(!cred_label(bprm->cred));
     894                 :            :         AA_BUG(!ctx);
     895                 :            : 
     896                 :          0 :         label = aa_get_newest_label(cred_label(bprm->cred));
     897                 :            : 
     898                 :            :         /*
     899                 :            :          * Detect no new privs being set, and store the label it
     900                 :            :          * occurred under. Ideally this would happen when nnp
     901                 :            :          * is set but there isn't a good way to do that yet.
     902                 :            :          *
     903                 :            :          * Testing for unconfined must be done before the subset test
     904                 :            :          */
     905                 :          0 :         if ((bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) && !unconfined(label) &&
     906                 :          0 :             !ctx->nnp)
     907                 :          0 :                 ctx->nnp = aa_get_label(label);
     908                 :            : 
     909                 :            :         /* buffer freed below, name is pointer into buffer */
     910                 :          0 :         get_buffers(buffer);
     911                 :            :         /* Test for onexec first as onexec override other x transitions. */
     912                 :          0 :         if (ctx->onexec)
     913                 :          0 :                 new = handle_onexec(label, ctx->onexec, ctx->token,
     914                 :            :                                     bprm, buffer, &cond, &unsafe);
     915                 :            :         else
     916                 :          0 :                 new = fn_label_build(label, profile, GFP_ATOMIC,
     917                 :            :                                 profile_transition(profile, bprm, buffer,
     918                 :            :                                                    &cond, &unsafe));
     919                 :            : 
     920                 :            :         AA_BUG(!new);
     921                 :          0 :         if (IS_ERR(new)) {
     922                 :            :                 error = PTR_ERR(new);
     923                 :          0 :                 goto done;
     924                 :          0 :         } else if (!new) {
     925                 :            :                 error = -ENOMEM;
     926                 :            :                 goto done;
     927                 :            :         }
     928                 :            : 
     929                 :            :         /* Policy has specified a domain transitions. If no_new_privs and
     930                 :            :          * confined ensure the transition is to confinement that is subset
     931                 :            :          * of the confinement when the task entered no new privs.
     932                 :            :          *
     933                 :            :          * NOTE: Domain transitions from unconfined and to stacked
     934                 :            :          * subsets are allowed even when no_new_privs is set because this
     935                 :            :          * aways results in a further reduction of permissions.
     936                 :            :          */
     937                 :          0 :         if ((bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) &&
     938                 :          0 :             !unconfined(label) &&
     939                 :          0 :             !aa_label_is_unconfined_subset(new, ctx->nnp)) {
     940                 :            :                 error = -EPERM;
     941                 :          0 :                 info = "no new privs";
     942                 :          0 :                 goto audit;
     943                 :            :         }
     944                 :            : 
     945                 :            :         if (bprm->unsafe & LSM_UNSAFE_SHARE) {
     946                 :            :                 /* FIXME: currently don't mediate shared state */
     947                 :            :                 ;
     948                 :            :         }
     949                 :            : 
     950                 :          0 :         if (bprm->unsafe & (LSM_UNSAFE_PTRACE)) {
     951                 :            :                 /* TODO: test needs to be profile of label to new */
     952                 :          0 :                 error = may_change_ptraced_domain(new, &info);
     953                 :          0 :                 if (error)
     954                 :            :                         goto audit;
     955                 :            :         }
     956                 :            : 
     957                 :          0 :         if (unsafe) {
     958                 :          0 :                 if (DEBUG_ON) {
     959                 :            :                         dbg_printk("scrubbing environment variables for %s "
     960                 :            :                                    "label=", bprm->filename);
     961                 :          0 :                         aa_label_printk(new, GFP_ATOMIC);
     962                 :            :                         dbg_printk("\n");
     963                 :            :                 }
     964                 :          0 :                 bprm->secureexec = 1;
     965                 :            :         }
     966                 :            : 
     967                 :          0 :         if (label->proxy != new->proxy) {
     968                 :            :                 /* when transitioning clear unsafe personality bits */
     969                 :          0 :                 if (DEBUG_ON) {
     970                 :            :                         dbg_printk("apparmor: clearing unsafe personality "
     971                 :            :                                    "bits. %s label=", bprm->filename);
     972                 :          0 :                         aa_label_printk(new, GFP_ATOMIC);
     973                 :            :                         dbg_printk("\n");
     974                 :            :                 }
     975                 :          0 :                 bprm->per_clear |= PER_CLEAR_ON_SETID;
     976                 :            :         }
     977                 :          0 :         aa_put_label(cred_label(bprm->cred));
     978                 :            :         /* transfer reference, released when cred is freed */
     979                 :          0 :         set_cred_label(bprm->cred, new);
     980                 :            : 
     981                 :            : done:
     982                 :            :         aa_put_label(label);
     983                 :          0 :         put_buffers(buffer);
     984                 :            : 
     985                 :          0 :         return error;
     986                 :            : 
     987                 :            : audit:
     988                 :          0 :         error = fn_for_each(label, profile,
     989                 :            :                         aa_audit_file(profile, &nullperms, OP_EXEC, MAY_EXEC,
     990                 :            :                                       bprm->filename, NULL, new,
     991                 :            :                                       file_inode(bprm->file)->i_uid, info,
     992                 :            :                                       error));
     993                 :            :         aa_put_label(new);
     994                 :            :         goto done;
     995                 :            : }
     996                 :            : 
     997                 :            : /*
     998                 :            :  * Functions for self directed profile change
     999                 :            :  */
    1000                 :            : 
    1001                 :            : 
    1002                 :            : /* helper fn for change_hat
    1003                 :            :  *
    1004                 :            :  * Returns: label for hat transition OR ERR_PTR.  Does NOT return NULL
    1005                 :            :  */
    1006                 :          0 : static struct aa_label *build_change_hat(struct aa_profile *profile,
    1007                 :            :                                          const char *name, bool sibling)
    1008                 :            : {
    1009                 :            :         struct aa_profile *root, *hat = NULL;
    1010                 :            :         const char *info = NULL;
    1011                 :            :         int error = 0;
    1012                 :            : 
    1013                 :          0 :         if (sibling && PROFILE_IS_HAT(profile)) {
    1014                 :          0 :                 root = aa_get_profile_rcu(&profile->parent);
    1015                 :          0 :         } else if (!sibling && !PROFILE_IS_HAT(profile)) {
    1016                 :          0 :                 root = aa_get_profile(profile);
    1017                 :            :         } else {
    1018                 :            :                 info = "conflicting target types";
    1019                 :            :                 error = -EPERM;
    1020                 :            :                 goto audit;
    1021                 :            :         }
    1022                 :            : 
    1023                 :          0 :         hat = aa_find_child(root, name);
    1024                 :          0 :         if (!hat) {
    1025                 :            :                 error = -ENOENT;
    1026                 :          0 :                 if (COMPLAIN_MODE(profile)) {
    1027                 :          0 :                         hat = aa_new_null_profile(profile, true, name,
    1028                 :            :                                                   GFP_KERNEL);
    1029                 :          0 :                         if (!hat) {
    1030                 :            :                                 info = "failed null profile create";
    1031                 :            :                                 error = -ENOMEM;
    1032                 :            :                         }
    1033                 :            :                 }
    1034                 :            :         }
    1035                 :            :         aa_put_profile(root);
    1036                 :            : 
    1037                 :            : audit:
    1038                 :          0 :         aa_audit_file(profile, &nullperms, OP_CHANGE_HAT, AA_MAY_CHANGEHAT,
    1039                 :            :                       name, hat ? hat->base.hname : NULL,
    1040                 :          0 :                       hat ? &hat->label : NULL, GLOBAL_ROOT_UID, info,
    1041                 :            :                       error);
    1042                 :          0 :         if (!hat || (error && error != -ENOENT))
    1043                 :          0 :                 return ERR_PTR(error);
    1044                 :            :         /* if hat && error - complain mode, already audited and we adjust for
    1045                 :            :          * complain mode allow by returning hat->label
    1046                 :            :          */
    1047                 :          0 :         return &hat->label;
    1048                 :            : }
    1049                 :            : 
    1050                 :            : /* helper fn for changing into a hat
    1051                 :            :  *
    1052                 :            :  * Returns: label for hat transition or ERR_PTR. Does not return NULL
    1053                 :            :  */
    1054                 :          0 : static struct aa_label *change_hat(struct aa_label *label, const char *hats[],
    1055                 :            :                                    int count, int flags)
    1056                 :            : {
    1057                 :            :         struct aa_profile *profile, *root, *hat = NULL;
    1058                 :            :         struct aa_label *new;
    1059                 :            :         struct label_it it;
    1060                 :            :         bool sibling = false;
    1061                 :            :         const char *name, *info = NULL;
    1062                 :            :         int i, error;
    1063                 :            : 
    1064                 :            :         AA_BUG(!label);
    1065                 :            :         AA_BUG(!hats);
    1066                 :            :         AA_BUG(count < 1);
    1067                 :            : 
    1068                 :          0 :         if (PROFILE_IS_HAT(labels_profile(label)))
    1069                 :            :                 sibling = true;
    1070                 :            : 
    1071                 :            :         /*find first matching hat */
    1072                 :          0 :         for (i = 0; i < count && !hat; i++) {
    1073                 :          0 :                 name = hats[i];
    1074                 :          0 :                 label_for_each_in_ns(it, labels_ns(label), label, profile) {
    1075                 :          0 :                         if (sibling && PROFILE_IS_HAT(profile)) {
    1076                 :          0 :                                 root = aa_get_profile_rcu(&profile->parent);
    1077                 :          0 :                         } else if (!sibling && !PROFILE_IS_HAT(profile)) {
    1078                 :          0 :                                 root = aa_get_profile(profile);
    1079                 :            :                         } else {        /* conflicting change type */
    1080                 :            :                                 info = "conflicting targets types";
    1081                 :            :                                 error = -EPERM;
    1082                 :            :                                 goto fail;
    1083                 :            :                         }
    1084                 :          0 :                         hat = aa_find_child(root, name);
    1085                 :            :                         aa_put_profile(root);
    1086                 :          0 :                         if (!hat) {
    1087                 :          0 :                                 if (!COMPLAIN_MODE(profile))
    1088                 :            :                                         goto outer_continue;
    1089                 :            :                                 /* complain mode succeed as if hat */
    1090                 :          0 :                         } else if (!PROFILE_IS_HAT(hat)) {
    1091                 :            :                                 info = "target not hat";
    1092                 :            :                                 error = -EPERM;
    1093                 :            :                                 aa_put_profile(hat);
    1094                 :            :                                 goto fail;
    1095                 :            :                         }
    1096                 :            :                         aa_put_profile(hat);
    1097                 :            :                 }
    1098                 :            :                 /* found a hat for all profiles in ns */
    1099                 :            :                 goto build;
    1100                 :            : outer_continue:
    1101                 :            :         ;
    1102                 :            :         }
    1103                 :            :         /* no hats that match, find appropriate error
    1104                 :            :          *
    1105                 :            :          * In complain mode audit of the failure is based off of the first
    1106                 :            :          * hat supplied.  This is done due how userspace interacts with
    1107                 :            :          * change_hat.
    1108                 :            :          */
    1109                 :            :         name = NULL;
    1110                 :          0 :         label_for_each_in_ns(it, labels_ns(label), label, profile) {
    1111                 :          0 :                 if (!list_empty(&profile->base.profiles)) {
    1112                 :            :                         info = "hat not found";
    1113                 :            :                         error = -ENOENT;
    1114                 :            :                         goto fail;
    1115                 :            :                 }
    1116                 :            :         }
    1117                 :            :         info = "no hats defined";
    1118                 :            :         error = -ECHILD;
    1119                 :            : 
    1120                 :            : fail:
    1121                 :          0 :         label_for_each_in_ns(it, labels_ns(label), label, profile) {
    1122                 :            :                 /*
    1123                 :            :                  * no target as it has failed to be found or built
    1124                 :            :                  *
    1125                 :            :                  * change_hat uses probing and should not log failures
    1126                 :            :                  * related to missing hats
    1127                 :            :                  */
    1128                 :            :                 /* TODO: get rid of GLOBAL_ROOT_UID */
    1129                 :          0 :                 if (count > 1 || COMPLAIN_MODE(profile)) {
    1130                 :          0 :                         aa_audit_file(profile, &nullperms, OP_CHANGE_HAT,
    1131                 :            :                                       AA_MAY_CHANGEHAT, name, NULL, NULL,
    1132                 :          0 :                                       GLOBAL_ROOT_UID, info, error);
    1133                 :            :                 }
    1134                 :            :         }
    1135                 :          0 :         return ERR_PTR(error);
    1136                 :            : 
    1137                 :            : build:
    1138                 :          0 :         new = fn_label_build_in_ns(label, profile, GFP_KERNEL,
    1139                 :            :                                    build_change_hat(profile, name, sibling),
    1140                 :            :                                    aa_get_label(&profile->label));
    1141                 :          0 :         if (!new) {
    1142                 :            :                 info = "label build failed";
    1143                 :            :                 error = -ENOMEM;
    1144                 :            :                 goto fail;
    1145                 :            :         } /* else if (IS_ERR) build_change_hat has logged error so return new */
    1146                 :            : 
    1147                 :            :         return new;
    1148                 :            : }
    1149                 :            : 
    1150                 :            : /**
    1151                 :            :  * aa_change_hat - change hat to/from subprofile
    1152                 :            :  * @hats: vector of hat names to try changing into (MAYBE NULL if @count == 0)
    1153                 :            :  * @count: number of hat names in @hats
    1154                 :            :  * @token: magic value to validate the hat change
    1155                 :            :  * @flags: flags affecting behavior of the change
    1156                 :            :  *
    1157                 :            :  * Returns %0 on success, error otherwise.
    1158                 :            :  *
    1159                 :            :  * Change to the first profile specified in @hats that exists, and store
    1160                 :            :  * the @hat_magic in the current task context.  If the count == 0 and the
    1161                 :            :  * @token matches that stored in the current task context, return to the
    1162                 :            :  * top level profile.
    1163                 :            :  *
    1164                 :            :  * change_hat only applies to profiles in the current ns, and each profile
    1165                 :            :  * in the ns must make the same transition otherwise change_hat will fail.
    1166                 :            :  */
    1167                 :          0 : int aa_change_hat(const char *hats[], int count, u64 token, int flags)
    1168                 :            : {
    1169                 :            :         const struct cred *cred;
    1170                 :          0 :         struct aa_task_ctx *ctx = task_ctx(current);
    1171                 :            :         struct aa_label *label, *previous, *new = NULL, *target = NULL;
    1172                 :            :         struct aa_profile *profile;
    1173                 :          0 :         struct aa_perms perms = {};
    1174                 :          0 :         const char *info = NULL;
    1175                 :            :         int error = 0;
    1176                 :            : 
    1177                 :            :         /* released below */
    1178                 :          0 :         cred = get_current_cred();
    1179                 :            :         label = aa_get_newest_cred_label(cred);
    1180                 :          0 :         previous = aa_get_newest_label(ctx->previous);
    1181                 :            : 
    1182                 :            :         /*
    1183                 :            :          * Detect no new privs being set, and store the label it
    1184                 :            :          * occurred under. Ideally this would happen when nnp
    1185                 :            :          * is set but there isn't a good way to do that yet.
    1186                 :            :          *
    1187                 :            :          * Testing for unconfined must be done before the subset test
    1188                 :            :          */
    1189                 :          0 :         if (task_no_new_privs(current) && !unconfined(label) && !ctx->nnp)
    1190                 :          0 :                 ctx->nnp = aa_get_label(label);
    1191                 :            : 
    1192                 :          0 :         if (unconfined(label)) {
    1193                 :          0 :                 info = "unconfined can not change_hat";
    1194                 :            :                 error = -EPERM;
    1195                 :          0 :                 goto fail;
    1196                 :            :         }
    1197                 :            : 
    1198                 :          0 :         if (count) {
    1199                 :          0 :                 new = change_hat(label, hats, count, flags);
    1200                 :            :                 AA_BUG(!new);
    1201                 :          0 :                 if (IS_ERR(new)) {
    1202                 :            :                         error = PTR_ERR(new);
    1203                 :            :                         new = NULL;
    1204                 :            :                         /* already audited */
    1205                 :          0 :                         goto out;
    1206                 :            :                 }
    1207                 :            : 
    1208                 :          0 :                 error = may_change_ptraced_domain(new, &info);
    1209                 :          0 :                 if (error)
    1210                 :            :                         goto fail;
    1211                 :            : 
    1212                 :            :                 /*
    1213                 :            :                  * no new privs prevents domain transitions that would
    1214                 :            :                  * reduce restrictions.
    1215                 :            :                  */
    1216                 :          0 :                 if (task_no_new_privs(current) && !unconfined(label) &&
    1217                 :          0 :                     !aa_label_is_unconfined_subset(new, ctx->nnp)) {
    1218                 :            :                         /* not an apparmor denial per se, so don't log it */
    1219                 :            :                         AA_DEBUG("no_new_privs - change_hat denied");
    1220                 :            :                         error = -EPERM;
    1221                 :            :                         goto out;
    1222                 :            :                 }
    1223                 :            : 
    1224                 :          0 :                 if (flags & AA_CHANGE_TEST)
    1225                 :            :                         goto out;
    1226                 :            : 
    1227                 :            :                 target = new;
    1228                 :          0 :                 error = aa_set_current_hat(new, token);
    1229                 :          0 :                 if (error == -EACCES)
    1230                 :            :                         /* kill task in case of brute force attacks */
    1231                 :            :                         goto kill;
    1232                 :          0 :         } else if (previous && !(flags & AA_CHANGE_TEST)) {
    1233                 :            :                 /*
    1234                 :            :                  * no new privs prevents domain transitions that would
    1235                 :            :                  * reduce restrictions.
    1236                 :            :                  */
    1237                 :          0 :                 if (task_no_new_privs(current) && !unconfined(label) &&
    1238                 :          0 :                     !aa_label_is_unconfined_subset(previous, ctx->nnp)) {
    1239                 :            :                         /* not an apparmor denial per se, so don't log it */
    1240                 :            :                         AA_DEBUG("no_new_privs - change_hat denied");
    1241                 :            :                         error = -EPERM;
    1242                 :            :                         goto out;
    1243                 :            :                 }
    1244                 :            : 
    1245                 :            :                 /* Return to saved label.  Kill task if restore fails
    1246                 :            :                  * to avoid brute force attacks
    1247                 :            :                  */
    1248                 :            :                 target = previous;
    1249                 :          0 :                 error = aa_restore_previous_label(token);
    1250                 :          0 :                 if (error) {
    1251                 :          0 :                         if (error == -EACCES)
    1252                 :            :                                 goto kill;
    1253                 :            :                         goto fail;
    1254                 :            :                 }
    1255                 :            :         } /* else ignore @flags && restores when there is no saved profile */
    1256                 :            : 
    1257                 :            : out:
    1258                 :            :         aa_put_label(new);
    1259                 :            :         aa_put_label(previous);
    1260                 :            :         aa_put_label(label);
    1261                 :          0 :         put_cred(cred);
    1262                 :            : 
    1263                 :          0 :         return error;
    1264                 :            : 
    1265                 :            : kill:
    1266                 :          0 :         info = "failed token match";
    1267                 :          0 :         perms.kill = AA_MAY_CHANGEHAT;
    1268                 :            : 
    1269                 :            : fail:
    1270                 :          0 :         fn_for_each_in_ns(label, profile,
    1271                 :            :                 aa_audit_file(profile, &perms, OP_CHANGE_HAT,
    1272                 :            :                               AA_MAY_CHANGEHAT, NULL, NULL, target,
    1273                 :            :                               GLOBAL_ROOT_UID, info, error));
    1274                 :            : 
    1275                 :            :         goto out;
    1276                 :            : }
    1277                 :            : 
    1278                 :            : 
    1279                 :          0 : static int change_profile_perms_wrapper(const char *op, const char *name,
    1280                 :            :                                         struct aa_profile *profile,
    1281                 :            :                                         struct aa_label *target, bool stack,
    1282                 :            :                                         u32 request, struct aa_perms *perms)
    1283                 :            : {
    1284                 :            :         const char *info = NULL;
    1285                 :            :         int error = 0;
    1286                 :            : 
    1287                 :            :         if (!error)
    1288                 :          0 :                 error = change_profile_perms(profile, target, stack, request,
    1289                 :            :                                              profile->file.start, perms);
    1290                 :          0 :         if (error)
    1291                 :          0 :                 error = aa_audit_file(profile, perms, op, request, name,
    1292                 :          0 :                                       NULL, target, GLOBAL_ROOT_UID, info,
    1293                 :            :                                       error);
    1294                 :            : 
    1295                 :          0 :         return error;
    1296                 :            : }
    1297                 :            : 
    1298                 :            : /**
    1299                 :            :  * aa_change_profile - perform a one-way profile transition
    1300                 :            :  * @fqname: name of profile may include namespace (NOT NULL)
    1301                 :            :  * @onexec: whether this transition is to take place immediately or at exec
    1302                 :            :  * @flags: flags affecting change behavior
    1303                 :            :  *
    1304                 :            :  * Change to new profile @name.  Unlike with hats, there is no way
    1305                 :            :  * to change back.  If @name isn't specified the current profile name is
    1306                 :            :  * used.
    1307                 :            :  * If @onexec then the transition is delayed until
    1308                 :            :  * the next exec.
    1309                 :            :  *
    1310                 :            :  * Returns %0 on success, error otherwise.
    1311                 :            :  */
    1312                 :          0 : int aa_change_profile(const char *fqname, int flags)
    1313                 :            : {
    1314                 :            :         struct aa_label *label, *new = NULL, *target = NULL;
    1315                 :            :         struct aa_profile *profile;
    1316                 :          0 :         struct aa_perms perms = {};
    1317                 :          0 :         const char *info = NULL;
    1318                 :            :         const char *auditname = fqname;         /* retain leading & if stack */
    1319                 :          0 :         bool stack = flags & AA_CHANGE_STACK;
    1320                 :          0 :         struct aa_task_ctx *ctx = task_ctx(current);
    1321                 :            :         int error = 0;
    1322                 :            :         char *op;
    1323                 :            :         u32 request;
    1324                 :            : 
    1325                 :          0 :         label = aa_get_current_label();
    1326                 :            : 
    1327                 :            :         /*
    1328                 :            :          * Detect no new privs being set, and store the label it
    1329                 :            :          * occurred under. Ideally this would happen when nnp
    1330                 :            :          * is set but there isn't a good way to do that yet.
    1331                 :            :          *
    1332                 :            :          * Testing for unconfined must be done before the subset test
    1333                 :            :          */
    1334                 :          0 :         if (task_no_new_privs(current) && !unconfined(label) && !ctx->nnp)
    1335                 :          0 :                 ctx->nnp = aa_get_label(label);
    1336                 :            : 
    1337                 :          0 :         if (!fqname || !*fqname) {
    1338                 :            :                 aa_put_label(label);
    1339                 :            :                 AA_DEBUG("no profile name");
    1340                 :            :                 return -EINVAL;
    1341                 :            :         }
    1342                 :            : 
    1343                 :          0 :         if (flags & AA_CHANGE_ONEXEC) {
    1344                 :            :                 request = AA_MAY_ONEXEC;
    1345                 :          0 :                 if (stack)
    1346                 :            :                         op = OP_STACK_ONEXEC;
    1347                 :            :                 else
    1348                 :            :                         op = OP_CHANGE_ONEXEC;
    1349                 :            :         } else {
    1350                 :            :                 request = AA_MAY_CHANGE_PROFILE;
    1351                 :          0 :                 if (stack)
    1352                 :            :                         op = OP_STACK;
    1353                 :            :                 else
    1354                 :            :                         op = OP_CHANGE_PROFILE;
    1355                 :            :         }
    1356                 :            : 
    1357                 :          0 :         if (*fqname == '&') {
    1358                 :            :                 stack = true;
    1359                 :            :                 /* don't have label_parse() do stacking */
    1360                 :          0 :                 fqname++;
    1361                 :            :         }
    1362                 :          0 :         target = aa_label_parse(label, fqname, GFP_KERNEL, true, false);
    1363                 :          0 :         if (IS_ERR(target)) {
    1364                 :            :                 struct aa_profile *tprofile;
    1365                 :            : 
    1366                 :          0 :                 info = "label not found";
    1367                 :            :                 error = PTR_ERR(target);
    1368                 :            :                 target = NULL;
    1369                 :            :                 /*
    1370                 :            :                  * TODO: fixme using labels_profile is not right - do profile
    1371                 :            :                  * per complain profile
    1372                 :            :                  */
    1373                 :          0 :                 if ((flags & AA_CHANGE_TEST) ||
    1374                 :          0 :                     !COMPLAIN_MODE(labels_profile(label)))
    1375                 :            :                         goto audit;
    1376                 :            :                 /* released below */
    1377                 :          0 :                 tprofile = aa_new_null_profile(labels_profile(label), false,
    1378                 :            :                                                fqname, GFP_KERNEL);
    1379                 :          0 :                 if (!tprofile) {
    1380                 :          0 :                         info = "failed null profile create";
    1381                 :            :                         error = -ENOMEM;
    1382                 :          0 :                         goto audit;
    1383                 :            :                 }
    1384                 :          0 :                 target = &tprofile->label;
    1385                 :          0 :                 goto check;
    1386                 :            :         }
    1387                 :            : 
    1388                 :            :         /*
    1389                 :            :          * self directed transitions only apply to current policy ns
    1390                 :            :          * TODO: currently requiring perms for stacking and straight change
    1391                 :            :          *       stacking doesn't strictly need this. Determine how much
    1392                 :            :          *       we want to loosen this restriction for stacking
    1393                 :            :          *
    1394                 :            :          * if (!stack) {
    1395                 :            :          */
    1396                 :          0 :         error = fn_for_each_in_ns(label, profile,
    1397                 :            :                         change_profile_perms_wrapper(op, auditname,
    1398                 :            :                                                      profile, target, stack,
    1399                 :            :                                                      request, &perms));
    1400                 :          0 :         if (error)
    1401                 :            :                 /* auditing done in change_profile_perms_wrapper */
    1402                 :            :                 goto out;
    1403                 :            : 
    1404                 :            :         /* } */
    1405                 :            : 
    1406                 :            : check:
    1407                 :            :         /* check if tracing task is allowed to trace target domain */
    1408                 :          0 :         error = may_change_ptraced_domain(target, &info);
    1409                 :          0 :         if (error && !fn_for_each_in_ns(label, profile,
    1410                 :            :                                         COMPLAIN_MODE(profile)))
    1411                 :            :                 goto audit;
    1412                 :            : 
    1413                 :            :         /* TODO: add permission check to allow this
    1414                 :            :          * if ((flags & AA_CHANGE_ONEXEC) && !current_is_single_threaded()) {
    1415                 :            :          *      info = "not a single threaded task";
    1416                 :            :          *      error = -EACCES;
    1417                 :            :          *      goto audit;
    1418                 :            :          * }
    1419                 :            :          */
    1420                 :          0 :         if (flags & AA_CHANGE_TEST)
    1421                 :            :                 goto out;
    1422                 :            : 
    1423                 :            :         /* stacking is always a subset, so only check the nonstack case */
    1424                 :          0 :         if (!stack) {
    1425                 :          0 :                 new = fn_label_build_in_ns(label, profile, GFP_KERNEL,
    1426                 :            :                                            aa_get_label(target),
    1427                 :            :                                            aa_get_label(&profile->label));
    1428                 :            :                 /*
    1429                 :            :                  * no new privs prevents domain transitions that would
    1430                 :            :                  * reduce restrictions.
    1431                 :            :                  */
    1432                 :          0 :                 if (task_no_new_privs(current) && !unconfined(label) &&
    1433                 :          0 :                     !aa_label_is_unconfined_subset(new, ctx->nnp)) {
    1434                 :            :                         /* not an apparmor denial per se, so don't log it */
    1435                 :            :                         AA_DEBUG("no_new_privs - change_hat denied");
    1436                 :            :                         error = -EPERM;
    1437                 :            :                         goto out;
    1438                 :            :                 }
    1439                 :            :         }
    1440                 :            : 
    1441                 :          0 :         if (!(flags & AA_CHANGE_ONEXEC)) {
    1442                 :            :                 /* only transition profiles in the current ns */
    1443                 :          0 :                 if (stack)
    1444                 :          0 :                         new = aa_label_merge(label, target, GFP_KERNEL);
    1445                 :          0 :                 if (IS_ERR_OR_NULL(new)) {
    1446                 :          0 :                         info = "failed to build target label";
    1447                 :          0 :                         if (!new)
    1448                 :            :                                 error = -ENOMEM;
    1449                 :            :                         else
    1450                 :            :                                 error = PTR_ERR(new);
    1451                 :            :                         new = NULL;
    1452                 :          0 :                         perms.allow = 0;
    1453                 :          0 :                         goto audit;
    1454                 :            :                 }
    1455                 :          0 :                 error = aa_replace_current_label(new);
    1456                 :            :         } else {
    1457                 :          0 :                 if (new) {
    1458                 :            :                         aa_put_label(new);
    1459                 :            :                         new = NULL;
    1460                 :            :                 }
    1461                 :            : 
    1462                 :            :                 /* full transition will be built in exec path */
    1463                 :          0 :                 error = aa_set_current_onexec(target, stack);
    1464                 :            :         }
    1465                 :            : 
    1466                 :            : audit:
    1467                 :          0 :         error = fn_for_each_in_ns(label, profile,
    1468                 :            :                         aa_audit_file(profile, &perms, op, request, auditname,
    1469                 :            :                                       NULL, new ? new : target,
    1470                 :            :                                       GLOBAL_ROOT_UID, info, error));
    1471                 :            : 
    1472                 :            : out:
    1473                 :            :         aa_put_label(new);
    1474                 :            :         aa_put_label(target);
    1475                 :            :         aa_put_label(label);
    1476                 :            : 
    1477                 :          0 :         return error;
    1478                 :            : }
    

Generated by: LCOV version 1.14