linux/security/device_cgroup.c
<<
>>
Prefs
   1/*
   2 * device_cgroup.c - device cgroup subsystem
   3 *
   4 * Copyright 2007 IBM Corp
   5 */
   6
   7#include <linux/device_cgroup.h>
   8#include <linux/cgroup.h>
   9#include <linux/ctype.h>
  10#include <linux/list.h>
  11#include <linux/uaccess.h>
  12#include <linux/seq_file.h>
  13#include <linux/slab.h>
  14#include <linux/rcupdate.h>
  15#include <linux/mutex.h>
  16
  17#define ACC_MKNOD 1
  18#define ACC_READ  2
  19#define ACC_WRITE 4
  20#define ACC_MASK (ACC_MKNOD | ACC_READ | ACC_WRITE)
  21
  22#define DEV_BLOCK 1
  23#define DEV_CHAR  2
  24#define DEV_ALL   4  /* this represents all devices */
  25
  26static DEFINE_MUTEX(devcgroup_mutex);
  27
  28enum devcg_behavior {
  29        DEVCG_DEFAULT_NONE,
  30        DEVCG_DEFAULT_ALLOW,
  31        DEVCG_DEFAULT_DENY,
  32};
  33
  34/*
  35 * exception list locking rules:
  36 * hold devcgroup_mutex for update/read.
  37 * hold rcu_read_lock() for read.
  38 */
  39
  40struct dev_exception_item {
  41        u32 major, minor;
  42        short type;
  43        short access;
  44        struct list_head list;
  45        struct rcu_head rcu;
  46};
  47
  48struct dev_cgroup {
  49        struct cgroup_subsys_state css;
  50        struct list_head exceptions;
  51        enum devcg_behavior behavior;
  52};
  53
  54static inline struct dev_cgroup *css_to_devcgroup(struct cgroup_subsys_state *s)
  55{
  56        return s ? container_of(s, struct dev_cgroup, css) : NULL;
  57}
  58
  59static inline struct dev_cgroup *task_devcgroup(struct task_struct *task)
  60{
  61        return css_to_devcgroup(task_css(task, devices_cgrp_id));
  62}
  63
  64/*
  65 * called under devcgroup_mutex
  66 */
  67static int dev_exceptions_copy(struct list_head *dest, struct list_head *orig)
  68{
  69        struct dev_exception_item *ex, *tmp, *new;
  70
  71        lockdep_assert_held(&devcgroup_mutex);
  72
  73        list_for_each_entry(ex, orig, list) {
  74                new = kmemdup(ex, sizeof(*ex), GFP_KERNEL);
  75                if (!new)
  76                        goto free_and_exit;
  77                list_add_tail(&new->list, dest);
  78        }
  79
  80        return 0;
  81
  82free_and_exit:
  83        list_for_each_entry_safe(ex, tmp, dest, list) {
  84                list_del(&ex->list);
  85                kfree(ex);
  86        }
  87        return -ENOMEM;
  88}
  89
  90/*
  91 * called under devcgroup_mutex
  92 */
  93static int dev_exception_add(struct dev_cgroup *dev_cgroup,
  94                             struct dev_exception_item *ex)
  95{
  96        struct dev_exception_item *excopy, *walk;
  97
  98        lockdep_assert_held(&devcgroup_mutex);
  99
 100        excopy = kmemdup(ex, sizeof(*ex), GFP_KERNEL);
 101        if (!excopy)
 102                return -ENOMEM;
 103
 104        list_for_each_entry(walk, &dev_cgroup->exceptions, list) {
 105                if (walk->type != ex->type)
 106                        continue;
 107                if (walk->major != ex->major)
 108                        continue;
 109                if (walk->minor != ex->minor)
 110                        continue;
 111
 112                walk->access |= ex->access;
 113                kfree(excopy);
 114                excopy = NULL;
 115        }
 116
 117        if (excopy != NULL)
 118                list_add_tail_rcu(&excopy->list, &dev_cgroup->exceptions);
 119        return 0;
 120}
 121
 122/*
 123 * called under devcgroup_mutex
 124 */
 125static void dev_exception_rm(struct dev_cgroup *dev_cgroup,
 126                             struct dev_exception_item *ex)
 127{
 128        struct dev_exception_item *walk, *tmp;
 129
 130        lockdep_assert_held(&devcgroup_mutex);
 131
 132        list_for_each_entry_safe(walk, tmp, &dev_cgroup->exceptions, list) {
 133                if (walk->type != ex->type)
 134                        continue;
 135                if (walk->major != ex->major)
 136                        continue;
 137                if (walk->minor != ex->minor)
 138                        continue;
 139
 140                walk->access &= ~ex->access;
 141                if (!walk->access) {
 142                        list_del_rcu(&walk->list);
 143                        kfree_rcu(walk, rcu);
 144                }
 145        }
 146}
 147
 148static void __dev_exception_clean(struct dev_cgroup *dev_cgroup)
 149{
 150        struct dev_exception_item *ex, *tmp;
 151
 152        list_for_each_entry_safe(ex, tmp, &dev_cgroup->exceptions, list) {
 153                list_del_rcu(&ex->list);
 154                kfree_rcu(ex, rcu);
 155        }
 156}
 157
 158/**
 159 * dev_exception_clean - frees all entries of the exception list
 160 * @dev_cgroup: dev_cgroup with the exception list to be cleaned
 161 *
 162 * called under devcgroup_mutex
 163 */
 164static void dev_exception_clean(struct dev_cgroup *dev_cgroup)
 165{
 166        lockdep_assert_held(&devcgroup_mutex);
 167
 168        __dev_exception_clean(dev_cgroup);
 169}
 170
 171static inline bool is_devcg_online(const struct dev_cgroup *devcg)
 172{
 173        return (devcg->behavior != DEVCG_DEFAULT_NONE);
 174}
 175
 176/**
 177 * devcgroup_online - initializes devcgroup's behavior and exceptions based on
 178 *                    parent's
 179 * @css: css getting online
 180 * returns 0 in case of success, error code otherwise
 181 */
 182static int devcgroup_online(struct cgroup_subsys_state *css)
 183{
 184        struct dev_cgroup *dev_cgroup = css_to_devcgroup(css);
 185        struct dev_cgroup *parent_dev_cgroup = css_to_devcgroup(css->parent);
 186        int ret = 0;
 187
 188        mutex_lock(&devcgroup_mutex);
 189
 190        if (parent_dev_cgroup == NULL)
 191                dev_cgroup->behavior = DEVCG_DEFAULT_ALLOW;
 192        else {
 193                ret = dev_exceptions_copy(&dev_cgroup->exceptions,
 194                                          &parent_dev_cgroup->exceptions);
 195                if (!ret)
 196                        dev_cgroup->behavior = parent_dev_cgroup->behavior;
 197        }
 198        mutex_unlock(&devcgroup_mutex);
 199
 200        return ret;
 201}
 202
 203static void devcgroup_offline(struct cgroup_subsys_state *css)
 204{
 205        struct dev_cgroup *dev_cgroup = css_to_devcgroup(css);
 206
 207        mutex_lock(&devcgroup_mutex);
 208        dev_cgroup->behavior = DEVCG_DEFAULT_NONE;
 209        mutex_unlock(&devcgroup_mutex);
 210}
 211
 212/*
 213 * called from kernel/cgroup.c with cgroup_lock() held.
 214 */
 215static struct cgroup_subsys_state *
 216devcgroup_css_alloc(struct cgroup_subsys_state *parent_css)
 217{
 218        struct dev_cgroup *dev_cgroup;
 219
 220        dev_cgroup = kzalloc(sizeof(*dev_cgroup), GFP_KERNEL);
 221        if (!dev_cgroup)
 222                return ERR_PTR(-ENOMEM);
 223        INIT_LIST_HEAD(&dev_cgroup->exceptions);
 224        dev_cgroup->behavior = DEVCG_DEFAULT_NONE;
 225
 226        return &dev_cgroup->css;
 227}
 228
 229static void devcgroup_css_free(struct cgroup_subsys_state *css)
 230{
 231        struct dev_cgroup *dev_cgroup = css_to_devcgroup(css);
 232
 233        __dev_exception_clean(dev_cgroup);
 234        kfree(dev_cgroup);
 235}
 236
 237#define DEVCG_ALLOW 1
 238#define DEVCG_DENY 2
 239#define DEVCG_LIST 3
 240
 241#define MAJMINLEN 13
 242#define ACCLEN 4
 243
 244static void set_access(char *acc, short access)
 245{
 246        int idx = 0;
 247        memset(acc, 0, ACCLEN);
 248        if (access & ACC_READ)
 249                acc[idx++] = 'r';
 250        if (access & ACC_WRITE)
 251                acc[idx++] = 'w';
 252        if (access & ACC_MKNOD)
 253                acc[idx++] = 'm';
 254}
 255
 256static char type_to_char(short type)
 257{
 258        if (type == DEV_ALL)
 259                return 'a';
 260        if (type == DEV_CHAR)
 261                return 'c';
 262        if (type == DEV_BLOCK)
 263                return 'b';
 264        return 'X';
 265}
 266
 267static void set_majmin(char *str, unsigned m)
 268{
 269        if (m == ~0)
 270                strcpy(str, "*");
 271        else
 272                sprintf(str, "%u", m);
 273}
 274
 275static int devcgroup_seq_show(struct seq_file *m, void *v)
 276{
 277        struct dev_cgroup *devcgroup = css_to_devcgroup(seq_css(m));
 278        struct dev_exception_item *ex;
 279        char maj[MAJMINLEN], min[MAJMINLEN], acc[ACCLEN];
 280
 281        rcu_read_lock();
 282        /*
 283         * To preserve the compatibility:
 284         * - Only show the "all devices" when the default policy is to allow
 285         * - List the exceptions in case the default policy is to deny
 286         * This way, the file remains as a "whitelist of devices"
 287         */
 288        if (devcgroup->behavior == DEVCG_DEFAULT_ALLOW) {
 289                set_access(acc, ACC_MASK);
 290                set_majmin(maj, ~0);
 291                set_majmin(min, ~0);
 292                seq_printf(m, "%c %s:%s %s\n", type_to_char(DEV_ALL),
 293                           maj, min, acc);
 294        } else {
 295                list_for_each_entry_rcu(ex, &devcgroup->exceptions, list) {
 296                        set_access(acc, ex->access);
 297                        set_majmin(maj, ex->major);
 298                        set_majmin(min, ex->minor);
 299                        seq_printf(m, "%c %s:%s %s\n", type_to_char(ex->type),
 300                                   maj, min, acc);
 301                }
 302        }
 303        rcu_read_unlock();
 304
 305        return 0;
 306}
 307
 308/**
 309 * match_exception      - iterates the exception list trying to find a complete match
 310 * @exceptions: list of exceptions
 311 * @type: device type (DEV_BLOCK or DEV_CHAR)
 312 * @major: device file major number, ~0 to match all
 313 * @minor: device file minor number, ~0 to match all
 314 * @access: permission mask (ACC_READ, ACC_WRITE, ACC_MKNOD)
 315 *
 316 * It is considered a complete match if an exception is found that will
 317 * contain the entire range of provided parameters.
 318 *
 319 * Return: true in case it matches an exception completely
 320 */
 321static bool match_exception(struct list_head *exceptions, short type,
 322                            u32 major, u32 minor, short access)
 323{
 324        struct dev_exception_item *ex;
 325
 326        list_for_each_entry_rcu(ex, exceptions, list) {
 327                if ((type & DEV_BLOCK) && !(ex->type & DEV_BLOCK))
 328                        continue;
 329                if ((type & DEV_CHAR) && !(ex->type & DEV_CHAR))
 330                        continue;
 331                if (ex->major != ~0 && ex->major != major)
 332                        continue;
 333                if (ex->minor != ~0 && ex->minor != minor)
 334                        continue;
 335                /* provided access cannot have more than the exception rule */
 336                if (access & (~ex->access))
 337                        continue;
 338                return true;
 339        }
 340        return false;
 341}
 342
 343/**
 344 * match_exception_partial - iterates the exception list trying to find a partial match
 345 * @exceptions: list of exceptions
 346 * @type: device type (DEV_BLOCK or DEV_CHAR)
 347 * @major: device file major number, ~0 to match all
 348 * @minor: device file minor number, ~0 to match all
 349 * @access: permission mask (ACC_READ, ACC_WRITE, ACC_MKNOD)
 350 *
 351 * It is considered a partial match if an exception's range is found to
 352 * contain *any* of the devices specified by provided parameters. This is
 353 * used to make sure no extra access is being granted that is forbidden by
 354 * any of the exception list.
 355 *
 356 * Return: true in case the provided range mat matches an exception completely
 357 */
 358static bool match_exception_partial(struct list_head *exceptions, short type,
 359                                    u32 major, u32 minor, short access)
 360{
 361        struct dev_exception_item *ex;
 362
 363        list_for_each_entry_rcu(ex, exceptions, list) {
 364                if ((type & DEV_BLOCK) && !(ex->type & DEV_BLOCK))
 365                        continue;
 366                if ((type & DEV_CHAR) && !(ex->type & DEV_CHAR))
 367                        continue;
 368                /*
 369                 * We must be sure that both the exception and the provided
 370                 * range aren't masking all devices
 371                 */
 372                if (ex->major != ~0 && major != ~0 && ex->major != major)
 373                        continue;
 374                if (ex->minor != ~0 && minor != ~0 && ex->minor != minor)
 375                        continue;
 376                /*
 377                 * In order to make sure the provided range isn't matching
 378                 * an exception, all its access bits shouldn't match the
 379                 * exception's access bits
 380                 */
 381                if (!(access & ex->access))
 382                        continue;
 383                return true;
 384        }
 385        return false;
 386}
 387
 388/**
 389 * verify_new_ex - verifies if a new exception is allowed by parent cgroup's permissions
 390 * @dev_cgroup: dev cgroup to be tested against
 391 * @refex: new exception
 392 * @behavior: behavior of the exception's dev_cgroup
 393 *
 394 * This is used to make sure a child cgroup won't have more privileges
 395 * than its parent
 396 */
 397static bool verify_new_ex(struct dev_cgroup *dev_cgroup,
 398                          struct dev_exception_item *refex,
 399                          enum devcg_behavior behavior)
 400{
 401        bool match = false;
 402
 403        RCU_LOCKDEP_WARN(!rcu_read_lock_held() &&
 404                         !lockdep_is_held(&devcgroup_mutex),
 405                         "device_cgroup:verify_new_ex called without proper synchronization");
 406
 407        if (dev_cgroup->behavior == DEVCG_DEFAULT_ALLOW) {
 408                if (behavior == DEVCG_DEFAULT_ALLOW) {
 409                        /*
 410                         * new exception in the child doesn't matter, only
 411                         * adding extra restrictions
 412                         */ 
 413                        return true;
 414                } else {
 415                        /*
 416                         * new exception in the child will add more devices
 417                         * that can be acessed, so it can't match any of
 418                         * parent's exceptions, even slightly
 419                         */ 
 420                        match = match_exception_partial(&dev_cgroup->exceptions,
 421                                                        refex->type,
 422                                                        refex->major,
 423                                                        refex->minor,
 424                                                        refex->access);
 425
 426                        if (match)
 427                                return false;
 428                        return true;
 429                }
 430        } else {
 431                /*
 432                 * Only behavior == DEVCG_DEFAULT_DENY allowed here, therefore
 433                 * the new exception will add access to more devices and must
 434                 * be contained completely in an parent's exception to be
 435                 * allowed
 436                 */
 437                match = match_exception(&dev_cgroup->exceptions, refex->type,
 438                                        refex->major, refex->minor,
 439                                        refex->access);
 440
 441                if (match)
 442                        /* parent has an exception that matches the proposed */
 443                        return true;
 444                else
 445                        return false;
 446        }
 447        return false;
 448}
 449
 450/*
 451 * parent_has_perm:
 452 * when adding a new allow rule to a device exception list, the rule
 453 * must be allowed in the parent device
 454 */
 455static int parent_has_perm(struct dev_cgroup *childcg,
 456                                  struct dev_exception_item *ex)
 457{
 458        struct dev_cgroup *parent = css_to_devcgroup(childcg->css.parent);
 459
 460        if (!parent)
 461                return 1;
 462        return verify_new_ex(parent, ex, childcg->behavior);
 463}
 464
 465/**
 466 * parent_allows_removal - verify if it's ok to remove an exception
 467 * @childcg: child cgroup from where the exception will be removed
 468 * @ex: exception being removed
 469 *
 470 * When removing an exception in cgroups with default ALLOW policy, it must
 471 * be checked if removing it will give the child cgroup more access than the
 472 * parent.
 473 *
 474 * Return: true if it's ok to remove exception, false otherwise
 475 */
 476static bool parent_allows_removal(struct dev_cgroup *childcg,
 477                                  struct dev_exception_item *ex)
 478{
 479        struct dev_cgroup *parent = css_to_devcgroup(childcg->css.parent);
 480
 481        if (!parent)
 482                return true;
 483
 484        /* It's always allowed to remove access to devices */
 485        if (childcg->behavior == DEVCG_DEFAULT_DENY)
 486                return true;
 487
 488        /*
 489         * Make sure you're not removing part or a whole exception existing in
 490         * the parent cgroup
 491         */
 492        return !match_exception_partial(&parent->exceptions, ex->type,
 493                                        ex->major, ex->minor, ex->access);
 494}
 495
 496/**
 497 * may_allow_all - checks if it's possible to change the behavior to
 498 *                 allow based on parent's rules.
 499 * @parent: device cgroup's parent
 500 * returns: != 0 in case it's allowed, 0 otherwise
 501 */
 502static inline int may_allow_all(struct dev_cgroup *parent)
 503{
 504        if (!parent)
 505                return 1;
 506        return parent->behavior == DEVCG_DEFAULT_ALLOW;
 507}
 508
 509/**
 510 * revalidate_active_exceptions - walks through the active exception list and
 511 *                                revalidates the exceptions based on parent's
 512 *                                behavior and exceptions. The exceptions that
 513 *                                are no longer valid will be removed.
 514 *                                Called with devcgroup_mutex held.
 515 * @devcg: cgroup which exceptions will be checked
 516 *
 517 * This is one of the three key functions for hierarchy implementation.
 518 * This function is responsible for re-evaluating all the cgroup's active
 519 * exceptions due to a parent's exception change.
 520 * Refer to Documentation/cgroups/devices.txt for more details.
 521 */
 522static void revalidate_active_exceptions(struct dev_cgroup *devcg)
 523{
 524        struct dev_exception_item *ex;
 525        struct list_head *this, *tmp;
 526
 527        list_for_each_safe(this, tmp, &devcg->exceptions) {
 528                ex = container_of(this, struct dev_exception_item, list);
 529                if (!parent_has_perm(devcg, ex))
 530                        dev_exception_rm(devcg, ex);
 531        }
 532}
 533
 534/**
 535 * propagate_exception - propagates a new exception to the children
 536 * @devcg_root: device cgroup that added a new exception
 537 * @ex: new exception to be propagated
 538 *
 539 * returns: 0 in case of success, != 0 in case of error
 540 */
 541static int propagate_exception(struct dev_cgroup *devcg_root,
 542                               struct dev_exception_item *ex)
 543{
 544        struct cgroup_subsys_state *pos;
 545        int rc = 0;
 546
 547        rcu_read_lock();
 548
 549        css_for_each_descendant_pre(pos, &devcg_root->css) {
 550                struct dev_cgroup *devcg = css_to_devcgroup(pos);
 551
 552                /*
 553                 * Because devcgroup_mutex is held, no devcg will become
 554                 * online or offline during the tree walk (see on/offline
 555                 * methods), and online ones are safe to access outside RCU
 556                 * read lock without bumping refcnt.
 557                 */
 558                if (pos == &devcg_root->css || !is_devcg_online(devcg))
 559                        continue;
 560
 561                rcu_read_unlock();
 562
 563                /*
 564                 * in case both root's behavior and devcg is allow, a new
 565                 * restriction means adding to the exception list
 566                 */
 567                if (devcg_root->behavior == DEVCG_DEFAULT_ALLOW &&
 568                    devcg->behavior == DEVCG_DEFAULT_ALLOW) {
 569                        rc = dev_exception_add(devcg, ex);
 570                        if (rc)
 571                                break;
 572                } else {
 573                        /*
 574                         * in the other possible cases:
 575                         * root's behavior: allow, devcg's: deny
 576                         * root's behavior: deny, devcg's: deny
 577                         * the exception will be removed
 578                         */
 579                        dev_exception_rm(devcg, ex);
 580                }
 581                revalidate_active_exceptions(devcg);
 582
 583                rcu_read_lock();
 584        }
 585
 586        rcu_read_unlock();
 587        return rc;
 588}
 589
 590/*
 591 * Modify the exception list using allow/deny rules.
 592 * CAP_SYS_ADMIN is needed for this.  It's at least separate from CAP_MKNOD
 593 * so we can give a container CAP_MKNOD to let it create devices but not
 594 * modify the exception list.
 595 * It seems likely we'll want to add a CAP_CONTAINER capability to allow
 596 * us to also grant CAP_SYS_ADMIN to containers without giving away the
 597 * device exception list controls, but for now we'll stick with CAP_SYS_ADMIN
 598 *
 599 * Taking rules away is always allowed (given CAP_SYS_ADMIN).  Granting
 600 * new access is only allowed if you're in the top-level cgroup, or your
 601 * parent cgroup has the access you're asking for.
 602 */
 603static int devcgroup_update_access(struct dev_cgroup *devcgroup,
 604                                   int filetype, char *buffer)
 605{
 606        const char *b;
 607        char temp[12];          /* 11 + 1 characters needed for a u32 */
 608        int count, rc = 0;
 609        struct dev_exception_item ex;
 610        struct dev_cgroup *parent = css_to_devcgroup(devcgroup->css.parent);
 611
 612        if (!capable(CAP_SYS_ADMIN))
 613                return -EPERM;
 614
 615        memset(&ex, 0, sizeof(ex));
 616        b = buffer;
 617
 618        switch (*b) {
 619        case 'a':
 620                switch (filetype) {
 621                case DEVCG_ALLOW:
 622                        if (css_has_online_children(&devcgroup->css))
 623                                return -EINVAL;
 624
 625                        if (!may_allow_all(parent))
 626                                return -EPERM;
 627                        dev_exception_clean(devcgroup);
 628                        devcgroup->behavior = DEVCG_DEFAULT_ALLOW;
 629                        if (!parent)
 630                                break;
 631
 632                        rc = dev_exceptions_copy(&devcgroup->exceptions,
 633                                                 &parent->exceptions);
 634                        if (rc)
 635                                return rc;
 636                        break;
 637                case DEVCG_DENY:
 638                        if (css_has_online_children(&devcgroup->css))
 639                                return -EINVAL;
 640
 641                        dev_exception_clean(devcgroup);
 642                        devcgroup->behavior = DEVCG_DEFAULT_DENY;
 643                        break;
 644                default:
 645                        return -EINVAL;
 646                }
 647                return 0;
 648        case 'b':
 649                ex.type = DEV_BLOCK;
 650                break;
 651        case 'c':
 652                ex.type = DEV_CHAR;
 653                break;
 654        default:
 655                return -EINVAL;
 656        }
 657        b++;
 658        if (!isspace(*b))
 659                return -EINVAL;
 660        b++;
 661        if (*b == '*') {
 662                ex.major = ~0;
 663                b++;
 664        } else if (isdigit(*b)) {
 665                memset(temp, 0, sizeof(temp));
 666                for (count = 0; count < sizeof(temp) - 1; count++) {
 667                        temp[count] = *b;
 668                        b++;
 669                        if (!isdigit(*b))
 670                                break;
 671                }
 672                rc = kstrtou32(temp, 10, &ex.major);
 673                if (rc)
 674                        return -EINVAL;
 675        } else {
 676                return -EINVAL;
 677        }
 678        if (*b != ':')
 679                return -EINVAL;
 680        b++;
 681
 682        /* read minor */
 683        if (*b == '*') {
 684                ex.minor = ~0;
 685                b++;
 686        } else if (isdigit(*b)) {
 687                memset(temp, 0, sizeof(temp));
 688                for (count = 0; count < sizeof(temp) - 1; count++) {
 689                        temp[count] = *b;
 690                        b++;
 691                        if (!isdigit(*b))
 692                                break;
 693                }
 694                rc = kstrtou32(temp, 10, &ex.minor);
 695                if (rc)
 696                        return -EINVAL;
 697        } else {
 698                return -EINVAL;
 699        }
 700        if (!isspace(*b))
 701                return -EINVAL;
 702        for (b++, count = 0; count < 3; count++, b++) {
 703                switch (*b) {
 704                case 'r':
 705                        ex.access |= ACC_READ;
 706                        break;
 707                case 'w':
 708                        ex.access |= ACC_WRITE;
 709                        break;
 710                case 'm':
 711                        ex.access |= ACC_MKNOD;
 712                        break;
 713                case '\n':
 714                case '\0':
 715                        count = 3;
 716                        break;
 717                default:
 718                        return -EINVAL;
 719                }
 720        }
 721
 722        switch (filetype) {
 723        case DEVCG_ALLOW:
 724                /*
 725                 * If the default policy is to allow by default, try to remove
 726                 * an matching exception instead. And be silent about it: we
 727                 * don't want to break compatibility
 728                 */
 729                if (devcgroup->behavior == DEVCG_DEFAULT_ALLOW) {
 730                        /* Check if the parent allows removing it first */
 731                        if (!parent_allows_removal(devcgroup, &ex))
 732                                return -EPERM;
 733                        dev_exception_rm(devcgroup, &ex);
 734                        break;
 735                }
 736
 737                if (!parent_has_perm(devcgroup, &ex))
 738                        return -EPERM;
 739                rc = dev_exception_add(devcgroup, &ex);
 740                break;
 741        case DEVCG_DENY:
 742                /*
 743                 * If the default policy is to deny by default, try to remove
 744                 * an matching exception instead. And be silent about it: we
 745                 * don't want to break compatibility
 746                 */
 747                if (devcgroup->behavior == DEVCG_DEFAULT_DENY)
 748                        dev_exception_rm(devcgroup, &ex);
 749                else
 750                        rc = dev_exception_add(devcgroup, &ex);
 751
 752                if (rc)
 753                        break;
 754                /* we only propagate new restrictions */
 755                rc = propagate_exception(devcgroup, &ex);
 756                break;
 757        default:
 758                rc = -EINVAL;
 759        }
 760        return rc;
 761}
 762
 763static ssize_t devcgroup_access_write(struct kernfs_open_file *of,
 764                                      char *buf, size_t nbytes, loff_t off)
 765{
 766        int retval;
 767
 768        mutex_lock(&devcgroup_mutex);
 769        retval = devcgroup_update_access(css_to_devcgroup(of_css(of)),
 770                                         of_cft(of)->private, strstrip(buf));
 771        mutex_unlock(&devcgroup_mutex);
 772        return retval ?: nbytes;
 773}
 774
 775static struct cftype dev_cgroup_files[] = {
 776        {
 777                .name = "allow",
 778                .write = devcgroup_access_write,
 779                .private = DEVCG_ALLOW,
 780        },
 781        {
 782                .name = "deny",
 783                .write = devcgroup_access_write,
 784                .private = DEVCG_DENY,
 785        },
 786        {
 787                .name = "list",
 788                .seq_show = devcgroup_seq_show,
 789                .private = DEVCG_LIST,
 790        },
 791        { }     /* terminate */
 792};
 793
 794struct cgroup_subsys devices_cgrp_subsys = {
 795        .css_alloc = devcgroup_css_alloc,
 796        .css_free = devcgroup_css_free,
 797        .css_online = devcgroup_online,
 798        .css_offline = devcgroup_offline,
 799        .legacy_cftypes = dev_cgroup_files,
 800};
 801
 802/**
 803 * __devcgroup_check_permission - checks if an inode operation is permitted
 804 * @dev_cgroup: the dev cgroup to be tested against
 805 * @type: device type
 806 * @major: device major number
 807 * @minor: device minor number
 808 * @access: combination of ACC_WRITE, ACC_READ and ACC_MKNOD
 809 *
 810 * returns 0 on success, -EPERM case the operation is not permitted
 811 */
 812static int __devcgroup_check_permission(short type, u32 major, u32 minor,
 813                                        short access)
 814{
 815        struct dev_cgroup *dev_cgroup;
 816        bool rc;
 817
 818        rcu_read_lock();
 819        dev_cgroup = task_devcgroup(current);
 820        if (dev_cgroup->behavior == DEVCG_DEFAULT_ALLOW)
 821                /* Can't match any of the exceptions, even partially */
 822                rc = !match_exception_partial(&dev_cgroup->exceptions,
 823                                              type, major, minor, access);
 824        else
 825                /* Need to match completely one exception to be allowed */
 826                rc = match_exception(&dev_cgroup->exceptions, type, major,
 827                                     minor, access);
 828        rcu_read_unlock();
 829
 830        if (!rc)
 831                return -EPERM;
 832
 833        return 0;
 834}
 835
 836int __devcgroup_inode_permission(struct inode *inode, int mask)
 837{
 838        short type, access = 0;
 839
 840        if (S_ISBLK(inode->i_mode))
 841                type = DEV_BLOCK;
 842        if (S_ISCHR(inode->i_mode))
 843                type = DEV_CHAR;
 844        if (mask & MAY_WRITE)
 845                access |= ACC_WRITE;
 846        if (mask & MAY_READ)
 847                access |= ACC_READ;
 848
 849        return __devcgroup_check_permission(type, imajor(inode), iminor(inode),
 850                        access);
 851}
 852
 853int devcgroup_inode_mknod(int mode, dev_t dev)
 854{
 855        short type;
 856
 857        if (!S_ISBLK(mode) && !S_ISCHR(mode))
 858                return 0;
 859
 860        if (S_ISBLK(mode))
 861                type = DEV_BLOCK;
 862        else
 863                type = DEV_CHAR;
 864
 865        return __devcgroup_check_permission(type, MAJOR(dev), MINOR(dev),
 866                        ACC_MKNOD);
 867
 868}
 869