Add a new ioctl for the larger params struct that includes the label.
We need to make the find_veriexec_file() function available publicly, so rename it to mac_veriexec_metadata_find_file_info() and make it non-static. Bump the version of the veriexec device interface so user space will know the labelized version of fingerprint loading is available. Approved by: sjg Obtained from: Juniper Networks, Inc. Differential Revision: https://reviews.freebsd.org/D20295
This commit is contained in:
parent
a19d3aa40b
commit
8a5976b33f
@ -46,6 +46,11 @@ struct verified_exec_params {
|
||||
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 @@ struct verified_exec_params {
|
||||
#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"
|
||||
|
||||
|
@ -68,6 +68,7 @@ verifiedexecioctl(struct cdev *dev __unused, u_long cmd, caddr_t data,
|
||||
{
|
||||
struct nameidata nid;
|
||||
struct vattr vattr;
|
||||
struct verified_exec_label_params *lparams;
|
||||
struct verified_exec_params *params;
|
||||
int error = 0;
|
||||
|
||||
@ -102,7 +103,12 @@ verifiedexecioctl(struct cdev *dev __unused, u_long cmd, caddr_t data,
|
||||
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 @@ verifiedexecioctl(struct cdev *dev __unused, u_long cmd, caddr_t data,
|
||||
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 @@ verifiedexecioctl(struct cdev *dev __unused, u_long cmd, caddr_t data,
|
||||
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 @@ verifiedexecioctl(struct cdev *dev __unused, u_long cmd, caddr_t data,
|
||||
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);
|
||||
|
@ -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_fingerprint_modevent(module_t mod, int type, void *data);
|
||||
*/
|
||||
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);
|
||||
|
@ -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 @@ struct mac_veriexec_file_info
|
||||
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 @@ int mac_veriexec_metadata_get_executable_flags(struct ucred *cred,
|
||||
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);
|
||||
|
@ -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 @@ get_veriexec_file(struct veriexec_devhead *head, dev_t fsid, long fileid,
|
||||
break;
|
||||
/* we need to garbage collect */
|
||||
LIST_REMOVE(ip, entries);
|
||||
if (ip->label)
|
||||
free(ip->label, M_VERIEXEC);
|
||||
free(ip, M_VERIEXEC);
|
||||
}
|
||||
}
|
||||
@ -150,48 +152,6 @@ get_veriexec_file(struct veriexec_devhead *head, dev_t fsid, long fileid,
|
||||
return (ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
@ -270,7 +230,7 @@ int
|
||||
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 @@ free_veriexec_dev(dev_t fsid, struct veriexec_devhead *head)
|
||||
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);
|
||||
}
|
||||
|
||||
@ -392,6 +354,38 @@ find_veriexec_dev(dev_t fsid, struct veriexec_devhead *head)
|
||||
return (lp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 @@ mac_veriexec_metadata_get_file_flags(dev_t fsid, long fileid, unsigned long gen,
|
||||
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 @@ mac_veriexec_metadata_fetch_fingerprint_status(struct vnode *vp,
|
||||
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 @@ mac_veriexec_metadata_fetch_fingerprint_status(struct vnode *vp,
|
||||
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 @@ mac_veriexec_metadata_add_file(int file_dev, dev_t fsid, long fileid,
|
||||
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 @@ mac_veriexec_metadata_add_file(int file_dev, dev_t fsid, long fileid,
|
||||
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 @@ mac_veriexec_metadata_add_file(int file_dev, dev_t fsid, long fileid,
|
||||
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,
|
||||
@ -717,6 +732,48 @@ mac_veriexec_metadata_add_file(int file_dev, dev_t fsid, long fileid,
|
||||
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
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user