]> Git Repo - linux.git/commitdiff
Merge branch 'smack-for-3.16' of git://git.gitorious.org/smack-next/kernel into next
authorJames Morris <[email protected]>
Tue, 20 May 2014 04:50:09 +0000 (14:50 +1000)
committerJames Morris <[email protected]>
Tue, 20 May 2014 04:50:09 +0000 (14:50 +1000)
1  2 
security/smack/smack_lsm.c

index 8177e7df8c2da4ffa4854425b93d104dd31378fe,9cb7559d60b236e4e7ac770b0e56100c7762577c..f2c30801ce413224bade6b1ba3f34fb676fd2e80
@@@ -157,6 -157,74 +157,74 @@@ static int smk_copy_rules(struct list_h
        return rc;
  }
  
+ /**
+  * smk_ptrace_mode - helper function for converting PTRACE_MODE_* into MAY_*
+  * @mode - input mode in form of PTRACE_MODE_*
+  *
+  * Returns a converted MAY_* mode usable by smack rules
+  */
+ static inline unsigned int smk_ptrace_mode(unsigned int mode)
+ {
+       switch (mode) {
+       case PTRACE_MODE_READ:
+               return MAY_READ;
+       case PTRACE_MODE_ATTACH:
+               return MAY_READWRITE;
+       }
+       return 0;
+ }
+ /**
+  * smk_ptrace_rule_check - helper for ptrace access
+  * @tracer: tracer process
+  * @tracee_label: label of the process that's about to be traced,
+  *                the pointer must originate from smack structures
+  * @mode: ptrace attachment mode (PTRACE_MODE_*)
+  * @func: name of the function that called us, used for audit
+  *
+  * Returns 0 on access granted, -error on error
+  */
+ static int smk_ptrace_rule_check(struct task_struct *tracer, char *tracee_label,
+                                unsigned int mode, const char *func)
+ {
+       int rc;
+       struct smk_audit_info ad, *saip = NULL;
+       struct task_smack *tsp;
+       struct smack_known *skp;
+       if ((mode & PTRACE_MODE_NOAUDIT) == 0) {
+               smk_ad_init(&ad, func, LSM_AUDIT_DATA_TASK);
+               smk_ad_setfield_u_tsk(&ad, tracer);
+               saip = &ad;
+       }
+       tsp = task_security(tracer);
+       skp = smk_of_task(tsp);
+       if ((mode & PTRACE_MODE_ATTACH) &&
+           (smack_ptrace_rule == SMACK_PTRACE_EXACT ||
+            smack_ptrace_rule == SMACK_PTRACE_DRACONIAN)) {
+               if (skp->smk_known == tracee_label)
+                       rc = 0;
+               else if (smack_ptrace_rule == SMACK_PTRACE_DRACONIAN)
+                       rc = -EACCES;
+               else if (capable(CAP_SYS_PTRACE))
+                       rc = 0;
+               else
+                       rc = -EACCES;
+               if (saip)
+                       smack_log(skp->smk_known, tracee_label, 0, rc, saip);
+               return rc;
+       }
+       /* In case of rule==SMACK_PTRACE_DEFAULT or mode==PTRACE_MODE_READ */
+       rc = smk_tskacc(tsp, tracee_label, smk_ptrace_mode(mode), saip);
+       return rc;
+ }
  /*
   * LSM hooks.
   * We he, that is fun!
  /**
   * smack_ptrace_access_check - Smack approval on PTRACE_ATTACH
   * @ctp: child task pointer
-  * @mode: ptrace attachment mode
+  * @mode: ptrace attachment mode (PTRACE_MODE_*)
   *
   * Returns 0 if access is OK, an error code otherwise
   *
-  * Do the capability checks, and require read and write.
+  * Do the capability checks.
   */
  static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)
  {
        int rc;
-       struct smk_audit_info ad;
        struct smack_known *skp;
  
        rc = cap_ptrace_access_check(ctp, mode);
                return rc;
  
        skp = smk_of_task(task_security(ctp));
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
-       smk_ad_setfield_u_tsk(&ad, ctp);
  
-       rc = smk_curacc(skp->smk_known, mode, &ad);
+       rc = smk_ptrace_rule_check(current, skp->smk_known, mode, __func__);
        return rc;
  }
  
   *
   * Returns 0 if access is OK, an error code otherwise
   *
-  * Do the capability checks, and require read and write.
+  * Do the capability checks, and require PTRACE_MODE_ATTACH.
   */
  static int smack_ptrace_traceme(struct task_struct *ptp)
  {
        int rc;
-       struct smk_audit_info ad;
        struct smack_known *skp;
  
        rc = cap_ptrace_traceme(ptp);
        if (rc != 0)
                return rc;
  
-       skp = smk_of_task(task_security(ptp));
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
-       smk_ad_setfield_u_tsk(&ad, ptp);
+       skp = smk_of_task(current_security());
  
-       rc = smk_curacc(skp->smk_known, MAY_READWRITE, &ad);
+       rc = smk_ptrace_rule_check(ptp, skp->smk_known,
+                                  PTRACE_MODE_ATTACH, __func__);
        return rc;
  }
  
@@@ -413,9 -476,11 +476,11 @@@ static int smack_sb_kern_mount(struct s
         * Initialize the root inode.
         */
        isp = inode->i_security;
-       if (inode->i_security == NULL) {
-               inode->i_security = new_inode_smack(sp->smk_root);
-               isp = inode->i_security;
+       if (isp == NULL) {
+               isp = new_inode_smack(sp->smk_root);
+               if (isp == NULL)
+                       return -ENOMEM;
+               inode->i_security = isp;
        } else
                isp->smk_inode = sp->smk_root;
  
@@@ -453,7 -518,7 +518,7 @@@ static int smack_sb_statfs(struct dentr
   * smack_bprm_set_creds - set creds for exec
   * @bprm: the exec information
   *
-  * Returns 0 if it gets a blob, -ENOMEM otherwise
+  * Returns 0 if it gets a blob, -EPERM if exec forbidden and -ENOMEM otherwise
   */
  static int smack_bprm_set_creds(struct linux_binprm *bprm)
  {
        if (isp->smk_task == NULL || isp->smk_task == bsp->smk_task)
                return 0;
  
-       if (bprm->unsafe)
+       if (bprm->unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
+               struct task_struct *tracer;
+               rc = 0;
+               rcu_read_lock();
+               tracer = ptrace_parent(current);
+               if (likely(tracer != NULL))
+                       rc = smk_ptrace_rule_check(tracer,
+                                                  isp->smk_task->smk_known,
+                                                  PTRACE_MODE_ATTACH,
+                                                  __func__);
+               rcu_read_unlock();
+               if (rc != 0)
+                       return rc;
+       } else if (bprm->unsafe)
                return -EPERM;
  
        bsp->smk_task = isp->smk_task;
@@@ -880,18 -960,20 +960,20 @@@ static void smack_inode_post_setxattr(s
                return;
        }
  
-       skp = smk_import_entry(value, size);
        if (strcmp(name, XATTR_NAME_SMACK) == 0) {
+               skp = smk_import_entry(value, size);
                if (skp != NULL)
                        isp->smk_inode = skp->smk_known;
                else
                        isp->smk_inode = smack_known_invalid.smk_known;
        } else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) {
+               skp = smk_import_entry(value, size);
                if (skp != NULL)
                        isp->smk_task = skp;
                else
                        isp->smk_task = &smack_known_invalid;
        } else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0) {
+               skp = smk_import_entry(value, size);
                if (skp != NULL)
                        isp->smk_mmap = skp;
                else
@@@ -938,24 -1020,37 +1020,37 @@@ static int smack_inode_removexattr(stru
            strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 ||
            strcmp(name, XATTR_NAME_SMACKEXEC) == 0 ||
            strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0 ||
-           strcmp(name, XATTR_NAME_SMACKMMAP)) {
+           strcmp(name, XATTR_NAME_SMACKMMAP) == 0) {
                if (!smack_privileged(CAP_MAC_ADMIN))
                        rc = -EPERM;
        } else
                rc = cap_inode_removexattr(dentry, name);
  
+       if (rc != 0)
+               return rc;
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
        smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
-       if (rc == 0)
-               rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
  
-       if (rc == 0) {
-               isp = dentry->d_inode->i_security;
+       rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
+       if (rc != 0)
+               return rc;
+       isp = dentry->d_inode->i_security;
+       /*
+        * Don't do anything special for these.
+        *      XATTR_NAME_SMACKIPIN
+        *      XATTR_NAME_SMACKIPOUT
+        *      XATTR_NAME_SMACKEXEC
+        */
+       if (strcmp(name, XATTR_NAME_SMACK) == 0)
                isp->smk_task = NULL;
+       else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0)
                isp->smk_mmap = NULL;
-       }
+       else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0)
+               isp->smk_flags &= ~SMK_INODE_TRANSMUTE;
  
-       return rc;
+       return 0;
  }
  
  /**
@@@ -1000,7 -1095,7 +1095,7 @@@ static int smack_inode_getsecurity(cons
        ssp = sock->sk->sk_security;
  
        if (strcmp(name, XATTR_SMACK_IPIN) == 0)
-               isp = ssp->smk_in;
+               isp = ssp->smk_in->smk_known;
        else if (strcmp(name, XATTR_SMACK_IPOUT) == 0)
                isp = ssp->smk_out->smk_known;
        else
@@@ -1367,19 -1462,32 +1462,32 @@@ static int smack_file_receive(struct fi
  /**
   * smack_file_open - Smack dentry open processing
   * @file: the object
-  * @cred: unused
+  * @cred: task credential
   *
   * Set the security blob in the file structure.
+  * Allow the open only if the task has read access. There are
+  * many read operations (e.g. fstat) that you can do with an
+  * fd even if you have the file open write-only.
   *
   * Returns 0
   */
  static int smack_file_open(struct file *file, const struct cred *cred)
  {
+       struct task_smack *tsp = cred->security;
        struct inode_smack *isp = file_inode(file)->i_security;
+       struct smk_audit_info ad;
+       int rc;
  
-       file->f_security = isp->smk_inode;
+       if (smack_privileged(CAP_MAC_OVERRIDE))
+               return 0;
  
-       return 0;
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
+       smk_ad_setfield_u_fs_path(&ad, file->f_path);
+       rc = smk_access(tsp->smk_task, isp->smk_inode, MAY_READ, &ad);
+       if (rc == 0)
+               file->f_security = isp->smk_inode;
+       return rc;
  }
  
  /*
@@@ -1764,7 -1872,7 +1872,7 @@@ static int smack_sk_alloc_security(stru
        if (ssp == NULL)
                return -ENOMEM;
  
-       ssp->smk_in = skp->smk_known;
+       ssp->smk_in = skp;
        ssp->smk_out = skp;
        ssp->smk_packet = NULL;
  
@@@ -2004,7 -2112,7 +2112,7 @@@ static int smk_ipv6_port_check(struct s
  
        if (act == SMK_RECEIVING) {
                skp = smack_net_ambient;
-               object = ssp->smk_in;
+               object = ssp->smk_in->smk_known;
        } else {
                skp = ssp->smk_out;
                object = smack_net_ambient->smk_known;
        list_for_each_entry(spp, &smk_ipv6_port_list, list) {
                if (spp->smk_port != port)
                        continue;
-               object = spp->smk_in;
+               object = spp->smk_in->smk_known;
                if (act == SMK_CONNECTING)
-                       ssp->smk_packet = spp->smk_out->smk_known;
+                       ssp->smk_packet = spp->smk_out;
                break;
        }
  
@@@ -2076,7 -2184,7 +2184,7 @@@ static int smack_inode_setsecurity(stru
        int rc = 0;
  
        if (value == NULL || size > SMK_LONGLABEL || size == 0)
-               return -EACCES;
+               return -EINVAL;
  
        skp = smk_import_entry(value, size);
        if (skp == NULL)
        ssp = sock->sk->sk_security;
  
        if (strcmp(name, XATTR_SMACK_IPIN) == 0)
-               ssp->smk_in = skp->smk_known;
+               ssp->smk_in = skp;
        else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) {
                ssp->smk_out = skp;
                if (sock->sk->sk_family == PF_INET) {
@@@ -2713,6 -2821,15 +2821,15 @@@ static void smack_d_instantiate(struct 
         * of the superblock.
         */
        if (opt_dentry->d_parent == opt_dentry) {
+               if (sbp->s_magic == CGROUP_SUPER_MAGIC) {
+                       /*
+                        * The cgroup filesystem is never mounted,
+                        * so there's no opportunity to set the mount
+                        * options.
+                        */
+                       sbsp->smk_root = smack_known_star.smk_known;
+                       sbsp->smk_default = smack_known_star.smk_known;
+               }
                isp->smk_inode = sbsp->smk_root;
                isp->smk_flags |= SMK_INODE_INSTANT;
                goto unlockandout;
         */
        switch (sbp->s_magic) {
        case SMACK_MAGIC:
+       case PIPEFS_MAGIC:
+       case SOCKFS_MAGIC:
+       case CGROUP_SUPER_MAGIC:
                /*
                 * Casey says that it's a little embarrassing
                 * that the smack file system doesn't do
                 * extended attributes.
-                */
-               final = smack_known_star.smk_known;
-               break;
-       case PIPEFS_MAGIC:
-               /*
+                *
                 * Casey says pipes are easy (?)
+                *
+                * Socket access is controlled by the socket
+                * structures associated with the task involved.
+                *
+                * Cgroupfs is special
                 */
                final = smack_known_star.smk_known;
                break;
                 */
                final = ckp->smk_known;
                break;
-       case SOCKFS_MAGIC:
-               /*
-                * Socket access is controlled by the socket
-                * structures associated with the task involved.
-                */
-               final = smack_known_star.smk_known;
-               break;
        case PROC_SUPER_MAGIC:
                /*
                 * Casey says procfs appears not to care.
@@@ -2959,30 -3073,34 +3073,34 @@@ static int smack_unix_stream_connect(st
                                     struct sock *other, struct sock *newsk)
  {
        struct smack_known *skp;
+       struct smack_known *okp;
        struct socket_smack *ssp = sock->sk_security;
        struct socket_smack *osp = other->sk_security;
        struct socket_smack *nsp = newsk->sk_security;
        struct smk_audit_info ad;
        int rc = 0;
  #ifdef CONFIG_AUDIT
        struct lsm_network_audit net;
-       smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
-       smk_ad_setfield_u_net_sk(&ad, other);
  #endif
  
        if (!smack_privileged(CAP_MAC_OVERRIDE)) {
                skp = ssp->smk_out;
-               rc = smk_access(skp, osp->smk_in, MAY_WRITE, &ad);
+               okp = osp->smk_out;
+ #ifdef CONFIG_AUDIT
+               smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
+               smk_ad_setfield_u_net_sk(&ad, other);
+ #endif
+               rc = smk_access(skp, okp->smk_known, MAY_WRITE, &ad);
+               if (rc == 0)
+                       rc = smk_access(okp, okp->smk_known, MAY_WRITE, NULL);
        }
  
        /*
         * Cross reference the peer labels for SO_PEERSEC.
         */
        if (rc == 0) {
-               nsp->smk_packet = ssp->smk_out->smk_known;
-               ssp->smk_packet = osp->smk_out->smk_known;
+               nsp->smk_packet = ssp->smk_out;
+               ssp->smk_packet = osp->smk_out;
        }
  
        return rc;
@@@ -3014,7 -3132,7 +3132,7 @@@ static int smack_unix_may_send(struct s
                return 0;
  
        skp = ssp->smk_out;
-       return smk_access(skp, osp->smk_in, MAY_WRITE, &ad);
+       return smk_access(skp, osp->smk_in->smk_known, MAY_WRITE, &ad);
  }
  
  /**
@@@ -3109,7 -3227,7 +3227,7 @@@ static struct smack_known *smack_from_s
                if (found)
                        return skp;
  
-               if (ssp != NULL && ssp->smk_in == smack_known_star.smk_known)
+               if (ssp != NULL && ssp->smk_in == &smack_known_star)
                        return &smack_known_web;
                return &smack_known_star;
        }
@@@ -3228,7 -3346,7 +3346,7 @@@ static int smack_socket_sock_rcv_skb(st
                 * This is the simplist possible security model
                 * for networking.
                 */
-               rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad);
+               rc = smk_access(skp, ssp->smk_in->smk_known, MAY_WRITE, &ad);
                if (rc != 0)
                        netlbl_skbuff_err(skb, rc, 0);
                break;
@@@ -3263,7 -3381,7 +3381,7 @@@ static int smack_socket_getpeersec_stre
  
        ssp = sock->sk->sk_security;
        if (ssp->smk_packet != NULL) {
-               rcp = ssp->smk_packet;
+               rcp = ssp->smk_packet->smk_known;
                slen = strlen(rcp) + 1;
        }
  
@@@ -3348,7 -3466,7 +3466,7 @@@ static void smack_sock_graft(struct soc
                return;
  
        ssp = sk->sk_security;
-       ssp->smk_in = skp->smk_known;
+       ssp->smk_in = skp;
        ssp->smk_out = skp;
        /* cssp->smk_packet is already set in smack_inet_csk_clone() */
  }
@@@ -3408,7 -3526,7 +3526,7 @@@ static int smack_inet_conn_request(stru
         * Receiving a packet requires that the other end be able to write
         * here. Read access is not required.
         */
-       rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad);
+       rc = smk_access(skp, ssp->smk_in->smk_known, MAY_WRITE, &ad);
        if (rc != 0)
                return rc;
  
@@@ -3452,7 -3570,7 +3570,7 @@@ static void smack_inet_csk_clone(struc
  
        if (req->peer_secid != 0) {
                skp = smack_from_secid(req->peer_secid);
-               ssp->smk_packet = skp->smk_known;
+               ssp->smk_packet = skp;
        } else
                ssp->smk_packet = NULL;
  }
@@@ -3506,12 -3624,11 +3624,12 @@@ static void smack_key_free(struct key *
   * an error code otherwise
   */
  static int smack_key_permission(key_ref_t key_ref,
 -                              const struct cred *cred, key_perm_t perm)
 +                              const struct cred *cred, unsigned perm)
  {
        struct key *keyp;
        struct smk_audit_info ad;
        struct smack_known *tkp = smk_of_task(cred->security);
 +      int request = 0;
  
        keyp = key_ref_to_ptr(key_ref);
        if (keyp == NULL)
        ad.a.u.key_struct.key = keyp->serial;
        ad.a.u.key_struct.key_desc = keyp->description;
  #endif
 -      return smk_access(tkp, keyp->security, MAY_READWRITE, &ad);
 +      if (perm & KEY_NEED_READ)
 +              request = MAY_READ;
 +      if (perm & (KEY_NEED_WRITE | KEY_NEED_LINK | KEY_NEED_SETATTR))
 +              request = MAY_WRITE;
 +      return smk_access(tkp, keyp->security, request, &ad);
  }
  #endif /* CONFIG_KEYS */
  
@@@ -3621,8 -3734,9 +3739,8 @@@ static int smack_audit_rule_match(u32 s
        struct smack_known *skp;
        char *rule = vrule;
  
 -      if (!rule) {
 -              audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR,
 -                        "Smack: missing rule\n");
 +      if (unlikely(!rule)) {
 +              WARN_ONCE(1, "Smack: missing rule\n");
                return -ENOENT;
        }
  
This page took 0.072798 seconds and 4 git commands to generate.