RHEL5/security/commoncap.c
<<
>>
Prefs
   1/* Common capabilities, needed by capability.o and root_plug.o 
   2 *
   3 *      This program is free software; you can redistribute it and/or modify
   4 *      it under the terms of the GNU General Public License as published by
   5 *      the Free Software Foundation; either version 2 of the License, or
   6 *      (at your option) any later version.
   7 *
   8 */
   9
  10#include <linux/capability.h>
  11#include <linux/module.h>
  12#include <linux/init.h>
  13#include <linux/kernel.h>
  14#include <linux/security.h>
  15#include <linux/file.h>
  16#include <linux/mm.h>
  17#include <linux/mman.h>
  18#include <linux/pagemap.h>
  19#include <linux/swap.h>
  20#include <linux/smp_lock.h>
  21#include <linux/skbuff.h>
  22#include <linux/netlink.h>
  23#include <linux/ptrace.h>
  24#include <linux/xattr.h>
  25#include <linux/hugetlb.h>
  26
  27int cap_netlink_send(struct sock *sk, struct sk_buff *skb)
  28{
  29        NETLINK_CB(skb).eff_cap = current->cap_effective;
  30        return 0;
  31}
  32
  33EXPORT_SYMBOL(cap_netlink_send);
  34
  35int cap_netlink_recv(struct sk_buff *skb, int cap)
  36{
  37        if (!cap_raised(NETLINK_CB(skb).eff_cap, cap))
  38                return -EPERM;
  39        return 0;
  40}
  41
  42EXPORT_SYMBOL(cap_netlink_recv);
  43
  44int cap_capable (struct task_struct *tsk, int cap)
  45{
  46        /* Derived from include/linux/sched.h:capable. */
  47        if (cap_raised(tsk->cap_effective, cap))
  48                return 0;
  49        return -EPERM;
  50}
  51
  52int cap_settime(struct timespec *ts, struct timezone *tz)
  53{
  54        if (!capable(CAP_SYS_TIME))
  55                return -EPERM;
  56        return 0;
  57}
  58
  59int cap_ptrace (struct task_struct *parent, struct task_struct *child)
  60{
  61        /* Derived from arch/i386/kernel/ptrace.c:sys_ptrace. */
  62        if (!cap_issubset(child->cap_permitted, parent->cap_permitted) &&
  63            !__capable(parent, CAP_SYS_PTRACE))
  64                return -EPERM;
  65        return 0;
  66}
  67
  68int cap_capget (struct task_struct *target, kernel_cap_t *effective,
  69                kernel_cap_t *inheritable, kernel_cap_t *permitted)
  70{
  71        /* Derived from kernel/capability.c:sys_capget. */
  72        *effective = cap_t (target->cap_effective);
  73        *inheritable = cap_t (target->cap_inheritable);
  74        *permitted = cap_t (target->cap_permitted);
  75        return 0;
  76}
  77
  78int cap_capset_check (struct task_struct *target, kernel_cap_t *effective,
  79                      kernel_cap_t *inheritable, kernel_cap_t *permitted)
  80{
  81        /* Derived from kernel/capability.c:sys_capset. */
  82        /* verify restrictions on target's new Inheritable set */
  83        if (!cap_issubset (*inheritable,
  84                           cap_combine (target->cap_inheritable,
  85                                        current->cap_permitted))) {
  86                return -EPERM;
  87        }
  88
  89        /* verify restrictions on target's new Permitted set */
  90        if (!cap_issubset (*permitted,
  91                           cap_combine (target->cap_permitted,
  92                                        current->cap_permitted))) {
  93                return -EPERM;
  94        }
  95
  96        /* verify the _new_Effective_ is a subset of the _new_Permitted_ */
  97        if (!cap_issubset (*effective, *permitted)) {
  98                return -EPERM;
  99        }
 100
 101        return 0;
 102}
 103
 104void cap_capset_set (struct task_struct *target, kernel_cap_t *effective,
 105                     kernel_cap_t *inheritable, kernel_cap_t *permitted)
 106{
 107        target->cap_effective = *effective;
 108        target->cap_inheritable = *inheritable;
 109        target->cap_permitted = *permitted;
 110}
 111
 112int cap_bprm_set_security (struct linux_binprm *bprm)
 113{
 114        /* Copied from fs/exec.c:prepare_binprm. */
 115
 116        /* We don't have VFS support for capabilities yet */
 117        cap_clear (bprm->cap_inheritable);
 118        cap_clear (bprm->cap_permitted);
 119        cap_clear (bprm->cap_effective);
 120
 121        /*  To support inheritance of root-permissions and suid-root
 122         *  executables under compatibility mode, we raise all three
 123         *  capability sets for the file.
 124         *
 125         *  If only the real uid is 0, we only raise the inheritable
 126         *  and permitted sets of the executable file.
 127         */
 128
 129        if (!issecure (SECURE_NOROOT)) {
 130                if (bprm->e_uid == 0 || current->uid == 0) {
 131                        cap_set_full (bprm->cap_inheritable);
 132                        cap_set_full (bprm->cap_permitted);
 133                }
 134                if (bprm->e_uid == 0)
 135                        cap_set_full (bprm->cap_effective);
 136        }
 137        return 0;
 138}
 139
 140void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
 141{
 142        /* Derived from fs/exec.c:compute_creds. */
 143        kernel_cap_t new_permitted, working;
 144
 145        new_permitted = cap_intersect (bprm->cap_permitted, cap_bset);
 146        working = cap_intersect (bprm->cap_inheritable,
 147                                 current->cap_inheritable);
 148        new_permitted = cap_combine (new_permitted, working);
 149
 150        if (bprm->e_uid != current->uid || bprm->e_gid != current->gid ||
 151            !cap_issubset (new_permitted, current->cap_permitted)) {
 152                current->mm->dumpable = suid_dumpable;
 153
 154                if (unsafe & ~LSM_UNSAFE_PTRACE_CAP) {
 155                        if (!capable(CAP_SETUID)) {
 156                                bprm->e_uid = current->uid;
 157                                bprm->e_gid = current->gid;
 158                        }
 159                        if (!capable (CAP_SETPCAP)) {
 160                                new_permitted = cap_intersect (new_permitted,
 161                                                        current->cap_permitted);
 162                        }
 163                }
 164        }
 165
 166        current->suid = current->euid = current->fsuid = bprm->e_uid;
 167        current->sgid = current->egid = current->fsgid = bprm->e_gid;
 168
 169        /* For init, we want to retain the capabilities set
 170         * in the init_task struct. Thus we skip the usual
 171         * capability rules */
 172        if (current->pid != 1) {
 173                current->cap_permitted = new_permitted;
 174                current->cap_effective =
 175                    cap_intersect (new_permitted, bprm->cap_effective);
 176        }
 177
 178        /* AUD: Audit candidate if current->cap_effective is set */
 179
 180        current->keep_capabilities = 0;
 181}
 182
 183int cap_bprm_secureexec (struct linux_binprm *bprm)
 184{
 185        /* If/when this module is enhanced to incorporate capability
 186           bits on files, the test below should be extended to also perform a 
 187           test between the old and new capability sets.  For now,
 188           it simply preserves the legacy decision algorithm used by
 189           the old userland. */
 190        return (current->euid != current->uid ||
 191                current->egid != current->gid);
 192}
 193
 194int cap_inode_setxattr(struct dentry *dentry, char *name, void *value,
 195                       size_t size, int flags)
 196{
 197        if (!strncmp(name, XATTR_SECURITY_PREFIX,
 198                     sizeof(XATTR_SECURITY_PREFIX) - 1)  &&
 199            !capable(CAP_SYS_ADMIN))
 200                return -EPERM;
 201        return 0;
 202}
 203
 204int cap_inode_removexattr(struct dentry *dentry, char *name)
 205{
 206        if (!strncmp(name, XATTR_SECURITY_PREFIX,
 207                     sizeof(XATTR_SECURITY_PREFIX) - 1)  &&
 208            !capable(CAP_SYS_ADMIN))
 209                return -EPERM;
 210        return 0;
 211}
 212
 213/* moved from kernel/sys.c. */
 214/* 
 215 * cap_emulate_setxuid() fixes the effective / permitted capabilities of
 216 * a process after a call to setuid, setreuid, or setresuid.
 217 *
 218 *  1) When set*uiding _from_ one of {r,e,s}uid == 0 _to_ all of
 219 *  {r,e,s}uid != 0, the permitted and effective capabilities are
 220 *  cleared.
 221 *
 222 *  2) When set*uiding _from_ euid == 0 _to_ euid != 0, the effective
 223 *  capabilities of the process are cleared.
 224 *
 225 *  3) When set*uiding _from_ euid != 0 _to_ euid == 0, the effective
 226 *  capabilities are set to the permitted capabilities.
 227 *
 228 *  fsuid is handled elsewhere. fsuid == 0 and {r,e,s}uid!= 0 should 
 229 *  never happen.
 230 *
 231 *  -astor 
 232 *
 233 * cevans - New behaviour, Oct '99
 234 * A process may, via prctl(), elect to keep its capabilities when it
 235 * calls setuid() and switches away from uid==0. Both permitted and
 236 * effective sets will be retained.
 237 * Without this change, it was impossible for a daemon to drop only some
 238 * of its privilege. The call to setuid(!=0) would drop all privileges!
 239 * Keeping uid 0 is not an option because uid 0 owns too many vital
 240 * files..
 241 * Thanks to Olaf Kirch and Peter Benie for spotting this.
 242 */
 243static inline void cap_emulate_setxuid (int old_ruid, int old_euid,
 244                                        int old_suid)
 245{
 246        if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) &&
 247            (current->uid != 0 && current->euid != 0 && current->suid != 0) &&
 248            !current->keep_capabilities) {
 249                cap_clear (current->cap_permitted);
 250                cap_clear (current->cap_effective);
 251        }
 252        if (old_euid == 0 && current->euid != 0) {
 253                cap_clear (current->cap_effective);
 254        }
 255        if (old_euid != 0 && current->euid == 0) {
 256                current->cap_effective = current->cap_permitted;
 257        }
 258}
 259
 260int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid,
 261                          int flags)
 262{
 263        switch (flags) {
 264        case LSM_SETID_RE:
 265        case LSM_SETID_ID:
 266        case LSM_SETID_RES:
 267                /* Copied from kernel/sys.c:setreuid/setuid/setresuid. */
 268                if (!issecure (SECURE_NO_SETUID_FIXUP)) {
 269                        cap_emulate_setxuid (old_ruid, old_euid, old_suid);
 270                }
 271                break;
 272        case LSM_SETID_FS:
 273                {
 274                        uid_t old_fsuid = old_ruid;
 275
 276                        /* Copied from kernel/sys.c:setfsuid. */
 277
 278                        /*
 279                         * FIXME - is fsuser used for all CAP_FS_MASK capabilities?
 280                         *          if not, we might be a bit too harsh here.
 281                         */
 282
 283                        if (!issecure (SECURE_NO_SETUID_FIXUP)) {
 284                                if (old_fsuid == 0 && current->fsuid != 0) {
 285                                        cap_t (current->cap_effective) &=
 286                                            ~CAP_FS_MASK;
 287                                }
 288                                if (old_fsuid != 0 && current->fsuid == 0) {
 289                                        cap_t (current->cap_effective) |=
 290                                            (cap_t (current->cap_permitted) &
 291                                             CAP_FS_MASK);
 292                                }
 293                        }
 294                        break;
 295                }
 296        default:
 297                return -EINVAL;
 298        }
 299
 300        return 0;
 301}
 302
 303void cap_task_reparent_to_init (struct task_struct *p)
 304{
 305        p->cap_effective = CAP_INIT_EFF_SET;
 306        p->cap_inheritable = CAP_INIT_INH_SET;
 307        p->cap_permitted = CAP_FULL_SET;
 308        p->keep_capabilities = 0;
 309        return;
 310}
 311
 312int cap_syslog (int type)
 313{
 314        if ((type != 3 && type != 10) && !capable(CAP_SYS_ADMIN))
 315                return -EPERM;
 316        return 0;
 317}
 318
 319int cap_vm_enough_memory(long pages)
 320{
 321        int cap_sys_admin = 0;
 322
 323        if (cap_capable(current, CAP_SYS_ADMIN) == 0)
 324                cap_sys_admin = 1;
 325        return __vm_enough_memory(pages, cap_sys_admin);
 326}
 327
 328EXPORT_SYMBOL(cap_capable);
 329EXPORT_SYMBOL(cap_settime);
 330EXPORT_SYMBOL(cap_ptrace);
 331EXPORT_SYMBOL(cap_capget);
 332EXPORT_SYMBOL(cap_capset_check);
 333EXPORT_SYMBOL(cap_capset_set);
 334EXPORT_SYMBOL(cap_bprm_set_security);
 335EXPORT_SYMBOL(cap_bprm_apply_creds);
 336EXPORT_SYMBOL(cap_bprm_secureexec);
 337EXPORT_SYMBOL(cap_inode_setxattr);
 338EXPORT_SYMBOL(cap_inode_removexattr);
 339EXPORT_SYMBOL(cap_task_post_setuid);
 340EXPORT_SYMBOL(cap_task_reparent_to_init);
 341EXPORT_SYMBOL(cap_syslog);
 342EXPORT_SYMBOL(cap_vm_enough_memory);
 343
 344MODULE_DESCRIPTION("Standard Linux Common Capabilities Security Module");
 345MODULE_LICENSE("GPL");
 346