bin/127918: [patch] ATA Security support for sbin/atacontrol

Daniel Roethlisberger daniel at roe.ch
Tue Oct 7 12:20:03 UTC 2008


>Number:         127918
>Category:       bin
>Synopsis:       [patch] ATA Security support for sbin/atacontrol
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Tue Oct 07 12:20:02 UTC 2008
>Closed-Date:
>Last-Modified:
>Originator:     Daniel Roethlisberger
>Release:        FreeBSD 6.3-RELEASE-p5 i386
>Organization:
>Environment:
System: FreeBSD calvin.ustdmz.roe.ch 6.3-RELEASE-p5 FreeBSD 6.3-RELEASE-p5 #0: Wed Oct 1 05:50:20 UTC 2008 root at i386-builder.daemonology.net:/usr/obj/usr/src/sys/SMP i386
>Description:
This patch adds support for the ATA Security commands to atacontrol.
It also includes trivial changes to sys/dev/ata/ata-queue.c to teach
the kernel about the ATA Security commands when printing error messages.
I've implemented the security commands using the T13 draft ATA 7 Volume 1
Revision 4b as primary reference.

Please consider this patch for inclusion into -current.

ATA Security adds commands to password protect a drive.  Normally, ATA
Security is handled by the BIOS and the security configuration is frozen
before the OS is loaded.  However, some BIOSes do not freeze the security
configuration.  In such cases, atacontrol can be used to issue security
commands to a device, for instance to unlock a device, set a password,
disable password protection, to wipe the device or just to freeze the
security configuration as part of the OS initialization process.

usage:  atacontrol security <device> <security-command>:
        atacontrol security <device>
        atacontrol security <device> freeze
        atacontrol security <device> set master
        atacontrol security <device> set user high|maximum
        atacontrol security <device> unlock master|user
        atacontrol security <device> disable master|user
        atacontrol security <device> erase master|user [enhanced]

See the patched manual page for details.
>How-To-Repeat:
>Fix:
The patch should apply to -current, but the code has been tested on
RELENG_7_1, RELENG_7_0 and RELENG_6_3 only.  You can also grab it from
http://daniel.roe.ch/code/ata/atasecurity-20081007-complete.diff

--- atasecurity-20081007-complete.diff begins here ---
diff -ruN ../HEAD/sbin/atacontrol/atacontrol.8 ./sbin/atacontrol/atacontrol.8
--- ../HEAD/sbin/atacontrol/atacontrol.8	2008-06-25 20:11:22.000000000 +0200
+++ ./sbin/atacontrol/atacontrol.8	2008-09-30 23:56:32.000000000 +0200
@@ -70,6 +70,10 @@
 .Ic cap
 .Ar device
 .Nm
+.Ic security
+.Ar device
+.Op Aq Ar security-command
+.Nm
 .Ic spindown
 .Ar device
 .Op Ar seconds
@@ -194,6 +198,76 @@
 .It Ic cap
 Show detailed info about the device on
 .Ar device .
+.It Ic security
+If no security command given, show details on the security status of the
+.Ar device .
+The following security commands are available:
+.Bl -tag -width "1234567"
+.It Ic freeze
+Freeze the security configuration of the device.
+Once frozen, no other security commands are accepted by the device.
+The device can only be unfrozen by a power cycle.
+An ATA Security compliant BIOS should freeze devices before booting the
+operating system.
+If your BIOS does not freeze the security configuration, you can freeze
+it after boot by adding an appropriate freeze command to e.g.\&
+.Pa /etc/rc.local .
+The freeze command is safe to execute on devices containing mounted
+filesystems.
+.It Ic set master
+Set the master password on the device and decrement the master password
+revision, if supported by the device.
+Setting the master password does not enable security.
+The master password serves as a fallback password to make a locked device
+usable again if the user password is lost.
+The set master command is safe to execute on devices containing
+mounted filesystems.
+.It Ic set user Bro Ic high | maximum Brc
+Set the user password and enable security.
+With security enabled, the device will be locked after power-on.
+In high security mode, either the user or the master password can
+unlock the device.
+In maximum security mode, only the user password can unlock the device.
+If the user password is lost, the master password can only be used to
+erase the device in order to make it usable again.
+The set user command is
+.Em not safe
+to execute on devices containing mounted filesystems.
+.It Ic unlock Bro Ic master | user Brc
+Unlock the device using either the master or the user password.
+Unlocking will make the device available for use by the system.
+The drive can only be unlocked by a master password if the security
+mode is high.  Unlocking does not disable security; after a reboot,
+the device will be locked again.
+The unlock command is safe to execute on devices containing mounted
+filesystems, but there is no point in doing so.
+.It Ic disable Bro Ic master | user Brc
+Disable security using either the master or the user password.
+By disabling security, the user password will be removed and
+the device will no longer be locked after power-on.  The master
+password is unaffected by the disable command.
+The disable command is safe to execute on devices containing mounted
+filesystems.
+.It Ic erase Bro Ic master | user Brc Op Ic enhanced
+Completely erase all blocks on the device.
+This will destroy all data on disk and then disable security.
+Erasing the device using the master password is the only way
+to recover a secured device in maximum security mode if the
+user password is lost.
+In normal erase mode, all addressable blocks are overwritten with zero.
+In enhanced erase mode, all blocks, including previously reallocated
+bad blocks, are overwritten with some predetermined pattern.
+Enhanced erase mode is not supported by all devices.
+Erasing a device will take a long time.
+Recent devices report the estimated erase time as part of the security
+status information.
+The erase command is
+.Em not safe
+to execute on devices containing mounted filesystems.
+.El
+.Pp
+.Em WARNING :
+The security commands can render a disk useless!
 .It Ic spindown
 Set or report timeout after which the
 .Ar device 
@@ -337,6 +411,38 @@
 .Pp
 Now a status command will show the array rebuilding.
 .Pp
+To display the security status of a disk run:
+.Pp
+.Dl "atacontrol security ad6"
+.Pp
+If the security configuration has not been frozen by the BIOS, freeze it
+to prevent further changes using:
+.Pp
+.Dl "atacontrol security ad6 freeze"
+.Pp
+To have the security configuration frozen as part of booting the system,
+add the above to
+.Pa /etc/rc.local
+or a similar facility provided by
+.Xr rc 8 .
+.Pp
+To use the ATA Security commands to completely wipe the disk,
+you can first set a user password, and then use that to erase
+the disk in enhanced mode.
+.Pp
+.Dl "atacontrol security ad6 set user"
+.Dl "atacontrol security ad6 erase user enhanced"
+.Pp
+The second command may take literally hours to complete while
+the disk is overwriting all blocks.
+Using the enhanced erase command has the advantage over a simple
+.Pp
+.Dl "dd if=/dev/zero of=/dev/ad6"
+.Pp
+in that erase will also erase blocks not directly addressable by dd due
+to bad block reallocations by the disk.
+If you are paranoid, you should do both.
+.Pp
 To spin down a disk after 30 minutes run
 .Pp
 .Dl "atacontrol spindown ad6 1800"
@@ -368,6 +474,9 @@
 utility was written by
 .An S\(/oren Schmidt
 .Aq sos at FreeBSD.org .
+Support for ATA Security was added by
+.An Daniel Roethlisberger
+.Aq daniel at roe.ch .
 .Pp
 This manual page was written by
 .An S\(/oren Schmidt
diff -ruN ../HEAD/sbin/atacontrol/atacontrol.c ./sbin/atacontrol/atacontrol.c
--- ../HEAD/sbin/atacontrol/atacontrol.c	2008-08-06 20:08:02.000000000 +0200
+++ ./sbin/atacontrol/atacontrol.c	2008-10-02 10:05:25.000000000 +0200
@@ -103,11 +103,29 @@
 		"        atacontrol status array\n"
 		"        atacontrol mode device [mode]\n"
 		"        atacontrol cap device\n"
+		"        atacontrol security device [<security-command>]\n"
 		"        atacontrol spindown device [seconds]\n"
 	);
 	exit(EX_USAGE);
 }
 
+static void
+security_usage(void)
+{
+	fprintf(stderr,
+		"usage:  atacontrol security <device> <security-command>:\n"
+		"        atacontrol security <device>\n"
+		"        atacontrol security <device> freeze\n"
+		"        atacontrol security <device> set master\n"
+		"        atacontrol security <device> set user high|maximum\n"
+		"        atacontrol security <device> unlock master|user\n"
+		"        atacontrol security <device> disable master|user\n"
+		"        atacontrol security <device> erase master|user "
+		                                     "[enhanced]\n"
+	);
+	exit(EX_USAGE);
+}
+
 static int
 version(int ver)
 {
@@ -122,6 +140,18 @@
 }
 
 static void
+ata_request(int fd, struct ata_ioc_request *req)
+{
+	if (ioctl(fd, IOCATAREQUEST, req) < 0)
+		err(1, "ioctl(IOCATAREQUEST)");
+
+	if (req->error) {
+		fprintf(stderr, "atacontrol: ATA request failed (0x%04x)\n", req->error);
+		exit(EX_IOERR);
+	}
+}
+
+static void
 param_print(struct ata_params *parm)
 {
 	printf("<%.40s/%.8s> ", parm->model, parm->revision);
@@ -309,6 +339,235 @@
 	}
 }
 
+static void
+security_print_time(u_int16_t tw)
+{
+	if (tw == 0)
+		printf("unspecified");
+	else if (tw >= 255)
+		printf("> 508 min");
+	else
+		printf("%i min", 2 * tw);
+}
+
+static void
+security_print(struct ata_params *parm)
+{
+	printf("\n");
+#if 0
+	printf("Security status           %04x\n", parm->security_status);
+#endif
+	printf("Security supported        %s\n",
+		parm->security_status & ATA_SECURITY_SUPPORTED ? "yes" : "no");
+	if (!(parm->security_status & ATA_SECURITY_SUPPORTED))
+		return;
+	printf("Security enabled          %s\n",
+		parm->security_status & ATA_SECURITY_ENABLED ? "yes" : "no");
+	printf("Drive locked              %s\n",
+		parm->security_status & ATA_SECURITY_LOCKED ? "yes" : "no");
+	printf("Security config frozen    %s\n",
+		parm->security_status & ATA_SECURITY_FROZEN ? "yes" : "no");
+	printf("Count expired             %s\n",
+		parm->security_status & ATA_SECURITY_COUNT_EXP ? "yes" : "no");
+	printf("Security level            %s\n",
+		parm->security_status & ATA_SECURITY_LEVEL ? "maximum" : "high");
+	printf("Enhanced erase supported  %s\n",
+		parm->security_status & ATA_SECURITY_ENH_SUPP ? "yes" : "no");
+	printf("Erase time                ");
+	security_print_time(parm->erase_time);
+	printf("\n");
+	printf("Enhanced erase time       ");
+	security_print_time(parm->enhanced_erase_time);
+	printf("\n");
+	printf("Master password rev       %04x%s\n",
+			parm->master_passwd_revision,
+			parm->master_passwd_revision == 0x0000 ||
+			parm->master_passwd_revision == 0xFFFF ?
+			" (unsupported)" : "");
+}
+
+static void
+security_ask_password(char *pw, size_t len, int master, int confirm)
+{
+	char *input;
+
+	input = getpass(master ? "Master password:" : "User password:");
+	if (!input) {
+		err(1, "getpass()");
+	}
+	if (strlen(input) > len) {
+		fprintf(stderr, "atacontrol: Password too long\n");
+		exit(EX_DATAERR);
+	}
+	strlcpy(pw, input, len);
+	if (!confirm)
+		return;
+	input = getpass(master ? "Retype master password:" :
+			"Retype user password:");
+	if (!input) {
+		err(1, "getpass()");
+	}
+	if (strcmp(pw, input)) {
+		fprintf(stderr, "atacontrol: Password mismatch\n");
+		exit(EX_DATAERR);
+	}
+}
+
+static u_int16_t
+security_get_revision(int fd)
+{
+	struct ata_params params;
+
+	if (ioctl(fd, IOCATAGPARM, &params) < 0)
+		err(1, "ioctl(IOCATAGPARM)");
+	return params.master_passwd_revision;
+}
+
+/*
+ * security <device>
+ */
+static void
+ata_security_print(int fd)
+{
+	struct ata_params params;
+
+	if (ioctl(fd, IOCATAGPARM, &params) < 0)
+		err(1, "ioctl(IOCATAGPARM)");
+	security_print(&params);
+}
+
+/*
+ * security <device> freeze
+ */
+static void
+ata_security_freeze(int fd)
+{
+	struct ata_ioc_request req;
+
+	memset(&req, 0, sizeof(req));
+	req.u.ata.command = ATA_SECURITY_FREEZE_LOCK;
+	req.timeout = 5;
+	req.flags = ATA_CMD_CONTROL;
+	ata_request(fd, &req);
+}
+
+/*
+ * security <device> set master
+ * security <device> set user high
+ * security <device> set user maximum
+ */
+static void
+ata_security_set(int fd, u_int16_t ctrl)
+{
+	struct ata_ioc_request req;
+	struct ata_security_password pwd;
+
+	memset(&pwd, 0, sizeof(pwd));
+	pwd.ctrl = ctrl;
+
+	if (ctrl & ATA_SECURITY_PASSWORD_MASTER) {
+		pwd.revision = security_get_revision(fd);
+		if (pwd.revision != 0 && pwd.revision != 0xffff &&
+				--pwd.revision == 0) {
+			pwd.revision = 0xfffe;
+		}
+	}
+
+	security_ask_password((char*)&pwd.password, sizeof(pwd.password),
+			ctrl & ATA_SECURITY_PASSWORD_MASTER, 1);
+
+	memset(&req, 0, sizeof(req));
+	req.u.ata.command = ATA_SECURITY_SET_PASSWORD;
+	req.timeout = 5;
+	req.flags = ATA_CMD_WRITE;
+	req.data = (caddr_t)&pwd;
+	req.count = sizeof(pwd);
+	ata_request(fd, &req);
+}
+
+/*
+ * security <device> unlock master
+ * security <device> unlock user
+ */
+static void
+ata_security_unlock(int fd, u_int16_t ctrl)
+{
+	struct ata_ioc_request req;
+	struct ata_security_password pwd;
+
+	memset(&pwd, 0, sizeof(pwd));
+	pwd.ctrl = ctrl;
+
+	security_ask_password((char*)&pwd.password, sizeof(pwd.password),
+			ctrl & ATA_SECURITY_PASSWORD_MASTER, 0);
+
+	memset(&req, 0, sizeof(req));
+	req.u.ata.command = ATA_SECURITY_UNLOCK;
+	req.timeout = 5;
+	req.flags = ATA_CMD_WRITE;
+	req.data = (caddr_t)&pwd;
+	req.count = sizeof(pwd);
+	ata_request(fd, &req);
+}
+
+/*
+ * security <device> disable master
+ * security <device> disable user
+ */
+static void
+ata_security_disable(int fd, u_int16_t ctrl)
+{
+	struct ata_ioc_request req;
+	struct ata_security_password pwd;
+
+	memset(&pwd, 0, sizeof(pwd));
+	pwd.ctrl = ctrl;
+
+	security_ask_password((char*)&pwd.password, sizeof(pwd.password),
+			ctrl & ATA_SECURITY_PASSWORD_MASTER, 0);
+
+	memset(&req, 0, sizeof(req));
+	req.u.ata.command = ATA_SECURITY_DISABLE_PASSWORD;
+	req.timeout = 5;
+	req.flags = ATA_CMD_WRITE;
+	req.data = (caddr_t)&pwd;
+	req.count = sizeof(pwd);
+	ata_request(fd, &req);
+}
+
+/*
+ * security <device> erase master
+ * security <device> erase master enhanced
+ * security <device> erase user
+ * security <device> erase user enhanced
+ */
+static void
+ata_security_erase(int fd, u_int16_t ctrl)
+{
+	struct ata_ioc_request req;
+	struct ata_security_password pwd;
+
+	memset(&pwd, 0, sizeof(pwd));
+	pwd.ctrl = ctrl;
+
+	security_ask_password((char*)&pwd.password, sizeof(pwd.password),
+			ctrl & ATA_SECURITY_PASSWORD_MASTER, 0);
+
+	memset(&req, 0, sizeof(req));
+	req.u.ata.command = ATA_SECURITY_ERASE_PREPARE;
+	req.timeout = 5;
+	req.flags = ATA_CMD_CONTROL;
+	ata_request(fd, &req);
+
+	memset(&req, 0, sizeof(req));
+	req.u.ata.command = ATA_SECURITY_ERASE_UNIT;
+	req.timeout = 86400; /* may take literally hours to complete */
+	req.flags = ATA_CMD_WRITE;
+	req.data = (caddr_t)&pwd;
+	req.count = sizeof(pwd);
+	ata_request(fd, &req);
+}
+
 static int
 open_dev(const char *arg, int mode)
 {
@@ -386,6 +645,69 @@
 		exit(EX_OK);
 	}
 
+	if (!strcmp(argv[1], "security") && argc >= 3 && argc <= 6) {
+		u_int16_t ctrl = 0;
+
+		fd = open_dev(argv[2], O_RDONLY);
+		if (argc == 3) {
+			ata_security_print(fd);
+			exit(EX_OK);
+		} else if (argc == 4 && !strcmp(argv[3], "freeze")) {
+			ata_security_freeze(fd);
+			exit(EX_OK);
+		} else if (argc >= 5 && !strcmp(argv[3], "set")) {
+			if (argc == 5 && !strcmp(argv[4], "master")) {
+				ctrl |= ATA_SECURITY_PASSWORD_MASTER;
+			} else if (argc == 6 && !strcmp(argv[4], "user")) {
+				ctrl |= ATA_SECURITY_PASSWORD_USER;
+				if (!strcmp(argv[5], "high"))
+					ctrl |= ATA_SECURITY_LEVEL_HIGH;
+				else if (!strcmp(argv[5], "maximum"))
+					ctrl |= ATA_SECURITY_LEVEL_MAXIMUM;
+				else
+					security_usage();
+			} else {
+				security_usage();
+			}
+			ata_security_set(fd, ctrl);
+			exit(EX_OK);
+		} else if (argc == 5 && !strcmp(argv[3], "unlock")) {
+			if (!strcmp(argv[4], "master"))
+				ctrl |= ATA_SECURITY_PASSWORD_MASTER;
+			else if (!strcmp(argv[4], "user"))
+				ctrl |= ATA_SECURITY_PASSWORD_USER;
+			else
+				security_usage();
+			ata_security_unlock(fd, ctrl);
+			exit(EX_OK);
+		} else if (argc == 5 && !strcmp(argv[3], "disable")) {
+			if (!strcmp(argv[4], "master"))
+				ctrl |= ATA_SECURITY_PASSWORD_MASTER;
+			else if (!strcmp(argv[4], "user"))
+				ctrl |= ATA_SECURITY_PASSWORD_USER;
+			else
+				security_usage();
+			ata_security_disable(fd, ctrl);
+			exit(EX_OK);
+		} else if (argc >= 5 && !strcmp(argv[3], "erase")) {
+			if (!strcmp(argv[4], "master"))
+				ctrl |= ATA_SECURITY_PASSWORD_MASTER;
+			else if (!strcmp(argv[4], "user"))
+				ctrl |= ATA_SECURITY_PASSWORD_USER;
+			else
+				security_usage();
+			if (argc == 5)
+				ctrl |= ATA_SECURITY_ERASE_NORMAL;
+			else if (!strcmp(argv[5], "enhanced"))
+				ctrl |= ATA_SECURITY_ERASE_ENHANCED;
+			else
+				security_usage();
+			ata_security_erase(fd, ctrl);
+			exit(EX_OK);
+		}
+		security_usage();
+	}
+
 	if ((fd = open("/dev/ata", O_RDWR)) < 0)
 		err(1, "control device not found");
 
diff -ruN ../HEAD/sys/dev/ata/ata-queue.c ./sys/dev/ata/ata-queue.c
--- ../HEAD/sys/dev/ata/ata-queue.c	2008-04-21 12:35:19.000000000 +0200
+++ ./sys/dev/ata/ata-queue.c	2008-10-01 00:25:18.000000000 +0200
@@ -730,7 +730,12 @@
 	    }
 	    sprintf(buffer, "SETFEATURES 0x%02x", request->u.ata.feature);
 	    return buffer;
-	case 0xf5: return ("SECURITY_FREE_LOCK");
+	case 0xf1: return ("SECURITY_SET_PASSWORD");
+	case 0xf2: return ("SECURITY_UNLOCK");
+	case 0xf3: return ("SECURITY_ERASE_PREPARE");
+	case 0xf4: return ("SECURITY_ERASE_UNIT");
+	case 0xf5: return ("SECURITY_FREEZE_LOCK");
+	case 0xf6: return ("SECURITY_DISABLE_PASSWORD");
 	case 0xf8: return ("READ_NATIVE_MAX_ADDRESS");
 	case 0xf9: return ("SET_MAX_ADDRESS");
 	}
diff -ruN ../HEAD/sys/sys/ata.h ./sys/sys/ata.h
--- ../HEAD/sys/sys/ata.h	2008-04-10 15:01:17.000000000 +0200
+++ ./sys/sys/ata.h	2008-09-28 21:53:56.000000000 +0200
@@ -170,10 +170,10 @@
 	} __packed support, enabled;
 
 /*088*/ u_int16_t       udmamodes;              /* UltraDMA modes */
-/*089*/ u_int16_t       erase_time;
-/*090*/ u_int16_t       enhanced_erase_time;
+/*089*/ u_int16_t       erase_time;             /* time req'd in 2min units */
+/*090*/ u_int16_t       enhanced_erase_time;    /* time req'd in 2min units */
 /*091*/ u_int16_t       apm_value;
-/*092*/ u_int16_t       master_passwd_revision;
+/*092*/ u_int16_t       master_passwd_revision; /* password revision code */
 /*093*/ u_int16_t       hwres;
 #define ATA_CABLE_ID                    0x2000
 
@@ -191,7 +191,16 @@
 	u_int16_t       lba_size48_4;
 	u_int16_t       reserved104[23];
 /*127*/ u_int16_t       removable_status;
+
 /*128*/ u_int16_t       security_status;
+#define ATA_SECURITY_LEVEL		0x0100	/* 0: high, 1: maximum */
+#define ATA_SECURITY_ENH_SUPP		0x0020	/* enhanced erase supported */
+#define ATA_SECURITY_COUNT_EXP		0x0010	/* count expired */
+#define ATA_SECURITY_FROZEN		0x0008	/* security config is frozen */
+#define ATA_SECURITY_LOCKED		0x0004	/* drive is locked */
+#define ATA_SECURITY_ENABLED		0x0002	/* ATA Security is enabled */
+#define ATA_SECURITY_SUPPORTED		0x0001	/* ATA Security is supported */
+
 	u_int16_t       reserved129[31];
 /*160*/ u_int16_t       cfa_powermode1;
 	u_int16_t       reserved161[15];
@@ -283,7 +292,12 @@
 #define         ATA_SF_DIS_RELIRQ       0xdd    /* disable release interrupt */
 #define         ATA_SF_ENAB_SRVIRQ      0x5e    /* enable service interrupt */
 #define         ATA_SF_DIS_SRVIRQ       0xde    /* disable service interrupt */
-#define ATA_SECURITY_FREEE_LOCK         0xf5    /* freeze security config */
+#define ATA_SECURITY_SET_PASSWORD       0xf1    /* set drive password */
+#define ATA_SECURITY_UNLOCK             0xf2    /* unlock drive using passwd */
+#define ATA_SECURITY_ERASE_PREPARE      0xf3    /* prepare to erase drive */
+#define ATA_SECURITY_ERASE_UNIT         0xf4    /* erase all blocks on drive */
+#define ATA_SECURITY_FREEZE_LOCK        0xf5    /* freeze security config */
+#define ATA_SECURITY_DISABLE_PASSWORD   0xf6    /* disable drive password */
 #define ATA_READ_NATIVE_MAX_ADDRESS     0xf8    /* read native max address */
 #define ATA_SET_MAX_ADDRESS             0xf9    /* set max address */
 
@@ -429,6 +443,20 @@
     int                 error;
 };
 
+struct ata_security_password {
+	u_int16_t		ctrl;
+#define ATA_SECURITY_PASSWORD_USER	0x0000
+#define ATA_SECURITY_PASSWORD_MASTER	0x0001
+#define ATA_SECURITY_ERASE_NORMAL	0x0000
+#define ATA_SECURITY_ERASE_ENHANCED	0x0002
+#define ATA_SECURITY_LEVEL_HIGH		0x0000
+#define ATA_SECURITY_LEVEL_MAXIMUM	0x0100
+
+	u_int8_t		password[32];
+	u_int16_t		revision;
+	u_int16_t		reserved[238];
+};
+
 /* pr device ATA ioctl calls */
 #define IOCATAREQUEST           _IOWR('a', 100, struct ata_ioc_request)
 #define IOCATAGPARM             _IOR('a', 101, struct ata_params)
--- atasecurity-20081007-complete.diff ends here ---


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list