Whamcloud - gitweb
LU-13525 sec: better struct sepol_downcall_data 80/38580/7
authorSebastien Buisson <sbuisson@ddn.com>
Tue, 12 May 2020 15:58:15 +0000 (00:58 +0900)
committerOleg Drokin <green@whamcloud.com>
Sun, 28 Jun 2020 02:47:16 +0000 (02:47 +0000)
struct sepol_downcall_data is badly formed for several reasons:
- it uses a __kernel_time_t field, which can be variably sized,
  depending on the size of __kernel_long_t. Replace it with a
  fixed-size __s64 type;
- it has __u32 sdd_magic that is immediately before a potentially
  64-bit field, whereas the 64-bit fields in a structure should
  always be naturally aligned on 64-bit boundaries to avoid potential
  incompatibility in the structure definition;
- it has __u16 sdd_sepol_len which may be followed by padding.

So create a better struct sepol_downcall_data, while maintaining
compatibility with 2.12 by keeping a struct sepol_downcall_data_old.

Signed-off-by: Sebastien Buisson <sbuisson@ddn.com>
Change-Id: I07c573c2eef64fb0c796d8af4acdc3428e0761a8
Reviewed-on: https://review.whamcloud.com/38580
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Olaf Faaland-LLNL <faaland1@llnl.gov>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lustre/include/uapi/linux/lustre/lustre_user.h
lustre/ptlrpc/sec_lproc.c
lustre/utils/l_getsepol.c

index 15d62b6..62d5746 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/types.h>
 #include <linux/unistd.h>
 #include <linux/lustre/lustre_fiemap.h>
+#include <linux/lustre/lustre_ver.h>
 
 #ifndef __KERNEL__
 # define __USE_ISOC99  1
@@ -1288,7 +1289,6 @@ static inline const char *qtype_name(int qtype)
 }
 
 #define IDENTITY_DOWNCALL_MAGIC 0x6d6dd629
-#define SEPOL_DOWNCALL_MAGIC 0x8b8bb842
 
 /* permission */
 #define N_PERMS_MAX      64
@@ -1310,12 +1310,25 @@ struct identity_downcall_data {
        __u32                            idd_groups[0];
 };
 
-struct sepol_downcall_data {
+#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 16, 53, 0)
+/* old interface struct is deprecated in 2.14 */
+#define SEPOL_DOWNCALL_MAGIC_OLD 0x8b8bb842
+struct sepol_downcall_data_old {
        __u32           sdd_magic;
        __s64           sdd_sepol_mtime;
        __u16           sdd_sepol_len;
        char            sdd_sepol[0];
 };
+#endif
+
+#define SEPOL_DOWNCALL_MAGIC 0x8b8bb843
+struct sepol_downcall_data {
+       __u32           sdd_magic;
+       __u16           sdd_sepol_len;
+       __u16           sdd_padding1;
+       __s64           sdd_sepol_mtime;
+       char            sdd_sepol[0];
+};
 
 #ifdef NEED_QUOTA_DEFS
 #ifndef QIF_BLIMITS
index 2f06143..41ef7e0 100644 (file)
@@ -136,6 +136,87 @@ out:
 
 LPROC_SEQ_FOPS_RO(sptlrpc_ctxs_lprocfs);
 
+#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 16, 53, 0)
+static ssize_t sepol_seq_write_old(struct obd_device *obd,
+                                  const char __user *buffer,
+                                  size_t count)
+{
+       struct client_obd *cli = &obd->u.cli;
+       struct obd_import *imp = cli->cl_import;
+       struct sepol_downcall_data_old *param;
+       int size = sizeof(*param);
+       __u16 len;
+       int rc = 0;
+
+       if (count < size) {
+               rc = -EINVAL;
+               CERROR("%s: invalid data count = %lu, size = %d: rc = %d\n",
+                      obd->obd_name, (unsigned long) count, size, rc);
+               return rc;
+       }
+
+       OBD_ALLOC(param, size);
+       if (param == NULL)
+               return -ENOMEM;
+
+       if (copy_from_user(param, buffer, size)) {
+               rc = -EFAULT;
+               CERROR("%s: bad sepol data: rc = %d\n", obd->obd_name, rc);
+               GOTO(out, rc);
+       }
+
+       if (param->sdd_magic != SEPOL_DOWNCALL_MAGIC_OLD) {
+               rc = -EINVAL;
+               CERROR("%s: sepol downcall bad params: rc = %d\n",
+                      obd->obd_name, rc);
+               GOTO(out, rc);
+       }
+
+       if (param->sdd_sepol_len == 0 ||
+           param->sdd_sepol_len >= sizeof(imp->imp_sec->ps_sepol)) {
+               rc = -EINVAL;
+               CERROR("%s: invalid sepol data returned: rc = %d\n",
+                      obd->obd_name, rc);
+               GOTO(out, rc);
+       }
+       len = param->sdd_sepol_len; /* save sdd_sepol_len */
+       OBD_FREE(param, size);
+       size = offsetof(struct sepol_downcall_data_old,
+                       sdd_sepol[len]);
+
+       if (count < size) {
+               rc = -EINVAL;
+               CERROR("%s: invalid sepol count = %lu, size = %d: rc = %d\n",
+                      obd->obd_name, (unsigned long) count, size, rc);
+               return rc;
+       }
+
+       /* alloc again with real size */
+       OBD_ALLOC(param, size);
+       if (param == NULL)
+               return -ENOMEM;
+
+       if (copy_from_user(param, buffer, size)) {
+               rc = -EFAULT;
+               CERROR("%s: cannot copy sepol data: rc = %d\n",
+                      obd->obd_name, rc);
+               GOTO(out, rc);
+       }
+
+       spin_lock(&imp->imp_sec->ps_lock);
+       snprintf(imp->imp_sec->ps_sepol, param->sdd_sepol_len + 1, "%s",
+                param->sdd_sepol);
+       imp->imp_sec->ps_sepol_mtime = ktime_set(param->sdd_sepol_mtime, 0);
+       spin_unlock(&imp->imp_sec->ps_lock);
+
+out:
+       if (param != NULL)
+               OBD_FREE(param, size);
+
+       return rc ? rc : count;
+}
+#endif
+
 static ssize_t
 lprocfs_sptlrpc_sepol_seq_write(struct file *file, const char __user *buffer,
                                size_t count, void *data)
@@ -145,13 +226,42 @@ lprocfs_sptlrpc_sepol_seq_write(struct file *file, const char __user *buffer,
        struct client_obd *cli = &obd->u.cli;
        struct obd_import *imp = cli->cl_import;
        struct sepol_downcall_data *param;
-       int size = sizeof(*param);
+       __u32 magic;
+       int size = sizeof(magic);
+       __u16 len;
        int rc = 0;
 
        if (count < size) {
-               CERROR("%s: invalid data count = %lu, size = %d\n",
-                      obd->obd_name, (unsigned long) count, size);
-               return -EINVAL;
+               rc = -EINVAL;
+               CERROR("%s: invalid buffer count = %lu, size = %d: rc = %d\n",
+                      obd->obd_name, (unsigned long) count, size, rc);
+               return rc;
+       }
+
+       if (copy_from_user(&magic, buffer, size)) {
+               rc = -EFAULT;
+               CERROR("%s: bad sepol magic: rc = %d\n", obd->obd_name, rc);
+               return rc;
+       }
+
+       if (magic != SEPOL_DOWNCALL_MAGIC) {
+#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 16, 53, 0)
+               if (magic == SEPOL_DOWNCALL_MAGIC_OLD) {
+                       return sepol_seq_write_old(obd, buffer, count);
+               }
+#endif
+               rc = -EINVAL;
+               CERROR("%s: sepol downcall bad magic '%#08x': rc = %d\n",
+                      obd->obd_name, magic, rc);
+               return rc;
+       }
+
+       size = sizeof(*param);
+       if (count < size) {
+               rc = -EINVAL;
+               CERROR("%s: invalid data count = %lu, size = %d: rc = %d\n",
+                      obd->obd_name, (unsigned long) count, size, rc);
+               return rc;
        }
 
        OBD_ALLOC(param, size);
@@ -159,36 +269,33 @@ lprocfs_sptlrpc_sepol_seq_write(struct file *file, const char __user *buffer,
                return -ENOMEM;
 
        if (copy_from_user(param, buffer, size)) {
-               CERROR("%s: bad sepol data\n", obd->obd_name);
-               GOTO(out, rc = -EFAULT);
-       }
-
-       if (param->sdd_magic != SEPOL_DOWNCALL_MAGIC) {
-               CERROR("%s: sepol downcall bad params\n",
-                      obd->obd_name);
-               GOTO(out, rc = -EINVAL);
+               rc = -EFAULT;
+               CERROR("%s: bad sepol data: rc = %d\n", obd->obd_name, rc);
+               GOTO(out, rc);
        }
 
        if (param->sdd_sepol_len == 0 ||
            param->sdd_sepol_len >= sizeof(imp->imp_sec->ps_sepol)) {
-               CERROR("%s: invalid sepol data returned\n",
-                      obd->obd_name);
-               GOTO(out, rc = -EINVAL);
+               rc = -EINVAL;
+               CERROR("%s: invalid sepol data returned: rc = %d\n",
+                      obd->obd_name, rc);
+               GOTO(out, rc);
        }
-       rc = param->sdd_sepol_len; /* save sdd_sepol_len */
+       len = param->sdd_sepol_len; /* save sdd_sepol_len */
        OBD_FREE(param, size);
        size = offsetof(struct sepol_downcall_data,
-                       sdd_sepol[rc]);
+                       sdd_sepol[len]);
 
        /* alloc again with real size */
-       rc = 0;
        OBD_ALLOC(param, size);
        if (param == NULL)
                return -ENOMEM;
 
        if (copy_from_user(param, buffer, size)) {
-               CERROR("%s: bad sepol data\n", obd->obd_name);
-               GOTO(out, rc = -EFAULT);
+               rc = -EFAULT;
+               CERROR("%s: cannot copy sepol data: rc = %d\n",
+                      obd->obd_name, rc);
+               GOTO(out, rc);
        }
 
        spin_lock(&imp->imp_sec->ps_lock);
index 6f2d33c..effa8e1 100644 (file)
@@ -65,7 +65,7 @@ static void errlog(const char *fmt, ...)
 {
        va_list args;
 
-       openlog(progname, LOG_PERROR | LOG_PID, LOG_AUTHPRIV);
+       openlog(progname, LOG_PID, LOG_AUTHPRIV);
 
        va_start(args, fmt);
        vsyslog(LOG_NOTICE, fmt, args);
@@ -222,6 +222,94 @@ int get_opts(int argc, char *const argv[])
        return 0;
 }
 
+#define sepol_downcall(type_t, magic) ({ \
+       glob_t path; \
+       int fd, size; \
+       struct type_t *data; \
+       int idx; \
+       char *p; \
+       \
+       size = offsetof(struct type_t, \
+                       sdd_sepol[LUSTRE_NODEMAP_SEPOL_LENGTH + 1]); \
+       data = malloc(size); \
+       if (!data) { \
+               errlog("malloc sepol downcall data(%d) failed!\n", size); \
+               rc = -ENOMEM; \
+               goto out_mdval; \
+       } \
+       memset(data, 0, size); \
+       \
+       /* Put all info together and generate string \
+        * to represent SELinux policy information \
+        */ \
+       rc = snprintf(data->sdd_sepol, LUSTRE_NODEMAP_SEPOL_LENGTH + 1, \
+                     "%.1d:%s:%u:", enforce, policy_type, policyver); \
+       if (rc >= LUSTRE_NODEMAP_SEPOL_LENGTH + 1) { \
+               rc = -EMSGSIZE; \
+               goto out_data_ ## type_t ; \
+       } \
+       \
+       p = data->sdd_sepol + strlen(data->sdd_sepol); \
+       size = LUSTRE_NODEMAP_SEPOL_LENGTH + 1 - strlen(data->sdd_sepol); \
+       for (idx = 0; idx < mdsize; idx++) { \
+               rc = snprintf(p, size, "%02x", \
+                             (unsigned char)(mdval[idx])); \
+               p += 2; \
+               size -= 2; \
+               if (size < 0 || rc >= size) { \
+                       rc = -EMSGSIZE; \
+                       goto out_data_ ## type_t ; \
+               } \
+       } \
+       data->sdd_sepol_len = p - data->sdd_sepol; \
+       \
+       size = offsetof(struct type_t, \
+                       sdd_sepol[data->sdd_sepol_len]); \
+       \
+       if (!obd_type || !obd_name) { \
+               /* called without arg (presumably from command line): \
+                * print SELinux status and exit \
+                */ \
+               printf("SELinux status info: %.*s\n", \
+                      data->sdd_sepol_len, data->sdd_sepol); \
+               return 0; \
+       } \
+       \
+       data->sdd_magic = magic; \
+       data->sdd_sepol_mtime = policymtime; \
+       /* Send SELinux policy info to kernelspace */ \
+       rc = cfs_get_param_paths(&path, "%s/%s/srpc_sepol", obd_type, \
+                                obd_name); \
+       if (rc != 0) { \
+               errlog("can't get param '%s/%s/srpc_sepol': %s\n", \
+                      obd_type, obd_name, strerror(errno)); \
+               rc = -errno; \
+               goto out_data_ ## type_t ; \
+       } \
+       \
+       fd = open(path.gl_pathv[0], O_WRONLY); \
+       if (fd < 0) { \
+               errlog("can't open file '%s':%s\n", path.gl_pathv[0], \
+                       strerror(errno)); \
+               rc = -errno; \
+               goto out_params_ ## type_t ; \
+       } \
+       \
+       rc = write(fd, data, size); \
+       close(fd); \
+       if (rc != size) { \
+               errlog("partial write ret %d: %s\n", rc, strerror(errno)); \
+               rc = -errno; \
+       } else { \
+               rc = 0; \
+       } \
+       \
+       out_params_ ## type_t :     \
+       cfs_free_param_data(&path); \
+       out_data_ ## type_t :       \
+       free(data); \
+})
+
 /**
  * Calculate SELinux status information.
  * String that represents SELinux status info has the following format:
@@ -243,14 +331,9 @@ int main(int argc, char **argv)
        struct stat st;
        time_t policymtime;
        int enforce;
-       struct sepol_downcall_data *data = NULL;
-       glob_t path;
-       int fd, size;
        char *policy_type = NULL;
        unsigned char *mdval = NULL;
        unsigned int mdsize = 0;
-       char *p;
-       int idx;
        int rc;
 
        progname = basename(argv[0]);
@@ -294,98 +377,28 @@ int main(int argc, char **argv)
        }
 
        /* Now we need to calculate SELinux status information */
-       size = offsetof(struct sepol_downcall_data,
-                       sdd_sepol[LUSTRE_NODEMAP_SEPOL_LENGTH + 1]);
-       data = malloc(size);
-       if (!data) {
-               errlog("malloc sepol downcall data(%d) failed!\n", size);
-               rc = -ENOMEM;
-               goto out;
-       }
-       memset(data, 0, size);
-
        /* Get policy name */
        rc = sepol_get_policy_info(&policy_type);
        if (rc < 0)
-               goto out_data;
+               goto out;
 
        /* Read binary SELinux policy, and compute hash */
        rc = sepol_get_policy_data(pol_bin_path, &mdval, &mdsize);
        if (rc < 0)
                goto out_poltyp;
 
-       /* Put all info together and generate string
-        * to represent SELinux policy information
-        */
-       rc = snprintf(data->sdd_sepol, LUSTRE_NODEMAP_SEPOL_LENGTH + 1,
-                     "%.1d:%s:%u:", enforce, policy_type, policyver);
-       if (rc >= LUSTRE_NODEMAP_SEPOL_LENGTH + 1) {
-               rc = -EMSGSIZE;
-               goto out_mdval;
-       }
-
-       p = data->sdd_sepol + strlen(data->sdd_sepol);
-       size = LUSTRE_NODEMAP_SEPOL_LENGTH + 1 - strlen(data->sdd_sepol);
-       for (idx = 0; idx < mdsize; idx++) {
-               rc = snprintf(p, size, "%02x",
-                             (unsigned char)(mdval[idx]));
-               p += 2;
-               size -= 2;
-               if (size < 0 || rc >= size) {
-                       rc = -EMSGSIZE;
-                       goto out_mdval;
-               }
-       }
-       data->sdd_sepol_len = p - data->sdd_sepol;
-
-       size = offsetof(struct sepol_downcall_data,
-                       sdd_sepol[data->sdd_sepol_len]);
-
-       if (!obd_type || !obd_name) {
-               /* called without arg (presumably from command line):
-                * print SELinux status and exit
-                */
-               printf("SELinux status info: %.*s\n",
-                      data->sdd_sepol_len, data->sdd_sepol);
-               return 0;
-       }
-
-       data->sdd_magic = SEPOL_DOWNCALL_MAGIC;
-       data->sdd_sepol_mtime = policymtime;
-       /* Send SELinux policy info to kernelspace */
-       rc = cfs_get_param_paths(&path, "%s/%s/srpc_sepol", obd_type, obd_name);
-       if (rc != 0) {
-               errlog("can't get param '%s/%s/srpc_sepol': %s\n",
-                      obd_type, obd_name, strerror(errno));
-               rc = -errno;
-               goto out_mdval;
-       }
-
-       fd = open(path.gl_pathv[0], O_WRONLY);
-       if (fd < 0) {
-               errlog("can't open file '%s':%s\n", path.gl_pathv[0],
-                      strerror(errno));
-               rc = -errno;
-               goto out_params;
-       }
-
-       rc = write(fd, data, size);
-       close(fd);
-       if (rc != size) {
-               errlog("partial write ret %d: %s\n", rc, strerror(errno));
-               rc = -errno;
-       } else {
-               rc = 0;
-       }
+       sepol_downcall(sepol_downcall_data, SEPOL_DOWNCALL_MAGIC);
+#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 16, 53, 0)
+       if (rc == -EINVAL)
+               /* try with old magic */
+               sepol_downcall(sepol_downcall_data_old,
+                              SEPOL_DOWNCALL_MAGIC_OLD);
+#endif
 
-out_params:
-       cfs_free_param_data(&path);
 out_mdval:
        free(mdval);
 out_poltyp:
        free(policy_type);
-out_data:
-       free(data);
 out:
        if (isatty(STDIN_FILENO))
                /* we are called from the command line */