linux/security/tomoyo/mount.c
<<
>>
Prefs
   1/*
   2 * security/tomoyo/mount.c
   3 *
   4 * Copyright (C) 2005-2010  NTT DATA CORPORATION
   5 */
   6
   7#include <linux/slab.h>
   8#include "common.h"
   9
  10/* Keywords for mount restrictions. */
  11
  12/* Allow to call 'mount --bind /source_dir /dest_dir' */
  13#define TOMOYO_MOUNT_BIND_KEYWORD                        "--bind"
  14/* Allow to call 'mount --move /old_dir    /new_dir ' */
  15#define TOMOYO_MOUNT_MOVE_KEYWORD                        "--move"
  16/* Allow to call 'mount -o remount /dir             ' */
  17#define TOMOYO_MOUNT_REMOUNT_KEYWORD                     "--remount"
  18/* Allow to call 'mount --make-unbindable /dir'       */
  19#define TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD             "--make-unbindable"
  20/* Allow to call 'mount --make-private /dir'          */
  21#define TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD                "--make-private"
  22/* Allow to call 'mount --make-slave /dir'            */
  23#define TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD                  "--make-slave"
  24/* Allow to call 'mount --make-shared /dir'           */
  25#define TOMOYO_MOUNT_MAKE_SHARED_KEYWORD                 "--make-shared"
  26
  27/**
  28 * tomoyo_audit_mount_log - Audit mount log.
  29 *
  30 * @r: Pointer to "struct tomoyo_request_info".
  31 *
  32 * Returns 0 on success, negative value otherwise.
  33 */
  34static int tomoyo_audit_mount_log(struct tomoyo_request_info *r)
  35{
  36        const char *dev = r->param.mount.dev->name;
  37        const char *dir = r->param.mount.dir->name;
  38        const char *type = r->param.mount.type->name;
  39        const unsigned long flags = r->param.mount.flags;
  40        if (r->granted)
  41                return 0;
  42        if (!strcmp(type, TOMOYO_MOUNT_REMOUNT_KEYWORD))
  43                tomoyo_warn_log(r, "mount -o remount %s 0x%lX", dir, flags);
  44        else if (!strcmp(type, TOMOYO_MOUNT_BIND_KEYWORD)
  45                 || !strcmp(type, TOMOYO_MOUNT_MOVE_KEYWORD))
  46                tomoyo_warn_log(r, "mount %s %s %s 0x%lX", type, dev, dir,
  47                                flags);
  48        else if (!strcmp(type, TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD) ||
  49                 !strcmp(type, TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD) ||
  50                 !strcmp(type, TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD) ||
  51                 !strcmp(type, TOMOYO_MOUNT_MAKE_SHARED_KEYWORD))
  52                tomoyo_warn_log(r, "mount %s %s 0x%lX", type, dir, flags);
  53        else
  54                tomoyo_warn_log(r, "mount -t %s %s %s 0x%lX", type, dev, dir,
  55                                flags);
  56        return tomoyo_supervisor(r,
  57                                 TOMOYO_KEYWORD_ALLOW_MOUNT "%s %s %s 0x%lX\n",
  58                                 tomoyo_pattern(r->param.mount.dev),
  59                                 tomoyo_pattern(r->param.mount.dir), type,
  60                                 flags);
  61}
  62
  63static bool tomoyo_check_mount_acl(struct tomoyo_request_info *r,
  64                                   const struct tomoyo_acl_info *ptr)
  65{
  66        const struct tomoyo_mount_acl *acl =
  67                container_of(ptr, typeof(*acl), head);
  68        return tomoyo_compare_number_union(r->param.mount.flags, &acl->flags) &&
  69                tomoyo_compare_name_union(r->param.mount.type, &acl->fs_type) &&
  70                tomoyo_compare_name_union(r->param.mount.dir, &acl->dir_name) &&
  71                (!r->param.mount.need_dev ||
  72                 tomoyo_compare_name_union(r->param.mount.dev, &acl->dev_name));
  73}
  74
  75/**
  76 * tomoyo_mount_acl - Check permission for mount() operation.
  77 *
  78 * @r:        Pointer to "struct tomoyo_request_info".
  79 * @dev_name: Name of device file.
  80 * @dir:      Pointer to "struct path".
  81 * @type:     Name of filesystem type.
  82 * @flags:    Mount options.
  83 *
  84 * Returns 0 on success, negative value otherwise.
  85 *
  86 * Caller holds tomoyo_read_lock().
  87 */
  88static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name,
  89                            struct path *dir, char *type, unsigned long flags)
  90{
  91        struct path path;
  92        struct file_system_type *fstype = NULL;
  93        const char *requested_type = NULL;
  94        const char *requested_dir_name = NULL;
  95        const char *requested_dev_name = NULL;
  96        struct tomoyo_path_info rtype;
  97        struct tomoyo_path_info rdev;
  98        struct tomoyo_path_info rdir;
  99        int need_dev = 0;
 100        int error = -ENOMEM;
 101
 102        /* Get fstype. */
 103        requested_type = tomoyo_encode(type);
 104        if (!requested_type)
 105                goto out;
 106        rtype.name = requested_type;
 107        tomoyo_fill_path_info(&rtype);
 108
 109        /* Get mount point. */
 110        requested_dir_name = tomoyo_realpath_from_path(dir);
 111        if (!requested_dir_name) {
 112                error = -ENOMEM;
 113                goto out;
 114        }
 115        rdir.name = requested_dir_name;
 116        tomoyo_fill_path_info(&rdir);
 117
 118        /* Compare fs name. */
 119        if (!strcmp(type, TOMOYO_MOUNT_REMOUNT_KEYWORD)) {
 120                /* dev_name is ignored. */
 121        } else if (!strcmp(type, TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD) ||
 122                   !strcmp(type, TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD) ||
 123                   !strcmp(type, TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD) ||
 124                   !strcmp(type, TOMOYO_MOUNT_MAKE_SHARED_KEYWORD)) {
 125                /* dev_name is ignored. */
 126        } else if (!strcmp(type, TOMOYO_MOUNT_BIND_KEYWORD) ||
 127                   !strcmp(type, TOMOYO_MOUNT_MOVE_KEYWORD)) {
 128                need_dev = -1; /* dev_name is a directory */
 129        } else {
 130                fstype = get_fs_type(type);
 131                if (!fstype) {
 132                        error = -ENODEV;
 133                        goto out;
 134                }
 135                if (fstype->fs_flags & FS_REQUIRES_DEV)
 136                        /* dev_name is a block device file. */
 137                        need_dev = 1;
 138        }
 139        if (need_dev) {
 140                /* Get mount point or device file. */
 141                if (kern_path(dev_name, LOOKUP_FOLLOW, &path)) {
 142                        error = -ENOENT;
 143                        goto out;
 144                }
 145                requested_dev_name = tomoyo_realpath_from_path(&path);
 146                if (!requested_dev_name) {
 147                        error = -ENOENT;
 148                        goto out;
 149                }
 150        } else {
 151                /* Map dev_name to "<NULL>" if no dev_name given. */
 152                if (!dev_name)
 153                        dev_name = "<NULL>";
 154                requested_dev_name = tomoyo_encode(dev_name);
 155                if (!requested_dev_name) {
 156                        error = -ENOMEM;
 157                        goto out;
 158                }
 159        }
 160        rdev.name = requested_dev_name;
 161        tomoyo_fill_path_info(&rdev);
 162        r->param_type = TOMOYO_TYPE_MOUNT_ACL;
 163        r->param.mount.need_dev = need_dev;
 164        r->param.mount.dev = &rdev;
 165        r->param.mount.dir = &rdir;
 166        r->param.mount.type = &rtype;
 167        r->param.mount.flags = flags;
 168        do {
 169                tomoyo_check_acl(r, tomoyo_check_mount_acl);
 170                error = tomoyo_audit_mount_log(r);
 171        } while (error == TOMOYO_RETRY_REQUEST);
 172 out:
 173        kfree(requested_dev_name);
 174        kfree(requested_dir_name);
 175        if (fstype)
 176                put_filesystem(fstype);
 177        kfree(requested_type);
 178        return error;
 179}
 180
 181/**
 182 * tomoyo_mount_permission - Check permission for mount() operation.
 183 *
 184 * @dev_name:  Name of device file.
 185 * @path:      Pointer to "struct path".
 186 * @type:      Name of filesystem type. May be NULL.
 187 * @flags:     Mount options.
 188 * @data_page: Optional data. May be NULL.
 189 *
 190 * Returns 0 on success, negative value otherwise.
 191 */
 192int tomoyo_mount_permission(char *dev_name, struct path *path, char *type,
 193                            unsigned long flags, void *data_page)
 194{
 195        struct tomoyo_request_info r;
 196        int error;
 197        int idx;
 198
 199        if (tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_MOUNT)
 200            == TOMOYO_CONFIG_DISABLED)
 201                return 0;
 202        if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
 203                flags &= ~MS_MGC_MSK;
 204        if (flags & MS_REMOUNT) {
 205                type = TOMOYO_MOUNT_REMOUNT_KEYWORD;
 206                flags &= ~MS_REMOUNT;
 207        }
 208        if (flags & MS_MOVE) {
 209                type = TOMOYO_MOUNT_MOVE_KEYWORD;
 210                flags &= ~MS_MOVE;
 211        }
 212        if (flags & MS_BIND) {
 213                type = TOMOYO_MOUNT_BIND_KEYWORD;
 214                flags &= ~MS_BIND;
 215        }
 216        if (flags & MS_UNBINDABLE) {
 217                type = TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD;
 218                flags &= ~MS_UNBINDABLE;
 219        }
 220        if (flags & MS_PRIVATE) {
 221                type = TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD;
 222                flags &= ~MS_PRIVATE;
 223        }
 224        if (flags & MS_SLAVE) {
 225                type = TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD;
 226                flags &= ~MS_SLAVE;
 227        }
 228        if (flags & MS_SHARED) {
 229                type = TOMOYO_MOUNT_MAKE_SHARED_KEYWORD;
 230                flags &= ~MS_SHARED;
 231        }
 232        if (!type)
 233                type = "<NULL>";
 234        idx = tomoyo_read_lock();
 235        error = tomoyo_mount_acl(&r, dev_name, path, type, flags);
 236        tomoyo_read_unlock(idx);
 237        return error;
 238}
 239
 240static bool tomoyo_same_mount_acl(const struct tomoyo_acl_info *a,
 241                                  const struct tomoyo_acl_info *b)
 242{
 243        const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head);
 244        const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head);
 245        return tomoyo_same_acl_head(&p1->head, &p2->head) &&
 246                tomoyo_same_name_union(&p1->dev_name, &p2->dev_name) &&
 247                tomoyo_same_name_union(&p1->dir_name, &p2->dir_name) &&
 248                tomoyo_same_name_union(&p1->fs_type, &p2->fs_type) &&
 249                tomoyo_same_number_union(&p1->flags, &p2->flags);
 250}
 251
 252/**
 253 * tomoyo_write_mount - Write "struct tomoyo_mount_acl" list.
 254 *
 255 * @data:      String to parse.
 256 * @domain:    Pointer to "struct tomoyo_domain_info".
 257 * @is_delete: True if it is a delete request.
 258 *
 259 * Returns 0 on success, negative value otherwise.
 260 *
 261 * Caller holds tomoyo_read_lock().
 262 */
 263int tomoyo_write_mount(char *data, struct tomoyo_domain_info *domain,
 264                       const bool is_delete)
 265{
 266        struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL };
 267        int error = is_delete ? -ENOENT : -ENOMEM;
 268        char *w[4];
 269        if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[3][0])
 270                return -EINVAL;
 271        if (!tomoyo_parse_name_union(w[0], &e.dev_name) ||
 272            !tomoyo_parse_name_union(w[1], &e.dir_name) ||
 273            !tomoyo_parse_name_union(w[2], &e.fs_type) ||
 274            !tomoyo_parse_number_union(w[3], &e.flags))
 275                goto out;
 276        error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
 277                                     tomoyo_same_mount_acl, NULL);
 278 out:
 279        tomoyo_put_name_union(&e.dev_name);
 280        tomoyo_put_name_union(&e.dir_name);
 281        tomoyo_put_name_union(&e.fs_type);
 282        tomoyo_put_number_union(&e.flags);
 283        return error;
 284}
 285