linux/security/yama/yama_lsm.c
<<
>>
Prefs
   1/*
   2 * Yama Linux Security Module
   3 *
   4 * Author: Kees Cook <keescook@chromium.org>
   5 *
   6 * Copyright (C) 2010 Canonical, Ltd.
   7 * Copyright (C) 2011 The Chromium OS Authors.
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License version 2, as
  11 * published by the Free Software Foundation.
  12 *
  13 */
  14
  15#include <linux/security.h>
  16#include <linux/sysctl.h>
  17#include <linux/ptrace.h>
  18#include <linux/prctl.h>
  19#include <linux/ratelimit.h>
  20#include <linux/workqueue.h>
  21
  22#define YAMA_SCOPE_DISABLED     0
  23#define YAMA_SCOPE_RELATIONAL   1
  24#define YAMA_SCOPE_CAPABILITY   2
  25#define YAMA_SCOPE_NO_ATTACH    3
  26
  27static int ptrace_scope = YAMA_SCOPE_RELATIONAL;
  28
  29/* describe a ptrace relationship for potential exception */
  30struct ptrace_relation {
  31        struct task_struct *tracer;
  32        struct task_struct *tracee;
  33        bool invalid;
  34        struct list_head node;
  35        struct rcu_head rcu;
  36};
  37
  38static LIST_HEAD(ptracer_relations);
  39static DEFINE_SPINLOCK(ptracer_relations_lock);
  40
  41static void yama_relation_cleanup(struct work_struct *work);
  42static DECLARE_WORK(yama_relation_work, yama_relation_cleanup);
  43
  44/**
  45 * yama_relation_cleanup - remove invalid entries from the relation list
  46 *
  47 */
  48static void yama_relation_cleanup(struct work_struct *work)
  49{
  50        struct ptrace_relation *relation;
  51
  52        spin_lock(&ptracer_relations_lock);
  53        rcu_read_lock();
  54        list_for_each_entry_rcu(relation, &ptracer_relations, node) {
  55                if (relation->invalid) {
  56                        list_del_rcu(&relation->node);
  57                        kfree_rcu(relation, rcu);
  58                }
  59        }
  60        rcu_read_unlock();
  61        spin_unlock(&ptracer_relations_lock);
  62}
  63
  64/**
  65 * yama_ptracer_add - add/replace an exception for this tracer/tracee pair
  66 * @tracer: the task_struct of the process doing the ptrace
  67 * @tracee: the task_struct of the process to be ptraced
  68 *
  69 * Each tracee can have, at most, one tracer registered. Each time this
  70 * is called, the prior registered tracer will be replaced for the tracee.
  71 *
  72 * Returns 0 if relationship was added, -ve on error.
  73 */
  74static int yama_ptracer_add(struct task_struct *tracer,
  75                            struct task_struct *tracee)
  76{
  77        struct ptrace_relation *relation, *added;
  78
  79        added = kmalloc(sizeof(*added), GFP_KERNEL);
  80        if (!added)
  81                return -ENOMEM;
  82
  83        added->tracee = tracee;
  84        added->tracer = tracer;
  85        added->invalid = false;
  86
  87        spin_lock(&ptracer_relations_lock);
  88        rcu_read_lock();
  89        list_for_each_entry_rcu(relation, &ptracer_relations, node) {
  90                if (relation->invalid)
  91                        continue;
  92                if (relation->tracee == tracee) {
  93                        list_replace_rcu(&relation->node, &added->node);
  94                        kfree_rcu(relation, rcu);
  95                        goto out;
  96                }
  97        }
  98
  99        list_add_rcu(&added->node, &ptracer_relations);
 100
 101out:
 102        rcu_read_unlock();
 103        spin_unlock(&ptracer_relations_lock);
 104        return 0;
 105}
 106
 107/**
 108 * yama_ptracer_del - remove exceptions related to the given tasks
 109 * @tracer: remove any relation where tracer task matches
 110 * @tracee: remove any relation where tracee task matches
 111 */
 112static void yama_ptracer_del(struct task_struct *tracer,
 113                             struct task_struct *tracee)
 114{
 115        struct ptrace_relation *relation;
 116        bool marked = false;
 117
 118        rcu_read_lock();
 119        list_for_each_entry_rcu(relation, &ptracer_relations, node) {
 120                if (relation->invalid)
 121                        continue;
 122                if (relation->tracee == tracee ||
 123                    (tracer && relation->tracer == tracer)) {
 124                        relation->invalid = true;
 125                        marked = true;
 126                }
 127        }
 128        rcu_read_unlock();
 129
 130        if (marked)
 131                schedule_work(&yama_relation_work);
 132}
 133
 134/**
 135 * yama_task_free - check for task_pid to remove from exception list
 136 * @task: task being removed
 137 */
 138void yama_task_free(struct task_struct *task)
 139{
 140        yama_ptracer_del(task, task);
 141}
 142
 143/**
 144 * yama_task_prctl - check for Yama-specific prctl operations
 145 * @option: operation
 146 * @arg2: argument
 147 * @arg3: argument
 148 * @arg4: argument
 149 * @arg5: argument
 150 *
 151 * Return 0 on success, -ve on error.  -ENOSYS is returned when Yama
 152 * does not handle the given option.
 153 */
 154int yama_task_prctl(int option, unsigned long arg2, unsigned long arg3,
 155                           unsigned long arg4, unsigned long arg5)
 156{
 157        int rc;
 158        struct task_struct *myself = current;
 159
 160        rc = cap_task_prctl(option, arg2, arg3, arg4, arg5);
 161        if (rc != -ENOSYS)
 162                return rc;
 163
 164        switch (option) {
 165        case PR_SET_PTRACER:
 166                /* Since a thread can call prctl(), find the group leader
 167                 * before calling _add() or _del() on it, since we want
 168                 * process-level granularity of control. The tracer group
 169                 * leader checking is handled later when walking the ancestry
 170                 * at the time of PTRACE_ATTACH check.
 171                 */
 172                rcu_read_lock();
 173                if (!thread_group_leader(myself))
 174                        myself = rcu_dereference(myself->group_leader);
 175                get_task_struct(myself);
 176                rcu_read_unlock();
 177
 178                if (arg2 == 0) {
 179                        yama_ptracer_del(NULL, myself);
 180                        rc = 0;
 181                } else if (arg2 == PR_SET_PTRACER_ANY || (int)arg2 == -1) {
 182                        rc = yama_ptracer_add(NULL, myself);
 183                } else {
 184                        struct task_struct *tracer;
 185
 186                        rcu_read_lock();
 187                        tracer = find_task_by_vpid(arg2);
 188                        if (tracer)
 189                                get_task_struct(tracer);
 190                        else
 191                                rc = -EINVAL;
 192                        rcu_read_unlock();
 193
 194                        if (tracer) {
 195                                rc = yama_ptracer_add(tracer, myself);
 196                                put_task_struct(tracer);
 197                        }
 198                }
 199
 200                put_task_struct(myself);
 201                break;
 202        }
 203
 204        return rc;
 205}
 206
 207/**
 208 * task_is_descendant - walk up a process family tree looking for a match
 209 * @parent: the process to compare against while walking up from child
 210 * @child: the process to start from while looking upwards for parent
 211 *
 212 * Returns 1 if child is a descendant of parent, 0 if not.
 213 */
 214static int task_is_descendant(struct task_struct *parent,
 215                              struct task_struct *child)
 216{
 217        int rc = 0;
 218        struct task_struct *walker = child;
 219
 220        if (!parent || !child)
 221                return 0;
 222
 223        rcu_read_lock();
 224        if (!thread_group_leader(parent))
 225                parent = rcu_dereference(parent->group_leader);
 226        while (walker->pid > 0) {
 227                if (!thread_group_leader(walker))
 228                        walker = rcu_dereference(walker->group_leader);
 229                if (walker == parent) {
 230                        rc = 1;
 231                        break;
 232                }
 233                walker = rcu_dereference(walker->real_parent);
 234        }
 235        rcu_read_unlock();
 236
 237        return rc;
 238}
 239
 240/**
 241 * ptracer_exception_found - tracer registered as exception for this tracee
 242 * @tracer: the task_struct of the process attempting ptrace
 243 * @tracee: the task_struct of the process to be ptraced
 244 *
 245 * Returns 1 if tracer has is ptracer exception ancestor for tracee.
 246 */
 247static int ptracer_exception_found(struct task_struct *tracer,
 248                                   struct task_struct *tracee)
 249{
 250        int rc = 0;
 251        struct ptrace_relation *relation;
 252        struct task_struct *parent = NULL;
 253        bool found = false;
 254
 255        rcu_read_lock();
 256        if (!thread_group_leader(tracee))
 257                tracee = rcu_dereference(tracee->group_leader);
 258        list_for_each_entry_rcu(relation, &ptracer_relations, node) {
 259                if (relation->invalid)
 260                        continue;
 261                if (relation->tracee == tracee) {
 262                        parent = relation->tracer;
 263                        found = true;
 264                        break;
 265                }
 266        }
 267
 268        if (found && (parent == NULL || task_is_descendant(parent, tracer)))
 269                rc = 1;
 270        rcu_read_unlock();
 271
 272        return rc;
 273}
 274
 275/**
 276 * yama_ptrace_access_check - validate PTRACE_ATTACH calls
 277 * @child: task that current task is attempting to ptrace
 278 * @mode: ptrace attach mode
 279 *
 280 * Returns 0 if following the ptrace is allowed, -ve on error.
 281 */
 282int yama_ptrace_access_check(struct task_struct *child,
 283                                    unsigned int mode)
 284{
 285        int rc;
 286
 287        /* If standard caps disallows it, so does Yama.  We should
 288         * only tighten restrictions further.
 289         */
 290        rc = cap_ptrace_access_check(child, mode);
 291        if (rc)
 292                return rc;
 293
 294        /* require ptrace target be a child of ptracer on attach */
 295        if (mode == PTRACE_MODE_ATTACH) {
 296                switch (ptrace_scope) {
 297                case YAMA_SCOPE_DISABLED:
 298                        /* No additional restrictions. */
 299                        break;
 300                case YAMA_SCOPE_RELATIONAL:
 301                        rcu_read_lock();
 302                        if (!task_is_descendant(current, child) &&
 303                            !ptracer_exception_found(current, child) &&
 304                            !ns_capable(__task_cred(child)->user_ns, CAP_SYS_PTRACE))
 305                                rc = -EPERM;
 306                        rcu_read_unlock();
 307                        break;
 308                case YAMA_SCOPE_CAPABILITY:
 309                        rcu_read_lock();
 310                        if (!ns_capable(__task_cred(child)->user_ns, CAP_SYS_PTRACE))
 311                                rc = -EPERM;
 312                        rcu_read_unlock();
 313                        break;
 314                case YAMA_SCOPE_NO_ATTACH:
 315                default:
 316                        rc = -EPERM;
 317                        break;
 318                }
 319        }
 320
 321        if (rc) {
 322                printk_ratelimited(KERN_NOTICE
 323                        "ptrace of pid %d was attempted by: %s (pid %d)\n",
 324                        child->pid, current->comm, current->pid);
 325        }
 326
 327        return rc;
 328}
 329
 330/**
 331 * yama_ptrace_traceme - validate PTRACE_TRACEME calls
 332 * @parent: task that will become the ptracer of the current task
 333 *
 334 * Returns 0 if following the ptrace is allowed, -ve on error.
 335 */
 336int yama_ptrace_traceme(struct task_struct *parent)
 337{
 338        int rc;
 339
 340        /* If standard caps disallows it, so does Yama.  We should
 341         * only tighten restrictions further.
 342         */
 343        rc = cap_ptrace_traceme(parent);
 344        if (rc)
 345                return rc;
 346
 347        /* Only disallow PTRACE_TRACEME on more aggressive settings. */
 348        switch (ptrace_scope) {
 349        case YAMA_SCOPE_CAPABILITY:
 350                if (!has_ns_capability(parent, current_user_ns(), CAP_SYS_PTRACE))
 351                        rc = -EPERM;
 352                break;
 353        case YAMA_SCOPE_NO_ATTACH:
 354                rc = -EPERM;
 355                break;
 356        }
 357
 358        if (rc) {
 359                printk_ratelimited(KERN_NOTICE
 360                        "ptraceme of pid %d was attempted by: %s (pid %d)\n",
 361                        current->pid, parent->comm, parent->pid);
 362        }
 363
 364        return rc;
 365}
 366
 367#ifndef CONFIG_SECURITY_YAMA_STACKED
 368static struct security_operations yama_ops = {
 369        .name =                 "yama",
 370
 371        .ptrace_access_check =  yama_ptrace_access_check,
 372        .ptrace_traceme =       yama_ptrace_traceme,
 373        .task_prctl =           yama_task_prctl,
 374        .task_free =            yama_task_free,
 375};
 376#endif
 377
 378#ifdef CONFIG_SYSCTL
 379static int yama_dointvec_minmax(struct ctl_table *table, int write,
 380                                void __user *buffer, size_t *lenp, loff_t *ppos)
 381{
 382        int rc;
 383
 384        if (write && !capable(CAP_SYS_PTRACE))
 385                return -EPERM;
 386
 387        rc = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
 388        if (rc)
 389                return rc;
 390
 391        /* Lock the max value if it ever gets set. */
 392        if (write && *(int *)table->data == *(int *)table->extra2)
 393                table->extra1 = table->extra2;
 394
 395        return rc;
 396}
 397
 398static int zero;
 399static int max_scope = YAMA_SCOPE_NO_ATTACH;
 400
 401struct ctl_path yama_sysctl_path[] = {
 402        { .procname = "kernel", },
 403        { .procname = "yama", },
 404        { }
 405};
 406
 407static struct ctl_table yama_sysctl_table[] = {
 408        {
 409                .procname       = "ptrace_scope",
 410                .data           = &ptrace_scope,
 411                .maxlen         = sizeof(int),
 412                .mode           = 0644,
 413                .proc_handler   = yama_dointvec_minmax,
 414                .extra1         = &zero,
 415                .extra2         = &max_scope,
 416        },
 417        { }
 418};
 419#endif /* CONFIG_SYSCTL */
 420
 421static __init int yama_init(void)
 422{
 423#ifndef CONFIG_SECURITY_YAMA_STACKED
 424        if (!security_module_enable(&yama_ops))
 425                return 0;
 426#endif
 427
 428        printk(KERN_INFO "Yama: becoming mindful.\n");
 429
 430#ifndef CONFIG_SECURITY_YAMA_STACKED
 431        if (register_security(&yama_ops))
 432                panic("Yama: kernel registration failed.\n");
 433#endif
 434
 435#ifdef CONFIG_SYSCTL
 436        if (!register_sysctl_paths(yama_sysctl_path, yama_sysctl_table))
 437                panic("Yama: sysctl registration failed.\n");
 438#endif
 439
 440        return 0;
 441}
 442
 443security_initcall(yama_init);
 444