Merge tag 'selinux-pr-20190702' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 9 Jul 2019 01:59:56 +0000 (18:59 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 9 Jul 2019 01:59:56 +0000 (18:59 -0700)
Pull selinux updates from Paul Moore:
 "Like the audit pull request this is a little early due to some
  upcoming vacation plans and uncertain network access while I'm away.
  Also like the audit PR, the list of patches here is pretty minor, the
  highlights include:

   - Explicitly use __le variables to make sure "sparse" can verify
     proper byte endian handling.

   - Remove some BUG_ON()s that are no longer needed.

   - Allow zero-byte writes to the "keycreate" procfs attribute without
     requiring key:create to make it easier for userspace to reset the
     keycreate label.

   - Consistently log the "invalid_context" field as an untrusted string
     in the AUDIT_SELINUX_ERR audit records"

* tag 'selinux-pr-20190702' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux:
  selinux: format all invalid context as untrusted
  selinux: fix empty write to keycreate file
  selinux: remove some no-op BUG_ONs
  selinux: provide __le variables explicitly

1  2 
security/selinux/hooks.c
security/selinux/ss/services.c

diff --combined security/selinux/hooks.c
@@@ -1,4 -1,3 +1,4 @@@
 +// SPDX-License-Identifier: GPL-2.0-only
  /*
   *  NSA Security-Enhanced Linux (SELinux) security module
   *
   *  Copyright (C) 2007 Hitachi Software Engineering Co., Ltd.
   *                   Yuichi Nakamura <ynakam@hitachisoft.jp>
   *  Copyright (C) 2016 Mellanox Technologies
 - *
 - *    This program is free software; you can redistribute it and/or modify
 - *    it under the terms of the GNU General Public License version 2,
 - *    as published by the Free Software Foundation.
   */
  
  #include <linux/init.h>
@@@ -1049,24 -1052,15 +1049,24 @@@ static int selinux_add_mnt_opt(const ch
        if (token == Opt_error)
                return -EINVAL;
  
 -      if (token != Opt_seclabel)
 +      if (token != Opt_seclabel) {
                val = kmemdup_nul(val, len, GFP_KERNEL);
 +              if (!val) {
 +                      rc = -ENOMEM;
 +                      goto free_opt;
 +              }
 +      }
        rc = selinux_add_opt(token, val, mnt_opts);
        if (unlikely(rc)) {
                kfree(val);
 -              if (*mnt_opts) {
 -                      selinux_free_mnt_opts(*mnt_opts);
 -                      *mnt_opts = NULL;
 -              }
 +              goto free_opt;
 +      }
 +      return rc;
 +
 +free_opt:
 +      if (*mnt_opts) {
 +              selinux_free_mnt_opts(*mnt_opts);
 +              *mnt_opts = NULL;
        }
        return rc;
  }
@@@ -2622,11 -2616,10 +2622,11 @@@ static int selinux_sb_eat_lsm_opts(cha
        char *from = options;
        char *to = options;
        bool first = true;
 +      int rc;
  
        while (1) {
                int len = opt_len(from);
 -              int token, rc;
 +              int token;
                char *arg = NULL;
  
                token = match_opt_prefix(from, len, &arg);
                                                *q++ = c;
                                }
                                arg = kmemdup_nul(arg, q - arg, GFP_KERNEL);
 +                              if (!arg) {
 +                                      rc = -ENOMEM;
 +                                      goto free_opt;
 +                              }
                        }
                        rc = selinux_add_opt(token, arg, mnt_opts);
                        if (unlikely(rc)) {
                                kfree(arg);
 -                              if (*mnt_opts) {
 -                                      selinux_free_mnt_opts(*mnt_opts);
 -                                      *mnt_opts = NULL;
 -                              }
 -                              return rc;
 +                              goto free_opt;
                        }
                } else {
                        if (!first) {   // copy with preceding comma
        }
        *to = '\0';
        return 0;
 +
 +free_opt:
 +      if (*mnt_opts) {
 +              selinux_free_mnt_opts(*mnt_opts);
 +              *mnt_opts = NULL;
 +      }
 +      return rc;
  }
  
  static int selinux_sb_remount(struct super_block *sb, void *mnt_opts)
@@@ -4651,14 -4637,6 +4651,14 @@@ static int selinux_socket_connect_helpe
        err = sock_has_perm(sk, SOCKET__CONNECT);
        if (err)
                return err;
 +      if (addrlen < offsetofend(struct sockaddr, sa_family))
 +              return -EINVAL;
 +
 +      /* connect(AF_UNSPEC) has special handling, as it is a documented
 +       * way to disconnect the socket
 +       */
 +      if (address->sa_family == AF_UNSPEC)
 +              return 0;
  
        /*
         * If a TCP, DCCP or SCTP socket, check name_connect permission
                 * need to check address->sa_family as it is possible to have
                 * sk->sk_family = PF_INET6 with addr->sa_family = AF_INET.
                 */
 -              if (addrlen < offsetofend(struct sockaddr, sa_family))
 -                      return -EINVAL;
                switch (address->sa_family) {
                case AF_INET:
                        addr4 = (struct sockaddr_in *)address;
@@@ -6351,11 -6331,12 +6351,12 @@@ static int selinux_setprocattr(const ch
        } else if (!strcmp(name, "fscreate")) {
                tsec->create_sid = sid;
        } else if (!strcmp(name, "keycreate")) {
-               error = avc_has_perm(&selinux_state,
-                                    mysid, sid, SECCLASS_KEY, KEY__CREATE,
-                                    NULL);
-               if (error)
-                       goto abort_change;
+               if (sid) {
+                       error = avc_has_perm(&selinux_state, mysid, sid,
+                                            SECCLASS_KEY, KEY__CREATE, NULL);
+                       if (error)
+                               goto abort_change;
+               }
                tsec->keycreate_sid = sid;
        } else if (!strcmp(name, "sockcreate")) {
                tsec->sockcreate_sid = sid;
@@@ -1,4 -1,3 +1,4 @@@
 +// SPDX-License-Identifier: GPL-2.0-only
  /*
   * Implementation of the security services.
   *
@@@ -36,6 -35,9 +36,6 @@@
   * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
   * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC
   * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
 - *    This program is free software; you can redistribute it and/or modify
 - *    it under the terms of the GNU General Public License as published by
 - *    the Free Software Foundation, version 2.
   */
  #include <linux/kernel.h>
  #include <linux/slab.h>
@@@ -649,9 -651,7 +649,7 @@@ static void context_struct_compute_av(s
        avkey.target_class = tclass;
        avkey.specified = AVTAB_AV | AVTAB_XPERMS;
        sattr = &policydb->type_attr_map_array[scontext->type - 1];
-       BUG_ON(!sattr);
        tattr = &policydb->type_attr_map_array[tcontext->type - 1];
-       BUG_ON(!tattr);
        ebitmap_for_each_positive_bit(sattr, snode, i) {
                ebitmap_for_each_positive_bit(tattr, tnode, j) {
                        avkey.source_type = i + 1;
@@@ -1057,9 -1057,7 +1055,7 @@@ void security_compute_xperms_decision(s
        avkey.target_class = tclass;
        avkey.specified = AVTAB_XPERMS;
        sattr = &policydb->type_attr_map_array[scontext->type - 1];
-       BUG_ON(!sattr);
        tattr = &policydb->type_attr_map_array[tcontext->type - 1];
-       BUG_ON(!tattr);
        ebitmap_for_each_positive_bit(sattr, snode, i) {
                ebitmap_for_each_positive_bit(tattr, tnode, j) {
                        avkey.source_type = i + 1;
@@@ -1586,6 -1584,7 +1582,7 @@@ static int compute_sid_handle_invalid_c
        struct policydb *policydb = &state->ss->policydb;
        char *s = NULL, *t = NULL, *n = NULL;
        u32 slen, tlen, nlen;
+       struct audit_buffer *ab;
  
        if (context_struct_to_string(policydb, scontext, &s, &slen))
                goto out;
                goto out;
        if (context_struct_to_string(policydb, newcontext, &n, &nlen))
                goto out;
-       audit_log(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR,
-                 "op=security_compute_sid invalid_context=%s"
-                 " scontext=%s"
-                 " tcontext=%s"
-                 " tclass=%s",
-                 n, s, t, sym_name(policydb, SYM_CLASSES, tclass-1));
+       ab = audit_log_start(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR);
+       audit_log_format(ab,
+                        "op=security_compute_sid invalid_context=");
+       /* no need to record the NUL with untrusted strings */
+       audit_log_n_untrustedstring(ab, n, nlen - 1);
+       audit_log_format(ab, " scontext=%s tcontext=%s tclass=%s",
+                        s, t, sym_name(policydb, SYM_CLASSES, tclass-1));
+       audit_log_end(ab);
  out:
        kfree(s);
        kfree(t);
@@@ -3005,10 -3006,16 +3004,16 @@@ int security_sid_mls_copy(struct selinu
                if (rc) {
                        if (!context_struct_to_string(policydb, &newcon, &s,
                                                      &len)) {
-                               audit_log(audit_context(),
-                                         GFP_ATOMIC, AUDIT_SELINUX_ERR,
-                                         "op=security_sid_mls_copy "
-                                         "invalid_context=%s", s);
+                               struct audit_buffer *ab;
+                               ab = audit_log_start(audit_context(),
+                                                    GFP_ATOMIC,
+                                                    AUDIT_SELINUX_ERR);
+                               audit_log_format(ab,
+                                                "op=security_sid_mls_copy invalid_context=");
+                               /* don't record NUL with untrusted strings */
+                               audit_log_n_untrustedstring(ab, s, len - 1);
+                               audit_log_end(ab);
                                kfree(s);
                        }
                        goto out_unlock;