From: Matthew Dillon Date: Sat, 16 May 2015 20:45:03 +0000 (-0700) Subject: swapon - Implement encrypted swap X-Git-Tag: v4.2.0rc~170 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/58b7380e3b94ae164042d357c09ef8b67419792a swapon - Implement encrypted swap Implement crypting of the swap device. When enabled in this manner /dev/urandom is used to generate a 256-bit random key and the base device is automatically cryptsetup and mapped, making crypted swap trivial. * Implement the 'crypt' fstab option, so swapon -a and swapoff -a work as expected for crypted swap. Again, the base device (e.g. /dev/da0s1b) should be specified. The option will automatically map it with cryptsetup and swap on the mapping. Also implement -c to crypt manual swapon/swapoff commands. If used for swapon it must also be used for swapoff. Again, specify the base device (e.g. /dev/da0s1b), not the /dev/mapper device, for both cases. * Implement the 'trim' fstab option, allow trim to be specified in the fstab instead of requiring a rc.conf option. * The trim option no longer exits with an error if the device does not support TRIM or TRIM is not enabled. --- diff --git a/sbin/swapon/swapon.8 b/sbin/swapon/swapon.8 index 040f22cd3c..a32cf64d5a 100644 --- a/sbin/swapon/swapon.8 +++ b/sbin/swapon/swapon.8 @@ -35,7 +35,7 @@ .Nm swapon , swapoff , swapctl .Nd "specify devices for paging and swapping" .Sh SYNOPSIS -.Nm swapon Fl aeiq | Ar +.Nm swapon Fl aceiq | Ar .Nm swapoff Fl aq | Ar .Nm swapctl .Op Fl AeghklmsU @@ -66,14 +66,30 @@ If the .Fl a option is used, all swap devices in .Pa /etc/fstab -will be added, unless their -.Dq noauto -option is also set. +will be added. +The following options are supported: +.Bl -tag -width indent +.It Dq noauto +The device is ignored and will not be added or removed with this option. +.It Dq crypt +Swap will be encrpted with a random key using a /dev/mapper name of +swap- , +for example 'swap-da0s1b'. +This will also load the dm_target_crypt module if necessary. +.It Dq trim +Swap will be TRIMed if the device supports it, otherwise this option +will be ignored. +.El +.Pp If the .Fl q option is used informational messages will not be written to standard output when a swap device is added. If the +.Fl c +option is used, the device will be encrypted with a random +key. +If the .Fl e option is used, the device will be trimmed if it supports trim and the trim_enabled sysctl is on. @@ -92,6 +108,14 @@ will be removed, unless their .Dq noauto option is also set. If the +.Fl c +option is used the device is mapped to the appropriate crypto device +and the crypto device is removed as well. +If this option is specified in +.Nm swapon +then it should also be specified in +.Nm swapoff . +If the .Fl q option is used informational messages will not be written to standard output when a swap device is removed. @@ -156,10 +180,14 @@ Output values in megabytes. List the devices making up system swap. .It Fl s Print a summary line for system swap. +.If Fl c +The swap is or should be crypted. .It Fl e Attempts to Trim the device if -[Aa] is used. .It Fl i Asks user confirmation when -a is used. +.It Fl q +Less noisy output. .Pp The .Ev BLOCKSIZE diff --git a/sbin/swapon/swapon.c b/sbin/swapon/swapon.c index 1ff942dabb..508a7fe4d3 100644 --- a/sbin/swapon/swapon.c +++ b/sbin/swapon/swapon.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -50,8 +51,11 @@ static void usage(void); static int swap_on_off(char *name, int doingall, int trim, int ask); +static char *docrypt(char *fs_spec, int pass); static void swaplist(int lflag, int sflag, int hflag); +static int qflag; + enum { SWAPON, SWAPOFF, SWAPCTL } orig_prog, which_prog = SWAPCTL; int @@ -61,7 +65,7 @@ main(int argc, char **argv) char *ptr; int ret; int ch; - int doall, sflag, lflag, hflag, qflag, eflag, iflag; + int doall, sflag, lflag, hflag, eflag, cflag, iflag; if ((ptr = strrchr(argv[0], '/')) == NULL) ptr = argv[0]; @@ -71,8 +75,8 @@ main(int argc, char **argv) which_prog = SWAPOFF; orig_prog = which_prog; - sflag = lflag = hflag = qflag = doall = eflag = iflag = 0; - while ((ch = getopt(argc, argv, "AadeghiklmqsU")) != -1) { + sflag = lflag = hflag = doall = eflag = cflag = iflag = 0; + while ((ch = getopt(argc, argv, "AacdeghiklmqsU")) != -1) { switch((char)ch) { case 'A': if (which_prog == SWAPCTL) { @@ -94,6 +98,9 @@ main(int argc, char **argv) else usage(); break; + case 'c': + cflag = 1; + break; case 'e': eflag = 1; break; @@ -141,33 +148,65 @@ main(int argc, char **argv) if (which_prog == SWAPON || which_prog == SWAPOFF) { if (doall) { while ((fsp = getfsent()) != NULL) { + char *fs_spec; + int dotrim = eflag; + if (strcmp(fsp->fs_type, FSTAB_SW)) continue; if (strstr(fsp->fs_mntops, "noauto")) continue; - if (swap_on_off(fsp->fs_spec, 1, eflag, iflag)) { + + if (strstr(fsp->fs_mntops, "notrim")) + dotrim = 0; + else if (strstr(fsp->fs_mntops, "trim")) + dotrim = 1; + + if (cflag || strstr(fsp->fs_mntops, "crypt")) + fs_spec = docrypt(fsp->fs_spec, 1); + else + fs_spec = strdup(fsp->fs_spec); + if (swap_on_off(fs_spec, 1, dotrim, iflag)) { ret = 1; } else { + if (cflag || + strstr(fsp->fs_mntops, "crypt")) { + docrypt(fsp->fs_spec, 2); + } if (!qflag) { - printf("%s: %sing %s as swap device\n", + printf("%s: %sing %s as swap " + "device\n", getprogname(), - which_prog == SWAPOFF ? "remov" : "add", - fsp->fs_spec); + (which_prog == SWAPOFF ? + "remov" : "add"), + fs_spec); } } + free(fs_spec); } } else if (*argv == NULL) { usage(); } for (; *argv; ++argv) { - if (swap_on_off(getdevpath(*argv, 0), 0, eflag, iflag)) { + char *ospec = getdevpath(*argv, 0); + char *fs_spec; + if (cflag) + fs_spec = docrypt(ospec, 1); + else + fs_spec = strdup(ospec); + if (swap_on_off(fs_spec, 0, eflag, iflag)) { ret = 1; - } else if (orig_prog == SWAPCTL) { - printf("%s: %sing %s as swap device\n", - getprogname(), - which_prog == SWAPOFF ? "remov" : "add", - *argv); + } else { + if (cflag) + docrypt(ospec, 2); + if (!qflag) { + printf("%s: %sing %s as swap device\n", + getprogname(), + (which_prog == SWAPOFF ? + "remov" : "add"), + fs_spec); + } } + free(fs_spec); } } else { if (lflag || sflag) @@ -178,6 +217,68 @@ main(int argc, char **argv) exit(ret); } +static +char * +docrypt(char *fs_spec, int pass) +{ + char *id; + char *res; + char *buf; + + if ((id = strrchr(fs_spec, '/')) == NULL) + id = fs_spec; + else + ++id; + asprintf(&id, "swap-%s", id); + asprintf(&res, "/dev/mapper/%s", id); + + switch(which_prog) { + case SWAPOFF: + if (pass != 2) + break; + asprintf(&buf, "/sbin/cryptsetup remove %s", id); + system(buf); + free(id); + break; + case SWAPON: + if (pass != 1) + break; + if (kldfind("dm_target_crypt") < 0) + kldload("dm_target_crypt"); + + asprintf(&buf, + "/sbin/cryptsetup --key-file /dev/urandom " + "--key-size 256 create %s %s", + id, fs_spec); + if (qflag == 0) + printf("%s\n", buf); + system(buf); + free(buf); + free(id); + + /* + * NOTE: Don't revert to /dev/da* on error because this could + * inadvertently add both /dev/da* and + * /dev/mapper/swap-da*. + * + * Allow the swapon operation to report failure or + * report a duplicate. + */ + break; + default: + free(res); + free(id); + res = strdup(fs_spec); + break; + } + + if (pass == 2) { + free (res); + res = NULL; + } + return res; +} + /* * TRIM the device */ @@ -261,7 +362,7 @@ swap_on_off(char *name, int doingall, int trim, int ask) return(1); } - if (which_prog == SWAPON && trim){ + if (which_prog == SWAPON && trim) { char sysctl_name[64]; int trim_enabled = 0; size_t olen = sizeof(trim_enabled); @@ -269,19 +370,22 @@ swap_on_off(char *name, int doingall, int trim, int ask) dev_name = strtok(dev_name + strlen("/dev/da"),"s"); sprintf(sysctl_name, "kern.cam.da.%s.trim_enabled", dev_name); sysctlbyname(sysctl_name, &trim_enabled, &olen, NULL, 0); - if(errno == ENOENT) { - printf("Device:%s does not support the TRIM command\n", - name); - usage(); - } - if(!trim_enabled) { - printf("Erase device option selected, but sysctl (%s) " - "is not enabled\n",sysctl_name); - usage(); + if (errno == ENOENT) { + if (qflag == 0) { + printf("TRIM not supported on %s, " + "ignoring\n", + name); + } + errno = 0; + } else if (!trim_enabled) { + if (qflag == 0) { + printf("TRIM not enabled on %s (%s), " + "ignoring\n", + name, sysctl_name); + } + } else { + trim_volume(name); } - - trim_volume(name); - } if ((which_prog == SWAPOFF ? swapoff(name) : swapon(name)) == -1) { switch(errno) {