LCOV - code coverage report
Current view: top level - security/apparmor - mount.c (source / functions) Hit Total Coverage
Test: Real Lines: 0 239 0.0 %
Date: 2020-10-17 15:46:16 Functions: 0 17 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 mediation of files
       6                 :            :  *
       7                 :            :  * Copyright (C) 1998-2008 Novell/SUSE
       8                 :            :  * Copyright 2009-2017 Canonical Ltd.
       9                 :            :  */
      10                 :            : 
      11                 :            : #include <linux/fs.h>
      12                 :            : #include <linux/mount.h>
      13                 :            : #include <linux/namei.h>
      14                 :            : #include <uapi/linux/mount.h>
      15                 :            : 
      16                 :            : #include "include/apparmor.h"
      17                 :            : #include "include/audit.h"
      18                 :            : #include "include/cred.h"
      19                 :            : #include "include/domain.h"
      20                 :            : #include "include/file.h"
      21                 :            : #include "include/match.h"
      22                 :            : #include "include/mount.h"
      23                 :            : #include "include/path.h"
      24                 :            : #include "include/policy.h"
      25                 :            : 
      26                 :            : 
      27                 :          0 : static void audit_mnt_flags(struct audit_buffer *ab, unsigned long flags)
      28                 :            : {
      29                 :          0 :         if (flags & MS_RDONLY)
      30                 :          0 :                 audit_log_format(ab, "ro");
      31                 :            :         else
      32                 :          0 :                 audit_log_format(ab, "rw");
      33                 :          0 :         if (flags & MS_NOSUID)
      34                 :          0 :                 audit_log_format(ab, ", nosuid");
      35                 :          0 :         if (flags & MS_NODEV)
      36                 :          0 :                 audit_log_format(ab, ", nodev");
      37                 :          0 :         if (flags & MS_NOEXEC)
      38                 :          0 :                 audit_log_format(ab, ", noexec");
      39                 :          0 :         if (flags & MS_SYNCHRONOUS)
      40                 :          0 :                 audit_log_format(ab, ", sync");
      41                 :          0 :         if (flags & MS_REMOUNT)
      42                 :          0 :                 audit_log_format(ab, ", remount");
      43                 :          0 :         if (flags & MS_MANDLOCK)
      44                 :          0 :                 audit_log_format(ab, ", mand");
      45                 :          0 :         if (flags & MS_DIRSYNC)
      46                 :          0 :                 audit_log_format(ab, ", dirsync");
      47                 :          0 :         if (flags & MS_NOATIME)
      48                 :          0 :                 audit_log_format(ab, ", noatime");
      49                 :          0 :         if (flags & MS_NODIRATIME)
      50                 :          0 :                 audit_log_format(ab, ", nodiratime");
      51                 :          0 :         if (flags & MS_BIND)
      52                 :          0 :                 audit_log_format(ab, flags & MS_REC ? ", rbind" : ", bind");
      53                 :          0 :         if (flags & MS_MOVE)
      54                 :          0 :                 audit_log_format(ab, ", move");
      55                 :          0 :         if (flags & MS_SILENT)
      56                 :          0 :                 audit_log_format(ab, ", silent");
      57                 :          0 :         if (flags & MS_POSIXACL)
      58                 :          0 :                 audit_log_format(ab, ", acl");
      59                 :          0 :         if (flags & MS_UNBINDABLE)
      60                 :          0 :                 audit_log_format(ab, flags & MS_REC ? ", runbindable" :
      61                 :            :                                  ", unbindable");
      62                 :          0 :         if (flags & MS_PRIVATE)
      63                 :          0 :                 audit_log_format(ab, flags & MS_REC ? ", rprivate" :
      64                 :            :                                  ", private");
      65                 :          0 :         if (flags & MS_SLAVE)
      66                 :          0 :                 audit_log_format(ab, flags & MS_REC ? ", rslave" :
      67                 :            :                                  ", slave");
      68                 :          0 :         if (flags & MS_SHARED)
      69                 :          0 :                 audit_log_format(ab, flags & MS_REC ? ", rshared" :
      70                 :            :                                  ", shared");
      71                 :          0 :         if (flags & MS_RELATIME)
      72                 :          0 :                 audit_log_format(ab, ", relatime");
      73                 :          0 :         if (flags & MS_I_VERSION)
      74                 :          0 :                 audit_log_format(ab, ", iversion");
      75                 :          0 :         if (flags & MS_STRICTATIME)
      76                 :          0 :                 audit_log_format(ab, ", strictatime");
      77                 :          0 :         if (flags & MS_NOUSER)
      78                 :          0 :                 audit_log_format(ab, ", nouser");
      79                 :          0 : }
      80                 :            : 
      81                 :            : /**
      82                 :            :  * audit_cb - call back for mount specific audit fields
      83                 :            :  * @ab: audit_buffer  (NOT NULL)
      84                 :            :  * @va: audit struct to audit values of  (NOT NULL)
      85                 :            :  */
      86                 :          0 : static void audit_cb(struct audit_buffer *ab, void *va)
      87                 :            : {
      88                 :            :         struct common_audit_data *sa = va;
      89                 :            : 
      90                 :          0 :         if (aad(sa)->mnt.type) {
      91                 :          0 :                 audit_log_format(ab, " fstype=");
      92                 :          0 :                 audit_log_untrustedstring(ab, aad(sa)->mnt.type);
      93                 :            :         }
      94                 :          0 :         if (aad(sa)->mnt.src_name) {
      95                 :          0 :                 audit_log_format(ab, " srcname=");
      96                 :          0 :                 audit_log_untrustedstring(ab, aad(sa)->mnt.src_name);
      97                 :            :         }
      98                 :          0 :         if (aad(sa)->mnt.trans) {
      99                 :          0 :                 audit_log_format(ab, " trans=");
     100                 :          0 :                 audit_log_untrustedstring(ab, aad(sa)->mnt.trans);
     101                 :            :         }
     102                 :          0 :         if (aad(sa)->mnt.flags) {
     103                 :          0 :                 audit_log_format(ab, " flags=\"");
     104                 :          0 :                 audit_mnt_flags(ab, aad(sa)->mnt.flags);
     105                 :          0 :                 audit_log_format(ab, "\"");
     106                 :            :         }
     107                 :          0 :         if (aad(sa)->mnt.data) {
     108                 :          0 :                 audit_log_format(ab, " options=");
     109                 :          0 :                 audit_log_untrustedstring(ab, aad(sa)->mnt.data);
     110                 :            :         }
     111                 :          0 : }
     112                 :            : 
     113                 :            : /**
     114                 :            :  * audit_mount - handle the auditing of mount operations
     115                 :            :  * @profile: the profile being enforced  (NOT NULL)
     116                 :            :  * @op: operation being mediated (NOT NULL)
     117                 :            :  * @name: name of object being mediated (MAYBE NULL)
     118                 :            :  * @src_name: src_name of object being mediated (MAYBE_NULL)
     119                 :            :  * @type: type of filesystem (MAYBE_NULL)
     120                 :            :  * @trans: name of trans (MAYBE NULL)
     121                 :            :  * @flags: filesystem independent mount flags
     122                 :            :  * @data: filesystem mount flags
     123                 :            :  * @request: permissions requested
     124                 :            :  * @perms: the permissions computed for the request (NOT NULL)
     125                 :            :  * @info: extra information message (MAYBE NULL)
     126                 :            :  * @error: 0 if operation allowed else failure error code
     127                 :            :  *
     128                 :            :  * Returns: %0 or error on failure
     129                 :            :  */
     130                 :          0 : static int audit_mount(struct aa_profile *profile, const char *op,
     131                 :            :                        const char *name, const char *src_name,
     132                 :            :                        const char *type, const char *trans,
     133                 :            :                        unsigned long flags, const void *data, u32 request,
     134                 :            :                        struct aa_perms *perms, const char *info, int error)
     135                 :            : {
     136                 :            :         int audit_type = AUDIT_APPARMOR_AUTO;
     137                 :          0 :         DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, op);
     138                 :            : 
     139                 :          0 :         if (likely(!error)) {
     140                 :          0 :                 u32 mask = perms->audit;
     141                 :            : 
     142                 :          0 :                 if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
     143                 :            :                         mask = 0xffff;
     144                 :            : 
     145                 :            :                 /* mask off perms that are not being force audited */
     146                 :          0 :                 request &= mask;
     147                 :            : 
     148                 :          0 :                 if (likely(!request))
     149                 :            :                         return 0;
     150                 :            :                 audit_type = AUDIT_APPARMOR_AUDIT;
     151                 :            :         } else {
     152                 :            :                 /* only report permissions that were denied */
     153                 :          0 :                 request = request & ~perms->allow;
     154                 :            : 
     155                 :          0 :                 if (request & perms->kill)
     156                 :            :                         audit_type = AUDIT_APPARMOR_KILL;
     157                 :            : 
     158                 :            :                 /* quiet known rejects, assumes quiet and kill do not overlap */
     159                 :          0 :                 if ((request & perms->quiet) &&
     160                 :          0 :                     AUDIT_MODE(profile) != AUDIT_NOQUIET &&
     161                 :            :                     AUDIT_MODE(profile) != AUDIT_ALL)
     162                 :          0 :                         request &= ~perms->quiet;
     163                 :            : 
     164                 :          0 :                 if (!request)
     165                 :            :                         return error;
     166                 :            :         }
     167                 :            : 
     168                 :          0 :         aad(&sa)->name = name;
     169                 :          0 :         aad(&sa)->mnt.src_name = src_name;
     170                 :          0 :         aad(&sa)->mnt.type = type;
     171                 :          0 :         aad(&sa)->mnt.trans = trans;
     172                 :          0 :         aad(&sa)->mnt.flags = flags;
     173                 :          0 :         if (data && (perms->audit & AA_AUDIT_DATA))
     174                 :          0 :                 aad(&sa)->mnt.data = data;
     175                 :          0 :         aad(&sa)->info = info;
     176                 :          0 :         aad(&sa)->error = error;
     177                 :            : 
     178                 :          0 :         return aa_audit(audit_type, profile, &sa, audit_cb);
     179                 :            : }
     180                 :            : 
     181                 :            : /**
     182                 :            :  * match_mnt_flags - Do an ordered match on mount flags
     183                 :            :  * @dfa: dfa to match against
     184                 :            :  * @state: state to start in
     185                 :            :  * @flags: mount flags to match against
     186                 :            :  *
     187                 :            :  * Mount flags are encoded as an ordered match. This is done instead of
     188                 :            :  * checking against a simple bitmask, to allow for logical operations
     189                 :            :  * on the flags.
     190                 :            :  *
     191                 :            :  * Returns: next state after flags match
     192                 :            :  */
     193                 :          0 : static unsigned int match_mnt_flags(struct aa_dfa *dfa, unsigned int state,
     194                 :            :                                     unsigned long flags)
     195                 :            : {
     196                 :            :         unsigned int i;
     197                 :            : 
     198                 :          0 :         for (i = 0; i <= 31 ; ++i) {
     199                 :          0 :                 if ((1 << i) & flags)
     200                 :          0 :                         state = aa_dfa_next(dfa, state, i + 1);
     201                 :            :         }
     202                 :            : 
     203                 :          0 :         return state;
     204                 :            : }
     205                 :            : 
     206                 :            : /**
     207                 :            :  * compute_mnt_perms - compute mount permission associated with @state
     208                 :            :  * @dfa: dfa to match against (NOT NULL)
     209                 :            :  * @state: state match finished in
     210                 :            :  *
     211                 :            :  * Returns: mount permissions
     212                 :            :  */
     213                 :          0 : static struct aa_perms compute_mnt_perms(struct aa_dfa *dfa,
     214                 :            :                                            unsigned int state)
     215                 :            : {
     216                 :          0 :         struct aa_perms perms = {
     217                 :          0 :                 .allow = dfa_user_allow(dfa, state),
     218                 :          0 :                 .audit = dfa_user_audit(dfa, state),
     219                 :          0 :                 .quiet = dfa_user_quiet(dfa, state),
     220                 :          0 :                 .xindex = dfa_user_xindex(dfa, state),
     221                 :            :         };
     222                 :            : 
     223                 :          0 :         return perms;
     224                 :            : }
     225                 :            : 
     226                 :            : static const char * const mnt_info_table[] = {
     227                 :            :         "match succeeded",
     228                 :            :         "failed mntpnt match",
     229                 :            :         "failed srcname match",
     230                 :            :         "failed type match",
     231                 :            :         "failed flags match",
     232                 :            :         "failed data match"
     233                 :            : };
     234                 :            : 
     235                 :            : /*
     236                 :            :  * Returns 0 on success else element that match failed in, this is the
     237                 :            :  * index into the mnt_info_table above
     238                 :            :  */
     239                 :          0 : static int do_match_mnt(struct aa_dfa *dfa, unsigned int start,
     240                 :            :                         const char *mntpnt, const char *devname,
     241                 :            :                         const char *type, unsigned long flags,
     242                 :            :                         void *data, bool binary, struct aa_perms *perms)
     243                 :            : {
     244                 :            :         unsigned int state;
     245                 :            : 
     246                 :            :         AA_BUG(!dfa);
     247                 :            :         AA_BUG(!perms);
     248                 :            : 
     249                 :          0 :         state = aa_dfa_match(dfa, start, mntpnt);
     250                 :            :         state = aa_dfa_null_transition(dfa, state);
     251                 :          0 :         if (!state)
     252                 :            :                 return 1;
     253                 :            : 
     254                 :          0 :         if (devname)
     255                 :          0 :                 state = aa_dfa_match(dfa, state, devname);
     256                 :            :         state = aa_dfa_null_transition(dfa, state);
     257                 :          0 :         if (!state)
     258                 :            :                 return 2;
     259                 :            : 
     260                 :          0 :         if (type)
     261                 :          0 :                 state = aa_dfa_match(dfa, state, type);
     262                 :            :         state = aa_dfa_null_transition(dfa, state);
     263                 :          0 :         if (!state)
     264                 :            :                 return 3;
     265                 :            : 
     266                 :          0 :         state = match_mnt_flags(dfa, state, flags);
     267                 :          0 :         if (!state)
     268                 :            :                 return 4;
     269                 :          0 :         *perms = compute_mnt_perms(dfa, state);
     270                 :          0 :         if (perms->allow & AA_MAY_MOUNT)
     271                 :            :                 return 0;
     272                 :            : 
     273                 :            :         /* only match data if not binary and the DFA flags data is expected */
     274                 :          0 :         if (data && !binary && (perms->allow & AA_MNT_CONT_MATCH)) {
     275                 :            :                 state = aa_dfa_null_transition(dfa, state);
     276                 :          0 :                 if (!state)
     277                 :            :                         return 4;
     278                 :            : 
     279                 :          0 :                 state = aa_dfa_match(dfa, state, data);
     280                 :          0 :                 if (!state)
     281                 :            :                         return 5;
     282                 :          0 :                 *perms = compute_mnt_perms(dfa, state);
     283                 :          0 :                 if (perms->allow & AA_MAY_MOUNT)
     284                 :            :                         return 0;
     285                 :            :         }
     286                 :            : 
     287                 :            :         /* failed at end of flags match */
     288                 :            :         return 4;
     289                 :            : }
     290                 :            : 
     291                 :            : 
     292                 :            : static int path_flags(struct aa_profile *profile, const struct path *path)
     293                 :            : {
     294                 :            :         AA_BUG(!profile);
     295                 :            :         AA_BUG(!path);
     296                 :            : 
     297                 :          0 :         return profile->path_flags |
     298                 :          0 :                 (S_ISDIR(path->dentry->d_inode->i_mode) ? PATH_IS_DIR : 0);
     299                 :            : }
     300                 :            : 
     301                 :            : /**
     302                 :            :  * match_mnt_path_str - handle path matching for mount
     303                 :            :  * @profile: the confining profile
     304                 :            :  * @mntpath: for the mntpnt (NOT NULL)
     305                 :            :  * @buffer: buffer to be used to lookup mntpath
     306                 :            :  * @devnme: string for the devname/src_name (MAY BE NULL OR ERRPTR)
     307                 :            :  * @type: string for the dev type (MAYBE NULL)
     308                 :            :  * @flags: mount flags to match
     309                 :            :  * @data: fs mount data (MAYBE NULL)
     310                 :            :  * @binary: whether @data is binary
     311                 :            :  * @devinfo: error str if (IS_ERR(@devname))
     312                 :            :  *
     313                 :            :  * Returns: 0 on success else error
     314                 :            :  */
     315                 :          0 : static int match_mnt_path_str(struct aa_profile *profile,
     316                 :            :                               const struct path *mntpath, char *buffer,
     317                 :            :                               const char *devname, const char *type,
     318                 :            :                               unsigned long flags, void *data, bool binary,
     319                 :            :                               const char *devinfo)
     320                 :            : {
     321                 :          0 :         struct aa_perms perms = { };
     322                 :          0 :         const char *mntpnt = NULL, *info = NULL;
     323                 :            :         int pos, error;
     324                 :            : 
     325                 :            :         AA_BUG(!profile);
     326                 :            :         AA_BUG(!mntpath);
     327                 :            :         AA_BUG(!buffer);
     328                 :            : 
     329                 :          0 :         if (!PROFILE_MEDIATES(profile, AA_CLASS_MOUNT))
     330                 :            :                 return 0;
     331                 :            : 
     332                 :          0 :         error = aa_path_name(mntpath, path_flags(profile, mntpath), buffer,
     333                 :            :                              &mntpnt, &info, profile->disconnected);
     334                 :          0 :         if (error)
     335                 :            :                 goto audit;
     336                 :          0 :         if (IS_ERR(devname)) {
     337                 :            :                 error = PTR_ERR(devname);
     338                 :            :                 devname = NULL;
     339                 :          0 :                 info = devinfo;
     340                 :          0 :                 goto audit;
     341                 :            :         }
     342                 :            : 
     343                 :            :         error = -EACCES;
     344                 :          0 :         pos = do_match_mnt(profile->policy.dfa,
     345                 :            :                            profile->policy.start[AA_CLASS_MOUNT],
     346                 :            :                            mntpnt, devname, type, flags, data, binary, &perms);
     347                 :          0 :         if (pos) {
     348                 :          0 :                 info = mnt_info_table[pos];
     349                 :          0 :                 goto audit;
     350                 :            :         }
     351                 :            :         error = 0;
     352                 :            : 
     353                 :            : audit:
     354                 :          0 :         return audit_mount(profile, OP_MOUNT, mntpnt, devname, type, NULL,
     355                 :            :                            flags, data, AA_MAY_MOUNT, &perms, info, error);
     356                 :            : }
     357                 :            : 
     358                 :            : /**
     359                 :            :  * match_mnt - handle path matching for mount
     360                 :            :  * @profile: the confining profile
     361                 :            :  * @mntpath: for the mntpnt (NOT NULL)
     362                 :            :  * @buffer: buffer to be used to lookup mntpath
     363                 :            :  * @devpath: path devname/src_name (MAYBE NULL)
     364                 :            :  * @devbuffer: buffer to be used to lookup devname/src_name
     365                 :            :  * @type: string for the dev type (MAYBE NULL)
     366                 :            :  * @flags: mount flags to match
     367                 :            :  * @data: fs mount data (MAYBE NULL)
     368                 :            :  * @binary: whether @data is binary
     369                 :            :  *
     370                 :            :  * Returns: 0 on success else error
     371                 :            :  */
     372                 :          0 : static int match_mnt(struct aa_profile *profile, const struct path *path,
     373                 :            :                      char *buffer, struct path *devpath, char *devbuffer,
     374                 :            :                      const char *type, unsigned long flags, void *data,
     375                 :            :                      bool binary)
     376                 :            : {
     377                 :          0 :         const char *devname = NULL, *info = NULL;
     378                 :            :         int error = -EACCES;
     379                 :            : 
     380                 :            :         AA_BUG(!profile);
     381                 :            :         AA_BUG(devpath && !devbuffer);
     382                 :            : 
     383                 :          0 :         if (!PROFILE_MEDIATES(profile, AA_CLASS_MOUNT))
     384                 :            :                 return 0;
     385                 :            : 
     386                 :          0 :         if (devpath) {
     387                 :          0 :                 error = aa_path_name(devpath, path_flags(profile, devpath),
     388                 :            :                                      devbuffer, &devname, &info,
     389                 :            :                                      profile->disconnected);
     390                 :          0 :                 if (error)
     391                 :          0 :                         devname = ERR_PTR(error);
     392                 :            :         }
     393                 :            : 
     394                 :          0 :         return match_mnt_path_str(profile, path, buffer, devname, type, flags,
     395                 :            :                                   data, binary, info);
     396                 :            : }
     397                 :            : 
     398                 :          0 : int aa_remount(struct aa_label *label, const struct path *path,
     399                 :            :                unsigned long flags, void *data)
     400                 :            : {
     401                 :            :         struct aa_profile *profile;
     402                 :            :         char *buffer = NULL;
     403                 :            :         bool binary;
     404                 :            :         int error;
     405                 :            : 
     406                 :            :         AA_BUG(!label);
     407                 :            :         AA_BUG(!path);
     408                 :            : 
     409                 :          0 :         binary = path->dentry->d_sb->s_type->fs_flags & FS_BINARY_MOUNTDATA;
     410                 :            : 
     411                 :          0 :         get_buffers(buffer);
     412                 :          0 :         error = fn_for_each_confined(label, profile,
     413                 :            :                         match_mnt(profile, path, buffer, NULL, NULL, NULL,
     414                 :            :                                   flags, data, binary));
     415                 :          0 :         put_buffers(buffer);
     416                 :            : 
     417                 :          0 :         return error;
     418                 :            : }
     419                 :            : 
     420                 :          0 : int aa_bind_mount(struct aa_label *label, const struct path *path,
     421                 :            :                   const char *dev_name, unsigned long flags)
     422                 :            : {
     423                 :            :         struct aa_profile *profile;
     424                 :            :         char *buffer = NULL, *old_buffer = NULL;
     425                 :            :         struct path old_path;
     426                 :            :         int error;
     427                 :            : 
     428                 :            :         AA_BUG(!label);
     429                 :            :         AA_BUG(!path);
     430                 :            : 
     431                 :          0 :         if (!dev_name || !*dev_name)
     432                 :            :                 return -EINVAL;
     433                 :            : 
     434                 :          0 :         flags &= MS_REC | MS_BIND;
     435                 :            : 
     436                 :          0 :         error = kern_path(dev_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path);
     437                 :          0 :         if (error)
     438                 :            :                 return error;
     439                 :            : 
     440                 :          0 :         get_buffers(buffer, old_buffer);
     441                 :          0 :         error = fn_for_each_confined(label, profile,
     442                 :            :                         match_mnt(profile, path, buffer, &old_path, old_buffer,
     443                 :            :                                   NULL, flags, NULL, false));
     444                 :          0 :         put_buffers(buffer, old_buffer);
     445                 :          0 :         path_put(&old_path);
     446                 :            : 
     447                 :          0 :         return error;
     448                 :            : }
     449                 :            : 
     450                 :          0 : int aa_mount_change_type(struct aa_label *label, const struct path *path,
     451                 :            :                          unsigned long flags)
     452                 :            : {
     453                 :            :         struct aa_profile *profile;
     454                 :            :         char *buffer = NULL;
     455                 :            :         int error;
     456                 :            : 
     457                 :            :         AA_BUG(!label);
     458                 :            :         AA_BUG(!path);
     459                 :            : 
     460                 :            :         /* These are the flags allowed by do_change_type() */
     461                 :          0 :         flags &= (MS_REC | MS_SILENT | MS_SHARED | MS_PRIVATE | MS_SLAVE |
     462                 :            :                   MS_UNBINDABLE);
     463                 :            : 
     464                 :          0 :         get_buffers(buffer);
     465                 :          0 :         error = fn_for_each_confined(label, profile,
     466                 :            :                         match_mnt(profile, path, buffer, NULL, NULL, NULL,
     467                 :            :                                   flags, NULL, false));
     468                 :          0 :         put_buffers(buffer);
     469                 :            : 
     470                 :          0 :         return error;
     471                 :            : }
     472                 :            : 
     473                 :          0 : int aa_move_mount(struct aa_label *label, const struct path *path,
     474                 :            :                   const char *orig_name)
     475                 :            : {
     476                 :            :         struct aa_profile *profile;
     477                 :            :         char *buffer = NULL, *old_buffer = NULL;
     478                 :            :         struct path old_path;
     479                 :            :         int error;
     480                 :            : 
     481                 :            :         AA_BUG(!label);
     482                 :            :         AA_BUG(!path);
     483                 :            : 
     484                 :          0 :         if (!orig_name || !*orig_name)
     485                 :            :                 return -EINVAL;
     486                 :            : 
     487                 :          0 :         error = kern_path(orig_name, LOOKUP_FOLLOW, &old_path);
     488                 :          0 :         if (error)
     489                 :            :                 return error;
     490                 :            : 
     491                 :          0 :         get_buffers(buffer, old_buffer);
     492                 :          0 :         error = fn_for_each_confined(label, profile,
     493                 :            :                         match_mnt(profile, path, buffer, &old_path, old_buffer,
     494                 :            :                                   NULL, MS_MOVE, NULL, false));
     495                 :          0 :         put_buffers(buffer, old_buffer);
     496                 :          0 :         path_put(&old_path);
     497                 :            : 
     498                 :          0 :         return error;
     499                 :            : }
     500                 :            : 
     501                 :          0 : int aa_new_mount(struct aa_label *label, const char *dev_name,
     502                 :            :                  const struct path *path, const char *type, unsigned long flags,
     503                 :            :                  void *data)
     504                 :            : {
     505                 :            :         struct aa_profile *profile;
     506                 :            :         char *buffer = NULL, *dev_buffer = NULL;
     507                 :            :         bool binary = true;
     508                 :            :         int error;
     509                 :            :         int requires_dev = 0;
     510                 :            :         struct path tmp_path, *dev_path = NULL;
     511                 :            : 
     512                 :            :         AA_BUG(!label);
     513                 :            :         AA_BUG(!path);
     514                 :            : 
     515                 :          0 :         if (type) {
     516                 :            :                 struct file_system_type *fstype;
     517                 :            : 
     518                 :          0 :                 fstype = get_fs_type(type);
     519                 :          0 :                 if (!fstype)
     520                 :            :                         return -ENODEV;
     521                 :          0 :                 binary = fstype->fs_flags & FS_BINARY_MOUNTDATA;
     522                 :          0 :                 requires_dev = fstype->fs_flags & FS_REQUIRES_DEV;
     523                 :          0 :                 put_filesystem(fstype);
     524                 :            : 
     525                 :          0 :                 if (requires_dev) {
     526                 :          0 :                         if (!dev_name || !*dev_name)
     527                 :            :                                 return -ENOENT;
     528                 :            : 
     529                 :          0 :                         error = kern_path(dev_name, LOOKUP_FOLLOW, &tmp_path);
     530                 :          0 :                         if (error)
     531                 :            :                                 return error;
     532                 :            :                         dev_path = &tmp_path;
     533                 :            :                 }
     534                 :            :         }
     535                 :            : 
     536                 :          0 :         get_buffers(buffer, dev_buffer);
     537                 :          0 :         if (dev_path) {
     538                 :          0 :                 error = fn_for_each_confined(label, profile,
     539                 :            :                         match_mnt(profile, path, buffer, dev_path, dev_buffer,
     540                 :            :                                   type, flags, data, binary));
     541                 :            :         } else {
     542                 :          0 :                 error = fn_for_each_confined(label, profile,
     543                 :            :                         match_mnt_path_str(profile, path, buffer, dev_name,
     544                 :            :                                            type, flags, data, binary, NULL));
     545                 :            :         }
     546                 :          0 :         put_buffers(buffer, dev_buffer);
     547                 :          0 :         if (dev_path)
     548                 :          0 :                 path_put(dev_path);
     549                 :            : 
     550                 :          0 :         return error;
     551                 :            : }
     552                 :            : 
     553                 :          0 : static int profile_umount(struct aa_profile *profile, struct path *path,
     554                 :            :                           char *buffer)
     555                 :            : {
     556                 :          0 :         struct aa_perms perms = { };
     557                 :          0 :         const char *name = NULL, *info = NULL;
     558                 :            :         unsigned int state;
     559                 :            :         int error;
     560                 :            : 
     561                 :            :         AA_BUG(!profile);
     562                 :            :         AA_BUG(!path);
     563                 :            : 
     564                 :          0 :         if (!PROFILE_MEDIATES(profile, AA_CLASS_MOUNT))
     565                 :            :                 return 0;
     566                 :            : 
     567                 :          0 :         error = aa_path_name(path, path_flags(profile, path), buffer, &name,
     568                 :            :                              &info, profile->disconnected);
     569                 :          0 :         if (error)
     570                 :            :                 goto audit;
     571                 :            : 
     572                 :          0 :         state = aa_dfa_match(profile->policy.dfa,
     573                 :            :                              profile->policy.start[AA_CLASS_MOUNT],
     574                 :            :                              name);
     575                 :          0 :         perms = compute_mnt_perms(profile->policy.dfa, state);
     576                 :          0 :         if (AA_MAY_UMOUNT & ~perms.allow)
     577                 :            :                 error = -EACCES;
     578                 :            : 
     579                 :            : audit:
     580                 :          0 :         return audit_mount(profile, OP_UMOUNT, name, NULL, NULL, NULL, 0, NULL,
     581                 :            :                            AA_MAY_UMOUNT, &perms, info, error);
     582                 :            : }
     583                 :            : 
     584                 :          0 : int aa_umount(struct aa_label *label, struct vfsmount *mnt, int flags)
     585                 :            : {
     586                 :            :         struct aa_profile *profile;
     587                 :            :         char *buffer = NULL;
     588                 :            :         int error;
     589                 :          0 :         struct path path = { .mnt = mnt, .dentry = mnt->mnt_root };
     590                 :            : 
     591                 :            :         AA_BUG(!label);
     592                 :            :         AA_BUG(!mnt);
     593                 :            : 
     594                 :          0 :         get_buffers(buffer);
     595                 :          0 :         error = fn_for_each_confined(label, profile,
     596                 :            :                         profile_umount(profile, &path, buffer));
     597                 :          0 :         put_buffers(buffer);
     598                 :            : 
     599                 :          0 :         return error;
     600                 :            : }
     601                 :            : 
     602                 :            : /* helper fn for transition on pivotroot
     603                 :            :  *
     604                 :            :  * Returns: label for transition or ERR_PTR. Does not return NULL
     605                 :            :  */
     606                 :          0 : static struct aa_label *build_pivotroot(struct aa_profile *profile,
     607                 :            :                                         const struct path *new_path,
     608                 :            :                                         char *new_buffer,
     609                 :            :                                         const struct path *old_path,
     610                 :            :                                         char *old_buffer)
     611                 :            : {
     612                 :          0 :         const char *old_name, *new_name = NULL, *info = NULL;
     613                 :            :         const char *trans_name = NULL;
     614                 :          0 :         struct aa_perms perms = { };
     615                 :            :         unsigned int state;
     616                 :            :         int error;
     617                 :            : 
     618                 :            :         AA_BUG(!profile);
     619                 :            :         AA_BUG(!new_path);
     620                 :            :         AA_BUG(!old_path);
     621                 :            : 
     622                 :          0 :         if (profile_unconfined(profile) ||
     623                 :          0 :             !PROFILE_MEDIATES(profile, AA_CLASS_MOUNT))
     624                 :          0 :                 return aa_get_newest_label(&profile->label);
     625                 :            : 
     626                 :          0 :         error = aa_path_name(old_path, path_flags(profile, old_path),
     627                 :            :                              old_buffer, &old_name, &info,
     628                 :            :                              profile->disconnected);
     629                 :          0 :         if (error)
     630                 :            :                 goto audit;
     631                 :          0 :         error = aa_path_name(new_path, path_flags(profile, new_path),
     632                 :            :                              new_buffer, &new_name, &info,
     633                 :            :                              profile->disconnected);
     634                 :          0 :         if (error)
     635                 :            :                 goto audit;
     636                 :            : 
     637                 :            :         error = -EACCES;
     638                 :          0 :         state = aa_dfa_match(profile->policy.dfa,
     639                 :            :                              profile->policy.start[AA_CLASS_MOUNT],
     640                 :            :                              new_name);
     641                 :          0 :         state = aa_dfa_null_transition(profile->policy.dfa, state);
     642                 :          0 :         state = aa_dfa_match(profile->policy.dfa, state, old_name);
     643                 :          0 :         perms = compute_mnt_perms(profile->policy.dfa, state);
     644                 :            : 
     645                 :          0 :         if (AA_MAY_PIVOTROOT & perms.allow)
     646                 :            :                 error = 0;
     647                 :            : 
     648                 :            : audit:
     649                 :          0 :         error = audit_mount(profile, OP_PIVOTROOT, new_name, old_name,
     650                 :            :                             NULL, trans_name, 0, NULL, AA_MAY_PIVOTROOT,
     651                 :            :                             &perms, info, error);
     652                 :          0 :         if (error)
     653                 :          0 :                 return ERR_PTR(error);
     654                 :            : 
     655                 :          0 :         return aa_get_newest_label(&profile->label);
     656                 :            : }
     657                 :            : 
     658                 :          0 : int aa_pivotroot(struct aa_label *label, const struct path *old_path,
     659                 :            :                  const struct path *new_path)
     660                 :            : {
     661                 :            :         struct aa_profile *profile;
     662                 :            :         struct aa_label *target = NULL;
     663                 :            :         char *old_buffer = NULL, *new_buffer = NULL, *info = NULL;
     664                 :            :         int error;
     665                 :            : 
     666                 :            :         AA_BUG(!label);
     667                 :            :         AA_BUG(!old_path);
     668                 :            :         AA_BUG(!new_path);
     669                 :            : 
     670                 :          0 :         get_buffers(old_buffer, new_buffer);
     671                 :          0 :         target = fn_label_build(label, profile, GFP_ATOMIC,
     672                 :            :                         build_pivotroot(profile, new_path, new_buffer,
     673                 :            :                                         old_path, old_buffer));
     674                 :          0 :         if (!target) {
     675                 :            :                 info = "label build failed";
     676                 :            :                 error = -ENOMEM;
     677                 :            :                 goto fail;
     678                 :          0 :         } else if (!IS_ERR(target)) {
     679                 :          0 :                 error = aa_replace_current_label(target);
     680                 :          0 :                 if (error) {
     681                 :            :                         /* TODO: audit target */
     682                 :            :                         aa_put_label(target);
     683                 :            :                         goto out;
     684                 :            :                 }
     685                 :            :         } else
     686                 :            :                 /* already audited error */
     687                 :            :                 error = PTR_ERR(target);
     688                 :            : out:
     689                 :          0 :         put_buffers(old_buffer, new_buffer);
     690                 :            : 
     691                 :          0 :         return error;
     692                 :            : 
     693                 :            : fail:
     694                 :            :         /* TODO: add back in auditing of new_name and old_name */
     695                 :          0 :         error = fn_for_each(label, profile,
     696                 :            :                         audit_mount(profile, OP_PIVOTROOT, NULL /*new_name */,
     697                 :            :                                     NULL /* old_name */,
     698                 :            :                                     NULL, NULL,
     699                 :            :                                     0, NULL, AA_MAY_PIVOTROOT, &nullperms, info,
     700                 :            :                                     error));
     701                 :          0 :         goto out;
     702                 :            : }
    

Generated by: LCOV version 1.14