diff -Nru iucode-tool-1.0/ChangeLog iucode-tool-1.0.1/ChangeLog --- iucode-tool-1.0/ChangeLog 2013-05-25 16:11:14.000000000 +0000 +++ iucode-tool-1.0.1/ChangeLog 2013-12-14 22:58:38.000000000 +0000 @@ -1,3 +1,15 @@ +2013-12-14, iucode_tool v1.0.1 + + * Fix several cosmetic code issues + * Manpage updates + + Make it clear that the output order of microcodes is not stabilized + + Make it clear that iucode_tool always break links when writing a + data file, and that it doesn't replace files atomically, so they + can get corrupted/lost if iucode-tool is interrupted while writing. + + Reword several notes for better readability + * Use openat() when loading from a directory + * Use openat() when creating files in a directory + 2013-05-25, iucode_tool v1.0 * Add verbose title to manpage iucode_tool(8) diff -Nru iucode-tool-1.0/README iucode-tool-1.0.1/README --- iucode-tool-1.0/README 2013-05-25 16:05:26.000000000 +0000 +++ iucode-tool-1.0.1/README 2013-12-14 22:58:38.000000000 +0000 @@ -1,9 +1,9 @@ - iucode_tool - Intel® 64 and IA-32 processor microcode tool + iucode_tool - Intel® 64 and IA-32 processor microcode tool - Version 1.0 - May 25th, 2013 + Version 1.0.1 + December 14th, 2013 Intel® 64 and IA-32 processors (x86_64 and i686 processors) are capable of diff -Nru iucode-tool-1.0/TODO iucode-tool-1.0.1/TODO --- iucode-tool-1.0/TODO 2013-05-25 16:06:43.000000000 +0000 +++ iucode-tool-1.0.1/TODO 2013-12-14 22:58:38.000000000 +0000 @@ -17,5 +17,3 @@ - return status when we skip a ucode? when we skip a file? * --overwrite: removes symlinks. Maybe it would be better to fail? - -* use openat()? diff -Nru iucode-tool-1.0/configure iucode-tool-1.0.1/configure --- iucode-tool-1.0/configure 2013-05-25 16:13:08.000000000 +0000 +++ iucode-tool-1.0.1/configure 2013-12-14 23:06:28.000000000 +0000 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for iucode_tool 1.0. +# Generated by GNU Autoconf 2.69 for iucode_tool 1.0.1. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -577,8 +577,8 @@ # Identity of this package. PACKAGE_NAME='iucode_tool' PACKAGE_TARNAME='iucode_tool' -PACKAGE_VERSION='1.0' -PACKAGE_STRING='iucode_tool 1.0' +PACKAGE_VERSION='1.0.1' +PACKAGE_STRING='iucode_tool 1.0.1' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -1274,7 +1274,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures iucode_tool 1.0 to adapt to many kinds of systems. +\`configure' configures iucode_tool 1.0.1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1344,7 +1344,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of iucode_tool 1.0:";; + short | recursive ) echo "Configuration of iucode_tool 1.0.1:";; esac cat <<\_ACEOF @@ -1444,7 +1444,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -iucode_tool configure 1.0 +iucode_tool configure 1.0.1 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1993,7 +1993,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by iucode_tool $as_me 1.0, which was +It was created by iucode_tool $as_me 1.0.1, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2882,7 +2882,7 @@ # Define the identity of the package. PACKAGE='iucode_tool' - VERSION='1.0' + VERSION='1.0.1' cat >>confdefs.h <<_ACEOF @@ -6542,7 +6542,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by iucode_tool $as_me 1.0, which was +This file was extended by iucode_tool $as_me 1.0.1, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -6608,7 +6608,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -iucode_tool config.status 1.0 +iucode_tool config.status 1.0.1 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff -Nru iucode-tool-1.0/configure.ac iucode-tool-1.0.1/configure.ac --- iucode-tool-1.0/configure.ac 2013-05-25 14:03:05.000000000 +0000 +++ iucode-tool-1.0.1/configure.ac 2013-12-14 22:58:38.000000000 +0000 @@ -16,7 +16,7 @@ dnl along with this program; if not, write to the Free Software dnl Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -AC_INIT([iucode_tool], [1.0]) +AC_INIT([iucode_tool], [1.0.1]) AC_PREREQ([2.61]) AC_CONFIG_SRCDIR([iucode_tool.c]) diff -Nru iucode-tool-1.0/debian/changelog iucode-tool-1.0.1/debian/changelog --- iucode-tool-1.0/debian/changelog 2013-05-25 16:42:31.000000000 +0000 +++ iucode-tool-1.0.1/debian/changelog 2013-12-14 23:07:18.000000000 +0000 @@ -1,3 +1,20 @@ +iucode-tool (1.0.1-1) unstable; urgency=low + + * New upstream maintenance release + + Fix several cosmetic code issues + + Manpage updates + + Make it clear that the output order of microcodes is not stabilized + + Make it clear that iucode_tool always break links when writing a + data file, and that it doesn't replace files atomically, so they + can get corrupted/lost if iucode-tool is interrupted while writing + + Reword several notes for better readability + + Use openat() when loading from a directory and when creating files in + a directory. Thus, iucode-tool will read/write to the same directory + even while racing another process that is trying to rename it while + iucode-tool is already running + + -- Henrique de Moraes Holschuh Sat, 14 Dec 2013 21:01:41 -0200 + iucode-tool (1.0-1) unstable; urgency=low * New upstream release diff -Nru iucode-tool-1.0/iucode_tool.8.in iucode-tool-1.0.1/iucode_tool.8.in --- iucode-tool-1.0/iucode_tool.8.in 2013-05-25 14:03:05.000000000 +0000 +++ iucode-tool-1.0.1/iucode_tool.8.in 2013-12-14 22:58:38.000000000 +0000 @@ -15,7 +15,7 @@ .\" along with this program; see the file COPYING. If not, write to .\" the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. .\" -.TH IUCODE_TOOL 8 "May 9th, 2013" "IUCODE_TOOL @VERSION@" "iucode_tool manual" +.TH IUCODE_TOOL 8 "November 24th, 2013" "IUCODE_TOOL @VERSION@" "iucode_tool manual" .\" Please update the above date whenever this man page is modified. .\" .\" Some roff macros, for reference: @@ -159,7 +159,7 @@ .TP .BI "-s ! | [!]" signature "[," pf_mask "]" -Select microcodes by the specificed signature and processor flags mask +Select microcodes by the specified signature and processor flags mask .IR "(pf_mask)" ". If " pf_mask is specified, it will select only microcodes that are suitable for at least one of the processor flag combinations in the mask. @@ -246,7 +246,8 @@ .B "--overwrite" Remove the destination file before writing. Without this option, \fBiucode_tool\fP will abort if the file already exists. Do note that -it will remove symlinks instead of following them. +it will remove non-directory symlinks instead of following them, and +that it will also break any hardlinks before writing the output file. .TP .B "--no-overwrite" @@ -255,15 +256,22 @@ writing files. .SH NOTES -.\"fixme: stdin example, multi-file example, -s example. \fBiucode_tool\fP reads all data to memory before doing any processing. .PP -The microcode data is sorted by cpu signature. Older revisions are -removed (either based on revision level or load order, depending on -the \fI--downgrade\fP option) before the data is written to a file or -uploaded to the kernel. +\fBiucode_tool\fP's selected microcode listing and microcode output +files are sorted by cpu signature, however the ordering inside a group +of microcodes that share the same cpu signature is \fIundefined\fP: it +is deterministic, but it is sensitive to command line parameters and +their ordering, and also depends on the ordering of the individual +microcodes inside each loaded data file. + +.PP +When multiple revisions of a microcode are selected, the older ones will +be skipped. Only the newest selected revision of a microcode (or the +last one in load order when the \fI--downgrade\fP option is active) will +be written to a file or uploaded to the kernel. .PP Intel microcode data files, both in binary and text formats, can be @@ -271,10 +279,13 @@ .PP \fBiucode_tool\fP does not follow symlinks when writing microcode data -files (\fI--write-to\fP and \fI--write-firmware\fP options). It will -either refuse to write the file and abort (default mode of operation), -or remove the symlink before writing (when the \fI--overwrite\fP option -is active). It does follow directory symlinks to locate the directory +files. It will either refuse to write the file and abort (default mode +of operation), or (when the \fI--overwrite\fP option is active) it will +remove the target symlink or file (and therefore breaking hardlinks) +\fIbefore\fP writing the new file. + +.PP +\fBiucode_tool\fP does follow directory symlinks to locate the directory to write files into. .SS Linux Notes @@ -310,6 +321,7 @@ hibernation, and also to update any system processor cores that were off-line at the time the update was applied. +.\"fixme: stdin example, multi-file example, -s example. .SH EXAMPLES .SS Updating files in \fI@MICROCODE_DIR_DEFAULT@\fB: .IP @@ -333,6 +345,10 @@ Microcode with negative revision numbers is not special-cased, and will not be preferred over regular microcode. +.PP +Files are not replaced atomically: if \fBiucode_tool\fP is interrupted while +writing to a file, that file will be corrupted. + .SH "SEE ALSO" \fBThe Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 3A: System Programming Guide, Part 1\fP (order number 253668), section 9.11. diff -Nru iucode-tool-1.0/iucode_tool.c iucode-tool-1.0.1/iucode_tool.c --- iucode-tool-1.0/iucode_tool.c 2013-05-25 14:03:05.000000000 +0000 +++ iucode-tool-1.0.1/iucode_tool.c 2013-12-14 22:58:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * uicode_tool - Manipulates Intel(R) IA32/x86_64 processor microcode bundles + * iucode_tool - Manipulates Intel(R) IA32/x86_64 processor microcode bundles * * Copyright (c) 2010-2013 Henrique de Moraes Holschuh * 2000 Simon Trimmer, Tigran Aivazian @@ -867,7 +867,11 @@ } } - fd = open(fn, O_RDONLY); + if (dir) { + fd = openat(dirfd(dir), dentry->d_name, O_RDONLY); + } else { + fd = open(fn, O_RDONLY); + } if (unlikely(fd == -1)) { err = errno; print_err("%s: cannot open: %s", fn, strerror(err)); @@ -1007,10 +1011,12 @@ if (fstat(fd, &stat) == -1) { err = errno; print_err("%s: cannot stat: %s", devname, strerror(err)); + close(fd); return err; } if (!S_ISCHR(stat.st_mode)) { print_err("%s: not a character device", devname); + close(fd); return EINVAL; } @@ -1161,12 +1167,16 @@ /** * write_intel_microcodes() - writes microcodes to bin file + * @dirfd: directory where to create file * @filename: file to write to * @ft: file type * @uc_write_list: uclist with the microcodes to write * * returns 0 if successful, or errno() if a problem happens * + * @dirfd should be either an open directory for openat(), or + * the special value AT_FDCWD. + * * @ft should be zero for binary format, 1 for linux early * initramfs cpio format. * @@ -1180,7 +1190,8 @@ * newer. This file should be prepended to the compressed initramfs * image. */ -static int write_intel_microcodes(const char * const filename, int ft, +static int write_intel_microcodes(const int dirfd, + const char * const filename, int ft, struct intel_uclist_entry *uc_write_list) { int fd; @@ -1195,7 +1206,7 @@ /* Unlink first */ if (unlink_files) { - if (unlink(filename) == -1) { + if (unlinkat(dirfd, filename, 0) == -1) { if (errno != ENOENT) { err = errno; print_err("%s: cannot unlink: %s", filename, @@ -1206,8 +1217,9 @@ print_msg(3, "unlinked %s", filename); } } - fd = open(filename, O_CREAT | O_WRONLY | O_EXCL, - S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH); + + fd = openat(dirfd, filename, O_CREAT | O_WRONLY | O_EXCL, + S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH); if (fd == -1) { err = errno; print_err("%s: cannot write to, or create file: %s", @@ -1658,7 +1670,7 @@ return 0; print_msg(1, "Writing selected microcodes to: %s", filename); - return write_intel_microcodes(filename, ft, microcodes); + return write_intel_microcodes(AT_FDCWD, filename, ft, microcodes); } static int do_upload_microcode(const char * const filename) @@ -1672,7 +1684,8 @@ static int do_write_named(const char * const dirname) { - char fn[PATH_MAX]; + char fn[35]; /* "s%08X_m%08X_r%08X.fw" */ + int dirfd; struct stat st; struct intel_uclist_entry e, *p; @@ -1682,16 +1695,25 @@ if (!microcodes) return 0; + dirfd = open(dirname, O_RDONLY); + if (dirfd == -1) { + rc = errno; + print_err("%s: cannot open: %s", dirname, + strerror(rc)); + return rc; + } + /* were we given a directory ? */ - if (stat(dirname, &st) == -1) { - int err = errno; + if (fstat(dirfd, &st) == -1) { + rc = errno; print_err("%s: cannot stat inode: %s", dirname, - strerror(err)); - return err; + strerror(rc)); + goto err_exit; } if (!S_ISDIR(st.st_mode)) { print_err("%s: is not a directory", dirname); - return EINVAL; + rc = EINVAL; + goto err_exit; } print_msg(1, "Writing microcode file(s) into %s", dirname); @@ -1701,18 +1723,12 @@ rc = 0; while (p && !rc) { - /* write to file in dirname/ */ - rc = snprintf(fn, sizeof(fn), "%s/s%08X_m%08X_r%08X.fw", dirname, + snprintf(fn, sizeof(fn), "s%08X_m%08X_r%08X.fw", p->cpuid, p->pf_mask, p->uc_rev); - if (rc < 1 || rc >= sizeof(fn)) { - print_err("%s: directory name too long, cannot create files inside", - dirname); - return EINVAL; - } memcpy(&e, p, sizeof(e)); e.next = NULL; - rc = write_intel_microcodes(fn, 0, &e); + rc = write_intel_microcodes(dirfd, fn, 0, &e); if (!rc) count++; @@ -1723,12 +1739,16 @@ else print_msg(1, "no files were written into %s", dirname); +err_exit: + close(dirfd); + return rc; } static int do_write_firmware(const char * const dirname) { - char fn[PATH_MAX]; + char fn[35]; /* "%02x-%02x-%02x" */ + int dirfd; struct stat st; struct intel_uclist_entry *samecpuid_list, *p; @@ -1738,16 +1758,25 @@ if (!microcodes) return 0; + dirfd = open(dirname, O_RDONLY); + if (dirfd == -1) { + rc = errno; + print_err("%s: cannot open: %s", dirname, + strerror(rc)); + return rc; + } + /* were we given a directory ? */ - if (stat(dirname, &st) == -1) { - int err = errno; + if (fstat(dirfd, &st) == -1) { + rc = errno; print_err("%s: cannot stat inode: %s", dirname, - strerror(err)); - return err; + strerror(rc)); + goto err_exit; } if (!S_ISDIR(st.st_mode)) { print_err("%s: is not a directory", dirname); - return EINVAL; + rc = EINVAL; + goto err_exit; } print_msg(1, "Writing microcode firmware file(s) into %s", dirname); @@ -1770,8 +1799,10 @@ p->cpuid, p->pf_mask, p->uc_rev, p->uc, p->uc_size, 0, &samecpuid_list); - if (__uclist_add_print_errors(add_status)) - return add_status; + if (__uclist_add_print_errors(add_status)) { + rc = add_status; + goto err_exit; + } p = p->next; } @@ -1786,15 +1817,10 @@ if (x86_family >= 0x06) x86_model += ((cpuid >> 16) & 0x0f) << 4; - rc = snprintf(fn, sizeof(fn), "%s/%02x-%02x-%02x", dirname, + snprintf(fn, sizeof(fn), "%02x-%02x-%02x", x86_family, x86_model, x86_mask); - if (rc < 1 || rc >= sizeof(fn)) { - print_err("%s: directory name too long, cannot create files inside", - dirname); - return EINVAL; - } - rc = write_intel_microcodes(fn, 0, samecpuid_list); + rc = write_intel_microcodes(dirfd, fn, 0, samecpuid_list); free_uclist(samecpuid_list); samecpuid_list = NULL; @@ -1807,6 +1833,9 @@ else print_msg(1, "no files were written into %s", dirname); +err_exit: + close(dirfd); + return rc; } @@ -1921,7 +1950,7 @@ /* Command line processing */ -const char program_version[] = +static const char program_version[] = PROGNAME " " VERSION "\n" "Copyright (c) 2010-2013 by Henrique de Moraes Holschuh\n\n" @@ -1932,7 +1961,7 @@ "This is free software; see the source for copying conditions.\n" "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR\n" "A PARTICULAR PURPOSE."; -const char program_bug_address[] = PACKAGE_BUGREPORT; +static const char program_bug_address[] = PACKAGE_BUGREPORT; static char cmdline_doc[] = PROGNAME " - Tool to manipulate Intel IA32/X86_64 microcode bundles\n" @@ -2399,7 +2428,7 @@ argp_err_exit_status = EXIT_USAGE; argp_program_version = program_version; argp_program_bug_address = NULL; /* FIXME */ - argp_parse(&cmdline_argp, argc, argv, ARGP_IN_ORDER, 0, NULL); + argp_parse(&cmdline_argp, argc, argv, ARGP_IN_ORDER, NULL, NULL); if (!command_line_actions) { print_msg(1, "nothing to do...");