mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 18:21:39 +01:00
Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Signed-off-by: Ian Jackson <ian.jackson.citrix.com>
414 lines
9.0 KiB
C
414 lines
9.0 KiB
C
/******************************************************************************
|
|
* xc_flask.c
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation;
|
|
* version 2.1 of the License.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include "xc_private.h"
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <sys/ioctl.h>
|
|
#include <stdint.h>
|
|
|
|
#define OCON_PIRQ_STR "pirq"
|
|
#define OCON_IOPORT_STR "ioport"
|
|
#define OCON_IOMEM_STR "iomem"
|
|
#define OCON_DEVICE_STR "pcidevice"
|
|
#define INITCONTEXTLEN 256
|
|
|
|
int xc_flask_op(xc_interface *xch, flask_op_t *op)
|
|
{
|
|
int ret = -1;
|
|
DECLARE_HYPERCALL;
|
|
DECLARE_HYPERCALL_BOUNCE(op, sizeof(*op), XC_HYPERCALL_BUFFER_BOUNCE_BOTH);
|
|
|
|
if ( xc_hypercall_bounce_pre(xch, op) )
|
|
{
|
|
PERROR("Could not bounce memory for flask op hypercall");
|
|
goto out;
|
|
}
|
|
|
|
hypercall.op = __HYPERVISOR_xsm_op;
|
|
hypercall.arg[0] = HYPERCALL_BUFFER_AS_ARG(op);
|
|
|
|
if ( (ret = do_xen_hypercall(xch, &hypercall)) < 0 )
|
|
{
|
|
if ( errno == EACCES )
|
|
fprintf(stderr, "XSM operation failed!\n");
|
|
}
|
|
|
|
xc_hypercall_bounce_post(xch, op);
|
|
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
int xc_flask_load(xc_interface *xc_handle, char *buf, uint32_t size)
|
|
{
|
|
int err;
|
|
flask_op_t op;
|
|
|
|
op.cmd = FLASK_LOAD;
|
|
op.buf = buf;
|
|
op.size = size;
|
|
|
|
if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
|
|
return err;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int xc_flask_context_to_sid(xc_interface *xc_handle, char *buf, uint32_t size, uint32_t *sid)
|
|
{
|
|
int err;
|
|
flask_op_t op;
|
|
|
|
op.cmd = FLASK_CONTEXT_TO_SID;
|
|
op.buf = buf;
|
|
op.size = size;
|
|
|
|
if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
|
|
return err;
|
|
|
|
sscanf(buf, "%u", sid);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int xc_flask_sid_to_context(xc_interface *xc_handle, int sid, char *buf, uint32_t size)
|
|
{
|
|
int err;
|
|
flask_op_t op;
|
|
|
|
op.cmd = FLASK_SID_TO_CONTEXT;
|
|
op.buf = buf;
|
|
op.size = size;
|
|
|
|
snprintf(buf, size, "%u", sid);
|
|
|
|
if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
|
|
return err;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int xc_flask_getenforce(xc_interface *xc_handle)
|
|
{
|
|
int err;
|
|
flask_op_t op;
|
|
char buf[20];
|
|
int size = 20;
|
|
int mode;
|
|
|
|
op.cmd = FLASK_GETENFORCE;
|
|
op.buf = buf;
|
|
op.size = size;
|
|
|
|
if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
|
|
return err;
|
|
|
|
sscanf(buf, "%i", &mode);
|
|
|
|
return mode;
|
|
}
|
|
|
|
int xc_flask_setenforce(xc_interface *xc_handle, int mode)
|
|
{
|
|
int err;
|
|
flask_op_t op;
|
|
char buf[20];
|
|
int size = 20;
|
|
|
|
op.cmd = FLASK_SETENFORCE;
|
|
op.buf = buf;
|
|
op.size = size;
|
|
|
|
snprintf(buf, size, "%i", mode);
|
|
|
|
if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
|
|
return err;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int xc_flask_add(xc_interface *xc_handle, char *cat, char *arg, char *scontext)
|
|
{
|
|
char buf[512];
|
|
flask_op_t op;
|
|
|
|
memset(buf, 0, 512);
|
|
snprintf(buf, 512, "%s %255s %s", cat, scontext, arg);
|
|
op.cmd = FLASK_ADD_OCONTEXT;
|
|
op.buf = buf;
|
|
op.size = 512;
|
|
|
|
return xc_flask_op(xc_handle, &op);
|
|
}
|
|
|
|
int xc_flask_add_pirq(xc_interface *xc_handle, unsigned int pirq, char *scontext)
|
|
{
|
|
char arg[16];
|
|
|
|
snprintf(arg, 16, "%u", pirq);
|
|
return xc_flask_add(xc_handle, OCON_PIRQ_STR, arg, scontext);
|
|
}
|
|
|
|
int xc_flask_add_ioport(xc_interface *xc_handle, unsigned long low, unsigned long high,
|
|
char *scontext)
|
|
{
|
|
char arg[64];
|
|
|
|
snprintf(arg, 64, "%lu %lu", low, high);
|
|
return xc_flask_add(xc_handle, OCON_IOPORT_STR, arg, scontext);
|
|
}
|
|
|
|
int xc_flask_add_iomem(xc_interface *xc_handle, unsigned long low, unsigned long high,
|
|
char *scontext)
|
|
{
|
|
char arg[64];
|
|
|
|
snprintf(arg, 64, "%lu %lu", low, high);
|
|
return xc_flask_add(xc_handle, OCON_IOMEM_STR, arg, scontext);
|
|
}
|
|
|
|
int xc_flask_add_device(xc_interface *xc_handle, unsigned long device, char *scontext)
|
|
{
|
|
char arg[32];
|
|
|
|
snprintf(arg, 32, "%lu", device);
|
|
return xc_flask_add(xc_handle, OCON_DEVICE_STR, arg, scontext);
|
|
}
|
|
|
|
static int xc_flask_del(xc_interface *xc_handle, char *cat, char *arg)
|
|
{
|
|
char buf[256];
|
|
flask_op_t op;
|
|
|
|
memset(buf, 0, 256);
|
|
snprintf(buf, 256, "%s %s", cat, arg);
|
|
op.cmd = FLASK_DEL_OCONTEXT;
|
|
op.buf = buf;
|
|
op.size = 256;
|
|
|
|
return xc_flask_op(xc_handle, &op);
|
|
}
|
|
|
|
int xc_flask_del_pirq(xc_interface *xc_handle, unsigned int pirq)
|
|
{
|
|
char arg[16];
|
|
|
|
snprintf(arg, 16, "%u", pirq);
|
|
return xc_flask_del(xc_handle, OCON_PIRQ_STR, arg);
|
|
}
|
|
|
|
int xc_flask_del_ioport(xc_interface *xc_handle, unsigned long low, unsigned long high)
|
|
{
|
|
char arg[64];
|
|
|
|
snprintf(arg, 64, "%lu %lu", low, high);
|
|
return xc_flask_del(xc_handle, OCON_IOPORT_STR, arg);
|
|
}
|
|
|
|
int xc_flask_del_iomem(xc_interface *xc_handle, unsigned long low, unsigned long high)
|
|
{
|
|
char arg[64];
|
|
|
|
snprintf(arg, 64, "%lu %lu", low, high);
|
|
return xc_flask_del(xc_handle, OCON_IOMEM_STR, arg);
|
|
}
|
|
|
|
int xc_flask_del_device(xc_interface *xc_handle, unsigned long device)
|
|
{
|
|
char arg[32];
|
|
|
|
snprintf(arg, 32, "%lu", device);
|
|
return xc_flask_del(xc_handle, OCON_DEVICE_STR, arg);
|
|
}
|
|
|
|
int xc_flask_access(xc_interface *xc_handle, const char *scon, const char *tcon,
|
|
uint16_t tclass, uint32_t req,
|
|
uint32_t *allowed, uint32_t *decided,
|
|
uint32_t *auditallow, uint32_t *auditdeny,
|
|
uint32_t *seqno)
|
|
{
|
|
/* maximum number of digits in a 16-bit decimal number: */
|
|
#define MAX_SHORT_DEC_LEN 5
|
|
|
|
char *buf;
|
|
int bufLen;
|
|
int err;
|
|
flask_op_t op;
|
|
uint32_t dummy_allowed;
|
|
uint32_t dummy_decided;
|
|
uint32_t dummy_auditallow;
|
|
uint32_t dummy_auditdeny;
|
|
uint32_t dummy_seqno;
|
|
|
|
if (!allowed)
|
|
allowed = &dummy_allowed;
|
|
if (!decided)
|
|
decided = &dummy_decided;
|
|
if (!auditallow)
|
|
auditallow = &dummy_auditallow;
|
|
if (!auditdeny)
|
|
auditdeny = &dummy_auditdeny;
|
|
if (!seqno)
|
|
seqno = &dummy_seqno;
|
|
|
|
if (!scon)
|
|
return -EINVAL;
|
|
if (!tcon)
|
|
return -EINVAL;
|
|
|
|
bufLen = strlen(scon) + 1 + strlen(tcon) + 1 +
|
|
MAX_SHORT_DEC_LEN + 1 +
|
|
sizeof(req)*2 + 1;
|
|
buf = malloc(bufLen);
|
|
snprintf(buf, bufLen, "%s %s %hu %x", scon, tcon, tclass, req);
|
|
|
|
op.cmd = FLASK_ACCESS;
|
|
op.buf = buf;
|
|
op.size = strlen(buf)+1;
|
|
|
|
if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
|
|
{
|
|
free(buf);
|
|
return err;
|
|
}
|
|
|
|
if (sscanf(op.buf, "%x %x %x %x %u",
|
|
allowed, decided,
|
|
auditallow, auditdeny,
|
|
seqno) != 5) {
|
|
err = -EILSEQ;
|
|
}
|
|
|
|
err = ((*allowed & req) == req)? 0 : -EPERM;
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
int xc_flask_avc_hashstats(xc_interface *xc_handle, char *buf, int size)
|
|
{
|
|
int err;
|
|
flask_op_t op;
|
|
|
|
op.cmd = FLASK_AVC_HASHSTATS;
|
|
op.buf = buf;
|
|
op.size = size;
|
|
|
|
if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
|
|
{
|
|
free(buf);
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int xc_flask_avc_cachestats(xc_interface *xc_handle, char *buf, int size)
|
|
{
|
|
int err;
|
|
flask_op_t op;
|
|
|
|
op.cmd = FLASK_AVC_CACHESTATS;
|
|
op.buf = buf;
|
|
op.size = size;
|
|
|
|
if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
|
|
{
|
|
free(buf);
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int xc_flask_policyvers(xc_interface *xc_handle, char *buf, int size)
|
|
{
|
|
int err;
|
|
flask_op_t op;
|
|
|
|
op.cmd = FLASK_POLICYVERS;
|
|
op.buf = buf;
|
|
op.size = size;
|
|
|
|
if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
|
|
{
|
|
free(buf);
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int xc_flask_getavc_threshold(xc_interface *xc_handle)
|
|
{
|
|
int err;
|
|
flask_op_t op;
|
|
char buf[20];
|
|
int size = 20;
|
|
int threshold;
|
|
|
|
op.cmd = FLASK_GETAVC_THRESHOLD;
|
|
op.buf = buf;
|
|
op.size = size;
|
|
|
|
if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
|
|
return err;
|
|
|
|
sscanf(buf, "%i", &threshold);
|
|
|
|
return threshold;
|
|
}
|
|
|
|
int xc_flask_setavc_threshold(xc_interface *xc_handle, int threshold)
|
|
{
|
|
int err;
|
|
flask_op_t op;
|
|
char buf[20];
|
|
int size = 20;
|
|
|
|
op.cmd = FLASK_SETAVC_THRESHOLD;
|
|
op.buf = buf;
|
|
op.size = size;
|
|
|
|
snprintf(buf, size, "%i", threshold);
|
|
|
|
if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
|
|
return err;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Local variables:
|
|
* mode: C
|
|
* c-set-style: "BSD"
|
|
* c-basic-offset: 4
|
|
* tab-width: 4
|
|
* indent-tabs-mode: nil
|
|
* End:
|
|
*/
|