diff options
Diffstat (limited to 'sys/geom')
-rw-r--r-- | sys/geom/eli/g_eli.c | 22 | ||||
-rw-r--r-- | sys/geom/eli/g_eli.h | 4 | ||||
-rw-r--r-- | sys/geom/eli/g_eli_ctl.c | 65 |
3 files changed, 67 insertions, 24 deletions
diff --git a/sys/geom/eli/g_eli.c b/sys/geom/eli/g_eli.c index 453b756..8844297 100644 --- a/sys/geom/eli/g_eli.c +++ b/sys/geom/eli/g_eli.c @@ -455,6 +455,10 @@ g_eli_access(struct g_provider *pp, int dr, int dw, int de) sc = gp->softc; if (dw > 0) { + if (sc->sc_flags & G_ELI_FLAG_RO) { + /* Deny write attempts. */ + return (EROFS); + } /* Someone is opening us for write, we need to remember that. */ sc->sc_flags |= G_ELI_FLAG_WOPEN; return (0); @@ -495,19 +499,19 @@ g_eli_create(struct gctl_req *req, struct g_class *mp, struct g_provider *bpp, gp->start = g_eli_start; /* * Spoiling cannot happen actually, because we keep provider open for - * writing all the time. + * writing all the time or provider is read-only. */ gp->spoiled = g_eli_orphan_spoil_assert; gp->orphan = g_eli_orphan; + gp->dumpconf = g_eli_dumpconf; /* - * If detach-on-last-close feature is not enabled, we can simply use - * g_std_access(). + * If detach-on-last-close feature is not enabled and we don't operate + * on read-only provider, we can simply use g_std_access(). */ - if (md->md_flags & G_ELI_FLAG_WO_DETACH) + if (md->md_flags & (G_ELI_FLAG_WO_DETACH | G_ELI_FLAG_RO)) gp->access = g_eli_access; else gp->access = g_std_access; - gp->dumpconf = g_eli_dumpconf; sc->sc_crypto = G_ELI_CRYPTO_SW; sc->sc_flags = md->md_flags; @@ -578,8 +582,13 @@ g_eli_create(struct gctl_req *req, struct g_class *mp, struct g_provider *bpp, * Keep provider open all the time, so we can run critical tasks, * like Master Keys deletion, without wondering if we can open * provider or not. + * We don't open provider for writing only when user requested read-only + * access. */ - error = g_access(cp, 1, 1, 1); + if (sc->sc_flags & G_ELI_FLAG_RO) + error = g_access(cp, 1, 0, 1); + else + error = g_access(cp, 1, 1, 1); if (error != 0) { if (req != NULL) { gctl_error(req, "Cannot access %s (error=%d).", @@ -997,6 +1006,7 @@ g_eli_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, ADD_FLAG(G_ELI_FLAG_AUTH, "AUTH"); ADD_FLAG(G_ELI_FLAG_WOPEN, "W-OPEN"); ADD_FLAG(G_ELI_FLAG_DESTROY, "DESTROY"); + ADD_FLAG(G_ELI_FLAG_RO, "READ-ONLY"); #undef ADD_FLAG } sbuf_printf(sb, "</Flags>\n"); diff --git a/sys/geom/eli/g_eli.h b/sys/geom/eli/g_eli.h index 82ce64f..e217c1f 100644 --- a/sys/geom/eli/g_eli.h +++ b/sys/geom/eli/g_eli.h @@ -59,6 +59,7 @@ */ #define G_ELI_VERSION 1 +/* ON DISK FLAGS. */ /* Use random, onetime keys. */ #define G_ELI_FLAG_ONETIME 0x00000001 /* Ask for the passphrase from the kernel, before mounting root. */ @@ -69,6 +70,9 @@ #define G_ELI_FLAG_RW_DETACH 0x00000008 /* Provide data authentication. */ #define G_ELI_FLAG_AUTH 0x00000010 +/* Provider is read-only, we should deny all write attempts. */ +#define G_ELI_FLAG_RO 0x00000020 +/* RUNTIME FLAGS. */ /* Provider was open for writing. */ #define G_ELI_FLAG_WOPEN 0x00010000 /* Destroy device. */ diff --git a/sys/geom/eli/g_eli_ctl.c b/sys/geom/eli/g_eli_ctl.c index a6db6c2..702f854 100644 --- a/sys/geom/eli/g_eli_ctl.c +++ b/sys/geom/eli/g_eli_ctl.c @@ -57,7 +57,7 @@ g_eli_ctl_attach(struct gctl_req *req, struct g_class *mp) struct g_provider *pp; const char *name; u_char *key, mkey[G_ELI_DATAIVKEYLEN]; - int *nargs, *detach; + int *nargs, *detach, *readonly; int keysize, error; u_int nkey; @@ -79,6 +79,12 @@ g_eli_ctl_attach(struct gctl_req *req, struct g_class *mp) return; } + readonly = gctl_get_paraml(req, "readonly", sizeof(*readonly)); + if (readonly == NULL) { + gctl_error(req, "No '%s' argument.", "readonly"); + return; + } + name = gctl_get_asciiparam(req, "arg0"); if (name == NULL) { gctl_error(req, "No 'arg%u' argument.", 0); @@ -124,8 +130,16 @@ g_eli_ctl_attach(struct gctl_req *req, struct g_class *mp) } G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name); + if (*detach && *readonly) { + bzero(&md, sizeof(md)); + gctl_error(req, "Options -d and -r are mutually exclusive.", + pp->name, error); + return; + } if (*detach) md.md_flags |= G_ELI_FLAG_WO_DETACH; + if (*readonly) + md.md_flags |= G_ELI_FLAG_RO; g_eli_create(req, mp, pp, &md, mkey, nkey); bzero(mkey, sizeof(mkey)); bzero(&md, sizeof(md)); @@ -374,6 +388,10 @@ g_eli_ctl_setkey(struct gctl_req *req, struct g_class *mp) gctl_error(req, "Provider %s is invalid.", name); return; } + if (sc->sc_flags & G_ELI_FLAG_RO) { + gctl_error(req, "Cannot change keys for read-only provider."); + return; + } cp = LIST_FIRST(&sc->sc_geom->consumer); pp = cp->provider; @@ -483,6 +501,10 @@ g_eli_ctl_delkey(struct gctl_req *req, struct g_class *mp) gctl_error(req, "Provider %s is invalid.", name); return; } + if (sc->sc_flags & G_ELI_FLAG_RO) { + gctl_error(req, "Cannot delete keys for read-only provider."); + return; + } cp = LIST_FIRST(&sc->sc_geom->consumer); pp = cp->provider; @@ -565,9 +587,7 @@ g_eli_kill_one(struct g_eli_softc *sc) { struct g_provider *pp; struct g_consumer *cp; - u_char *sector; - int err, error = 0; - u_int i; + int error = 0; g_topology_assert(); @@ -580,22 +600,31 @@ g_eli_kill_one(struct g_eli_softc *sc) cp = LIST_FIRST(&sc->sc_geom->consumer); pp = cp->provider; - sector = malloc(pp->sectorsize, M_ELI, M_WAITOK); - for (i = 0; i <= g_eli_overwrites; i++) { - if (i == g_eli_overwrites) - bzero(sector, pp->sectorsize); - else - arc4rand(sector, pp->sectorsize, 0); - err = g_write_data(cp, pp->mediasize - pp->sectorsize, sector, - pp->sectorsize); - if (err != 0) { - G_ELI_DEBUG(0, "Cannot erase metadata on %s " - "(error=%d).", pp->name, err); - if (error == 0) - error = err; + if (sc->sc_flags & G_ELI_FLAG_RO) { + G_ELI_DEBUG(0, "WARNING: Metadata won't be erased on read-only " + "provider: %s.", pp->name); + } else { + u_char *sector; + u_int i; + int err; + + sector = malloc(pp->sectorsize, M_ELI, M_WAITOK); + for (i = 0; i <= g_eli_overwrites; i++) { + if (i == g_eli_overwrites) + bzero(sector, pp->sectorsize); + else + arc4rand(sector, pp->sectorsize, 0); + err = g_write_data(cp, pp->mediasize - pp->sectorsize, + sector, pp->sectorsize); + if (err != 0) { + G_ELI_DEBUG(0, "Cannot erase metadata on %s " + "(error=%d).", pp->name, err); + if (error == 0) + error = err; + } } + free(sector, M_ELI); } - free(sector, M_ELI); if (error == 0) G_ELI_DEBUG(0, "%s has been killed.", pp->name); g_eli_destroy(sc, 1); |