Index: sys/dev/veriexec/veriexec_ioctl.h =================================================================== --- sys/dev/veriexec/veriexec_ioctl.h +++ sys/dev/veriexec/veriexec_ioctl.h @@ -46,6 +46,11 @@ unsigned char fingerprint[MAXFINGERPRINTLEN]; }; +struct verified_exec_label_params { + struct verified_exec_params params; + char label[MAXLABELLEN]; +}; + #define VERIEXEC_LOAD _IOW('S', 0x1, struct verified_exec_params) #define VERIEXEC_ACTIVE _IO('S', 0x2) /* start checking */ #define VERIEXEC_ENFORCE _IO('S', 0x3) /* fail exec */ @@ -55,6 +60,7 @@ #define VERIEXEC_GETSTATE _IOR('S', 0x7, int) /* get state */ #define VERIEXEC_SIGNED_LOAD _IOW('S', 0x8, struct verified_exec_params) #define VERIEXEC_GETVERSION _IOR('S', 0x9, int) /* get version */ +#define VERIEXEC_LABEL_LOAD _IOW('S', 0xa, struct verified_exec_label_params) #define _PATH_DEV_VERIEXEC _PATH_DEV "veriexec" Index: sys/dev/veriexec/verified_exec.c =================================================================== --- sys/dev/veriexec/verified_exec.c +++ sys/dev/veriexec/verified_exec.c @@ -68,6 +68,7 @@ { struct nameidata nid; struct vattr vattr; + struct verified_exec_label_params *lparams; struct verified_exec_params *params; int error = 0; @@ -102,7 +103,12 @@ if (error) return (error); - params = (struct verified_exec_params *)data; + lparams = (struct verified_exec_label_params *)data; + if (cmd == VERIEXEC_LABEL_LOAD) + params = &lparams->params; + else + params = (struct verified_exec_params *)data; + switch (cmd) { case VERIEXEC_ACTIVE: mtx_lock(&ve_mutex); @@ -158,6 +164,7 @@ return (EPERM); /* no updates when secure */ /* FALLTHROUGH */ + case VERIEXEC_LABEL_LOAD: case VERIEXEC_SIGNED_LOAD: /* * If we use a loader that will only use a @@ -176,8 +183,9 @@ if (mac_veriexec_in_state(VERIEXEC_STATE_LOCKED)) error = EPERM; else { + size_t labellen = 0; int flags = FREAD; - int override = (cmd == VERIEXEC_SIGNED_LOAD); + int override = (cmd != VERIEXEC_LOAD); /* * Get the attributes for the file name passed @@ -221,13 +229,18 @@ FINGERPRINT_INVALID); VOP_UNLOCK(nid.ni_vp, 0); (void) vn_close(nid.ni_vp, FREAD, td->td_ucred, td); + if (params->flags & VERIEXEC_LABEL) + labellen = strnlen(lparams->label, + sizeof(lparams->label) - 1) + 1; mtx_lock(&ve_mutex); error = mac_veriexec_metadata_add_file( ((params->flags & VERIEXEC_FILE) != 0), vattr.va_fsid, vattr.va_fileid, vattr.va_gen, - params->fingerprint, params->flags, - params->fp_type, override); + params->fingerprint, + (params->flags & VERIEXEC_LABEL) ? + lparams->label : NULL, labellen, + params->flags, params->fp_type, override); mac_veriexec_set_state(VERIEXEC_STATE_LOADED); mtx_unlock(&ve_mutex); Index: sys/security/mac_veriexec/mac_veriexec.h =================================================================== --- sys/security/mac_veriexec/mac_veriexec.h +++ sys/security/mac_veriexec/mac_veriexec.h @@ -1,7 +1,7 @@ /* * $FreeBSD$ * - * Copyright (c) 2011, 2012, 2013, 2015, 2016, Juniper Networks, Inc. + * Copyright (c) 2011, 2012, 2013, 2015, 2016, 2019, Juniper Networks, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -49,6 +49,7 @@ * Enough room for the largest signature... */ #define MAXFINGERPRINTLEN 64 /* enough room for largest signature */ +#define MAXLABELLEN 128 /* * Types of veriexec inodes we can have @@ -57,8 +58,8 @@ #define VERIEXEC_FILE (1<<1) /* Fingerprint of a plain file */ #define VERIEXEC_NOTRACE (1<<2) /**< PTRACE not allowed */ #define VERIEXEC_TRUSTED (1<<3) /**< Safe to write /dev/mem */ -/* XXX these are currently unimplemented */ #define VERIEXEC_NOFIPS (1<<4) /**< Not allowed in FIPS mode */ +#define VERIEXEC_LABEL (1<<5) /**< We have a label */ #define VERIEXEC_STATE_INACTIVE 0 /**< Ignore */ #define VERIEXEC_STATE_LOADED (1<<0) /**< Sigs have been loaded */ @@ -71,7 +72,7 @@ /** * Version of the MAC/veriexec module */ -#define MAC_VERIEXEC_VERSION 1 +#define MAC_VERIEXEC_VERSION 2 /* Valid states for the fingerprint flag - if signed exec is being used */ typedef enum fingerprint_status { @@ -152,7 +153,8 @@ */ int mac_veriexec_metadata_add_file(int file_dev, dev_t fsid, long fileid, unsigned long gen, unsigned char fingerprint[MAXFINGERPRINTLEN], - int flags, const char *fp_type, int override); + char *label, size_t labellen, int flags, const char *fp_type, + int override); int mac_veriexec_metadata_has_file(dev_t fsid, long fileid, unsigned long gen); int mac_veriexec_proc_is_trusted(struct ucred *cred, struct proc *p); Index: sys/security/mac_veriexec/mac_veriexec_internal.h =================================================================== --- sys/security/mac_veriexec/mac_veriexec_internal.h +++ sys/security/mac_veriexec/mac_veriexec_internal.h @@ -1,7 +1,7 @@ /* * $FreeBSD$ * - * Copyright (c) 2011, 2012, 2013, 2015, 2016, Juniper Networks, Inc. + * Copyright (c) 2011, 2012, 2013, 2015, 2016, 2019, Juniper Networks, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -54,6 +54,8 @@ unsigned long gen; struct mac_veriexec_fpops *ops; unsigned char fingerprint[MAXFINGERPRINTLEN]; + char *label; + size_t labellen; LIST_ENTRY(mac_veriexec_file_info) entries; }; @@ -76,6 +78,9 @@ struct proc *p, int *flags, int check_files); int mac_veriexec_metadata_get_file_flags(dev_t fsid, long fileid, unsigned long gen, int *flags, int check_files); +struct mac_veriexec_file_info * + mac_veriexec_metadata_get_file_info(dev_t fsid, long fileid, + unsigned long gen, int *found_dev, int check_files); void mac_veriexec_metadata_init(void); void mac_veriexec_metadata_print_db(struct sbuf *sbp); int mac_veriexec_metadata_unmounted(dev_t fsid, struct thread *td); Index: sys/security/mac_veriexec/veriexec_metadata.c =================================================================== --- sys/security/mac_veriexec/veriexec_metadata.c +++ sys/security/mac_veriexec/veriexec_metadata.c @@ -1,7 +1,7 @@ /* * $FreeBSD$ * - * Copyright (c) 2011, 2012, 2013, 2015, 2016, Juniper Networks, Inc. + * Copyright (c) 2011, 2012, 2013, 2015, 2016, 2019, Juniper Networks, Inc. * All rights reserved. * * Originally derived from: @@ -138,6 +138,8 @@ break; /* we need to garbage collect */ LIST_REMOVE(ip, entries); + if (ip->label) + free(ip->label, M_VERIEXEC); free(ip, M_VERIEXEC); } } @@ -152,48 +154,6 @@ /** * @internal - * @brief Search the meta-data store for information on the specified file. - * - * @param fsid file system identifier to look for - * @param fileid file to look for - * @param gen generation of file - * @param found_dev indicator that an entry for the file system was found - * @param check_files if 1, check the files list first, otherwise check the - * exectuables list first - * - * @return A pointer to the meta-data inforation if meta-data exists for - * the specified file identifier, otherwise @c NULL - */ -static struct mac_veriexec_file_info * -find_veriexec_file(dev_t fsid, long fileid, unsigned long gen, int *found_dev, - int check_files) -{ - struct veriexec_devhead *search[3]; - struct mac_veriexec_file_info *ip; - int x; - - /* Determine the order of the lists to search */ - if (check_files) { - search[0] = &veriexec_file_dev_head; - search[1] = &veriexec_dev_head; - } else { - search[0] = &veriexec_dev_head; - search[1] = &veriexec_file_dev_head; - } - search[2] = NULL; - - VERIEXEC_DEBUG(3, ("%s: searching for dev %ju, file %lu\n", - __func__, (uintmax_t)fsid, fileid)); - - /* Search for the specified file */ - for (ip = NULL, x = 0; ip == NULL && search[x]; x++) - ip = get_veriexec_file(search[x], fsid, fileid, gen, found_dev); - - return (ip); -} - -/** - * @internal * @brief Display the fingerprint for each entry in the device list * * @param sbp sbuf to write output to @@ -270,7 +230,7 @@ mac_veriexec_metadata_has_file(dev_t fsid, long fileid, unsigned long gen) { - return (find_veriexec_file(fsid, fileid, gen, NULL, + return (mac_veriexec_metadata_get_file_info(fsid, fileid, gen, NULL, VERIEXEC_FILES_FIRST) != NULL); } @@ -312,6 +272,8 @@ for (ip = LIST_FIRST(&(lp->file_head)); ip != NULL; ip = nip) { nip = LIST_NEXT(ip, entries); LIST_REMOVE(ip, entries); + if (ip->label) + free(ip->label, M_VERIEXEC); free(ip, M_VERIEXEC); } @@ -393,6 +355,38 @@ } /** + * @internal + * @brief Allocate and initialize label record with the provided data. + * + * @param labelp Location to store the initialized label + * @param src Pointer to label string to copy + * @param srclen Length of label string to copy + * + * @return Length of resulting label + * + * @note Called with ve_mutex locked. + */ +static size_t +mac_veriexec_init_label(char **labelp, size_t labellen, char *src, + size_t srclen) +{ + char *label; + + label = *labelp; + if (labellen < srclen) { + mtx_unlock(&ve_mutex); + if (label != NULL) + free(label, M_VERIEXEC); + label = malloc(srclen, M_VERIEXEC, M_WAITOK); + mtx_lock(&ve_mutex); + labellen = srclen; + *labelp = label; + } + memcpy(label, src, srclen); + return labellen; +} + +/** * @brief When a device is unmounted, we want to toss the signatures recorded * against it. * @@ -446,7 +440,8 @@ struct mac_veriexec_file_info *ip; int found_dev; - ip = find_veriexec_file(fsid, fileid, gen, &found_dev, check_files); + ip = mac_veriexec_metadata_get_file_info(fsid, fileid, gen, &found_dev, + check_files); if (ip == NULL) return (ENOENT); @@ -518,8 +513,8 @@ status = mac_veriexec_get_fingerprint_status(vp); if (status == FINGERPRINT_INVALID || status == FINGERPRINT_NODEV) { found_dev = 0; - ip = find_veriexec_file(vap->va_fsid, vap->va_fileid, - vap->va_gen, &found_dev, check_files); + ip = mac_veriexec_metadata_get_file_info(vap->va_fsid, + vap->va_fileid, vap->va_gen, &found_dev, check_files); if (ip == NULL) { status = (found_dev) ? FINGERPRINT_NOENTRY : FINGERPRINT_NODEV; @@ -611,7 +606,7 @@ int mac_veriexec_metadata_add_file(int file_dev, dev_t fsid, long fileid, unsigned long gen, unsigned char fingerprint[MAXFINGERPRINTLEN], - int flags, const char *fp_type, int override) + char *label, size_t labellen, int flags, const char *fp_type, int override) { struct mac_veriexec_fpops *fpops; struct veriexec_dev_list *lp; @@ -619,6 +614,10 @@ struct mac_veriexec_file_info *ip; struct mac_veriexec_file_info *np = NULL; + /* Label and labellen must be set if VERIEXEC_LABEL is set */ + if ((flags & VERIEXEC_LABEL) != 0 && (label == NULL || labellen == 0)) + return (EINVAL); + /* Look up the device entry */ if (file_dev) head = &veriexec_file_dev_head; @@ -652,6 +651,15 @@ ip->ops = fpops; memcpy(ip->fingerprint, fingerprint, fpops->digest_len); + if (flags & VERIEXEC_LABEL) { + ip->labellen = mac_veriexec_init_label( + &ip->label, ip->labellen, label, + labellen); + } else if (ip->labellen > 0) { + free(ip->label, M_VERIEXEC); + ip->labellen = 0; + ip->label = NULL; + } } else if ((flags & (VERIEXEC_INDIRECT|VERIEXEC_FILE))) ip->flags |= flags; @@ -697,6 +705,13 @@ ip->fileid = fileid; ip->gen = gen; memcpy(ip->fingerprint, fingerprint, fpops->digest_len); + if (flags & VERIEXEC_LABEL) + ip->labellen = mac_veriexec_init_label(&ip->label, + ip->labellen, label, labellen); + else { + ip->label = NULL; + ip->labellen = 0; + } VERIEXEC_DEBUG(3, ("add file %ju.%lu (files=%d)\n", (uintmax_t)ip->fileid, @@ -716,6 +731,48 @@ #endif return (0); } + +/** + * @brief Search the meta-data store for information on the specified file. + * + * @param fsid file system identifier to look for + * @param fileid file to look for + * @param gen generation of file + * @param found_dev indicator that an entry for the file system was found + * @param check_files if 1, check the files list first, otherwise check the + * exectuables list first + * + * @return A pointer to the meta-data inforation if meta-data exists for + * the specified file identifier, otherwise @c NULL + */ +struct mac_veriexec_file_info * +mac_veriexec_metadata_get_file_info(dev_t fsid, long fileid, unsigned long gen, + int *found_dev, int check_files) +{ + struct veriexec_devhead *search[3]; + struct mac_veriexec_file_info *ip; + int x; + + /* Determine the order of the lists to search */ + if (check_files) { + search[0] = &veriexec_file_dev_head; + search[1] = &veriexec_dev_head; + } else { + search[0] = &veriexec_dev_head; + search[1] = &veriexec_file_dev_head; + } + search[2] = NULL; + + VERIEXEC_DEBUG(3, ("%s: searching for dev %ju, file %lu\n", + __func__, (uintmax_t)fsid, fileid)); + + /* Search for the specified file */ + for (ip = NULL, x = 0; ip == NULL && search[x]; x++) + ip = get_veriexec_file(search[x], fsid, fileid, gen, found_dev); + + return (ip); +} + /** * @brief Intialize the meta-data store