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