From: Sebastien Buisson Date: Tue, 12 May 2020 15:58:15 +0000 (+0900) Subject: LU-13525 sec: better struct sepol_downcall_data X-Git-Tag: 2.13.55~86 X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=commitdiff_plain;h=82b8cb5528f489e9ceb7a1899722fc4108e85739;ds=sidebyside LU-13525 sec: better struct sepol_downcall_data 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 Change-Id: I07c573c2eef64fb0c796d8af4acdc3428e0761a8 Reviewed-on: https://review.whamcloud.com/38580 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Olaf Faaland-LLNL Reviewed-by: Andreas Dilger Reviewed-by: Oleg Drokin --- diff --git a/lustre/include/uapi/linux/lustre/lustre_user.h b/lustre/include/uapi/linux/lustre/lustre_user.h index 15d62b6..62d5746 100644 --- a/lustre/include/uapi/linux/lustre/lustre_user.h +++ b/lustre/include/uapi/linux/lustre/lustre_user.h @@ -50,6 +50,7 @@ #include #include #include +#include #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 diff --git a/lustre/ptlrpc/sec_lproc.c b/lustre/ptlrpc/sec_lproc.c index 2f06143..41ef7e0 100644 --- a/lustre/ptlrpc/sec_lproc.c +++ b/lustre/ptlrpc/sec_lproc.c @@ -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); diff --git a/lustre/utils/l_getsepol.c b/lustre/utils/l_getsepol.c index 6f2d33c..effa8e10 100644 --- a/lustre/utils/l_getsepol.c +++ b/lustre/utils/l_getsepol.c @@ -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 */