This patch introduces new attribute to filesystem element
to support customizable security for mount type.
Valid mount_security are: passthrough and mapped.
Usage:
<filesystem type='mount' mount_security='passthrough'>
<source dir='/export/to/guest'/>
<target dir='mount_tag'/>
</filesystem>
Here is the detailed explanation on these security models:
Security model: mapped
----------------------
Fileserver intercepts and maps all the file object create requests.
Files on the fileserver will be created with Fileserver's user credentials
and the
client-user's credentials are stored in extended attributes.
During getattr() server extracts the client-user's credentials from extended
attributes and sends to the client.
This adds a great deal of security in the cloud environments where the
guest's(client) user space is kept completely isolated from host's user
space.
Security model : passthrough
----------------------------
In this security model, Fileserver passes down all requests to the
underlying filesystem. File system objects on the fileserver will be created
with client-user's credentials. This is done by setting setuid()/setgid()
during creation or chmod/chown after file creation. At the end of create
protocol
request, files on the fileserver will be owned by cleint-user's uid/gid.
This model mimic's current NFSv3 level of security.
Note: This patch is based on Daniel's patch to support 9pfs.
It shall be applied after applying Daniel's patch to support 9pfs.
Signed-off-by: Harsh Prateek Bora <harsh(a)linux.vnet.ibm.com>
---
docs/schemas/domain.rng | 6 ++++++
src/conf/domain_conf.c | 29 +++++++++++++++++++++++++++--
src/conf/domain_conf.h | 10 ++++++++++
src/qemu/qemu_conf.c | 9 +++++++--
4 files changed, 50 insertions(+), 4 deletions(-)
diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng
index ccb8cf3..36eec63 100644
--- a/docs/schemas/domain.rng
+++ b/docs/schemas/domain.rng
@@ -761,6 +761,12 @@
</choice>
<optional>
<ref name="address"/>
+ <attribute name="mount_security">
+ <choice>
+ <value>passthrough</value>
+ <value>mapped</value>
+ </choice>
+ </attribute>
</optional>
</element>
</define>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index e05d5d7..ece6937 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -161,6 +161,11 @@ VIR_ENUM_IMPL(virDomainFS, VIR_DOMAIN_FS_TYPE_LAST,
"file",
"template")
+VIR_ENUM_IMPL(virDomainFSMountSecurity, VIR_DOMAIN_FS_SECURITY_LAST,
+ "passthrough",
+ "mapped")
+
+
VIR_ENUM_IMPL(virDomainNet, VIR_DOMAIN_NET_TYPE_LAST,
"user",
"ethernet",
@@ -1847,6 +1852,7 @@ virDomainFSDefParseXML(xmlNodePtr node,
char *type = NULL;
char *source = NULL;
char *target = NULL;
+ char *mount_security = NULL;
if (VIR_ALLOC(def) < 0) {
virReportOOMError();
@@ -1864,6 +1870,17 @@ virDomainFSDefParseXML(xmlNodePtr node,
def->type = VIR_DOMAIN_FS_TYPE_MOUNT;
}
+ mount_security = virXMLPropString(node, "mount_security");
+ if (mount_security) {
+ if ((def->mount_security =
virDomainFSMountSecurityTypeFromString(mount_security)) < 0) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unknown mount security '%s'"),
mount_security);
+ goto error;
+ }
+ } else {
+ def->mount_security = VIR_DOMAIN_FS_SECURITY_PASSTHROUGH;
+ }
+
cur = node->children;
while (cur != NULL) {
if (cur->type == XML_ELEMENT_NODE) {
@@ -5602,6 +5619,7 @@ virDomainFSDefFormat(virBufferPtr buf,
int flags)
{
const char *type = virDomainFSTypeToString(def->type);
+ const char *mount_sec =
virDomainFSMountSecurityTypeToString(def->mount_security);
if (!type) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
@@ -5609,9 +5627,16 @@ virDomainFSDefFormat(virBufferPtr buf,
return -1;
}
+ if (!mount_sec) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unexpected mount security %d"),
def->mount_security);
+ return -1;
+ }
+
+
virBufferVSprintf(buf,
- " <filesystem type='%s'>\n",
- type);
+ " <filesystem type='%s'
mount_security='%s'>\n",
+ type, mount_sec);
if (def->src) {
switch (def->type) {
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 7195c04..3463942 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -236,10 +236,19 @@ enum virDomainFSType {
VIR_DOMAIN_FS_TYPE_LAST
};
+/* Filesystem mount security model */
+enum virDomainFSMountSecurity {
+ VIR_DOMAIN_FS_SECURITY_PASSTHROUGH,
+ VIR_DOMAIN_FS_SECURITY_MAPPED,
+
+ VIR_DOMAIN_FS_SECURITY_LAST
+};
+
typedef struct _virDomainFSDef virDomainFSDef;
typedef virDomainFSDef *virDomainFSDefPtr;
struct _virDomainFSDef {
int type;
+ int mount_security;
char *src;
char *dst;
unsigned int readonly : 1;
@@ -1167,6 +1176,7 @@ VIR_ENUM_DECL(virDomainDiskErrorPolicy)
VIR_ENUM_DECL(virDomainController)
VIR_ENUM_DECL(virDomainControllerModel)
VIR_ENUM_DECL(virDomainFS)
+VIR_ENUM_DECL(virDomainFSMountSecurity)
VIR_ENUM_DECL(virDomainNet)
VIR_ENUM_DECL(virDomainChrDevice)
VIR_ENUM_DECL(virDomainChrChannelTarget)
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 18a302a..012be27 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -2014,6 +2014,7 @@ qemuAssignDeviceAliases(virDomainDefPtr def, unsigned long long
qemuCmdFlags)
if (virAsprintf(&def->fss[i]->info.alias, "fs%d", i) < 0)
goto no_memory;
}
+
for (i = 0; i < def->nsounds ; i++) {
if (virAsprintf(&def->sounds[i]->info.alias, "sound%d", i)
< 0)
goto no_memory;
@@ -2783,11 +2784,15 @@ char *qemuBuildFSStr(virDomainFSDefPtr fs,
if (fs->type != VIR_DOMAIN_FS_TYPE_MOUNT) {
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("can only passthrough directories"));
+ _("only supports mount filesystem type"));
goto error;
}
- virBufferAddLit(&opt, "local,security_model=passthrough");
+ virBufferAddLit(&opt, "local");
+ if (fs->mount_security == VIR_DOMAIN_FS_SECURITY_PASSTHROUGH)
+ virBufferAddLit(&opt, ",mount_security=passthrough");
+ else if (fs->mount_security == VIR_DOMAIN_FS_SECURITY_MAPPED)
+ virBufferAddLit(&opt, ",mount_security=mapped");
virBufferVSprintf(&opt, ",id=%s%s", QEMU_FSDEV_HOST_PREFIX,
fs->info.alias);
virBufferVSprintf(&opt, ",path=%s", fs->src);
--
1.7.1.1