OSDN Git Service

Merge tag 'selinux-pr-20190305' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 7 Mar 2019 20:12:45 +0000 (12:12 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 7 Mar 2019 20:12:45 +0000 (12:12 -0800)
Pull SELinux updates from Paul Moore:
 "Nine SELinux patches for v5.1, all bug fixes.

  As far as I'm concerned, nothing really jumps out as risky or special
  to me, but each commit has a decent description so you can judge for
  yourself. As usual, everything passes the selinux-testsuite; please
  merge for v5.1"

* tag 'selinux-pr-20190305' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux:
  selinux: fix avc audit messages
  selinux: replace BUG_ONs with WARN_ONs in avc.c
  selinux: log invalid contexts in AVCs
  selinux: replace some BUG_ON()s with a WARN_ON()
  selinux: inline some AVC functions used only once
  selinux: do not override context on context mounts
  selinux: never allow relabeling on context mounts
  selinux: stop passing MAY_NOT_BLOCK to the AVC upon follow_link
  selinux: avoid silent denials in permissive mode under RCU walk

security/selinux/avc.c
security/selinux/hooks.c
security/selinux/include/avc.h
security/selinux/include/security.h
security/selinux/ss/services.c

index 635e5c1..8346a4f 100644 (file)
@@ -130,75 +130,6 @@ static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass)
 }
 
 /**
- * avc_dump_av - Display an access vector in human-readable form.
- * @tclass: target security class
- * @av: access vector
- */
-static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
-{
-       const char **perms;
-       int i, perm;
-
-       if (av == 0) {
-               audit_log_format(ab, " null");
-               return;
-       }
-
-       BUG_ON(!tclass || tclass >= ARRAY_SIZE(secclass_map));
-       perms = secclass_map[tclass-1].perms;
-
-       audit_log_format(ab, " {");
-       i = 0;
-       perm = 1;
-       while (i < (sizeof(av) * 8)) {
-               if ((perm & av) && perms[i]) {
-                       audit_log_format(ab, " %s", perms[i]);
-                       av &= ~perm;
-               }
-               i++;
-               perm <<= 1;
-       }
-
-       if (av)
-               audit_log_format(ab, " 0x%x", av);
-
-       audit_log_format(ab, " }");
-}
-
-/**
- * avc_dump_query - Display a SID pair and a class in human-readable form.
- * @ssid: source security identifier
- * @tsid: target security identifier
- * @tclass: target security class
- */
-static void avc_dump_query(struct audit_buffer *ab, struct selinux_state *state,
-                          u32 ssid, u32 tsid, u16 tclass)
-{
-       int rc;
-       char *scontext;
-       u32 scontext_len;
-
-       rc = security_sid_to_context(state, ssid, &scontext, &scontext_len);
-       if (rc)
-               audit_log_format(ab, "ssid=%d", ssid);
-       else {
-               audit_log_format(ab, "scontext=%s", scontext);
-               kfree(scontext);
-       }
-
-       rc = security_sid_to_context(state, tsid, &scontext, &scontext_len);
-       if (rc)
-               audit_log_format(ab, " tsid=%d", tsid);
-       else {
-               audit_log_format(ab, " tcontext=%s", scontext);
-               kfree(scontext);
-       }
-
-       BUG_ON(!tclass || tclass >= ARRAY_SIZE(secclass_map));
-       audit_log_format(ab, " tclass=%s", secclass_map[tclass-1].name);
-}
-
-/**
  * avc_init - Initialize the AVC.
  *
  * Initialize the access vector cache.
@@ -735,11 +666,36 @@ out:
 static void avc_audit_pre_callback(struct audit_buffer *ab, void *a)
 {
        struct common_audit_data *ad = a;
-       audit_log_format(ab, "avc:  %s ",
-                        ad->selinux_audit_data->denied ? "denied" : "granted");
-       avc_dump_av(ab, ad->selinux_audit_data->tclass,
-                       ad->selinux_audit_data->audited);
-       audit_log_format(ab, " for ");
+       struct selinux_audit_data *sad = ad->selinux_audit_data;
+       u32 av = sad->audited;
+       const char **perms;
+       int i, perm;
+
+       audit_log_format(ab, "avc:  %s ", sad->denied ? "denied" : "granted");
+
+       if (av == 0) {
+               audit_log_format(ab, " null");
+               return;
+       }
+
+       perms = secclass_map[sad->tclass-1].perms;
+
+       audit_log_format(ab, " {");
+       i = 0;
+       perm = 1;
+       while (i < (sizeof(av) * 8)) {
+               if ((perm & av) && perms[i]) {
+                       audit_log_format(ab, " %s", perms[i]);
+                       av &= ~perm;
+               }
+               i++;
+               perm <<= 1;
+       }
+
+       if (av)
+               audit_log_format(ab, " 0x%x", av);
+
+       audit_log_format(ab, " } for ");
 }
 
 /**
@@ -751,14 +707,47 @@ static void avc_audit_pre_callback(struct audit_buffer *ab, void *a)
 static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
 {
        struct common_audit_data *ad = a;
-       audit_log_format(ab, " ");
-       avc_dump_query(ab, ad->selinux_audit_data->state,
-                      ad->selinux_audit_data->ssid,
-                      ad->selinux_audit_data->tsid,
-                      ad->selinux_audit_data->tclass);
-       if (ad->selinux_audit_data->denied) {
-               audit_log_format(ab, " permissive=%u",
-                                ad->selinux_audit_data->result ? 0 : 1);
+       struct selinux_audit_data *sad = ad->selinux_audit_data;
+       char *scontext;
+       u32 scontext_len;
+       int rc;
+
+       rc = security_sid_to_context(sad->state, sad->ssid, &scontext,
+                                    &scontext_len);
+       if (rc)
+               audit_log_format(ab, " ssid=%d", sad->ssid);
+       else {
+               audit_log_format(ab, " scontext=%s", scontext);
+               kfree(scontext);
+       }
+
+       rc = security_sid_to_context(sad->state, sad->tsid, &scontext,
+                                    &scontext_len);
+       if (rc)
+               audit_log_format(ab, " tsid=%d", sad->tsid);
+       else {
+               audit_log_format(ab, " tcontext=%s", scontext);
+               kfree(scontext);
+       }
+
+       audit_log_format(ab, " tclass=%s", secclass_map[sad->tclass-1].name);
+
+       if (sad->denied)
+               audit_log_format(ab, " permissive=%u", sad->result ? 0 : 1);
+
+       /* in case of invalid context report also the actual context string */
+       rc = security_sid_to_context_inval(sad->state, sad->ssid, &scontext,
+                                          &scontext_len);
+       if (!rc && scontext) {
+               audit_log_format(ab, " srawcon=%s", scontext);
+               kfree(scontext);
+       }
+
+       rc = security_sid_to_context_inval(sad->state, sad->tsid, &scontext,
+                                          &scontext_len);
+       if (!rc && scontext) {
+               audit_log_format(ab, " trawcon=%s", scontext);
+               kfree(scontext);
        }
 }
 
@@ -772,6 +761,9 @@ noinline int slow_avc_audit(struct selinux_state *state,
        struct common_audit_data stack_data;
        struct selinux_audit_data sad;
 
+       if (WARN_ON(!tclass || tclass >= ARRAY_SIZE(secclass_map)))
+               return -EINVAL;
+
        if (!a) {
                a = &stack_data;
                a->type = LSM_AUDIT_DATA_NONE;
@@ -838,6 +830,7 @@ out:
  * @ssid,@tsid,@tclass : identifier of an AVC entry
  * @seqno : sequence number when decision was made
  * @xpd: extended_perms_decision to be added to the node
+ * @flags: the AVC_* flags, e.g. AVC_NONBLOCKING, AVC_EXTENDED_PERMS, or 0.
  *
  * if a valid AVC entry doesn't exist,this function returns -ENOENT.
  * if kmalloc() called internal returns NULL, this function returns -ENOMEM.
@@ -856,6 +849,22 @@ static int avc_update_node(struct selinux_avc *avc,
        struct hlist_head *head;
        spinlock_t *lock;
 
+       /*
+        * If we are in a non-blocking code path, e.g. VFS RCU walk,
+        * then we must not add permissions to a cache entry
+        * because we cannot safely audit the denial.  Otherwise,
+        * during the subsequent blocking retry (e.g. VFS ref walk), we
+        * will find the permissions already granted in the cache entry
+        * and won't audit anything at all, leading to silent denials in
+        * permissive mode that only appear when in enforcing mode.
+        *
+        * See the corresponding handling in slow_avc_audit(), and the
+        * logic in selinux_inode_permission for the MAY_NOT_BLOCK flag,
+        * which is transliterated into AVC_NONBLOCKING.
+        */
+       if (flags & AVC_NONBLOCKING)
+               return 0;
+
        node = avc_alloc_node(avc);
        if (!node) {
                rc = -ENOMEM;
@@ -1050,7 +1059,8 @@ int avc_has_extended_perms(struct selinux_state *state,
        int rc = 0, rc2;
 
        xp_node = &local_xp_node;
-       BUG_ON(!requested);
+       if (WARN_ON(!requested))
+               return -EACCES;
 
        rcu_read_lock();
 
@@ -1115,7 +1125,7 @@ decision:
  * @tsid: target security identifier
  * @tclass: target security class
  * @requested: requested permissions, interpreted based on @tclass
- * @flags:  AVC_STRICT or 0
+ * @flags:  AVC_STRICT, AVC_NONBLOCKING, or 0
  * @avd: access vector decisions
  *
  * Check the AVC to determine whether the @requested permissions are granted
@@ -1140,7 +1150,8 @@ inline int avc_has_perm_noaudit(struct selinux_state *state,
        int rc = 0;
        u32 denied;
 
-       BUG_ON(!requested);
+       if (WARN_ON(!requested))
+               return -EACCES;
 
        rcu_read_lock();
 
@@ -1191,24 +1202,6 @@ int avc_has_perm(struct selinux_state *state, u32 ssid, u32 tsid, u16 tclass,
        return rc;
 }
 
-int avc_has_perm_flags(struct selinux_state *state,
-                      u32 ssid, u32 tsid, u16 tclass, u32 requested,
-                      struct common_audit_data *auditdata,
-                      int flags)
-{
-       struct av_decision avd;
-       int rc, rc2;
-
-       rc = avc_has_perm_noaudit(state, ssid, tsid, tclass, requested, 0,
-                                 &avd);
-
-       rc2 = avc_audit(state, ssid, tsid, tclass, requested, &avd, rc,
-                       auditdata, flags);
-       if (rc2)
-               return rc2;
-       return rc;
-}
-
 u32 avc_policy_seqno(struct selinux_state *state)
 {
        return state->avc->avc_cache.latest_notif;
index 5d92167..2f82a54 100644 (file)
@@ -490,16 +490,10 @@ static int may_context_mount_inode_relabel(u32 sid,
        return rc;
 }
 
-static int selinux_is_sblabel_mnt(struct super_block *sb)
+static int selinux_is_genfs_special_handling(struct super_block *sb)
 {
-       struct superblock_security_struct *sbsec = sb->s_security;
-
-       return sbsec->behavior == SECURITY_FS_USE_XATTR ||
-               sbsec->behavior == SECURITY_FS_USE_TRANS ||
-               sbsec->behavior == SECURITY_FS_USE_TASK ||
-               sbsec->behavior == SECURITY_FS_USE_NATIVE ||
-               /* Special handling. Genfs but also in-core setxattr handler */
-               !strcmp(sb->s_type->name, "sysfs") ||
+       /* Special handling. Genfs but also in-core setxattr handler */
+       return  !strcmp(sb->s_type->name, "sysfs") ||
                !strcmp(sb->s_type->name, "pstore") ||
                !strcmp(sb->s_type->name, "debugfs") ||
                !strcmp(sb->s_type->name, "tracefs") ||
@@ -509,6 +503,34 @@ static int selinux_is_sblabel_mnt(struct super_block *sb)
                  !strcmp(sb->s_type->name, "cgroup2")));
 }
 
+static int selinux_is_sblabel_mnt(struct super_block *sb)
+{
+       struct superblock_security_struct *sbsec = sb->s_security;
+
+       /*
+        * IMPORTANT: Double-check logic in this function when adding a new
+        * SECURITY_FS_USE_* definition!
+        */
+       BUILD_BUG_ON(SECURITY_FS_USE_MAX != 7);
+
+       switch (sbsec->behavior) {
+       case SECURITY_FS_USE_XATTR:
+       case SECURITY_FS_USE_TRANS:
+       case SECURITY_FS_USE_TASK:
+       case SECURITY_FS_USE_NATIVE:
+               return 1;
+
+       case SECURITY_FS_USE_GENFS:
+               return selinux_is_genfs_special_handling(sb);
+
+       /* Never allow relabeling on context mounts */
+       case SECURITY_FS_USE_MNTPOINT:
+       case SECURITY_FS_USE_NONE:
+       default:
+               return 0;
+       }
+}
+
 static int sb_finish_set_opts(struct super_block *sb)
 {
        struct superblock_security_struct *sbsec = sb->s_security;
@@ -2881,9 +2903,8 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode,
        if (IS_ERR(isec))
                return PTR_ERR(isec);
 
-       return avc_has_perm_flags(&selinux_state,
-                                 sid, isec->sid, isec->sclass, FILE__READ, &ad,
-                                 rcu ? MAY_NOT_BLOCK : 0);
+       return avc_has_perm(&selinux_state,
+                           sid, isec->sid, isec->sclass, FILE__READ, &ad);
 }
 
 static noinline int audit_inode_permission(struct inode *inode,
@@ -2938,7 +2959,9 @@ static int selinux_inode_permission(struct inode *inode, int mask)
                return PTR_ERR(isec);
 
        rc = avc_has_perm_noaudit(&selinux_state,
-                                 sid, isec->sid, isec->sclass, perms, 0, &avd);
+                                 sid, isec->sid, isec->sclass, perms,
+                                 (flags & MAY_NOT_BLOCK) ? AVC_NONBLOCKING : 0,
+                                 &avd);
        audited = avc_audit_required(perms, &avd, rc,
                                     from_access ? FILE__AUDIT_ACCESS : 0,
                                     &denied);
@@ -3197,12 +3220,16 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
                                     const void *value, size_t size, int flags)
 {
        struct inode_security_struct *isec = inode_security_novalidate(inode);
+       struct superblock_security_struct *sbsec = inode->i_sb->s_security;
        u32 newsid;
        int rc;
 
        if (strcmp(name, XATTR_SELINUX_SUFFIX))
                return -EOPNOTSUPP;
 
+       if (!(sbsec->flags & SBLABEL_MNT))
+               return -EOPNOTSUPP;
+
        if (!value || !size)
                return -EACCES;
 
@@ -6236,7 +6263,10 @@ static void selinux_inode_invalidate_secctx(struct inode *inode)
  */
 static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
 {
-       return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0);
+       int rc = selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX,
+                                          ctx, ctxlen, 0);
+       /* Do not return error when suppressing label (SBLABEL_MNT not set). */
+       return rc == -EOPNOTSUPP ? 0 : rc;
 }
 
 /*
index ef899bc..7be0e1e 100644 (file)
@@ -142,6 +142,7 @@ static inline int avc_audit(struct selinux_state *state,
 
 #define AVC_STRICT 1 /* Ignore permissive mode. */
 #define AVC_EXTENDED_PERMS 2   /* update extended permissions */
+#define AVC_NONBLOCKING    4   /* non blocking */
 int avc_has_perm_noaudit(struct selinux_state *state,
                         u32 ssid, u32 tsid,
                         u16 tclass, u32 requested,
@@ -152,11 +153,6 @@ int avc_has_perm(struct selinux_state *state,
                 u32 ssid, u32 tsid,
                 u16 tclass, u32 requested,
                 struct common_audit_data *auditdata);
-int avc_has_perm_flags(struct selinux_state *state,
-                      u32 ssid, u32 tsid,
-                      u16 tclass, u32 requested,
-                      struct common_audit_data *auditdata,
-                      int flags);
 
 int avc_has_extended_perms(struct selinux_state *state,
                           u32 ssid, u32 tsid, u16 tclass, u32 requested,
index ba8eedf..f68fb25 100644 (file)
@@ -255,6 +255,9 @@ int security_sid_to_context(struct selinux_state *state, u32 sid,
 int security_sid_to_context_force(struct selinux_state *state,
                                  u32 sid, char **scontext, u32 *scontext_len);
 
+int security_sid_to_context_inval(struct selinux_state *state,
+                                 u32 sid, char **scontext, u32 *scontext_len);
+
 int security_context_to_sid(struct selinux_state *state,
                            const char *scontext, u32 scontext_len,
                            u32 *out_sid, gfp_t gfp);
index d6e7b48..a0a2aa9 100644 (file)
@@ -1280,7 +1280,8 @@ const char *security_get_initial_sid_context(u32 sid)
 
 static int security_sid_to_context_core(struct selinux_state *state,
                                        u32 sid, char **scontext,
-                                       u32 *scontext_len, int force)
+                                       u32 *scontext_len, int force,
+                                       int only_invalid)
 {
        struct policydb *policydb;
        struct sidtab *sidtab;
@@ -1325,8 +1326,14 @@ static int security_sid_to_context_core(struct selinux_state *state,
                rc = -EINVAL;
                goto out_unlock;
        }
-       rc = context_struct_to_string(policydb, context, scontext,
-                                     scontext_len);
+       if (only_invalid && !context->len) {
+               scontext = NULL;
+               scontext_len = 0;
+               rc = 0;
+       } else {
+               rc = context_struct_to_string(policydb, context, scontext,
+                                             scontext_len);
+       }
 out_unlock:
        read_unlock(&state->ss->policy_rwlock);
 out:
@@ -1348,14 +1355,34 @@ int security_sid_to_context(struct selinux_state *state,
                            u32 sid, char **scontext, u32 *scontext_len)
 {
        return security_sid_to_context_core(state, sid, scontext,
-                                           scontext_len, 0);
+                                           scontext_len, 0, 0);
 }
 
 int security_sid_to_context_force(struct selinux_state *state, u32 sid,
                                  char **scontext, u32 *scontext_len)
 {
        return security_sid_to_context_core(state, sid, scontext,
-                                           scontext_len, 1);
+                                           scontext_len, 1, 0);
+}
+
+/**
+ * security_sid_to_context_inval - Obtain a context for a given SID if it
+ *                                 is invalid.
+ * @sid: security identifier, SID
+ * @scontext: security context
+ * @scontext_len: length in bytes
+ *
+ * Write the string representation of the context associated with @sid
+ * into a dynamically allocated string of the correct size, but only if the
+ * context is invalid in the current policy.  Set @scontext to point to
+ * this string (or NULL if the context is valid) and set @scontext_len to
+ * the length of the string (or 0 if the context is valid).
+ */
+int security_sid_to_context_inval(struct selinux_state *state, u32 sid,
+                                 char **scontext, u32 *scontext_len)
+{
+       return security_sid_to_context_core(state, sid, scontext,
+                                           scontext_len, 1, 1);
 }
 
 /*