summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Plattner <aplattner@nvidia.com>2013-04-09 09:03:00 -0700
committerAaron Plattner <aplattner@nvidia.com>2013-04-09 09:03:00 -0700
commit8391c1d912302dc9577ee09afc257ba71d95a07b (patch)
tree3e176b66e4f0f859c63927280bcd643f934f25e8
parent89a64f3d6ab1097f819ea4925a58f3aea50f6fcd (diff)
319.12319.12
-rw-r--r--README8
-rw-r--r--backup.c181
-rw-r--r--command-list.c43
-rw-r--r--common-utils/common-utils.c47
-rw-r--r--common-utils/common-utils.h33
-rw-r--r--dist-files.mk2
-rw-r--r--files.c220
-rw-r--r--files.h3
-rw-r--r--install-from-cwd.c405
-rw-r--r--kernel.c792
-rw-r--r--kernel.h40
-rw-r--r--log.c21
-rw-r--r--manifest.c214
-rw-r--r--manifest.h39
-rw-r--r--misc.c195
-rw-r--r--misc.h7
-rw-r--r--nvidia-installer.c32
-rw-r--r--nvidia-installer.h274
-rw-r--r--option_table.h57
-rw-r--r--precompiled.c65
-rw-r--r--precompiled.h3
-rw-r--r--user-interface.c46
-rw-r--r--user-interface.h26
-rw-r--r--utils.mk6
-rw-r--r--version.mk2
25 files changed, 2093 insertions, 668 deletions
diff --git a/README b/README
index fdec382..6201d5f 100644
--- a/README
+++ b/README
@@ -17,6 +17,14 @@ implementation of nvidia-installer, but the source code is fairly
well commented.
+Build dependencies of nvidia-installer include:
+
+ libkmod ncurses pciutils
+
+Please ensure that the appropriate development packages for these
+dependencies have been installed before building nvidia-installer.
+
+
One interesting thing to note is that user interface shared libraries
are built into nvidia-installer to avoid potential problems with
the installer not being able to find the user interface libraries (or
diff --git a/backup.c b/backup.c
index 47c4c4b..9030e6f 100644
--- a/backup.c
+++ b/backup.c
@@ -121,6 +121,7 @@ static int sanity_check_backup_log_entries(Options *op, BackupInfo *b);
static char *create_backwards_compatible_version_string(const char *str);
+static int reverse_strlen_compare(const void *a, const void *b);
@@ -148,7 +149,7 @@ int init_backup(Options *op, Package *p)
/* create the backup directory, with perms only for owner */
- if (!mkdir_recursive(op, BACKUP_DIRECTORY, BACKUP_DIRECTORY_PERMS)) {
+ if (!mkdir_with_log(op, BACKUP_DIRECTORY, BACKUP_DIRECTORY_PERMS, FALSE)) {
return FALSE;
}
@@ -494,9 +495,7 @@ static int parse_crc(const char *buf, uint32 *crc)
/*
* log_mkdir() - takes a newline-delimited list of directories and appends
- * them to the log of directories created during installation. The caller
- * should ensure that directories are listed in decreasing order of depth,
- * so that removing them in that order will work.
+ * them to the log of directories created during installation.
*/
int log_mkdir(Options *op, const char *dirs)
{
@@ -534,18 +533,32 @@ int log_mkdir(Options *op, const char *dirs)
return TRUE;
}
+
+
+/*
+ * reverse_strlen_compare() - Compare two strings by length, for sorting
+ * in order of decreasing length.
+ */
+static int reverse_strlen_compare(const void *a, const void *b)
+{
+ return strlen((const char *)b) - strlen((const char *)a);
+}
+
+
+
/*
* rmdir_recursive() - Use BACKUP_MKDIR_LOG to find directories that were
* created by a previous nvidia-installer, and delete any such directories.
* Returns TRUE if the log is found and all directories are successfully
* deleted; returns FALSE if any directories failed to be deleted or the
- * log isn't found.
+ * log isn't found. The log enries are processed in reverse order, so that
+ * child directories get properly deleted before their parents.
*/
static int rmdir_recursive(Options *op)
{
FILE *log;
- char *dir;
- int eof = FALSE, ret = TRUE;
+ char *dir, **dirs;
+ int eof = FALSE, ret = TRUE, lines, i;
/* open the log file */
@@ -556,20 +569,43 @@ static int rmdir_recursive(Options *op)
return FALSE;
}
- while (!eof) {
+ /* Count the number of lines */
+
+ for (lines = 0; !eof; lines++) {
dir = fget_next_line(log, &eof);
- if (dir) {
+ nvfree(dir);
+ }
+
+ rewind(log);
+
+ dirs = nvalloc(lines * sizeof(char*));
+
+ for (i = 0; i < lines; i++) {
+ dirs[i] = fget_next_line(log, &eof);
+ }
+
+ qsort(dirs, lines, sizeof(char*), reverse_strlen_compare);
+
+ for (i = lines; i < lines; i++) {
+ if (dirs[i]) {
/* Ignore empty lines and the backup directory itself, since it is
* never empty as long as the dirs file is still around. */
- if (strlen(dir) && strcmp(dir, BACKUP_DIRECTORY) != 0) {
- if (rmdir(dir) != 0) {
- ui_warn(op, "Failed to delete the directory '%s' (%s).",
- dir, strerror(errno));
+ if (strlen(dirs[i]) && strcmp(dir, BACKUP_DIRECTORY) != 0) {
+ if (rmdir(dirs[i]) != 0) {
+ ui_log(op, "Failed to delete the directory '%s' (%s).",
+ dirs[i], strerror(errno));
ret = FALSE;
}
}
}
- free(dir);
+ nvfree(dirs[i]);
+ }
+
+ nvfree(dirs);
+
+ if (!ret) {
+ ui_warn(op, "Failed to delete some directories. See %s for details.",
+ op->log_file_name);
}
/* close the log file */
@@ -595,6 +631,7 @@ static int do_uninstall(Options *op, const char *version)
int i, len, ok;
char *tmpstr, *cmd;
float percent;
+ int removal_failed = FALSE, restore_failed = FALSE;
static const char existing_installation_is_borked[] =
"Your driver installation has been "
@@ -667,16 +704,18 @@ static int do_uninstall(Options *op, const char *version)
case INSTALLED_FILE:
if (unlink(e->filename) == -1) {
- ui_warn(op, "Unable to remove installed file '%s' (%s).",
- e->filename, strerror(errno));
+ ui_log(op, "Unable to remove installed file '%s' (%s).",
+ e->filename, strerror(errno));
+ removal_failed = TRUE;
}
ui_status_update(op, percent, e->filename);
break;
case INSTALLED_SYMLINK:
if (unlink(e->filename) == -1) {
- ui_warn(op, "Unable to remove installed symlink '%s' (%s).",
- e->filename, strerror(errno));
+ ui_log(op, "Unable to remove installed symlink '%s' (%s).",
+ e->filename, strerror(errno));
+ removal_failed = TRUE;
}
ui_status_update(op, percent, e->filename);
break;
@@ -707,22 +746,21 @@ static int do_uninstall(Options *op, const char *version)
*/
if (ok) {
- ui_warn(op, "Unable to restore symbolic link "
- "%s -> %s (%s).", e->filename, e->target,
- strerror(errno));
- } else {
- ui_log(op, "Unable to restore symbolic link "
- "%s -> %s (%s).", e->filename, e->target,
- strerror(errno));
+ restore_failed = TRUE;
}
+
+ ui_log(op, "Unable to restore symbolic link "
+ "%s -> %s (%s).", e->filename, e->target,
+ strerror(errno));
} else {
/* XXX do we need to chmod the symlink? */
if (lchown(e->filename, e->uid, e->gid)) {
- ui_warn(op, "Unable to restore owner (%d) and group "
- "(%d) for symbolic link '%s' (%s).",
- e->uid, e->gid, e->filename, strerror(errno));
+ ui_log(op, "Unable to restore owner (%d) and group "
+ "(%d) for symbolic link '%s' (%s).",
+ e->uid, e->gid, e->filename, strerror(errno));
+ restore_failed = TRUE;
}
}
ui_status_update(op, percent, e->filename);
@@ -733,16 +771,19 @@ static int do_uninstall(Options *op, const char *version)
tmpstr = nvalloc(len + 1);
snprintf(tmpstr, len, "%s/%d", BACKUP_DIRECTORY, e->num);
if (!nvrename(op, tmpstr, e->filename)) {
- ui_warn(op, "Unable to restore file '%s'.", e->filename);
+ ui_log(op, "Unable to restore file '%s'.", e->filename);
+ restore_failed = TRUE;
} else {
if (chown(e->filename, e->uid, e->gid)) {
- ui_warn(op, "Unable to restore owner (%d) and group "
- "(%d) for file '%s' (%s).",
- e->uid, e->gid, e->filename, strerror(errno));
+ ui_log(op, "Unable to restore owner (%d) and group "
+ "(%d) for file '%s' (%s).",
+ e->uid, e->gid, e->filename, strerror(errno));
+ restore_failed = TRUE;
} else {
if (chmod(e->filename, e->mode) == -1) {
- ui_warn(op, "Unable to restore permissions %04o for "
- "file '%s'.", e->mode, e->filename);
+ ui_log(op, "Unable to restore permissions %04o for "
+ "file '%s'.", e->mode, e->filename);
+ restore_failed = TRUE;
}
}
}
@@ -752,6 +793,16 @@ static int do_uninstall(Options *op, const char *version)
}
}
+ if (removal_failed) {
+ ui_warn(op, "Failed to remove some installed files/symlinks. See %s "
+ "for details", op->log_file_name);
+ }
+
+ if (restore_failed) {
+ ui_warn(op, "Failed to restore some backed up files/symlinks, and/or "
+ "their attributes. See %s for details", op->log_file_name);
+ }
+
if (!rmdir_recursive(op)) {
ui_log(op, "Unable to delete directories created by previous "
"installation.");
@@ -837,7 +888,8 @@ static BackupInfo *read_backup_log_file(Options *op)
buf = mmap(0, length, PROT_READ, MAP_FILE | MAP_SHARED, fd, 0);
if (!buf) {
- ui_error(op, "Unable to mmap file '%s' (%s).", strerror(errno));
+ ui_error(op, "Unable to mmap file '%s' (%s).", BACKUP_LOG,
+ strerror(errno));
return NULL;
}
@@ -1015,22 +1067,43 @@ static int check_backup_log_entries(Options *op, BackupInfo *b)
case INSTALLED_FILE:
- /* check if the file is still there, and has the same crc */
+ /* check if the file is still there */
if (access(e->filename, F_OK) == -1) {
ui_log(op, "Unable to access previously installed file "
"'%s' (%s).", e->filename, strerror(errno));
ret = e->ok = FALSE;
} else {
- crc = compute_crc(op, e->filename);
-
- if (crc != e->crc) {
- ui_log(op, "The previously installed file '%s' has a "
- "different checksum (%lu) than "
- "when it was installed (%lu). %s will not be "
- "uninstalled.",
- e->filename, crc, e->crc, e->filename);
- ret = e->ok = FALSE;
+ /* check if the file still has the same crc; if not, try
+ * un-prelinking it and check the crc again */
+ if (!verify_crc(op, e->filename, e->crc, &crc)) {
+ ui_expert(op, "The previously installed file '%s' has a "
+ "different checksum (%ul) than when it was "
+ "installed (%ul). This may be due to prelinking; "
+ "attempting `prelink -u %s` to restore the file.",
+ e->filename, crc, e->crc, e->filename);
+
+ if (unprelink(op, e->filename) != 0) {
+ ui_log(op, "The previously installed file '%s' seems "
+ "to have changed, but `prelink -u` failed; "
+ "unable to restore '%s' to an un-prelinked "
+ "state.", e->filename, e->filename);
+ ret = e->ok = FALSE;
+ } else if (!verify_crc(op, e->filename, e->crc, &crc)) {
+ ui_log(op, "The previously installed file '%s' has a "
+ "different checksum (%ul) after running `pre"
+ "link -u` than when it was installed (%ul).",
+ e->filename, crc, e->crc);
+ ret = e->ok = FALSE;
+ }
+
+ if (ret) {
+ ui_expert(op, "Un-prelinking successful: '%s' will "
+ "be uninstalled.", e->filename);
+ } else {
+ ui_log(op, "Un-prelinking unsuccessful: '%s' will "
+ "not be uninstalled.", e->filename);
+ }
}
}
ui_status_update(op, percent, e->filename);
@@ -1110,10 +1183,9 @@ static int check_backup_log_entries(Options *op, BackupInfo *b)
if (crc != e->crc) {
ui_log(op, "Backed up file '%s' (saved as '%s) has "
- "different checksum (%lu) than"
- "when it was backed up (%lu). %s will not be "
- "restored.", e->filename, tmpstr,
- crc, e->crc, e->filename);
+ "different checksum (%" PRIu32 ") than when it was "
+ "backed up (%" PRIu32"). %s will not be restored.",
+ e->filename, tmpstr, crc, e->crc, e->filename);
ret = e->ok = FALSE;
}
}
@@ -1463,8 +1535,9 @@ static int sanity_check_backup_log_entries(Options *op, BackupInfo *b)
if (crc != e->crc) {
ui_error(op, "The installed file '%s' has a different "
- "checksum (%lu) than when it was installed "
- "(%lu).", e->filename, crc, e->crc);
+ "checksum (%" PRIu32 ") than when it was "
+ "installed (%" PRIu32 ").", e->filename, crc,
+ e->crc);
ret = FALSE;
}
}
@@ -1523,9 +1596,9 @@ static int sanity_check_backup_log_entries(Options *op, BackupInfo *b)
if (crc != e->crc) {
ui_error(op, "Backed up file '%s' (saved as '%s) has a "
- "different checksum (%lu) than"
- "when it was backed up (%lu).",
- e->filename, tmpstr, crc, e->crc);
+ "different checksum (%" PRIu32 ") than when it "
+ "was backed up (%" PRIu32 ").", e->filename,
+ tmpstr, crc, e->crc);
ret = FALSE;
}
}
diff --git a/command-list.c b/command-list.c
index 98c9723..48506d0 100644
--- a/command-list.c
+++ b/command-list.c
@@ -42,6 +42,7 @@
#include "misc.h"
#include "files.h"
#include "kernel.h"
+#include "manifest.h"
static void free_file_list(FileList* l);
@@ -62,7 +63,8 @@ static void find_conflicting_kernel_modules(Options *op,
Package *p,
FileList *l);
-static void find_existing_files(Package *p, FileList *l, uint64_t);
+static void find_existing_files(Package *p, FileList *l,
+ PackageEntryFileTypeList *file_type_list);
static void condense_file_list(Package *p, FileList *l);
@@ -92,11 +94,12 @@ CommandList *build_command_list(Options *op, Package *p)
FileList *l;
CommandList *c;
int i, cmd;
- uint64_t installable_files;
+ PackageEntryFileTypeList installable_files;
+ PackageEntryFileTypeList tmp_installable_files;
char *tmp;
- installable_files = get_installable_file_mask(op);
-
+ get_installable_file_type_list(op, &installable_files);
+
l = (FileList *) nvalloc(sizeof(FileList));
c = (CommandList *) nvalloc(sizeof(CommandList));
@@ -205,10 +208,12 @@ CommandList *build_command_list(Options *op, Package *p)
/*
* find any existing files that clash with what we're going to
* install
- * DON'T include files of type FILE_TYPE_NEWSYM
*/
-
- find_existing_files(p, l, installable_files | FILE_TYPE_SYMLINK);
+
+ tmp_installable_files = installable_files;
+ add_symlinks_to_file_type_list(&tmp_installable_files);
+
+ find_existing_files(p, l, &tmp_installable_files);
/* condense the file list */
@@ -244,14 +249,14 @@ CommandList *build_command_list(Options *op, Package *p)
*/
if (op->selinux_enabled &&
(op->utils[EXECSTACK] != NULL) &&
- (p->entries[i].flags & FILE_TYPE_SHARED_LIB)) {
+ (p->entries[i].caps.is_shared_lib)) {
tmp = nvstrcat(op->utils[EXECSTACK], " -c ",
p->entries[i].dst, NULL);
} else {
tmp = NULL;
}
- if (p->entries[i].flags & installable_files) {
+ if (installable_files.types[p->entries[i].type]) {
add_command(c, INSTALL_CMD,
p->entries[i].file,
p->entries[i].dst,
@@ -266,14 +271,14 @@ CommandList *build_command_list(Options *op, Package *p)
* based on templates earlier.
*/
- if ((p->entries[i].flags & FILE_TYPE_LIBGL_LA) ||
- (p->entries[i].flags & FILE_TYPE_DOT_DESKTOP)) {
+ if ((p->entries[i].type == FILE_TYPE_LIBGL_LA) ||
+ (p->entries[i].type == FILE_TYPE_DOT_DESKTOP)) {
add_command(c, DELETE_CMD,
p->entries[i].file);
}
if (op->selinux_enabled &&
- (p->entries[i].flags & FILE_TYPE_SHARED_LIB)) {
+ (p->entries[i].caps.is_shared_lib)) {
tmp = nvstrcat(op->utils[CHCON], " -t ", op->selinux_chcon_type,
" ", p->entries[i].dst, NULL);
add_command(c, RUN_CMD, tmp);
@@ -285,11 +290,10 @@ CommandList *build_command_list(Options *op, Package *p)
/* create any needed symbolic links */
for (i = 0; i < p->num_entries; i++) {
- if ((p->entries[i].flags & FILE_TYPE_SYMLINK) ||
- (p->entries[i].flags & FILE_TYPE_NEWSYM)) {
+ if (p->entries[i].caps.is_symlink) {
/* if it's a NEWSYM and the file already exists, don't add a command
* for it */
- if (p->entries[i].flags & FILE_TYPE_NEWSYM) {
+ if (p->entries[i].type == FILE_TYPE_XMODULE_NEWSYM) {
struct stat buf;
if(!stat(p->entries[i].dst, &buf) || errno != ENOENT) {
ui_expert(op, "Not creating a symlink from %s to %s "
@@ -308,7 +312,7 @@ CommandList *build_command_list(Options *op, Package *p)
/* find any commands we should run */
for (i = 0; i < p->num_entries; i++) {
- if (p->entries[i].flags & FILE_TYPE_KERNEL_MODULE_CMD) {
+ if (p->entries[i].type == FILE_TYPE_KERNEL_MODULE_CMD) {
add_command(c, RUN_CMD, p->entries[i].file, NULL, 0);
}
}
@@ -322,7 +326,7 @@ CommandList *build_command_list(Options *op, Package *p)
if (op->no_abi_note) {
for (i = 0; i < p->num_entries; i++) {
- if (p->entries[i].flags & FILE_TYPE_OPENGL_LIB) {
+ if (p->entries[i].type == FILE_TYPE_OPENGL_LIB) {
tmp = nvstrcat(op->utils[OBJCOPY],
" --remove-section=.note.ABI-tag ",
p->entries[i].dst,
@@ -728,13 +732,14 @@ static void find_conflicting_kernel_modules(Options *op,
* FileList.
*/
-static void find_existing_files(Package *p, FileList *l, uint64_t flag)
+static void find_existing_files(Package *p, FileList *l,
+ PackageEntryFileTypeList *file_type_list)
{
int i;
struct stat stat_buf;
for (i = 0; i < p->num_entries; i++) {
- if (p->entries[i].flags & flag) {
+ if (file_type_list->types[p->entries[i].type]) {
if (lstat(p->entries[i].dst, &stat_buf) == 0) {
add_file_to_list(NULL, p->entries[i].dst, l);
}
diff --git a/common-utils/common-utils.c b/common-utils/common-utils.c
index a8ee75a..a11d996 100644
--- a/common-utils/common-utils.c
+++ b/common-utils/common-utils.c
@@ -200,6 +200,44 @@ char *nvstrtolower(char *s)
/*
+ * nvstrtoupper() - convert the given string to uppercase.
+ */
+
+char *nvstrtoupper(char *s)
+{
+ char *start = s;
+
+ if (s == NULL) return NULL;
+
+ while (*s) {
+ *s = toupper(*s);
+ s++;
+ }
+
+ return start;
+
+} /* nvstrtoupper() */
+
+
+
+/*
+ * nvasprintf() - implementation of asprintf() that checks return values; if an
+ * error occurs, an error is printed to stderr and exit is called.
+ * -- this function will only return on success.
+ */
+char *nvasprintf(const char *fmt, ...)
+{
+ char *str;
+
+ NV_VSNPRINTF(str, fmt);
+
+ return str;
+
+} /* nvasprintf() */
+
+
+
+/*
* nvfree() - frees memory allocated with nvalloc(), provided
* a non-NULL pointer is provided.
*/
@@ -646,3 +684,12 @@ char *fget_next_line(FILE *fp, int *eof)
return NULL; /* should never get here */
}
+
+char *nvstrchrnul(char *s, int c)
+{
+ char *result = strchr(s, c);
+ if (!result) {
+ return (s + strlen(s));
+ }
+ return result;
+}
diff --git a/common-utils/common-utils.h b/common-utils/common-utils.h
index 626fd1b..7e2838f 100644
--- a/common-utils/common-utils.h
+++ b/common-utils/common-utils.h
@@ -40,6 +40,18 @@
#define VERBOSITY_DEFAULT VERBOSITY_ERROR
+/*
+ * Define a printf format attribute macro. This definition is based on the one
+ * from Xfuncproto.h, available in the 'xproto' package at
+ * http://xorg.freedesktop.org/releases/individual/proto/
+ */
+
+#if defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 203)
+# define NV_ATTRIBUTE_PRINTF(x,y) __attribute__((__format__(__printf__,x,y)))
+#else /* not gcc >= 2.3 */
+# define NV_ATTRIBUTE_PRINTF(x,y)
+#endif
+
typedef struct {
char **t; /* the text rows */
int n; /* number of rows */
@@ -52,6 +64,9 @@ void *nvrealloc(void *ptr, size_t size);
char *nvstrdup(const char *s);
char *nvstrndup(const char *s, size_t n);
char *nvstrtolower(char *s);
+char *nvstrtoupper(char *s);
+char *nvstrchrnul(char *s, int c);
+char *nvasprintf(const char *fmt, ...) NV_ATTRIBUTE_PRINTF(1, 2);
void nvfree(void *s);
char *tilde_expansion(const char *str);
@@ -66,11 +81,11 @@ void nv_free_text_rows(TextRows *t);
void reset_current_terminal_width(unsigned short new_val);
void silence_fmt(int val);
-void fmtout(const char *fmt, ...);
-void fmtoutp(const char *prefix, const char *fmt, ...);
-void fmterr(const char *fmt, ...);
-void fmtwarn(const char *fmt, ...);
-void fmt(FILE *stream, const char *prefix, const char *fmt, ...);
+void fmtout(const char *fmt, ...) NV_ATTRIBUTE_PRINTF(1, 2);
+void fmtoutp(const char *prefix, const char *fmt, ...) NV_ATTRIBUTE_PRINTF(2, 3);
+void fmterr(const char *fmt, ...) NV_ATTRIBUTE_PRINTF(1, 2);
+void fmtwarn(const char *fmt, ...) NV_ATTRIBUTE_PRINTF(1, 2);
+void fmt(FILE *stream, const char *prefix, const char *fmt, ...) NV_ATTRIBUTE_PRINTF(3, 4);
char *fget_next_line(FILE *fp, int *eof);
@@ -99,9 +114,9 @@ do { \
va_list ap; \
int len, current_len = NV_FMT_BUF_LEN; \
\
- (buf) = malloc(current_len); \
- \
while (1) { \
+ (buf) = nvalloc(current_len); \
+ \
va_start(ap, fmt); \
len = vsnprintf((buf), current_len, (fmt), ap); \
va_end(ap); \
@@ -113,8 +128,8 @@ do { \
} else { \
current_len += NV_FMT_BUF_LEN; \
} \
- free(buf); \
- (buf) = malloc(current_len); \
+ \
+ nvfree(buf); \
} \
} \
} while (0)
diff --git a/dist-files.mk b/dist-files.mk
index d50c576..b08a951 100644
--- a/dist-files.mk
+++ b/dist-files.mk
@@ -43,6 +43,7 @@ SRC += stream-ui.c
SRC += update.c
SRC += user-interface.c
SRC += sanity.c
+SRC += manifest.c
DIST_FILES := $(SRC)
@@ -61,6 +62,7 @@ DIST_FILES += snarf-internal.h
DIST_FILES += snarf.h
DIST_FILES += update.h
DIST_FILES += user-interface.h
+DIST_FILES += manifest.h
DIST_FILES += COPYING
DIST_FILES += README
diff --git a/files.c b/files.c
index 23cd757..58ef3d2 100644
--- a/files.c
+++ b/files.c
@@ -387,14 +387,14 @@ void select_tls_class(Options *op, Package *p)
/*
* tls libraries will not run on this system; just install the
* classic OpenGL libraries: clear the FILE_TYPE of any
- * FILE_CLASS_NEW_TLS package entries.
+ * FILE_TLS_CLASS_NEW package entries.
*/
ui_log(op, "Installing classic TLS OpenGL libraries.");
for (i = 0; i < p->num_entries; i++) {
- if ((p->entries[i].flags & FILE_CLASS_NEW_TLS) &&
- (p->entries[i].flags & FILE_CLASS_NATIVE)) {
+ if ((p->entries[i].tls_class == FILE_TLS_CLASS_NEW) &&
+ (p->entries[i].compat_arch == FILE_COMPAT_ARCH_NATIVE)) {
/*
* XXX don't try to free the destination string for
* these invalidated TLS libraries; this prevents
@@ -402,7 +402,7 @@ void select_tls_class(Options *op, Package *p)
* I've been unable to reproduce/root cause.
*/
/* nvfree(p->entries[i].dst); */
- p->entries[i].flags &= ~FILE_TYPE_MASK;
+ p->entries[i].type = FILE_TYPE_NONE;
p->entries[i].dst = NULL;
}
}
@@ -432,14 +432,14 @@ void select_tls_class(Options *op, Package *p)
/*
* 32bit tls libraries will not run on this system; just
* install the classic OpenGL libraries: clear the FILE_TYPE
- * of any FILE_CLASS_NEW_TLS_32 package entries.
+ * of any tls_class==NEW && compat_arch==COMPAT32 package entries.
*/
ui_log(op, "Installing classic TLS 32bit OpenGL libraries.");
for (i = 0; i < p->num_entries; i++) {
- if ((p->entries[i].flags & FILE_CLASS_NEW_TLS) &&
- (p->entries[i].flags & FILE_CLASS_COMPAT32)) {
+ if ((p->entries[i].tls_class == FILE_TLS_CLASS_NEW) &&
+ (p->entries[i].compat_arch == FILE_COMPAT_ARCH_COMPAT32)) {
/*
* XXX don't try to free the destination string for
* these invalidated TLS libraries; this prevents
@@ -447,7 +447,7 @@ void select_tls_class(Options *op, Package *p)
* I've been unable to reproduce/root cause.
*/
/* nvfree(p->entries[i].dst); */
- p->entries[i].flags &= ~FILE_TYPE_MASK;
+ p->entries[i].type = FILE_TYPE_NONE;
p->entries[i].dst = NULL;
}
}
@@ -489,7 +489,7 @@ int set_destinations(Options *op, Package *p)
for (i = 0; i < p->num_entries; i++) {
- switch (p->entries[i].flags & FILE_TYPE_MASK) {
+ switch (p->entries[i].type) {
case FILE_TYPE_KERNEL_MODULE_CMD:
/* we don't install kernel module commands */
@@ -509,7 +509,7 @@ int set_destinations(Options *op, Package *p)
case FILE_TYPE_OPENGL_LIB:
case FILE_TYPE_OPENGL_SYMLINK:
- if (p->entries[i].flags & FILE_CLASS_COMPAT32) {
+ if (p->entries[i].compat_arch == FILE_COMPAT_ARCH_COMPAT32) {
prefix = op->compat32_prefix;
dir = op->compat32_libdir;
} else {
@@ -521,7 +521,7 @@ int set_destinations(Options *op, Package *p)
case FILE_TYPE_VDPAU_LIB:
case FILE_TYPE_VDPAU_SYMLINK:
- if (p->entries[i].flags & FILE_CLASS_COMPAT32) {
+ if (p->entries[i].compat_arch == FILE_COMPAT_ARCH_COMPAT32) {
prefix = op->compat32_prefix;
dir = op->compat32_libdir;
} else {
@@ -533,7 +533,7 @@ int set_destinations(Options *op, Package *p)
case FILE_TYPE_CUDA_LIB:
case FILE_TYPE_CUDA_SYMLINK:
- if (p->entries[i].flags & FILE_CLASS_COMPAT32) {
+ if (p->entries[i].compat_arch == FILE_COMPAT_ARCH_COMPAT32) {
prefix = op->compat32_prefix;
dir = op->compat32_libdir;
} else {
@@ -568,7 +568,7 @@ int set_destinations(Options *op, Package *p)
case FILE_TYPE_TLS_LIB:
case FILE_TYPE_TLS_SYMLINK:
- if (p->entries[i].flags & FILE_CLASS_COMPAT32) {
+ if (p->entries[i].compat_arch == FILE_COMPAT_ARCH_COMPAT32) {
prefix = op->compat32_prefix;
dir = op->compat32_libdir;
} else {
@@ -586,7 +586,7 @@ int set_destinations(Options *op, Package *p)
break;
case FILE_TYPE_LIBGL_LA:
- if (p->entries[i].flags & FILE_CLASS_COMPAT32) {
+ if (p->entries[i].compat_arch == FILE_COMPAT_ARCH_COMPAT32) {
prefix = op->compat32_prefix;
dir = op->compat32_libdir;
} else {
@@ -597,8 +597,8 @@ int set_destinations(Options *op, Package *p)
break;
case FILE_TYPE_NVCUVID_LIB:
- case FILE_TYPE_NVCUVID_SYMLINK:
- if (p->entries[i].flags & FILE_CLASS_COMPAT32) {
+ case FILE_TYPE_NVCUVID_LIB_SYMLINK:
+ if (p->entries[i].compat_arch == FILE_COMPAT_ARCH_COMPAT32) {
prefix = op->compat32_prefix;
dir = op->compat32_libdir;
} else {
@@ -609,8 +609,8 @@ int set_destinations(Options *op, Package *p)
break;
case FILE_TYPE_ENCODEAPI_LIB:
- case FILE_TYPE_ENCODEAPI_SYMLINK:
- if (p->entries[i].flags & FILE_CLASS_COMPAT32) {
+ case FILE_TYPE_ENCODEAPI_LIB_SYMLINK:
+ if (p->entries[i].compat_arch == FILE_COMPAT_ARCH_COMPAT32) {
prefix = op->compat32_prefix;
dir = op->compat32_libdir;
} else {
@@ -621,7 +621,7 @@ int set_destinations(Options *op, Package *p)
break;
case FILE_TYPE_VGX_LIB:
- case FILE_TYPE_VGX_SYMLINK:
+ case FILE_TYPE_VGX_LIB_SYMLINK:
prefix = op->opengl_prefix;
dir = op->opengl_libdir;
path = "";
@@ -646,11 +646,17 @@ int set_destinations(Options *op, Package *p)
break;
case FILE_TYPE_MANPAGE:
+ case FILE_TYPE_NVIDIA_MODPROBE_MANPAGE:
prefix = op->documentation_prefix;
dir = op->documentation_mandir;
path = p->entries[i].path;
break;
+ case FILE_TYPE_APPLICATION_PROFILE:
+ prefix = op->application_profile_path;
+ dir = path = "";
+ break;
+
case FILE_TYPE_UTILITY_BINARY:
case FILE_TYPE_UTILITY_BIN_SYMLINK:
prefix = op->utility_prefix;
@@ -679,7 +685,13 @@ int set_destinations(Options *op, Package *p)
continue;
+ case FILE_TYPE_MODULE_SIGNING_KEY:
+ prefix = op->module_signing_key_path;
+ dir = path = "";
+ break;
+
case FILE_TYPE_EXPLICIT_PATH:
+ case FILE_TYPE_NVIDIA_MODPROBE:
prefix = p->entries[i].path;
dir = path = "";
break;
@@ -706,7 +718,7 @@ int set_destinations(Options *op, Package *p)
collapse_multiple_slashes(p->entries[i].dst);
#if defined(NV_X86_64)
- if ((p->entries[i].flags & FILE_CLASS_COMPAT32) &&
+ if ((p->entries[i].compat_arch == FILE_COMPAT_ARCH_COMPAT32) &&
(op->compat32_chroot != NULL)) {
/*
@@ -995,6 +1007,7 @@ int add_kernel_module_to_package(Options *op, Package *p)
NULL, /* target */
dst,
FILE_TYPE_KERNEL_MODULE,
+ FILE_TLS_CLASS_NONE,
0644);
return TRUE;
@@ -1004,9 +1017,8 @@ int add_kernel_module_to_package(Options *op, Package *p)
/*
- * remove_non_kernel_module_files_from_package() - clear the
- * FILE_TYPE_MASK bits for each package entry that is not of type
- * FILE_TYPE_KERNEL_MODULE or FILE_TYPE_KERNEL_MODULE_SRC
+ * Clear the file type for each package entry that is not type
+ * FILE_TYPE_KERNEL_MODULE or FILE_TYPE_KERNEL_MODULE_SRC.
*/
void remove_non_kernel_module_files_from_package(Options *op, Package *p)
@@ -1014,28 +1026,26 @@ void remove_non_kernel_module_files_from_package(Options *op, Package *p)
int i;
for (i = 0; i < p->num_entries; i++) {
- uint64_t flags = p->entries[i].flags & FILE_TYPE_MASK;
- if ((flags != FILE_TYPE_KERNEL_MODULE) &&
- (flags != FILE_TYPE_KERNEL_MODULE_CMD) &&
- (flags != FILE_TYPE_KERNEL_MODULE_SRC))
- p->entries[i].flags &= ~FILE_TYPE_MASK;
+ if ((p->entries[i].type != FILE_TYPE_KERNEL_MODULE) &&
+ (p->entries[i].type != FILE_TYPE_KERNEL_MODULE_CMD) &&
+ (p->entries[i].type != FILE_TYPE_KERNEL_MODULE_SRC)) {
+ p->entries[i].type = FILE_TYPE_NONE;
+ }
}
-
-} /* remove_non_kernel_module_files_from_package() */
+}
/*
- * clear the FILE_TYPE_MASK bits for each package entry that is not of
- * type FILE_TYPE_OPENGL_FILE
+ * Clear the file type for each package entry that is not type
+ * FILE_TYPE_OPENGL_FILE.
*/
void remove_opengl_files_from_package(Options *op, Package *p)
{
int i;
for (i = 0; i < p->num_entries; i++) {
- uint64_t flags = p->entries[i].flags & FILE_TYPE_MASK;
- if (flags & FILE_TYPE_OPENGL_FILE) {
- p->entries[i].flags &= ~FILE_TYPE_MASK;
+ if (p->entries[i].caps.is_opengl) {
+ p->entries[i].type = FILE_TYPE_NONE;
}
}
}
@@ -1572,7 +1582,7 @@ int copy_directory_contents(Options *op, const char *src, const char *dst)
int pack_precompiled_kernel_interface(Options *op, Package *p)
{
- char *cmd, time_str[256], *proc_version_string;
+ char *cmd, time_str[256], *proc_version_string, *suffix, *file, *newfile;
char *result, *descr;
time_t t;
struct utsname buf;
@@ -1603,12 +1613,13 @@ int pack_precompiled_kernel_interface(Options *op, Package *p)
/* build the mkprecompiled command */
+ suffix = nvstrcat("-", p->version, ".", time_str, NULL);
+
cmd = nvstrcat("./mkprecompiled --interface=",
p->kernel_module_build_directory, "/",
PRECOMPILED_KERNEL_INTERFACE_FILENAME,
" --output=", p->precompiled_kernel_interface_directory,
- "/", PRECOMPILED_KERNEL_INTERFACE_FILENAME,
- "-", p->version, ".", time_str,
+ "/", PRECOMPILED_KERNEL_INTERFACE_FILENAME, suffix,
" --description=\"", descr, "\"",
" --proc-version=\"", proc_version_string, "\"",
" --version=", p->version, NULL);
@@ -1620,15 +1631,41 @@ int pack_precompiled_kernel_interface(Options *op, Package *p)
nvfree(cmd);
nvfree(proc_version_string);
nvfree(descr);
+
+ /* pack the detached signature and checksum, if they exist */
+
+ file = nvstrcat(p->kernel_module_build_directory, "/",
+ DETACHED_SIGNATURE_FILENAME, NULL);
+
+ if (access(file, R_OK) == 0) {
+ newfile = nvstrcat(p->precompiled_kernel_interface_directory, "/",
+ DETACHED_SIGNATURE_FILENAME, suffix, NULL);
+ rename(file, newfile);
+ nvfree(newfile);
+ }
+
+ nvfree(file);
+
+ file = nvstrcat(p->kernel_module_build_directory, "/",
+ KERNEL_MODULE_CHECKSUM_FILENAME, NULL);
+
+ if (access(file, R_OK) == 0) {
+ newfile = nvstrcat(p->precompiled_kernel_interface_directory, "/",
+ KERNEL_MODULE_CHECKSUM_FILENAME, suffix, NULL);
+ rename(file, newfile);
+ nvfree(newfile);
+ }
+
+ nvfree(file);
/* remove the old kernel interface file */
- cmd = nvstrcat(p->kernel_module_build_directory, "/",
- PRECOMPILED_KERNEL_INTERFACE_FILENAME, NULL);
+ file = nvstrcat(p->kernel_module_build_directory, "/",
+ PRECOMPILED_KERNEL_INTERFACE_FILENAME, NULL);
- unlink(cmd); /* XXX what to do if this fails? */
+ unlink(file); /* XXX what to do if this fails? */
- nvfree(cmd);
+ nvfree(file);
if (ret != 0) {
ui_error(op, "Unable to package precompiled kernel interface: %s",
@@ -1652,7 +1689,7 @@ int pack_precompiled_kernel_interface(Options *op, Package *p)
* 'replace'.
*/
-static char *nv_strreplace(char *src, char *orig, char *replace)
+char *nv_strreplace(char *src, char *orig, char *replace)
{
char *prev_s, *end_s, *s;
char *d, *dst;
@@ -1886,9 +1923,9 @@ void process_libGL_la_files(Options *op, Package *p)
NVIDIA_INSTALLER_VERSION, NULL);
for (i = 0; i < package_num_entries; i++) {
- if ((p->entries[i].flags & FILE_TYPE_LIBGL_LA)) {
+ if ((p->entries[i].type == FILE_TYPE_LIBGL_LA)) {
- if (p->entries[i].flags & FILE_CLASS_COMPAT32) {
+ if (p->entries[i].compat_arch == FILE_COMPAT_ARCH_COMPAT32) {
replacements[0] = nvstrcat(op->compat32_prefix,
"/", op->compat32_libdir, NULL);
} else {
@@ -1898,7 +1935,7 @@ void process_libGL_la_files(Options *op, Package *p)
/* invalidate the template file */
- p->entries[i].flags &= ~FILE_TYPE_MASK;
+ p->entries[i].type = FILE_TYPE_NONE;
p->entries[i].dst = NULL;
tmpfile = process_template_file(op, &p->entries[i], tokens,
@@ -1922,8 +1959,8 @@ void process_libGL_la_files(Options *op, Package *p)
nvstrdup(p->entries[i].name),
NULL, /* target */
NULL, /* dst */
- ((p->entries[i].flags & FILE_CLASS_MASK) |
- FILE_TYPE_LIBGL_LA),
+ FILE_TYPE_LIBGL_LA,
+ p->entries[i].tls_class,
p->entries[i].mode);
}
@@ -1961,11 +1998,11 @@ void process_dot_desktop_files(Options *op, Package *p)
collapse_multiple_slashes(replacements[0]);
for (i = 0; i < package_num_entries; i++) {
- if ((p->entries[i].flags & FILE_TYPE_DOT_DESKTOP)) {
+ if ((p->entries[i].type == FILE_TYPE_DOT_DESKTOP)) {
/* invalidate the template file */
- p->entries[i].flags &= ~FILE_TYPE_MASK;
+ p->entries[i].type = FILE_TYPE_NONE;
p->entries[i].dst = NULL;
nvfree(replacements[1]);
@@ -1998,8 +2035,8 @@ void process_dot_desktop_files(Options *op, Package *p)
nvstrdup(p->entries[i].name),
NULL, /* target */
NULL, /* dst */
- ((p->entries[i].flags & FILE_CLASS_MASK) |
- FILE_TYPE_DOT_DESKTOP),
+ FILE_TYPE_DOT_DESKTOP,
+ p->entries[i].tls_class,
p->entries[i].mode);
}
}
@@ -2048,7 +2085,8 @@ void get_default_prefixes_and_paths(Options *op)
#if defined(NV_X86_64)
if ((op->distro == DEBIAN) ||
- (op->distro == UBUNTU)) {
+ (op->distro == UBUNTU) ||
+ (op->distro == ARCH)) {
default_libdir = DEBIAN_DEFAULT_64BIT_LIBDIR;
} else {
default_libdir = DEFAULT_64BIT_LIBDIR;
@@ -2087,7 +2125,8 @@ void get_default_prefixes_and_paths(Options *op)
if (!op->compat32_libdir) {
if ((op->distro == UBUNTU) ||
- (op->distro == GENTOO)) {
+ (op->distro == GENTOO) ||
+ (op->distro == ARCH)) {
op->compat32_libdir = UBUNTU_DEFAULT_COMPAT32_LIBDIR;
} else {
op->compat32_libdir = DEFAULT_LIBDIR;
@@ -2134,8 +2173,14 @@ void get_default_prefixes_and_paths(Options *op)
if (!op->documentation_mandir)
op->documentation_mandir = DEFAULT_MANDIR;
+ if (!op->application_profile_path)
+ op->application_profile_path = DEFAULT_APPLICATION_PROFILE_PATH;
+
if (!op->kernel_module_src_prefix)
op->kernel_module_src_prefix = DEFAULT_KERNEL_MODULE_SRC_PREFIX;
+
+ if (!op->module_signing_key_path)
+ op->module_signing_key_path = DEFAULT_MODULE_SIGNING_KEY_PATH;
/* kernel_module_src_dir's default value is set in set_destinations() */
} /* get_default_prefixes_and_paths() */
@@ -2421,3 +2466,70 @@ static void get_x_library_and_module_paths(Options *op)
}
} /* get_x_library_and_module_paths() */
+
+
+
+/*
+ * get_filename() - Prompt the user for the path to a file. If no file exists
+ * at the given path, keep reprompting until a valid path to a regular file or
+ * symbolic link is given. This is just a thin wrapper around ui_get_input().
+ */
+char *get_filename(Options *op, const char *def, const char *fmt, ...)
+{
+ struct stat stat_buf;
+ char *file = NULL;
+
+ /* XXX This function should never be called if op->no_questions is set,
+ * but just in case that happens by accident, do something besides looping
+ * infinitely if def is a filename that doesn't exist. */
+ if (op->no_questions) {
+ return nvstrdup(def);
+ }
+
+ file = ui_get_input(op, file ? file : def, fmt);
+
+ while (stat(file, &stat_buf) == -1 ||
+ !(S_ISREG(stat_buf.st_mode) || S_ISLNK(stat_buf.st_mode))) {
+ char *oldfile = file;
+
+ ui_message(op, "File \"%s\" does not exist, or is not a regular "
+ "file. Please enter another filename.", file);
+
+ file = ui_get_input(op, oldfile ? oldfile : def, fmt);
+ nvfree(oldfile);
+ }
+
+ return file;
+} /* get_filename() */
+
+
+
+/*
+ * secure_delete() - Securely delete a file, using `shred -u`. If `shred` isn't
+ * found, fall back to just unlinking, but print a warning message.
+ */
+int secure_delete(Options *op, const char *file)
+{
+ char *cmd;
+
+ cmd = find_system_util("shred");
+
+ if (cmd) {
+ int ret;
+ char *cmdline = nvstrcat(cmd, " -u \"", file, "\"", NULL);
+
+ ret = run_command(op, cmdline, NULL, FALSE, 0, TRUE);
+ log_printf(op, NULL, "%s: %s", cmdline, ret == 0 ? "" : "failed!");
+
+ nvfree(cmd);
+ nvfree(cmdline);
+
+ return ret == 0;
+ } else {
+ ui_warn(op, "`shred` was not found on the system. The file %s will "
+ "be deleted, but not securely. It may be possible to recover "
+ "the file after deletion.", file);
+ unlink(file);
+ return FALSE;
+ }
+} /* secure_delete() */
diff --git a/files.h b/files.h
index 18e5e1e..a7f0d16 100644
--- a/files.h
+++ b/files.h
@@ -61,5 +61,8 @@ void process_libGL_la_files(Options *op, Package *p);
void process_dot_desktop_files(Options *op, Package *p);
int set_security_context(Options *op, const char *filename);
void get_default_prefixes_and_paths(Options *op);
+char *nv_strreplace(char *src, char *orig, char *replace);
+char *get_filename(Options *op, const char *def, const char *fmt, ...) NV_ATTRIBUTE_PRINTF(3, 4);
+int secure_delete(Options *op, const char *file);
#endif /* __NVIDIA_INSTALLER_FILES_H__ */
diff --git a/install-from-cwd.c b/install-from-cwd.c
index a7b040c..7fe719d 100644
--- a/install-from-cwd.c
+++ b/install-from-cwd.c
@@ -45,6 +45,12 @@
#include "files.h"
#include "misc.h"
#include "sanity.h"
+#include "manifest.h"
+
+/* default names for generated signing keys */
+
+#define SECKEY_NAME "tmp.key"
+#define PUBKEY_NAME "tmp.der"
/* local prototypes */
@@ -52,6 +58,7 @@
static Package *parse_manifest(Options *op);
static int install_kernel_module(Options *op, Package *p);
static void free_package(Package *p);
+static int assisted_module_signing(Options *op, Package *p);
/*
@@ -140,9 +147,11 @@ int install_from_cwd(Options *op)
if (!op->no_kernel_module) {
/* Offer the DKMS option if DKMS exists and the kernel module sources
- * will be installed somewhere */
+ * will be installed somewhere. Don't offer DKMS as an option if module
+ * signing was requested. */
- if (find_system_util("dkms") && !op->no_kernel_module_source) {
+ if (find_system_util("dkms") && !op->no_kernel_module_source &&
+ !(op->module_signing_secret_key && op->module_signing_public_key)) {
op->dkms = ui_yes_no(op, op->dkms,
"Would you like to register the kernel module "
"sources with DKMS? This will allow DKMS to "
@@ -378,6 +387,8 @@ int install_from_cwd(Options *op)
static int install_kernel_module(Options *op, Package *p)
{
+ PrecompiledInfo *precompiled_info;
+
/* determine where to install the kernel module */
if (!determine_kernel_module_installation_path(op)) return FALSE;
@@ -399,10 +410,10 @@ static int install_kernel_module(Options *op, Package *p)
* headers installed, so it's better to catch that earlier on.
*/
- if (find_precompiled_kernel_interface(op, p)) {
+ if ((precompiled_info = find_precompiled_kernel_interface(op, p))) {
/*
- * we have a prebuild kernel interface, so now link the kernel
+ * we have a prebuilt kernel interface, so now link the kernel
* interface with the binary portion of the kernel module.
*
* XXX if linking fails, maybe we should fall through and
@@ -411,7 +422,8 @@ static int install_kernel_module(Options *op, Package *p)
* abort.
*/
- if (!link_kernel_module(op, p)) return FALSE;
+ if (!link_kernel_module(op, p, p->kernel_module_build_directory,
+ precompiled_info)) return FALSE;
} else {
/*
@@ -441,6 +453,9 @@ static int install_kernel_module(Options *op, Package *p)
if (!build_kernel_module(op, p)) return FALSE;
}
+ /* Optionally sign the kernel module */
+ if (!assisted_module_signing(op, p)) return FALSE;
+
/*
* if we got this far, we have a complete kernel module; test it
* to be sure it's OK
@@ -692,84 +707,15 @@ static Package *parse_manifest (Options *op)
/* every file has a type field */
- p->entries[n].flags = 0x0;
+ p->entries[n].type = FILE_TYPE_NONE;
flag = read_next_word(c, &c);
if (!flag) goto invalid_manifest_file;
- if (strcmp(flag, "KERNEL_MODULE_SRC") == 0)
- p->entries[n].flags |= FILE_TYPE_KERNEL_MODULE_SRC;
- else if (strcmp(flag, "KERNEL_MODULE_CMD") == 0)
- p->entries[n].flags |= FILE_TYPE_KERNEL_MODULE_CMD;
- else if (strcmp(flag, "OPENGL_HEADER") == 0)
- p->entries[n].flags |= FILE_TYPE_OPENGL_HEADER;
- else if (strcmp(flag, "CUDA_ICD") == 0)
- p->entries[n].flags |= FILE_TYPE_CUDA_ICD;
- else if (strcmp(flag, "OPENGL_LIB") == 0)
- p->entries[n].flags |= FILE_TYPE_OPENGL_LIB;
- else if (strcmp(flag, "CUDA_LIB") == 0)
- p->entries[n].flags |= FILE_TYPE_CUDA_LIB;
- else if (strcmp(flag, "LIBGL_LA") == 0)
- p->entries[n].flags |= FILE_TYPE_LIBGL_LA;
- else if (strcmp(flag, "XLIB_STATIC_LIB") == 0)
- p->entries[n].flags |= FILE_TYPE_XLIB_STATIC_LIB;
- else if (strcmp(flag, "XLIB_SHARED_LIB") == 0)
- p->entries[n].flags |= FILE_TYPE_XLIB_SHARED_LIB;
- else if (strcmp(flag, "TLS_LIB") == 0)
- p->entries[n].flags |= FILE_TYPE_TLS_LIB;
- else if (strcmp(flag, "UTILITY_LIB") == 0)
- p->entries[n].flags |= FILE_TYPE_UTILITY_LIB;
- else if (strcmp(flag, "DOCUMENTATION") == 0)
- p->entries[n].flags |= FILE_TYPE_DOCUMENTATION;
- else if (strcmp(flag, "MANPAGE") == 0)
- p->entries[n].flags |= FILE_TYPE_MANPAGE;
- else if (strcmp(flag, "EXPLICIT_PATH") == 0)
- p->entries[n].flags |= FILE_TYPE_EXPLICIT_PATH;
- else if (strcmp(flag, "OPENGL_SYMLINK") == 0)
- p->entries[n].flags |= FILE_TYPE_OPENGL_SYMLINK;
- else if (strcmp(flag, "CUDA_SYMLINK") == 0)
- p->entries[n].flags |= FILE_TYPE_CUDA_SYMLINK;
- else if (strcmp(flag, "XLIB_SYMLINK") == 0)
- p->entries[n].flags |= FILE_TYPE_XLIB_SYMLINK;
- else if (strcmp(flag, "TLS_SYMLINK") == 0)
- p->entries[n].flags |= FILE_TYPE_TLS_SYMLINK;
- else if (strcmp(flag, "UTILITY_LIB_SYMLINK") == 0)
- p->entries[n].flags |= FILE_TYPE_UTILITY_LIB_SYMLINK;
- else if (strcmp(flag, "INSTALLER_BINARY") == 0)
- p->entries[n].flags |= FILE_TYPE_INSTALLER_BINARY;
- else if (strcmp(flag, "UTILITY_BINARY") == 0)
- p->entries[n].flags |= FILE_TYPE_UTILITY_BINARY;
- else if (strcmp(flag, "UTILITY_BIN_SYMLINK") == 0)
- p->entries[n].flags |= FILE_TYPE_UTILITY_BIN_SYMLINK;
- else if (strcmp(flag, "DOT_DESKTOP") == 0)
- p->entries[n].flags |= FILE_TYPE_DOT_DESKTOP;
- else if (strcmp(flag, "XMODULE_SHARED_LIB") == 0)
- p->entries[n].flags |= FILE_TYPE_XMODULE_SHARED_LIB;
- else if (strcmp(flag, "XMODULE_SYMLINK") == 0)
- p->entries[n].flags |= FILE_TYPE_XMODULE_SYMLINK;
- else if (strcmp(flag, "GLX_MODULE_SHARED_LIB") == 0)
- p->entries[n].flags |= FILE_TYPE_GLX_MODULE_SHARED_LIB;
- else if (strcmp(flag, "GLX_MODULE_SYMLINK") == 0)
- p->entries[n].flags |= FILE_TYPE_GLX_MODULE_SYMLINK;
- else if (strcmp(flag, "XMODULE_NEWSYM") == 0)
- p->entries[n].flags |= FILE_TYPE_XMODULE_NEWSYM;
- else if (strcmp(flag, "VDPAU_LIB") == 0)
- p->entries[n].flags |= FILE_TYPE_VDPAU_LIB;
- else if (strcmp(flag, "VDPAU_SYMLINK") == 0)
- p->entries[n].flags |= FILE_TYPE_VDPAU_SYMLINK;
- else if (strcmp(flag, "NVCUVID_LIB") == 0)
- p->entries[n].flags |= FILE_TYPE_NVCUVID_LIB;
- else if (strcmp(flag, "NVCUVID_LIB_SYMLINK") == 0)
- p->entries[n].flags |= FILE_TYPE_NVCUVID_SYMLINK;
- else if (strcmp(flag, "ENCODEAPI_LIB") == 0)
- p->entries[n].flags |= FILE_TYPE_ENCODEAPI_LIB;
- else if (strcmp(flag, "ENCODEAPI_LIB_SYMLINK") == 0)
- p->entries[n].flags |= FILE_TYPE_ENCODEAPI_SYMLINK;
- else if (strcmp(flag, "VGX_LIB") == 0)
- p->entries[n].flags |= FILE_TYPE_VGX_LIB;
- else if (strcmp(flag, "VGX_LIB_SYMLINK") == 0)
- p->entries[n].flags |= FILE_TYPE_VGX_SYMLINK;
- else {
+ p->entries[n].type = parse_manifest_file_type(flag,
+ &p->entries[n].caps);
+
+ if (p->entries[n].type == FILE_TYPE_NONE) {
nvfree(flag);
goto invalid_manifest_file;
}
@@ -778,14 +724,16 @@ static Package *parse_manifest (Options *op)
/* some libs/symlinks have an arch field */
- if (p->entries[n].flags & FILE_TYPE_HAVE_ARCH) {
+ p->entries[n].compat_arch = FILE_COMPAT_ARCH_NONE;
+
+ if (p->entries[n].caps.has_arch) {
flag = read_next_word(c, &c);
if (!flag) goto invalid_manifest_file;
if (strcmp(flag, "COMPAT32") == 0)
- p->entries[n].flags |= FILE_CLASS_COMPAT32;
+ p->entries[n].compat_arch = FILE_COMPAT_ARCH_COMPAT32;
else if (strcmp(flag, "NATIVE") == 0)
- p->entries[n].flags |= FILE_CLASS_NATIVE;
+ p->entries[n].compat_arch = FILE_COMPAT_ARCH_NATIVE;
else {
nvfree(flag);
goto invalid_manifest_file;
@@ -796,14 +744,16 @@ static Package *parse_manifest (Options *op)
/* some libs/symlinks have a class field */
- if (p->entries[n].flags & FILE_TYPE_HAVE_CLASS) {
+ p->entries[n].tls_class = FILE_TLS_CLASS_NONE;
+
+ if (p->entries[n].caps.has_tls_class) {
flag = read_next_word(c, &c);
if (!flag) goto invalid_manifest_file;
if (strcmp(flag, "CLASSIC") == 0)
- p->entries[n].flags |= FILE_CLASS_CLASSIC_TLS;
+ p->entries[n].tls_class = FILE_TLS_CLASS_CLASSIC;
else if (strcmp(flag, "NEW") == 0)
- p->entries[n].flags |= FILE_CLASS_NEW_TLS;
+ p->entries[n].tls_class = FILE_TLS_CLASS_NEW;
else {
nvfree(flag);
goto invalid_manifest_file;
@@ -814,16 +764,16 @@ static Package *parse_manifest (Options *op)
/* libs and documentation have a path field */
- if (p->entries[n].flags & FILE_TYPE_HAVE_PATH) {
+ if (p->entries[n].caps.has_path) {
p->entries[n].path = read_next_word(c, &c);
if (!p->entries[n].path) goto invalid_manifest_file;
} else {
p->entries[n].path = NULL;
}
- /* symlinks and newsyms have a target */
+ /* symlinks have a target */
- if (p->entries[n].flags & FILE_TYPE_HAVE_TARGET) {
+ if (p->entries[n].caps.is_symlink) {
p->entries[n].target = read_next_word(c, &c);
if (!p->entries[n].target) goto invalid_manifest_file;
} else {
@@ -900,7 +850,8 @@ void add_package_entry(Package *p,
char *name,
char *target,
char *dst,
- uint64_t flags,
+ PackageEntryFileType type,
+ PackageEntryFileTlsClass tls_class,
mode_t mode)
{
int n;
@@ -911,13 +862,17 @@ void add_package_entry(Package *p,
p->entries =
(PackageEntry *) nvrealloc(p->entries, (n + 1) * sizeof(PackageEntry));
- p->entries[n].file = file;
- p->entries[n].path = path;
- p->entries[n].name = name;
- p->entries[n].target = target;
- p->entries[n].dst = dst;
- p->entries[n].flags = flags;
- p->entries[n].mode = mode;
+ memset(&p->entries[n], 0, sizeof(PackageEntry));
+
+ p->entries[n].file = file;
+ p->entries[n].path = path;
+ p->entries[n].name = name;
+ p->entries[n].target = target;
+ p->entries[n].dst = dst;
+ p->entries[n].type = type;
+ p->entries[n].tls_class = tls_class;
+ p->entries[n].mode = mode;
+ p->entries[n].caps = get_file_type_capabilities(type);
if (stat(p->entries[n].file, &stat_buf) != -1) {
p->entries[n].inode = stat_buf.st_ino;
@@ -984,3 +939,261 @@ static void free_package(Package *p)
nvfree((char *) p);
} /* free_package() */
+
+
+
+/*
+ * assisted_module_signing() - Guide the user through the module signing process
+ */
+
+static int assisted_module_signing(Options *op, Package *p)
+{
+ int generate_keys = FALSE, do_sign = FALSE, secureboot;
+
+ secureboot = secure_boot_enabled();
+
+ if (secureboot < 0) {
+ ui_log(op, "Unable to determine if Secure Boot is enabled: %s",
+ strerror(-secureboot));
+ }
+
+ if (op->kernel_module_signed) {
+ /* The kernel module is already signed, e.g. from linking a precompiled
+ * interface + appending a detached signature */
+ return TRUE;
+ }
+
+ if (test_kernel_config_option(op, p, "CONFIG_DUMMY_OPTION") ==
+ KERNEL_CONFIG_OPTION_UNKNOWN) {
+ /* Unable to test kernel configuration options, possibly due to
+ * missing kernel headers. Since we might be installing on a
+ * system that doesn't have the headers, bail out. */
+ return TRUE;
+ }
+
+ if (op->module_signing_secret_key && op->module_signing_public_key) {
+ /* If the user supplied signing keys, sign the module, regardless of
+ * whether or not we actually need to. */
+ do_sign = TRUE;
+ } else if (test_kernel_config_option(op, p, "CONFIG_MODULE_SIG_FORCE") ==
+ KERNEL_CONFIG_OPTION_DEFINED) {
+ /* If CONFIG_MODULE_SIG_FORCE is set, we must sign. */
+ ui_message(op, "The target kernel has CONFIG_MODULE_SIG_FORCE set, "
+ "which means that it requires that kernel modules be "
+ "cryptographically signed by a trusted key.");
+ do_sign = TRUE;
+ } else if (secureboot != 1 && !op->expert) {
+ /* If this is a non-UEFI system, or a UEFI system with secure boot
+ * disabled, or we are unable to determine whether the system has
+ * secure boot enabled, bail out unless in expert mode. */
+ return TRUE;
+ } else if (test_kernel_config_option(op, p, "CONFIG_MODULE_SIG") ==
+ KERNEL_CONFIG_OPTION_DEFINED){
+ /* The kernel may or may not enforce module signatures; ask the user
+ * whether to sign the module. */
+
+ const char* sb_message = (secureboot == 1) ?
+ "This system also has UEFI Secure Boot "
+ "enabled; many distributions enforce "
+ "module signature verification on UEFI "
+ "systems when Secure Boot is enabled. " :
+ "";
+
+ do_sign = ui_yes_no(op, FALSE, "The target kernel has "
+ "CONFIG_MODULE_SIG set, which means that it "
+ "supports cryptographic signatures on kernel "
+ "modules. On some systems, the kernel may "
+ "refuse to load modules without a valid "
+ "signature from a trusted key. %sWould you like "
+ "to sign the NVIDIA kernel module?", sb_message);
+ }
+
+ if (!do_sign) {
+ /* The user explicitly opted out of module signing, or the kernel does
+ * not support module signatures, and no signing keys were provided;
+ * there is nothing for us to do here. */
+ return TRUE;
+ }
+
+ /* If we're missing either key, we need to get both from the user. */
+ if (!op->module_signing_secret_key || !op->module_signing_public_key) {
+ generate_keys = !ui_yes_no(op, FALSE, "Do you already have a key pair "
+ "which can be used to sign the NVIDIA "
+ "kernel module? Answer 'Yes' to use an "
+ "existing key pair, or 'No' to generate a "
+ "new key pair.");
+ if (generate_keys) {
+ char *cmdline;
+ int ret;
+
+ if (!op->utils[OPENSSL]) {
+ ui_error(op, "Unable to generate key pair: openssl not "
+ "found!");
+ return FALSE;
+ }
+
+ log_printf(op, NULL, "Generating key pair for module signing...");
+
+ /* Generate a key pair using openssl.
+ * XXX We assume that sign-file requires the X.509 certificate
+ * in DER format; if this changes in the future we will need
+ * to be able to accommodate the actual required format. */
+
+ cmdline = nvstrcat("cd ", p->kernel_module_build_directory, "; ",
+ op->utils[OPENSSL], " req -new -x509 -newkey "
+ "rsa:2048 -days 7300 -nodes -sha256 -subj "
+ "\"/CN=nvidia-installer generated signing key/\""
+ " -keyout " SECKEY_NAME " -outform DER -out "
+ PUBKEY_NAME, NULL);
+
+ ret = run_command(op, cmdline, NULL, TRUE, 8, TRUE);
+
+ nvfree(cmdline);
+
+ if (ret != 0) {
+ ui_error(op, "Failed to generate key pair!");
+ return FALSE;
+ }
+
+ log_printf(op, NULL, "Signing keys generated successfully.");
+
+ /* Set the signing keys to the newly generated pair. The paths
+ * are relative to p->kernel_module_build_directory, since we
+ * cd to it before signing the module. */
+ op->module_signing_secret_key = SECKEY_NAME;
+ op->module_signing_public_key = PUBKEY_NAME;
+ } else {
+ /* The user already has keys; prompt for their locations. */
+ op->module_signing_secret_key =
+ get_filename(op, op->module_signing_secret_key,
+ "Please provide the path to the private key");
+ op->module_signing_public_key =
+ get_filename(op, op->module_signing_public_key,
+ "Please provide the path to the public key");
+ }
+ }
+
+ /* Now that we have keys (user-supplied or installer-generated),
+ * sign the kernel module which we built earlier. */
+ if (!sign_kernel_module(op, p->kernel_module_build_directory, TRUE)) {
+ return FALSE;
+ }
+
+ if (generate_keys) {
+
+ /* If keys were generated, we should install the verification cert
+ * so that the user can make the kernel trust it, and either delete
+ * or install the private signing key. */
+ char *file, *name, *result = NULL, *fingerprint, *cmdline;
+ char short_fingerprint[9];
+ int ret, delete_secret_key;
+
+ delete_secret_key = ui_yes_no(op, TRUE, "The NVIDIA kernel module was "
+ "successfully signed with a newly "
+ "generated key pair. Would you like to "
+ "delete the private signing key?");
+
+ /* Get the fingerprint of the X.509 certificate. We already used
+ openssl to create a keypair at this point, so we know we have it;
+ otherwise, we would have already returned by now. */
+ cmdline = nvstrcat(op->utils[OPENSSL], " x509 -noout -fingerprint ",
+ "-inform DER -in ", p->kernel_module_build_directory,
+ "/"PUBKEY_NAME, NULL);
+ ret = run_command(op, cmdline, &result, FALSE, 0, FALSE);
+ nvfree(cmdline);
+
+ /* Format: "SHA1 Fingerprint=00:00:00:00:..." */
+ fingerprint = strchr(result, '=') + 1;
+
+ if (ret != 0 || !fingerprint || strlen(fingerprint) < 40) {
+ char *sha1sum = find_system_util("sha1sum");
+
+ if (sha1sum) {
+ /* the openssl command failed, or we parsed its output
+ * incorrectly; try to get a sha1sum of the DER certificate */
+ cmdline = nvstrcat(sha1sum, p->kernel_module_build_directory,
+ "/"PUBKEY_NAME, NULL);
+ ret = run_command(op, cmdline, &result, FALSE, 0, FALSE);
+ nvfree(sha1sum);
+ nvfree(cmdline);
+
+ fingerprint = result;
+ }
+
+ if (!sha1sum || ret != 0 || !fingerprint ||
+ strlen(fingerprint) < 40) {
+ /* Unable to determine fingerprint */
+ fingerprint = "UNKNOWN";
+ } else {
+ char *end = strchr(fingerprint, ' ');
+ *end = '\0';
+ }
+ } else {
+ /* Remove any ':' characters from fingerprint and truncate */
+ char *tmp = nv_strreplace(fingerprint, ":", "");
+ strncpy(short_fingerprint, tmp, sizeof(fingerprint));
+ nvfree(tmp);
+ }
+ short_fingerprint[sizeof(short_fingerprint) - 1] = '\0';
+
+ /* Add the public key to the package */
+ file = nvstrcat(p->kernel_module_build_directory, "/"PUBKEY_NAME, NULL);
+
+ /* XXX name will be leaked when freeing package */
+ name = nvstrcat("nvidia-modsign-crt-", short_fingerprint, ".der", NULL);
+
+ add_package_entry(p,
+ file,
+ NULL, /* path */
+ name,
+ NULL, /* target */
+ NULL, /* dst */
+ FILE_TYPE_MODULE_SIGNING_KEY,
+ FILE_TLS_CLASS_NONE,
+ 0444);
+
+ ui_message(op, "An X.509 certificate containing the public signing "
+ "key will be installed to %s/%s. The SHA1 fingerprint of "
+ "this certificate is: %s.\n\nThis certificate must be "
+ "added to a key database which is trusted by your kernel "
+ "in order for the kernel to be able to verify the module "
+ "signature.", op->module_signing_key_path, name,
+ fingerprint);
+
+ nvfree(result);
+
+ /* Delete or install the private key */
+ file = nvstrcat(p->kernel_module_build_directory, "/"SECKEY_NAME, NULL);
+
+ if (delete_secret_key) {
+ secure_delete(op, file);
+ } else {
+
+ /* Add the private key to the package */
+
+ name = nvstrcat("nvidia-modsign-key-", short_fingerprint, ".key",
+ NULL);
+
+ add_package_entry(p,
+ file,
+ NULL, /* path */
+ name,
+ NULL, /* target */
+ NULL, /* dst */
+ FILE_TYPE_MODULE_SIGNING_KEY,
+ FILE_TLS_CLASS_NONE,
+ 0400);
+
+ ui_message(op, "The private signing key will be installed to %s/%s. "
+ "After the public key is added to a key database which "
+ "is trusted by your kernel, you may reuse the saved "
+ "public/private key pair to sign additional kernel "
+ "modules, without needing to re-enroll the public key. "
+ "Please take some reasonable precautions to secure the "
+ "private key: see the README for suggestions.",
+ op->module_signing_key_path, name);
+ }
+ } /* if (generate_keys) */
+
+ return TRUE;
+} /* assisted_module_signing() */
diff --git a/kernel.c b/kernel.c
index 49167bd..ccab0e7 100644
--- a/kernel.c
+++ b/kernel.c
@@ -32,6 +32,8 @@
#include <string.h>
#include <limits.h>
#include <fts.h>
+#include <dlfcn.h>
+#include <libkmod.h>
#include "nvidia-installer.h"
#include "kernel.h"
@@ -63,6 +65,20 @@ static char *build_distro_precompiled_kernel_interface_dir(Options *op);
static char *convert_include_path_to_source_path(const char *inc);
static char *guess_kernel_module_filename(Options *op);
static char *get_machine_arch(Options *op);
+static int init_libkmod(void);
+static void close_libkmod(void);
+static int run_conftest(Options *op, Package *p, const char *args,
+ char **result);
+
+/* libkmod handle and function pointers */
+static void *libkmod = NULL;
+static struct kmod_ctx* (*lkmod_new)(const char*, const char* const*) = NULL;
+static struct kmod_ctx* (*lkmod_unref)(struct kmod_ctx*) = NULL;
+static struct kmod_module* (*lkmod_module_unref)(struct kmod_module *) = NULL;
+static int (*lkmod_module_new_from_path)(struct kmod_ctx*, const char*,
+ struct kmod_module**) = NULL;
+static int (*lkmod_module_insert_module)(struct kmod_module*, unsigned int,
+ const char*) = NULL;
/*
* Message text that is used by several error messages.
@@ -145,6 +161,37 @@ int determine_kernel_module_installation_path(Options *op)
/*
+ * run_conftest() - run conftest.sh with the given additional arguments; pass
+ * the result back to the caller. Returns TRUE on success, or FALSE on failure.
+ */
+
+static int run_conftest(Options *op, Package *p, const char *args, char **result)
+{
+ char *CC, *cmd, *arch;
+ int ret;
+
+ arch = get_machine_arch(op);
+ if (!arch)
+ return FALSE;
+
+ CC = getenv("CC");
+ if (!CC) CC = "cc";
+
+ cmd = nvstrcat("sh ", p->kernel_module_build_directory,
+ "/conftest.sh ", CC, " ", CC, " ", arch, " ",
+ op->kernel_source_path, " ",
+ op->kernel_output_path, " ",
+ args, NULL);
+
+ ret = run_command(op, cmd, result, FALSE, 0, TRUE);
+ nvfree(cmd);
+
+ return ret == 0;
+} /* run_conftest() */
+
+
+
+/*
* determine_kernel_source_path() - find the qualified path to the
* kernel source tree. This is called from install_from_cwd() if we
* need to compile the kernel interface files. Assigns
@@ -154,9 +201,8 @@ int determine_kernel_module_installation_path(Options *op)
int determine_kernel_source_path(Options *op, Package *p)
{
- char *CC, *cmd, *result;
+ char *result;
char *source_files[2], *source_path;
- char *arch;
int ret, count = 0;
/* determine the kernel source path */
@@ -242,24 +288,11 @@ int determine_kernel_source_path(Options *op, Package *p)
}
free(result);
- arch = get_machine_arch(op);
- if (!arch)
- return FALSE;
if (!determine_kernel_output_path(op)) return FALSE;
- CC = getenv("CC");
- if (!CC) CC = "cc";
-
- cmd = nvstrcat("sh ", p->kernel_module_build_directory,
- "/conftest.sh ", CC, " ", CC, " ", arch, " ",
- op->kernel_source_path, " ",
- op->kernel_output_path, " ",
- "get_uname", NULL);
-
- ret = run_command(op, cmd, &result, FALSE, 0, TRUE);
- nvfree(cmd);
+ ret = run_conftest(op, p, "get_uname", &result);
- if (ret != 0) {
+ if (!ret) {
ui_error(op, "Unable to determine the version of the kernel "
"sources located in '%s'. %s",
op->kernel_source_path, install_your_kernel_source);
@@ -382,6 +415,87 @@ int determine_kernel_output_path(Options *op)
/*
+ * attach_signature() - If we have a detached signature, verify the checksum of
+ * the linked module and append the signature.
+ */
+static int attach_signature(Options *op, Package *p,
+ const PrecompiledInfo *info) {
+ uint32 actual_crc;
+ char *module_filename;
+ int ret = FALSE, command_ret;
+
+ ui_log(op, "Attaching module signature to linked kernel module.");
+
+ module_filename = nvstrcat(p->kernel_module_build_directory, "/",
+ p->kernel_module_filename, NULL);
+
+ command_ret = verify_crc(op, module_filename, info->linked_module_crc,
+ &actual_crc);
+
+ if (command_ret) {
+ FILE *module_file, *signature_file;
+
+ module_file = fopen(module_filename, "a+");
+ signature_file = fopen(info->detached_signature, "r");
+
+ if (module_file && signature_file) {
+ char buf;
+
+ while(fread(&buf, 1, 1, signature_file)) {
+ command_ret = fwrite(&buf, 1, 1, module_file);
+ if (command_ret != 1) {
+ goto attach_done;
+ }
+ }
+
+ ret = feof(signature_file) &&
+ !ferror(signature_file) &&
+ !ferror(module_file);
+
+ op->kernel_module_signed = ret;
+attach_done:
+ fclose(module_file);
+ fclose(signature_file);
+ } else {
+ ret = ui_yes_no(op, FALSE,
+ "A detached signature was included with the "
+ "precompiled interface, but opening the linked "
+ "kernel module and/or the signature file failed."
+ "\n\nThe detached signature will not be added; "
+ "would you still like to install the unsigned "
+ "kernel module?");
+ }
+ } else {
+ ret = ui_yes_no(op, FALSE,
+ "A detached signature was included with the "
+ "precompiled interface, but the checksum of the linked "
+ "kernel module (%d) did not match the checksum of the "
+ "the kernel module for which the detached signature "
+ "was generated (%d).\n\nThis can happen if the linker "
+ "on the installation target system is not the same as "
+ "the linker on the system that built the precompiled "
+ "interface.\n\nThe detached signature will not be "
+ "added; would you still like to install the unsigned "
+ "kernel module?", actual_crc, info->linked_module_crc);
+ }
+
+ if (ret) {
+ if(op->kernel_module_signed) {
+ ui_log(op, "Signature attached successfully.");
+ } else {
+ ui_log(op, "Signature not attached.");
+ }
+ } else {
+ ui_error(op, "Failed to attach signature.");
+ }
+
+ nvfree(module_filename);
+ return ret;
+} /* attach_signature() */
+
+
+
+/*
* link_kernel_module() - link the prebuilt kernel interface against
* the binary-only core of the kernel module. This results in a
* complete kernel module, ready for installation.
@@ -390,15 +504,15 @@ int determine_kernel_output_path(Options *op)
* ld -r -o nvidia.o nv-linux.o nv-kernel.o
*/
-int link_kernel_module(Options *op, Package *p)
+int link_kernel_module(Options *op, Package *p, const char *build_directory,
+ const PrecompiledInfo *info)
{
char *cmd, *result;
int ret;
p->kernel_module_filename = guess_kernel_module_filename(op);
- cmd = nvstrcat("cd ", p->kernel_module_build_directory,
- "; ", op->utils[LD],
+ cmd = nvstrcat("cd ", build_directory, "; ", op->utils[LD],
" ", LD_OPTIONS,
" -o ", p->kernel_module_filename,
" ", PRECOMPILED_KERNEL_INTERFACE_FILENAME,
@@ -415,6 +529,10 @@ int link_kernel_module(Options *op, Package *p)
ui_log(op, "Kernel module linked successfully.");
+ if (info && info->detached_signature) {
+ return attach_signature(op, p, info);
+ }
+
return TRUE;
} /* link_kernel_module() */
@@ -428,13 +546,8 @@ int link_kernel_module(Options *op, Package *p)
int build_kernel_module(Options *op, Package *p)
{
- char *CC, *result, *cmd, *tmp;
- char *arch;
+ char *result, *cmd, *tmp;
int len, ret;
-
- arch = get_machine_arch(op);
- if (!arch)
- return FALSE;
/*
* touch all the files in the build directory to avoid make time
@@ -443,23 +556,13 @@ int build_kernel_module(Options *op, Package *p)
touch_directory(op, p->kernel_module_build_directory);
- CC = getenv("CC");
- if (!CC) CC = "cc";
-
/*
* Check if conftest.sh can determine the Makefile, there's
* no hope for the make rules if this fails.
*/
- cmd = nvstrcat("sh ", p->kernel_module_build_directory,
- "/conftest.sh ", CC, " ", CC, " ", arch, " ",
- op->kernel_source_path, " ",
- op->kernel_output_path, " ",
- "select_makefile just_msg", NULL);
-
- ret = run_command(op, cmd, &result, FALSE, 0, TRUE);
- nvfree(cmd);
+ ret = run_conftest(op, p, "select_makefile just_msg", &result);
- if (ret != 0) {
+ if (!ret) {
ui_error(op, "%s", result); /* display conftest.sh's error message */
nvfree(result);
return FALSE;
@@ -535,6 +638,211 @@ int build_kernel_module(Options *op, Package *p)
/*
+ * sign_kernel_module() - sign the kernel module. The caller is responsible
+ * for ensuring that the kernel module is already built successfully and that
+ * op->module_signing_{secret,public}_key are set.
+ */
+int sign_kernel_module(Options *op, const char *build_directory, int status) {
+ char *cmd, *mod_sign_cmd, *mod_sign_hash;
+ int ret, success;
+
+ /* if module_signing_script isn't set, then set mod_sign_cmd below to end
+ * the nvstrcat() that builds cmd early. */
+ mod_sign_cmd = op->module_signing_script ?
+ nvstrcat(" mod_sign_cmd=", op->module_signing_script, NULL) :
+ NULL;
+
+ mod_sign_hash = op->module_signing_hash ?
+ nvstrcat(" CONFIG_MODULE_SIG_HASH=",
+ op->module_signing_hash, NULL) :
+ NULL;
+
+ if (status) {
+ ui_status_begin(op, "Signing kernel module:", "Signing");
+ }
+
+ cmd = nvstrcat("cd ", build_directory, "; make module-sign"
+ " SYSSRC=", op->kernel_source_path,
+ " SYSOUT=", op->kernel_output_path,
+ " MODSECKEY=", op->module_signing_secret_key,
+ " MODPUBKEY=", op->module_signing_public_key,
+ mod_sign_cmd ? mod_sign_cmd : "",
+ mod_sign_hash ? mod_sign_hash : "", NULL);
+
+ ret = run_command(op, cmd, NULL, TRUE, 20 /* XXX */, TRUE);
+ success = ret == 0;
+
+ nvfree(mod_sign_hash);
+ nvfree(mod_sign_cmd);
+ nvfree(cmd);
+
+ if (status) {
+ ui_status_end(op, success ? "done." : "Failed to sign kernel module.");
+ } else {
+ ui_log(op, success ? "Signed kernel module." : "Module signing failed");
+ }
+ op->kernel_module_signed = success;
+ return success;
+} /* sign_kernel_module */
+
+
+
+/*
+ * byte_tail() - write to outfile from infile, starting at the specified byte
+ * offset, and going until the end of infile. This is needed because `tail -c`
+ * is unreliable in some implementations.
+ */
+static int byte_tail(const char *infile, const char *outfile, int start)
+{
+ FILE *in = NULL, *out = NULL;
+ int success = FALSE, ret;
+ char buf;
+
+ in = fopen(infile, "r");
+ out = fopen(outfile, "w");
+
+ if (!in || !out) {
+ goto done;
+ }
+
+ ret = fseek(in, start, SEEK_SET);
+ if (ret != 0) {
+ goto done;
+ }
+
+ while(fread(&buf, 1, 1, in)) {
+ ret = fwrite(&buf, 1, 1, out);
+ if (ret != 1) {
+ goto done;
+ }
+ }
+
+ success = feof(in) && !ferror(in) && !ferror(out);
+
+done:
+ fclose(in);
+ fclose(out);
+ return success;
+}
+
+
+
+/*
+ * create_detached_signature() - Link the precompiled interface with nv-kernel.o,
+ * sign the resulting linked nvidia.ko, and split the signature off into a separate
+ * file. Copy a checksum and detached signature for the linked module to the kernel
+ * module build directory on success.
+ */
+static int create_detached_signature(Options *op, Package *p,
+ const char *build_dir)
+{
+ int ret, command_ret;
+ struct stat st;
+ FILE *checksum_file;
+ char *module_path = NULL, *tmp_path = NULL, *error = NULL, *dstfile = NULL;
+
+ ui_status_begin(op, "Creating a detached signature for the linked "
+ "kernel module:", "Linking module");
+
+ tmp_path = nvstrcat(build_dir, "/", PRECOMPILED_KERNEL_INTERFACE_FILENAME,
+ NULL);
+ symlink(p->kernel_interface_filename, tmp_path);
+
+ ret = link_kernel_module(op, p, build_dir, NULL);
+
+ if (!ret) {
+ ui_error(op, "Failed to link a kernel module for signing.");
+ goto done;
+ }
+
+ module_path = nvstrcat(build_dir, "/", p->kernel_module_filename, NULL);
+ command_ret = stat(module_path, &st);
+
+ if (command_ret != 0) {
+ ret = FALSE;
+ error = "Unable to determine size of linked module.";
+ goto done;
+ }
+
+ ui_status_update(op, .25, "Generating module checksum");
+
+ nvfree(tmp_path);
+ tmp_path = nvstrcat(build_dir, "/", KERNEL_MODULE_CHECKSUM_FILENAME, NULL);
+ checksum_file = fopen(tmp_path, "w");
+
+ if(checksum_file) {
+ uint32 crc = compute_crc(op, module_path);
+ command_ret = fwrite(&crc, sizeof(crc), 1, checksum_file);
+ fclose(checksum_file);
+ if (command_ret != 1) {
+ ret = FALSE;
+ error = "Failed to write the module checksum.";
+ goto done;
+ }
+ } else {
+ ret = FALSE;
+ error = "Failed to open the checksum file for writing.";
+ goto done;
+ }
+
+ dstfile = nvstrcat(p->kernel_module_build_directory, "/",
+ KERNEL_MODULE_CHECKSUM_FILENAME, NULL);
+
+ if (!copy_file(op, tmp_path, dstfile, 0644)) {
+ ret = FALSE;
+ error = "Failed to copy the kernel module checksum file.";
+ goto done;
+ }
+
+ ui_status_update(op, .50, "Signing linked module");
+
+ ret = sign_kernel_module(op, build_dir, FALSE);
+
+ if (!ret) {
+ error = "Failed to sign the linked kernel module.";
+ goto done;
+ }
+
+ ui_status_update(op, .75, "Detaching module signature");
+
+ nvfree(tmp_path);
+ tmp_path = nvstrcat(build_dir, "/", DETACHED_SIGNATURE_FILENAME, NULL);
+ ret = byte_tail(module_path, tmp_path, st.st_size);
+
+ if (!ret) {
+ error = "Failed to detach the module signature";
+ goto done;
+ }
+
+ nvfree(dstfile);
+ dstfile = nvstrcat(p->kernel_module_build_directory, "/",
+ DETACHED_SIGNATURE_FILENAME, NULL);
+
+ if (!copy_file(op, tmp_path, dstfile, 0644)) {
+ ret = FALSE;
+ error = "Failed to copy the detached signature file.";
+ goto done;
+ }
+
+done:
+ if (ret) {
+ ui_status_end(op, "done.");
+ } else {
+ ui_status_end(op, "Error.");
+ if (error) {
+ ui_error(op, error);
+ }
+ }
+
+ nvfree(dstfile);
+ nvfree(tmp_path);
+ nvfree(module_path);
+ return ret;
+} /* create_detached_signature() */
+
+
+
+/*
* build_kernel_interface() - build the kernel interface, and place it
* here:
*
@@ -622,8 +930,12 @@ int build_kernel_interface(Options *op, Package *p)
PRECOMPILED_KERNEL_INTERFACE_FILENAME, NULL);
if (!copy_file(op, kernel_interface, dstfile, 0644)) goto failed;
-
- ret = TRUE;
+
+ if (op->module_signing_secret_key && op->module_signing_public_key) {
+ ret = create_detached_signature(op, p, tmpdir);
+ } else {
+ ret = TRUE;
+ }
failed:
@@ -681,16 +993,144 @@ void check_for_warning_messages(Options *op)
/*
+ * init_libkmod() - Attempt to dlopen() libkmod and the function symbols we
+ * need from it. Set the global libkmod handle and function pointers on
+ * success. Return TRUE if loading all symbols succeeded; FALSE otherwise.
+ */
+static int init_libkmod(void)
+{
+ if (!libkmod) {
+ libkmod = dlopen("libkmod.so.2", RTLD_LAZY);
+ if(!libkmod) {
+ return FALSE;
+ }
+
+ lkmod_new = dlsym(libkmod, "kmod_new");
+ lkmod_unref = dlsym(libkmod, "kmod_unref");
+ lkmod_module_unref = dlsym(libkmod, "kmod_module_unref");
+ lkmod_module_new_from_path = dlsym(libkmod, "kmod_module_new_from_path");
+ lkmod_module_insert_module = dlsym(libkmod, "kmod_module_insert_module");
+ }
+
+ if (libkmod) {
+ /* libkmod was already open, or was just successfully dlopen()ed:
+ * check to make sure all of the symbols are set */
+ if (lkmod_new && lkmod_unref && lkmod_module_unref &&
+ lkmod_module_new_from_path && lkmod_module_insert_module) {
+ return TRUE;
+ } else {
+ /* One or more symbols missing; abort */
+ close_libkmod();
+ return FALSE;
+ }
+ }
+ return FALSE;
+} /* init_libkmod() */
+
+
+
+/*
+ * close_libkmod() - clear all libkmod function pointers and dlclose() libkmod
+ */
+static void close_libkmod(void)
+{
+ if (libkmod) {
+ dlclose(libkmod);
+ }
+
+ libkmod = NULL;
+ lkmod_new = NULL;
+ lkmod_unref = NULL;
+ lkmod_module_unref = NULL;
+ lkmod_module_new_from_path = NULL;
+ lkmod_module_insert_module = NULL;
+} /* close_libkmod() */
+
+
+
+/*
+ * do_insmod() - load the kernel module using libkmod if available; fall back
+ * to insmod otherwise. Returns the result of kmod_module_insert_module() if
+ * available, or of insmod otherwise. Pass the result of module loading up
+ * through the data argument, regardless of whether we used libkmod or insmod.
+ */
+static int do_insmod(Options *op, const char *module, char **data)
+{
+ int ret = 0, libkmod_failed = FALSE;
+ *data = NULL;
+
+ if (init_libkmod()) {
+ struct kmod_ctx *ctx = NULL;
+ struct kmod_module *mod = NULL;
+ const char *config_paths = NULL;
+
+ ctx = lkmod_new(NULL, &config_paths);
+ if (!ctx) {
+ libkmod_failed = TRUE;
+ goto kmod_done;
+ }
+
+ ret = lkmod_module_new_from_path(ctx, module, &mod);
+ if (ret < 0) {
+ libkmod_failed = TRUE;
+ goto kmod_done;
+ }
+
+ ret = lkmod_module_insert_module(mod, 0, "");
+ if (ret < 0) {
+ /* insmod ignores > 0 return codes of kmod_module_insert_module(),
+ * so we should do it too. On failure, strdup() the error string to
+ * *data to ensure that it can be freed later. */
+ *data = nvstrdup(strerror(-ret));
+ }
+
+kmod_done:
+ if (mod) {
+ lkmod_module_unref(mod);
+ }
+ if (ctx) {
+ lkmod_unref(ctx);
+ }
+ } else {
+ if (op->expert) {
+ ui_log(op, "Unable to load module with libkmod; "
+ "falling back to insmod.");
+ }
+ libkmod_failed = TRUE;
+ }
+
+ if (!libkmod || libkmod_failed) {
+ char *cmd;
+
+ /* Fall back to insmod */
+
+ cmd = nvstrcat(op->utils[INSMOD], " ", module, NULL);
+
+ /* only output the result of the test if in expert mode */
+
+ ret = run_command(op, cmd, data, op->expert, 0, TRUE);
+ nvfree(cmd);
+ }
+
+ close_libkmod();
+
+ return ret;
+} /* do_insmod() */
+
+
+
+/*
* test_kernel_module() - attempt to insmod the kernel module and then
* rmmod it. Return TRUE if the insmod succeeded, or FALSE otherwise.
*/
int test_kernel_module(Options *op, Package *p)
{
- char *cmd = NULL, *data;
+ char *cmd = NULL, *data = NULL, *module_path;
int old_loglevel = 0, new_loglevel = 0;
- int fd, ret, name[] = { CTL_KERN, KERN_PRINTK };
+ int fd, ret, name[] = { CTL_KERN, KERN_PRINTK }, i;
size_t len = sizeof(int);
+ const char *depmods[] = { "i2c-core", "drm" };
/*
* If we're building/installing for a different kernel, then we
@@ -719,51 +1159,106 @@ int test_kernel_module(Options *op, Package *p)
}
/*
- * On Linux 2.6+ we depend on the i2c-core.ko kernel module unless
- * the kernel was configured without support for it. Preload it here to
- * satisfy the dependency, which isn't resolved by `insmod`.
+ * Attempt to load modules that nvidia.ko might depend on. Silently ignore
+ * failures: if nvidia.ko doesn't depend on the module that failed, the test
+ * load below will succeed and it doesn't matter that the load here failed.
*/
- if (strncmp(get_kernel_name(op), "2.4", 3) != 0) {
- cmd = nvstrcat(op->utils[MODPROBE], " -q i2c-core", NULL);
+ for (i = 0; i < ARRAY_LEN(depmods); i++) {
+ cmd = nvstrcat(op->utils[MODPROBE], " -q ", depmods[i], NULL);
run_command(op, cmd, NULL, FALSE, 0, TRUE);
nvfree(cmd);
}
- cmd = nvstrcat(op->utils[INSMOD], " ",
- p->kernel_module_build_directory, "/",
- p->kernel_module_filename, NULL);
-
- /* only output the result of the test if in expert mode */
-
- ret = run_command(op, cmd, &data, op->expert, 0, TRUE);
+ /* Load nvidia.ko */
+ module_path = nvstrcat(p->kernel_module_build_directory, "/",
+ p->kernel_module_filename, NULL);
+ ret = do_insmod(op, module_path, &data);
+ nvfree(module_path);
if (ret != 0) {
- ui_error(op, "Unable to load the kernel module '%s'. This "
- "happens most frequently when this kernel module was "
- "built against the wrong or improperly configured "
- "kernel sources, with a version of gcc that differs "
- "from the one used to build the target kernel, or "
- "if a driver such as rivafb, nvidiafb, or nouveau is present "
- "and prevents the NVIDIA kernel module from obtaining "
- "ownership of the NVIDIA graphics device(s), or "
- "NVIDIA GPU installed in this system is not supported "
- "by this NVIDIA Linux graphics driver release.\n\n"
- "Please see the log entries 'Kernel module load "
- "error' and 'Kernel messages' at the end of the file "
- "'%s' for more information.",
- p->kernel_module_filename, op->log_file_name);
+ int ignore_error;
+
+ /* Handle cases where we might want to allow the kernel module to be
+ * installed, even though the test load failed. */
+ switch (-ret) {
+ case ENOKEY:
+ if (op->kernel_module_signed) {
+ ignore_error = ui_yes_no(op, TRUE,
+ "The signed kernel module failed to "
+ "load, because the kernel does not "
+ "trust any key which is capable of "
+ "verifying the module signature. "
+ "Would you like to install the signed "
+ "kernel module anyway?\n\nNote that "
+ "you will not be able to load the "
+ "installed module until after a key "
+ "that can verify the module signature "
+ "is added to a key database that is "
+ "trusted by the kernel. This will "
+ "likely require rebooting your "
+ "computer.");
+ } else {
+ char *secureboot_message, *dkms_message;
+
+ secureboot_message = secure_boot_enabled() == 1 ?
+ "and sign the kernel module when "
+ "prompted to do so." :
+ "and set the --module-signing-secret-"
+ "key and --module-signing-public-key "
+ "options on the command line, or run "
+ "the installer in expert mode to "
+ "enable the interactive module "
+ "signing prompts.";
+
+ dkms_message = op->dkms ? " Module signing is incompatible "
+ "with DKMS, so please select the "
+ "non-DKMS option when building the "
+ "kernel module to be signed." : "";
+
+ ui_error(op, "The kernel module failed to load, because it "
+ "was not signed by a key that is trusted by the "
+ "kernel. Please try installing the driver again, %s%s",
+ secureboot_message, dkms_message);
+ ignore_error = FALSE;
+ }
+ break;
- /*
- * if in expert mode, run_command() would have caused this to
- * be written to the log file; so if not in expert mode, print
- * the output now.
- */
+ default:
+ ignore_error = FALSE;
+ }
- if (!op->expert) ui_log(op, "Kernel module load error: %s", data);
- ret = FALSE;
+ if (ignore_error) {
+ ui_log(op, "An error was encountered when loading the kernel "
+ "module, but that error was ignored, and the kernel module "
+ "will be installed, anyway. The error was: %s", data);
+ ret = TRUE;
+ } else {
+ ui_error(op, "Unable to load the kernel module '%s'. This "
+ "happens most frequently when this kernel module was "
+ "built against the wrong or improperly configured "
+ "kernel sources, with a version of gcc that differs "
+ "from the one used to build the target kernel, or "
+ "if a driver such as rivafb, nvidiafb, or nouveau is "
+ "present and prevents the NVIDIA kernel module from "
+ "obtaining ownership of the NVIDIA graphics device(s), "
+ "or no NVIDIA GPU installed in this system is supported "
+ "by this NVIDIA Linux graphics driver release.\n\n"
+ "Please see the log entries 'Kernel module load "
+ "error' and 'Kernel messages' at the end of the file "
+ "'%s' for more information.",
+ p->kernel_module_filename, op->log_file_name);
+
+ /*
+ * if in expert mode, run_command() would have caused this to
+ * be written to the log file; so if not in expert mode, print
+ * the output now.
+ */
+
+ if (!op->expert) ui_log(op, "Kernel module load error: %s", data);
+ ret = FALSE;
+ }
} else {
- nvfree(cmd);
/*
* check if the kernel module detected problems with this
@@ -781,9 +1276,9 @@ int test_kernel_module(Options *op, Package *p)
cmd = nvstrcat(op->utils[RMMOD], " ", p->kernel_module_name, NULL);
run_command(op, cmd, NULL, FALSE, 0, TRUE);
ret = TRUE;
+ nvfree(cmd);
}
-
- nvfree(cmd);
+
nvfree(data);
/*
@@ -809,6 +1304,15 @@ int test_kernel_module(Options *op, Package *p)
sysctl(name, 2, NULL, 0, &old_loglevel, len);
}
+ /*
+ * Unload dependencies that might have been loaded earlier.
+ */
+ for (i = 0; i < ARRAY_LEN(depmods); i++) {
+ cmd = nvstrcat(op->utils[MODPROBE], " -qr ", depmods[i], NULL);
+ run_command(op, cmd, NULL, FALSE, 0, TRUE);
+ nvfree(cmd);
+ }
+
return ret;
} /* test_kernel_module() */
@@ -946,7 +1450,7 @@ int check_for_unloaded_kernel_module(Options *op, Package *p)
* be installed for a kernel other than the currently running one.
*/
-int find_precompiled_kernel_interface(Options *op, Package *p)
+PrecompiledInfo *find_precompiled_kernel_interface(Options *op, Package *p)
{
char *proc_version_string, *output_filename, *tmp;
PrecompiledInfo *info = NULL;
@@ -955,7 +1459,7 @@ int find_precompiled_kernel_interface(Options *op, Package *p)
if (op->no_precompiled_interface) {
ui_log(op, "Not probing for precompiled kernel interfaces.");
- return FALSE;
+ return NULL;
}
/* retrieve the proc version string for the running kernel */
@@ -1022,7 +1526,7 @@ int find_precompiled_kernel_interface(Options *op, Package *p)
"found at '%s'; this means that the installer will need "
"to compile a kernel interface for your kernel.",
op->precompiled_kernel_interfaces_url);
- return FALSE;
+ return NULL;
}
}
@@ -1034,14 +1538,13 @@ int find_precompiled_kernel_interface(Options *op, Package *p)
"use this? (answering 'no' will require the "
"installer to compile the interface)",
info->description)) {
- /* XXX free info */
+ free_precompiled(info);
info = NULL;
}
}
if (info) {
- /* XXX free info */
- return TRUE;
+ return info;
}
failed:
@@ -1052,7 +1555,7 @@ int find_precompiled_kernel_interface(Options *op, Package *p)
"compile a new kernel interface.");
}
- return FALSE;
+ return NULL;
} /* find_precompiled_kernel_interface() */
@@ -1086,6 +1589,31 @@ char *get_kernel_name(Options *op)
/*
+ * test_kernel_config_option() - test to see if the given option is defined
+ * in the target kernel's configuration.
+ */
+
+KernelConfigOptionStatus test_kernel_config_option(Options* op, Package *p,
+ const char *option)
+{
+ if (op->kernel_source_path && op->kernel_output_path) {
+ int ret;
+ char *conftest_cmd;
+
+ conftest_cmd = nvstrcat("test_configuration_option ", option, NULL);
+ ret = run_conftest(op, p, conftest_cmd, NULL);
+ nvfree(conftest_cmd);
+
+ return ret ? KERNEL_CONFIG_OPTION_DEFINED :
+ KERNEL_CONFIG_OPTION_NOT_DEFINED;
+ }
+
+ return KERNEL_CONFIG_OPTION_UNKNOWN;
+}
+
+
+
+/*
***************************************************************************
* local static routines
***************************************************************************
@@ -1434,10 +1962,11 @@ download_updated_kernel_interface(Options *op, Package *p,
if (info && (info->crc != crc)) {
ui_error(op, "The embedded checksum of the downloaded file "
- "'%s' (%d) does not match the computed checksum ",
- "(%d); not using.", buf, info->crc, crc);
+ "'%s' (%" PRIu32 ") does not match the computed "
+ "checksum (%" PRIu32 "); not using.", buf, info->crc,
+ crc);
unlink(dstfile);
- /* XXX free info */
+ free_precompiled(info);
info = NULL;
}
@@ -1474,9 +2003,9 @@ download_updated_kernel_interface(Options *op, Package *p,
int check_cc_version(Options *op, Package *p)
{
- char *cmd, *CC, *result;
- char *arch;
+ char *result;
int ret;
+ Options dummyop;
/*
* If we're building/installing for a different kernel, then we
@@ -1491,25 +2020,15 @@ int check_cc_version(Options *op, Package *p)
return TRUE;
}
- arch = get_machine_arch(op);
- if (!arch)
- return FALSE;
-
- CC = getenv("CC");
- if (!CC) CC = "cc";
-
- ui_log(op, "Performing CC version check with CC=\"%s\".", CC);
-
- cmd = nvstrcat("sh ", p->kernel_module_build_directory,
- "/conftest.sh ", CC, " ", CC, " ", arch, " ",
- "DUMMY_SOURCE DUMMY_OUTPUT ",
- "cc_version_check just_msg", NULL);
+ /* Kernel source/output paths may not be set yet; we don't need them
+ * for this test, anyway. */
+ dummyop = *op;
+ dummyop.kernel_source_path = "DUMMY_SOURCE_PATH";
+ dummyop.kernel_output_path = "DUMMY_OUTPUT_PATH";
- ret = run_command(op, cmd, &result, FALSE, 0, TRUE);
-
- nvfree(cmd);
+ ret = run_conftest(&dummyop, p, "cc_version_check just_msg", &result);
- if (ret == 0) return TRUE;
+ if (ret) return TRUE;
ret = ui_yes_no(op, TRUE, "The CC version check failed:\n\n%s\n\n"
"If you know what you are doing and want to "
@@ -1536,30 +2055,14 @@ int check_cc_version(Options *op, Package *p)
static int fbdev_check(Options *op, Package *p)
{
- char *CC, *cmd, *result;
- char *arch;
+ char *result;
int ret;
- arch = get_machine_arch(op);
- if (!arch)
- return FALSE;
-
- CC = getenv("CC");
- if (!CC) CC = "cc";
-
ui_log(op, "Performing rivafb check.");
- cmd = nvstrcat("sh ", p->kernel_module_build_directory,
- "/conftest.sh ", CC, " ", CC, " ", arch, " ",
- op->kernel_source_path, " ",
- op->kernel_output_path, " ",
- "rivafb_sanity_check just_msg", NULL);
-
- ret = run_command(op, cmd, &result, FALSE, 0, TRUE);
-
- nvfree(cmd);
+ ret = run_conftest(op, p,"rivafb_sanity_check just_msg", &result);
- if (ret != 0) {
+ if (!ret) {
ui_error(op, "%s", result);
nvfree(result);
@@ -1568,17 +2071,9 @@ static int fbdev_check(Options *op, Package *p)
ui_log(op, "Performing nvidiafb check.");
- cmd = nvstrcat("sh ", p->kernel_module_build_directory,
- "/conftest.sh ", CC, " ", CC, " ", arch, " ",
- op->kernel_source_path, " ",
- op->kernel_output_path, " ",
- "nvidiafb_sanity_check just_msg", NULL);
-
- ret = run_command(op, cmd, &result, FALSE, 0, TRUE);
+ ret = run_conftest(op, p,"nvidiafb_sanity_check just_msg", &result);
- nvfree(cmd);
-
- if (ret != 0) {
+ if (!ret) {
ui_error(op, "%s", result);
nvfree(result);
@@ -1598,30 +2093,14 @@ static int fbdev_check(Options *op, Package *p)
static int xen_check(Options *op, Package *p)
{
- char *CC, *cmd, *result;
- char *arch;
+ char *result;
int ret;
- arch = get_machine_arch(op);
- if (!arch)
- return FALSE;
-
- CC = getenv("CC");
- if (!CC) CC = "cc";
-
ui_log(op, "Performing Xen check.");
- cmd = nvstrcat("sh ", p->kernel_module_build_directory,
- "/conftest.sh ", CC, " ", CC, " ", arch, " ",
- op->kernel_source_path, " ",
- op->kernel_output_path, " ",
- "xen_sanity_check just_msg", NULL);
-
- ret = run_command(op, cmd, &result, FALSE, 0, TRUE);
+ ret = run_conftest(op, p,"xen_sanity_check just_msg", &result);
- nvfree(cmd);
-
- if (ret != 0) {
+ if (!ret) {
ui_error(op, "%s", result);
nvfree(result);
@@ -1662,7 +2141,8 @@ static PrecompiledInfo *scan_dir(Options *op, Package *p,
while ((ent = readdir(dir)) != NULL) {
if (((strcmp(ent->d_name, ".")) == 0) ||
- ((strcmp(ent->d_name, "..")) == 0)) continue;
+ ((strcmp(ent->d_name, "..")) == 0) ||
+ strstr(ent->d_name, DETACHED_SIGNATURE_FILENAME)) continue;
filename = nvstrcat(directory_name, "/", ent->d_name, NULL);
diff --git a/kernel.h b/kernel.h
index 7e9c164..ecab5c8 100644
--- a/kernel.h
+++ b/kernel.h
@@ -21,18 +21,34 @@
#define __NVIDIA_INSTALLER_KERNEL_H__
#include "nvidia-installer.h"
+#include "precompiled.h"
-int determine_kernel_module_installation_path (Options*);
-int determine_kernel_source_path (Options*, Package*);
-int determine_kernel_output_path (Options*);
-int link_kernel_module (Options*, Package*);
-int check_cc_version (Options*, Package*);
-int build_kernel_module (Options*, Package*);
-int build_kernel_interface (Options*, Package*);
-int test_kernel_module (Options*, Package*);
-int load_kernel_module (Options*, Package*);
-int check_for_unloaded_kernel_module (Options*, Package*);
-int find_precompiled_kernel_interface (Options*, Package*);
-char *get_kernel_name (Options*);
+typedef enum {
+ KERNEL_CONFIG_OPTION_NOT_DEFINED = 0,
+ KERNEL_CONFIG_OPTION_DEFINED,
+ KERNEL_CONFIG_OPTION_UNKNOWN
+} KernelConfigOptionStatus;
+
+int determine_kernel_module_installation_path (Options*);
+int determine_kernel_source_path (Options*, Package*);
+int determine_kernel_output_path (Options*);
+int link_kernel_module (Options*, Package*,
+ const char*,
+ const PrecompiledInfo *);
+int check_cc_version (Options*, Package*);
+int build_kernel_module (Options*, Package*);
+int build_kernel_interface (Options*, Package*);
+int test_kernel_module (Options*, Package*);
+int load_kernel_module (Options*, Package*);
+int check_for_unloaded_kernel_module (Options*, Package*);
+PrecompiledInfo *find_precompiled_kernel_interface (Options*, Package*);
+char *get_kernel_name (Options*);
+KernelConfigOptionStatus test_kernel_config_option (Options*, Package*,
+ const char*);
+int sign_kernel_module (Options*, const char*, int);
+
+#ifndef ENOKEY
+#define ENOKEY 126 /* Required key not available */
+#endif
#endif /* __NVIDIA_INSTALLER_KERNEL_H__ */
diff --git a/log.c b/log.c
index 743449a..20b3c2c 100644
--- a/log.c
+++ b/log.c
@@ -88,25 +88,25 @@ void log_init(Options *op, int argc, char * const argv[])
return;
}
- log_printf(op, TRUE, NULL, "%s log file '%s'",
+ log_printf(op, NULL, "%s log file '%s'",
PROGRAM_NAME, op->log_file_name);
now = time(NULL);
- log_printf(op, TRUE, NULL, "creation time: %s", ctime(&now));
- log_printf(op, TRUE, NULL, "installer version: %s",
+ log_printf(op, NULL, "creation time: %s", ctime(&now));
+ log_printf(op, NULL, "installer version: %s",
NVIDIA_INSTALLER_VERSION);
- log_printf(op, TRUE, NULL, "");
+ log_printf(op, NULL, "");
path = getenv("PATH");
- log_printf(op, TRUE, NULL, "PATH: %s", STRSTR(path));
- log_printf(op, TRUE, NULL, "");
+ log_printf(op, NULL, "PATH: %s", STRSTR(path));
+ log_printf(op, NULL, "");
- log_printf(op, TRUE, NULL, "nvidia-installer command line:");
+ log_printf(op, NULL, "nvidia-installer command line:");
for (i = 0; i < argc; i++) {
- log_printf(op, TRUE, " ", "%s", argv[i]);
+ log_printf(op, " ", "%s", argv[i]);
}
- log_printf(op, TRUE, NULL, "");
+ log_printf(op, NULL, "");
} /* log_init() */
@@ -118,8 +118,7 @@ void log_init(Options *op, int argc, char * const argv[])
* option is not set, then nothing is done here.
*/
-void log_printf(Options *op, const int wb,
- const char *prefix, const char *fmt, ...)
+void log_printf(Options *op, const char *prefix, const char *fmt, ...)
{
char *buf;
int append_newline = TRUE;
diff --git a/manifest.c b/manifest.c
new file mode 100644
index 0000000..5d8bcf0
--- /dev/null
+++ b/manifest.c
@@ -0,0 +1,214 @@
+/*
+ * nvidia-installer: A tool for installing NVIDIA software packages on
+ * Unix and Linux systems.
+ *
+ * Copyright (C) 2013 NVIDIA Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses>.
+ */
+
+#include <string.h>
+
+#include "manifest.h"
+
+#define T TRUE
+#define F FALSE
+
+#define ENTRY(_name, \
+ _has_arch, \
+ _has_tls_class, \
+ _installable, \
+ _has_path, \
+ _is_symlink, \
+ _is_shared_lib, \
+ _is_opengl) \
+ #_name , FILE_TYPE_ ## _name , \
+ { \
+ .has_arch = _has_arch, \
+ .has_tls_class = _has_tls_class, \
+ .installable = _installable, \
+ .has_path = _has_path, \
+ .is_symlink = _is_symlink, \
+ .is_shared_lib = _is_shared_lib, \
+ .is_opengl = _is_opengl \
+ }
+
+/*
+ * Define properties of each FILE_TYPE. Keep in sync with the
+ * PackageEntryFileType definition in nvidia-installer.h.
+ */
+static const struct {
+ const char *name;
+ PackageEntryFileType type;
+ PackageEntryFileCapabilities caps;
+} packageEntryFileTypeTable[] = {
+
+ /*
+ * is_opengl ---------------------------------+
+ * is_shared_lib ------------------------------+ |
+ * is_symlink ---------------------------+ | |
+ * has_path ------------------------+ | | |
+ * installable ---------------------+ | | | |
+ * has_tls_class ------------------+ | | | | |
+ * has_arch ---------------+ | | | | | |
+ * | | | | | | |
+ */
+ { ENTRY(KERNEL_MODULE_SRC, F, F, T, F, F, F, F ) },
+ { ENTRY(KERNEL_MODULE_CMD, F, F, F, F, F, F, F ) },
+ { ENTRY(KERNEL_MODULE, F, F, T, F, F, F, F ) },
+ { ENTRY(OPENGL_HEADER, F, F, T, T, F, F, T ) },
+ { ENTRY(CUDA_ICD, F, F, T, F, F, F, F ) },
+ { ENTRY(OPENGL_LIB, T, F, T, F, F, T, T ) },
+ { ENTRY(CUDA_LIB, T, F, T, T, F, T, F ) },
+ { ENTRY(LIBGL_LA, T, F, T, F, F, F, T ) },
+ { ENTRY(XLIB_STATIC_LIB, F, F, T, F, F, F, F ) },
+ { ENTRY(XLIB_SHARED_LIB, F, F, T, F, F, T, F ) },
+ { ENTRY(TLS_LIB, T, T, T, T, F, T, T ) },
+ { ENTRY(UTILITY_LIB, F, F, T, F, F, T, F ) },
+ { ENTRY(DOCUMENTATION, F, F, T, T, F, F, F ) },
+ { ENTRY(APPLICATION_PROFILE, F, F, T, T, F, F, F ) },
+ { ENTRY(MANPAGE, F, F, T, T, F, F, F ) },
+ { ENTRY(EXPLICIT_PATH, F, F, T, T, F, F, F ) },
+ { ENTRY(OPENGL_SYMLINK, T, F, F, F, T, F, T ) },
+ { ENTRY(CUDA_SYMLINK, T, F, F, T, T, F, F ) },
+ { ENTRY(XLIB_SYMLINK, F, F, F, F, T, F, F ) },
+ { ENTRY(TLS_SYMLINK, T, T, F, T, T, F, T ) },
+ { ENTRY(UTILITY_LIB_SYMLINK, F, F, F, F, T, F, F ) },
+ { ENTRY(INSTALLER_BINARY, F, F, T, F, F, F, F ) },
+ { ENTRY(UTILITY_BINARY, F, F, T, F, F, F, F ) },
+ { ENTRY(UTILITY_BIN_SYMLINK, F, F, F, F, T, F, F ) },
+ { ENTRY(DOT_DESKTOP, F, F, T, T, F, F, F ) },
+ { ENTRY(XMODULE_SHARED_LIB, F, F, T, T, F, T, F ) },
+ { ENTRY(XMODULE_SYMLINK, F, F, F, T, T, F, F ) },
+ { ENTRY(GLX_MODULE_SHARED_LIB, F, F, T, T, F, T, T ) },
+ { ENTRY(GLX_MODULE_SYMLINK, F, F, F, T, T, F, T ) },
+ { ENTRY(XMODULE_NEWSYM, F, F, F, T, T, F, F ) },
+ { ENTRY(VDPAU_LIB, T, F, T, T, F, T, F ) },
+ { ENTRY(VDPAU_SYMLINK, T, F, F, T, T, F, F ) },
+ { ENTRY(NVCUVID_LIB, T, F, T, F, F, T, F ) },
+ { ENTRY(NVCUVID_LIB_SYMLINK, T, F, F, F, T, F, F ) },
+ { ENTRY(ENCODEAPI_LIB, T, F, T, F, F, T, F ) },
+ { ENTRY(ENCODEAPI_LIB_SYMLINK, T, F, F, F, T, F, F ) },
+ { ENTRY(VGX_LIB, F, F, T, F, F, T, F ) },
+ { ENTRY(VGX_LIB_SYMLINK, F, F, F, F, T, F, F ) },
+ { ENTRY(NVIDIA_MODPROBE, F, F, T, T, F, F, F ) },
+ { ENTRY(NVIDIA_MODPROBE_MANPAGE,F, F, T, T, F, F, F ) },
+ { ENTRY(MODULE_SIGNING_KEY, F, F, T, F, F, F, F ) },
+};
+
+/*
+ * Scan packageEntryFileTypeTable[] for the given file type. If we find
+ * it, return the capabilities for the type.
+ */
+PackageEntryFileCapabilities get_file_type_capabilities(
+ PackageEntryFileType type
+)
+{
+ int i;
+ PackageEntryFileCapabilities nullCaps = { F, F, F, F, F, F, F };
+
+ for (i = 0; i < ARRAY_LEN(packageEntryFileTypeTable); i++) {
+ if (type == packageEntryFileTypeTable[i].type) {
+ return packageEntryFileTypeTable[i].caps;
+ }
+ }
+
+ return nullCaps;
+}
+
+/*
+ * Scan packageEntryFileTypeTable[] for the given string. If we find
+ * it, return the corresponding type and assign the capabilities for
+ * the type.
+ */
+PackageEntryFileType parse_manifest_file_type(
+ const char *str,
+ PackageEntryFileCapabilities *caps
+)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_LEN(packageEntryFileTypeTable); i++) {
+ if (strcmp(str, packageEntryFileTypeTable[i].name) == 0) {
+ *caps = packageEntryFileTypeTable[i].caps;
+ return packageEntryFileTypeTable[i].type;
+ }
+ }
+
+ return FILE_TYPE_NONE;
+}
+
+/*
+ * Return a list of what file types should be considered installable.
+ */
+void get_installable_file_type_list(
+ Options *op,
+ PackageEntryFileTypeList *installable_file_types
+)
+{
+ int i;
+
+ memset(installable_file_types, 0, sizeof(*installable_file_types));
+
+ for (i = 0; i < ARRAY_LEN(packageEntryFileTypeTable); i++) {
+
+ PackageEntryFileType type = packageEntryFileTypeTable[i].type;
+
+ if ((type == FILE_TYPE_OPENGL_HEADER) && !op->opengl_headers) {
+ continue;
+ }
+
+ if ((type == FILE_TYPE_KERNEL_MODULE_SRC) &&
+ op->no_kernel_module_source) {
+ continue;
+ }
+
+ if (((type == FILE_TYPE_NVIDIA_MODPROBE) ||
+ (type == FILE_TYPE_NVIDIA_MODPROBE_MANPAGE)) &&
+ !op->nvidia_modprobe) {
+ continue;
+ }
+
+ if (!packageEntryFileTypeTable[i].caps.installable) {
+ continue;
+ }
+
+ installable_file_types->types[type] = 1;
+ }
+}
+
+/*
+ * Add symlink file types to the given file list. This is used when
+ * building a list of existing files to remove. The NEWSYM type
+ * requires special handling: while it is a symlink, we do not remove
+ * it from the filesystem if it already exists.
+ */
+void add_symlinks_to_file_type_list(PackageEntryFileTypeList *file_type_list)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_LEN(packageEntryFileTypeTable); i++) {
+
+ PackageEntryFileType type = packageEntryFileTypeTable[i].type;
+
+ if (!packageEntryFileTypeTable[i].caps.is_symlink) {
+ continue;
+ }
+
+ if (type == FILE_TYPE_XMODULE_NEWSYM) {
+ continue;
+ }
+
+ file_type_list->types[type] = 1;
+ }
+}
diff --git a/manifest.h b/manifest.h
new file mode 100644
index 0000000..0b6aa58
--- /dev/null
+++ b/manifest.h
@@ -0,0 +1,39 @@
+/*
+ * nvidia-installer: A tool for installing NVIDIA software packages on
+ * Unix and Linux systems.
+ *
+ * Copyright (C) 2013 NVIDIA Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses>.
+ */
+
+#ifndef __NVIDIA_INSTALLER_MANIFEST_H__
+#define __NVIDIA_INSTALLER_MANIFEST_H__
+
+#include "nvidia-installer.h"
+
+PackageEntryFileCapabilities get_file_type_capabilities(
+ PackageEntryFileType type);
+
+PackageEntryFileType parse_manifest_file_type(
+ const char *str,
+ PackageEntryFileCapabilities *caps);
+
+void get_installable_file_type_list(
+ Options *op,
+ PackageEntryFileTypeList *installable_file_types);
+
+void add_symlinks_to_file_type_list(
+ PackageEntryFileTypeList *file_type_list);
+
+#endif /* __NVIDIA_INSTALLER_MANIFEST_H__ */
diff --git a/misc.c b/misc.c
index 31de17e..0a4d2b7 100644
--- a/misc.c
+++ b/misc.c
@@ -48,6 +48,7 @@
#include "misc.h"
#include "crc.h"
#include "nvLegacy.h"
+#include "manifest.h"
static int check_symlink(Options*, const char*, const char*, const char*);
static int check_file(Options*, const char*, const mode_t, const uint32);
@@ -146,7 +147,7 @@ int check_runlevel(Options *op)
if (ret != 2) {
ui_warn(op, "Skipping the runlevel check (unrecognized output from "
- "the `runlevel` utility: '%d').", data);
+ "the `runlevel` utility: '%s').", data);
nvfree(data);
return TRUE;
}
@@ -200,7 +201,7 @@ int adjust_cwd(Options *op, const char *program_name)
path = (char *) nvalloc(len + 1);
strncpy(path, program_name, len);
path[len] = '\0';
- if (op->expert) log_printf(op, TRUE, NULL, "chdir(\"%s\")", path);
+ if (op->expert) log_printf(op, NULL, "chdir(\"%s\")", path);
if (chdir(path)) {
fprintf(stderr, "Unable to chdir to %s (%s)",
path, strerror(errno));
@@ -509,7 +510,8 @@ int find_system_utils(Options *op)
{ "getenforce", "selinux" },
{ "execstack", "selinux" },
{ "pkg-config", "pkg-config" },
- { "X", "xserver" }
+ { "X", "xserver" },
+ { "openssl", "openssl" }
};
int i, j;
@@ -857,7 +859,7 @@ int do_install(Options *op, Package *p, CommandList *c)
if (!ret) return FALSE;
- ui_log(op, "Driver file installation is complete.", p->description);
+ ui_log(op, "Driver file installation is complete.");
return TRUE;
@@ -1051,7 +1053,7 @@ void should_install_opengl_headers(Options *op, Package *p)
*/
for (i = 0; i < p->num_entries; i++) {
- if (p->entries[i].flags & FILE_TYPE_OPENGL_HEADER) {
+ if (p->entries[i].type == FILE_TYPE_OPENGL_HEADER) {
have_headers = TRUE;
break;
}
@@ -1099,7 +1101,7 @@ void should_install_compat32_files(Options *op, Package *p)
*/
for (i = 0; i < p->num_entries; i++) {
- if (p->entries[i].flags & FILE_CLASS_COMPAT32) {
+ if (p->entries[i].compat_arch == FILE_COMPAT_ARCH_COMPAT32) {
have_compat32_files = TRUE;
break;
}
@@ -1133,9 +1135,9 @@ void should_install_compat32_files(Options *op, Package *p)
if (!install_compat32_files) {
for (i = 0; i < p->num_entries; i++) {
- if (p->entries[i].flags & FILE_CLASS_COMPAT32) {
+ if (p->entries[i].compat_arch == FILE_COMPAT_ARCH_COMPAT32) {
/* invalidate file */
- p->entries[i].flags &= ~FILE_TYPE_MASK;
+ p->entries[i].type = FILE_TYPE_NONE;
p->entries[i].dst = NULL;
}
}
@@ -1154,26 +1156,28 @@ void check_installed_files_from_package(Options *op, Package *p)
{
int i, ret = TRUE;
float percent;
- uint64_t installable_files;
+ PackageEntryFileTypeList installable_files;
ui_status_begin(op, "Running post-install sanity check:", "Checking");
- installable_files = get_installable_file_mask(op);
-
+ get_installable_file_type_list(op, &installable_files);
+
for (i = 0; i < p->num_entries; i++) {
percent = (float) i / (float) p->num_entries;
ui_status_update(op, percent, p->entries[i].dst);
- if (p->entries[i].flags & FILE_TYPE_SYMLINK) {
+ if (p->entries[i].caps.is_symlink &&
/* Don't bother checking FILE_TYPE_NEWSYMs because we may not have
* installed them. */
+ p->entries[i].type != FILE_TYPE_XMODULE_NEWSYM) {
+
if (!check_symlink(op, p->entries[i].target,
p->entries[i].dst,
p->description)) {
ret = FALSE;
}
- } else if (p->entries[i].flags & installable_files) {
+ } else if (installable_files.types[p->entries[i].type]) {
if (!check_file(op, p->entries[i].dst, p->entries[i].mode, 0)) {
ret = FALSE;
}
@@ -1241,6 +1245,46 @@ static int check_symlink(Options *op, const char *target, const char *link,
/*
+ * unprelink() - attempt to run `prelink -u` on a file to restore it to
+ * its pre-prelinked state.
+ */
+int unprelink(Options *op, const char *filename)
+{
+ char *cmd;
+ int ret = ENOENT;
+
+ cmd = find_system_util("prelink");
+ if (cmd) {
+ char *cmdline;
+ cmdline = nvstrcat(cmd, " -u ", filename, NULL);
+ ret = run_command(op, cmdline, NULL, FALSE, 0, TRUE);
+ nvfree(cmd);
+ nvfree(cmdline);
+ }
+ return ret;
+} /* unprelink() */
+
+
+
+/*
+ * verify_crc() - Compute the CRC of a file and compare it against an
+ * expected value. Returns TRUE if the values match, FALSE otherwise.
+ *
+ */
+int verify_crc(Options *op, const char *filename, unsigned int crc,
+ unsigned int *actual_crc)
+{
+ /* only check the crc if we were handed a non-emtpy crc */
+ if (crc == 0) {
+ return TRUE;
+ }
+ *actual_crc = compute_crc(op, filename);
+ return crc == *actual_crc;
+} /* verify_crc() */
+
+
+
+/*
* check_file() - check that the specified installed file exists, has
* the correct permissions, and has the correct crc.
*
@@ -1274,13 +1318,27 @@ static int check_file(Options *op, const char *filename,
return FALSE;
}
- /* only check the crc if we were handed a non-emtpy crc */
- if (crc != 0) {
- actual_crc = compute_crc(op, filename);
- if (crc != actual_crc) {
+ if (!verify_crc(op, filename, crc, &actual_crc)) {
+ int ret;
+
+ ui_expert(op, "The installed file '%s' has a different checksum (%ul) "
+ "than when it was installed (%ul). This may be due to "
+ "prelinking; attemping `prelink -u %s` to restore the file.",
+ filename, actual_crc, crc, filename);
+
+ ret = unprelink(op, filename);
+ if (ret != 0) {
+ ui_warn(op, "The installed file '%s' seems to have changed, but "
+ "`prelink -u` failed; unable to restore '%s' to an "
+ "un-prelinked state.", filename, filename);
+ return FALSE;
+ }
+
+ if (!verify_crc(op, filename, crc, &actual_crc)) {
ui_warn(op, "The installed file '%s' has a different checksum "
- "(%ul) than when it was installed (%ul).",
+ "(%ul) after running `prelink -u` than when it was "
+ "installed (%ul).",
filename, actual_crc, crc);
return FALSE;
}
@@ -1292,23 +1350,6 @@ static int check_file(Options *op, const char *filename,
-/*
- * get_installable_file_mask() - return the mask of what file types
- * should be considered installable.
- */
-
-uint64_t get_installable_file_mask(Options *op)
-{
- uint64_t installable_files = FILE_TYPE_INSTALLABLE_FILE;
- if (!op->opengl_headers) installable_files &= ~FILE_TYPE_OPENGL_HEADER;
- if (op->no_kernel_module_source)
- installable_files &= ~FILE_TYPE_KERNEL_MODULE_SRC;
- return installable_files;
-
-} /* get_installable_file_mask() */
-
-
-
#if defined(NV_TLS_TEST)
/*
* tls_test() - Starting with glibc 2.3, there is a new thread local
@@ -1655,25 +1696,27 @@ static int rtld_test_internal(Options *op, Package *p,
/* perform the test(s) */
for (i = 0; i < p->num_entries; i++) {
- if (!(p->entries[i].flags & FILE_TYPE_RTLD_CHECKED))
+ if ((p->entries[i].type != FILE_TYPE_OPENGL_LIB) &&
+ (p->entries[i].type != FILE_TYPE_TLS_LIB)) {
continue;
- else if ((which_tls & TLS_LIB_TYPE_FORCED) &&
- (p->entries[i].flags & FILE_TYPE_TLS_LIB))
+ } else if ((which_tls & TLS_LIB_TYPE_FORCED) &&
+ (p->entries[i].type == FILE_TYPE_TLS_LIB)) {
continue;
#if defined(NV_X86_64)
- else if ((p->entries[i].flags & FILE_CLASS_NATIVE)
- && compat_32_libs)
+ } else if ((p->entries[i].compat_arch == FILE_COMPAT_ARCH_NATIVE)
+ && compat_32_libs) {
continue;
- else if ((p->entries[i].flags & FILE_CLASS_COMPAT32)
- && !compat_32_libs)
+ } else if ((p->entries[i].compat_arch == FILE_COMPAT_ARCH_COMPAT32)
+ && !compat_32_libs) {
continue;
#endif /* NV_X86_64 */
- else if ((which_tls == TLS_LIB_NEW_TLS) &&
- (p->entries[i].flags & FILE_CLASS_CLASSIC_TLS))
+ } else if ((which_tls == TLS_LIB_NEW_TLS) &&
+ (p->entries[i].tls_class == FILE_TLS_CLASS_CLASSIC)) {
continue;
- else if ((which_tls == TLS_LIB_CLASSIC_TLS) &&
- (p->entries[i].flags & FILE_CLASS_NEW_TLS))
+ } else if ((which_tls == TLS_LIB_CLASSIC_TLS) &&
+ (p->entries[i].tls_class == FILE_TLS_CLASS_NEW)) {
continue;
+ }
name = nvstrdup(p->entries[i].name);
if (!name) continue;
@@ -1830,6 +1873,7 @@ Distribution get_distribution(Options *op)
if (access("/etc/SuSE-release", F_OK) == 0) return SUSE;
if (access("/etc/UnitedLinux-release", F_OK) == 0) return UNITED_LINUX;
if (access("/etc/gentoo-release", F_OK) == 0) return GENTOO;
+ if (access("/etc/arch-release", F_OK) == 0) return ARCH;
/*
* Attempt to determine if the host system is 'Ubuntu Linux'
@@ -2711,3 +2755,62 @@ int dkms_remove_module(Options *op, const char *version)
{
return run_dkms(op, DKMS_REMOVE, version, NULL, NULL);
}
+
+/*
+ * Test the last bit of the given file. Return 1 if the bit is set, 0 if it is
+ * not set, and < 0 on error.
+ *
+ */
+static int test_last_bit(const char *file) {
+ char buf;
+ int ret, data_read = FALSE;
+ FILE *fp = fopen(file, "r");
+
+ if (!fp) {
+ return -errno;
+ }
+
+ /* XXX Using fseek(3) could make this more efficient for larger files, but
+ * trying to read after an fseek(stream, -1, SEEK_END) call on a UEFI
+ * variable file in sysfs hits a premature EOF. */
+
+ while(fread(&buf, 1, 1, fp)) {
+ data_read = TRUE;
+ }
+
+ if (ferror(fp)) {
+ ret = -ferror(fp);
+ } else if (data_read) {
+ ret = buf & 1;
+ } else {
+ ret = -EIO;
+ }
+
+ fclose(fp);
+ return ret;
+}
+
+static const char* secure_boot_files[] = {
+ "/sys/firmware/efi/vars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c/data",
+ "/sys/firmware/efi/efivars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c",
+};
+
+/*
+ * secure_boot_enabled() - Check the known paths where secure boot status is
+ * exposed. If secure boot is enabled, return 1. If secure boot is disabled,
+ * return 0. On failure to detect whether secure boot is enabled, return < 0.
+ */
+int secure_boot_enabled(void) {
+ int i, ret = -ENOENT;
+
+ for (i = 0; i < ARRAY_LEN(secure_boot_files); i++) {
+ if (access(secure_boot_files[i], R_OK) == 0) {
+ ret = test_last_bit(secure_boot_files[i]);
+ if (ret >= 0) {
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
diff --git a/misc.h b/misc.h
index b78e958..b8c37ac 100644
--- a/misc.h
+++ b/misc.h
@@ -46,12 +46,11 @@ int check_selinux(Options *op);
int check_proc_modprobe_path(Options *op);
int check_development_tools(Options *op, Package *p);
char *extract_version_string(const char *str);
-int continue_after_error(Options *op, const char *fmt, ...);
+int continue_after_error(Options *op, const char *fmt, ...) NV_ATTRIBUTE_PRINTF(2, 3);
int do_install(Options *op, Package *p, CommandList *c);
void should_install_opengl_headers(Options *op, Package *p);
void should_install_compat32_files(Options *op, Package *p);
void check_installed_files_from_package(Options *op, Package *p);
-uint64_t get_installable_file_mask(Options *op);
int tls_test(Options *op, int compat_32_libs);
int check_runtime_configuration(Options *op, Package *p);
void collapse_multiple_slashes(char *s);
@@ -66,5 +65,9 @@ int check_for_nouveau(Options *op);
int dkms_module_installed(Options *op, const char *version);
int dkms_install_module(Options *op, const char *version, const char *kernel);
int dkms_remove_module(Options *op, const char *version);
+int unprelink(Options *op, const char *filename);
+int verify_crc(Options *op, const char *filename, unsigned int crc,
+ unsigned int *actual_crc);
+int secure_boot_enabled(void);
#endif /* __NVIDIA_INSTALLER_MISC_H__ */
diff --git a/nvidia-installer.c b/nvidia-installer.c
index 75168ea..0117c5a 100644
--- a/nvidia-installer.c
+++ b/nvidia-installer.c
@@ -138,6 +138,7 @@ static Options *load_default_options(void)
op->logging = TRUE; /* log by default */
op->opengl_headers = FALSE; /* do not install our GL headers by default */
+ op->nvidia_modprobe = TRUE;
op->run_nvidia_xconfig = FALSE;
op->selinux_option = SELINUX_DEFAULT;
@@ -253,6 +254,8 @@ static void parse_commandline(int argc, char *argv[], Options *op)
#endif
case DOCUMENTATION_PREFIX_OPTION:
op->documentation_prefix = strval; break;
+ case APPLICATION_PROFILE_PATH_OPTION:
+ op->application_profile_path = strval; break;
case INSTALLER_PREFIX_OPTION:
op->installer_prefix = strval; break;
case UTILITY_PREFIX_OPTION:
@@ -282,6 +285,8 @@ static void parse_commandline(int argc, char *argv[], Options *op)
op->tmpdir = strval; break;
case OPENGL_HEADERS_OPTION:
op->opengl_headers = TRUE; break;
+ case NO_NVIDIA_MODPROBE_OPTION:
+ op->nvidia_modprobe = FALSE; break;
case FORCE_TLS_OPTION:
if (strcasecmp(strval, "new") == 0)
op->which_tls = FORCE_NEW_TLS;
@@ -382,6 +387,21 @@ static void parse_commandline(int argc, char *argv[], Options *op)
case DKMS_OPTION:
op->dkms = TRUE;
break;
+ case MODULE_SIGNING_SECRET_KEY_OPTION:
+ op->module_signing_secret_key = strval;
+ break;
+ case MODULE_SIGNING_PUBLIC_KEY_OPTION:
+ op->module_signing_public_key = strval;
+ break;
+ case MODULE_SIGNING_SCRIPT_OPTION:
+ op->module_signing_script = strval;
+ break;
+ case MODULE_SIGNING_KEY_PATH_OPTION:
+ op->module_signing_key_path = strval;
+ break;
+ case MODULE_SIGNING_HASH_OPTION:
+ op->module_signing_hash = strval;
+ break;
default:
goto fail;
}
@@ -420,6 +440,18 @@ static void parse_commandline(int argc, char *argv[], Options *op)
exit(0);
}
+ /* Disable DKMS if module signing was requested; the two options are
+ * mutually exclusive. */
+ if (op->dkms &&
+ op->module_signing_secret_key && op->module_signing_public_key) {
+ ui_warn(op, "You selected the DKMS kernel module option, and also "
+ "specified a pair of module signing keys. Keys cannot be "
+ "managed securely under the automated DKMS framework. The "
+ "DKMS option will be disabled.");
+ op->dkms = FALSE;
+ }
+
+
/*
* if the installer prefix was not specified, default it to the
* utility prefix; this is done so that the installer prefix is
diff --git a/nvidia-installer.h b/nvidia-installer.h
index 580d69f..ea95051 100644
--- a/nvidia-installer.h
+++ b/nvidia-installer.h
@@ -24,7 +24,7 @@
#define __NVIDIA_INSTALLER_H__
#include <sys/types.h>
-#include <stdint.h>
+#include <inttypes.h>
#include "common-utils.h"
@@ -55,6 +55,7 @@ typedef enum {
EXECSTACK,
PKG_CONFIG,
XSERVER,
+ OPENSSL,
MAX_SYSTEM_OPTIONAL_UTILS
} SystemOptionalUtils;
@@ -85,6 +86,7 @@ typedef enum {
DEBIAN,
UBUNTU,
GENTOO,
+ ARCH,
OTHER
} Distribution;
@@ -116,6 +118,7 @@ typedef struct __options {
int latest;
int force_update;
int opengl_headers;
+ int nvidia_modprobe;
int no_questions;
int silent;
int which_tls;
@@ -168,6 +171,8 @@ typedef struct __options {
char *documentation_docdir;
char *documentation_mandir;
+ char *application_profile_path;
+
int modular_xorg;
char *kernel_source_path;
@@ -192,6 +197,14 @@ typedef struct __options {
char *precompiled_kernel_interfaces_url;
const char *selinux_chcon_type;
+ char *module_signing_secret_key;
+ char *module_signing_public_key;
+ char *module_signing_script;
+ char *module_signing_key_path;
+ char *module_signing_hash;
+
+ int kernel_module_signed;
+
Distribution distro;
void *ui_priv; /* for use by the ui's */
@@ -200,6 +213,85 @@ typedef struct __options {
} Options;
+/*
+ * Types of installed files. Keep in sync with
+ * manifest.c:packageEntryFileTypeTable[]
+ */
+typedef enum {
+ FILE_TYPE_NONE,
+ FILE_TYPE_KERNEL_MODULE_SRC,
+ FILE_TYPE_KERNEL_MODULE_CMD,
+ FILE_TYPE_OPENGL_HEADER,
+ FILE_TYPE_OPENGL_LIB,
+ FILE_TYPE_XLIB_STATIC_LIB,
+ FILE_TYPE_XLIB_SHARED_LIB,
+ FILE_TYPE_DOCUMENTATION,
+ FILE_TYPE_OPENGL_SYMLINK,
+ FILE_TYPE_XLIB_SYMLINK,
+ FILE_TYPE_KERNEL_MODULE,
+ FILE_TYPE_INSTALLER_BINARY,
+ FILE_TYPE_UTILITY_BINARY,
+ FILE_TYPE_LIBGL_LA,
+ FILE_TYPE_TLS_LIB,
+ FILE_TYPE_TLS_SYMLINK,
+ FILE_TYPE_UTILITY_LIB,
+ FILE_TYPE_DOT_DESKTOP,
+ FILE_TYPE_UTILITY_LIB_SYMLINK,
+ FILE_TYPE_XMODULE_SHARED_LIB,
+ FILE_TYPE_XMODULE_SYMLINK,
+ FILE_TYPE_XMODULE_NEWSYM, /* Create a symlink if the file doesn't exist */
+ FILE_TYPE_MANPAGE,
+ FILE_TYPE_EXPLICIT_PATH,
+ FILE_TYPE_CUDA_LIB,
+ FILE_TYPE_CUDA_SYMLINK,
+ FILE_TYPE_VDPAU_LIB,
+ FILE_TYPE_VDPAU_SYMLINK,
+ FILE_TYPE_UTILITY_BIN_SYMLINK,
+ FILE_TYPE_CUDA_ICD,
+ FILE_TYPE_NVCUVID_LIB,
+ FILE_TYPE_NVCUVID_LIB_SYMLINK,
+ FILE_TYPE_GLX_MODULE_SHARED_LIB,
+ FILE_TYPE_GLX_MODULE_SYMLINK,
+ FILE_TYPE_ENCODEAPI_LIB,
+ FILE_TYPE_ENCODEAPI_LIB_SYMLINK,
+ FILE_TYPE_VGX_LIB,
+ FILE_TYPE_VGX_LIB_SYMLINK,
+ FILE_TYPE_APPLICATION_PROFILE,
+ FILE_TYPE_NVIDIA_MODPROBE,
+ FILE_TYPE_NVIDIA_MODPROBE_MANPAGE,
+ FILE_TYPE_MODULE_SIGNING_KEY,
+ FILE_TYPE_MAX
+} PackageEntryFileType;
+
+typedef enum {
+ FILE_TLS_CLASS_NONE,
+ FILE_TLS_CLASS_NEW,
+ FILE_TLS_CLASS_CLASSIC,
+} PackageEntryFileTlsClass;
+
+typedef enum {
+ FILE_COMPAT_ARCH_NONE,
+ FILE_COMPAT_ARCH_NATIVE,
+ FILE_COMPAT_ARCH_COMPAT32,
+} PackageEntryFileCompatArch;
+
+typedef struct {
+ unsigned int has_arch : 1;
+ unsigned int has_tls_class : 1;
+ unsigned int installable : 1;
+ unsigned int has_path : 1;
+ unsigned int is_symlink : 1;
+ unsigned int is_shared_lib : 1;
+ unsigned int is_opengl : 1;
+} PackageEntryFileCapabilities;
+
+/*
+ * PackageEntryFileTypeList::types[] are booleans, indexed by
+ * PackageEntryFileType enum value.
+ */
+typedef struct {
+ uint8_t types[FILE_TYPE_MAX];
+} PackageEntryFileTypeList;
typedef struct __package_entry {
@@ -233,7 +325,11 @@ typedef struct __package_entry {
* function.
*/
- uint64_t flags;
+ PackageEntryFileCapabilities caps;
+ PackageEntryFileType type;
+ PackageEntryFileTlsClass tls_class;
+ PackageEntryFileCompatArch compat_arch;
+
mode_t mode;
ino_t inode;
@@ -275,162 +371,6 @@ typedef struct __package {
#define NV_LINE_LEN 1024
#define NV_MIN_LINE_LEN 256
-/* file types */
-
-#define FILE_TYPE_MASK 0x0000003fffffffffULL
-
-#define FILE_TYPE_KERNEL_MODULE_SRC 0x0000000000000001ULL
-#define FILE_TYPE_KERNEL_MODULE_CMD 0x0000000000000002ULL
-#define FILE_TYPE_OPENGL_HEADER 0x0000000000000004ULL
-#define FILE_TYPE_OPENGL_LIB 0x0000000000000008ULL
-#define FILE_TYPE_XLIB_STATIC_LIB 0x0000000000000010ULL
-#define FILE_TYPE_XLIB_SHARED_LIB 0x0000000000000020ULL
-#define FILE_TYPE_DOCUMENTATION 0x0000000000000040ULL
-#define FILE_TYPE_OPENGL_SYMLINK 0x0000000000000080ULL
-#define FILE_TYPE_XLIB_SYMLINK 0x0000000000000100ULL
-#define FILE_TYPE_KERNEL_MODULE 0x0000000000000200ULL
-#define FILE_TYPE_INSTALLER_BINARY 0x0000000000000400ULL
-#define FILE_TYPE_UTILITY_BINARY 0x0000000000000800ULL
-#define FILE_TYPE_LIBGL_LA 0x0000000000001000ULL
-#define FILE_TYPE_TLS_LIB 0x0000000000002000ULL
-#define FILE_TYPE_TLS_SYMLINK 0x0000000000004000ULL
-#define FILE_TYPE_UTILITY_LIB 0x0000000000008000ULL
-#define FILE_TYPE_DOT_DESKTOP 0x0000000000010000ULL
-#define FILE_TYPE_UTILITY_LIB_SYMLINK 0x0000000000020000ULL
-#define FILE_TYPE_XMODULE_SHARED_LIB 0x0000000000040000ULL
-#define FILE_TYPE_XMODULE_SYMLINK 0x0000000000080000ULL
-/* Create a symlink only if the file doesn't exist */
-#define FILE_TYPE_XMODULE_NEWSYM 0x0000000000100000ULL
-#define FILE_TYPE_MANPAGE 0x0000000000200000ULL
-#define FILE_TYPE_EXPLICIT_PATH 0x0000000000400000ULL
-#define FILE_TYPE_CUDA_LIB 0x0000000000800000ULL
-#define FILE_TYPE_CUDA_SYMLINK 0x0000000001000000ULL
-#define FILE_TYPE_VDPAU_LIB 0x0000000002000000ULL
-#define FILE_TYPE_VDPAU_SYMLINK 0x0000000004000000ULL
-/* unused 0x0000000008000000ULL */
-#define FILE_TYPE_UTILITY_BIN_SYMLINK 0x0000000010000000ULL
-#define FILE_TYPE_CUDA_ICD 0x0000000020000000ULL
-#define FILE_TYPE_NVCUVID_LIB 0x0000000040000000ULL
-#define FILE_TYPE_NVCUVID_SYMLINK 0x0000000080000000ULL
-#define FILE_TYPE_GLX_MODULE_SHARED_LIB 0x0000000100000000ULL
-#define FILE_TYPE_GLX_MODULE_SYMLINK 0x0000000200000000ULL
-#define FILE_TYPE_ENCODEAPI_LIB 0x0000000400000000ULL
-#define FILE_TYPE_ENCODEAPI_SYMLINK 0x0000000800000000ULL
-#define FILE_TYPE_VGX_LIB 0x0000001000000000ULL
-#define FILE_TYPE_VGX_SYMLINK 0x0000002000000000ULL
-
-/* file class: this is used to distinguish OpenGL libraries */
-
-#define FILE_CLASS_MASK 0xf000000000000000ULL
-
-#define FILE_CLASS_NEW_TLS 0x1000000000000000ULL
-#define FILE_CLASS_CLASSIC_TLS 0x2000000000000000ULL
-#define FILE_CLASS_NATIVE 0x4000000000000000ULL
-#define FILE_CLASS_COMPAT32 0x8000000000000000ULL
-
-#define FILE_TYPE_XLIB_LIB (FILE_TYPE_XLIB_STATIC_LIB | \
- FILE_TYPE_XLIB_SHARED_LIB)
-
-#define FILE_TYPE_INSTALLABLE_FILE (FILE_TYPE_OPENGL_LIB | \
- FILE_TYPE_CUDA_LIB | \
- FILE_TYPE_XLIB_LIB | \
- FILE_TYPE_TLS_LIB | \
- FILE_TYPE_UTILITY_LIB | \
- FILE_TYPE_DOCUMENTATION | \
- FILE_TYPE_MANPAGE | \
- FILE_TYPE_EXPLICIT_PATH | \
- FILE_TYPE_OPENGL_HEADER | \
- FILE_TYPE_CUDA_ICD | \
- FILE_TYPE_KERNEL_MODULE | \
- FILE_TYPE_INSTALLER_BINARY | \
- FILE_TYPE_UTILITY_BINARY | \
- FILE_TYPE_LIBGL_LA | \
- FILE_TYPE_XMODULE_SHARED_LIB | \
- FILE_TYPE_GLX_MODULE_SHARED_LIB | \
- FILE_TYPE_DOT_DESKTOP | \
- FILE_TYPE_VDPAU_LIB | \
- FILE_TYPE_NVCUVID_LIB | \
- FILE_TYPE_KERNEL_MODULE_SRC | \
- FILE_TYPE_ENCODEAPI_LIB | \
- FILE_TYPE_VGX_LIB)
-
-#define FILE_TYPE_HAVE_PATH (FILE_TYPE_XMODULE_SHARED_LIB | \
- FILE_TYPE_XMODULE_SYMLINK | \
- FILE_TYPE_GLX_MODULE_SHARED_LIB | \
- FILE_TYPE_GLX_MODULE_SYMLINK | \
- FILE_TYPE_XMODULE_NEWSYM | \
- FILE_TYPE_MANPAGE | \
- FILE_TYPE_EXPLICIT_PATH | \
- FILE_TYPE_OPENGL_HEADER | \
- FILE_TYPE_CUDA_LIB | \
- FILE_TYPE_CUDA_SYMLINK | \
- FILE_TYPE_TLS_LIB | \
- FILE_TYPE_TLS_SYMLINK | \
- FILE_TYPE_DOT_DESKTOP | \
- FILE_TYPE_DOCUMENTATION | \
- FILE_TYPE_VDPAU_SYMLINK | \
- FILE_TYPE_VDPAU_LIB)
-
-
-#define FILE_TYPE_HAVE_ARCH (FILE_TYPE_OPENGL_LIB | \
- FILE_TYPE_CUDA_LIB | \
- FILE_TYPE_OPENGL_SYMLINK | \
- FILE_TYPE_CUDA_SYMLINK | \
- FILE_TYPE_LIBGL_LA | \
- FILE_TYPE_TLS_LIB | \
- FILE_TYPE_TLS_SYMLINK | \
- FILE_TYPE_VDPAU_SYMLINK | \
- FILE_TYPE_VDPAU_LIB | \
- FILE_TYPE_NVCUVID_LIB | \
- FILE_TYPE_NVCUVID_SYMLINK | \
- FILE_TYPE_ENCODEAPI_LIB | \
- FILE_TYPE_ENCODEAPI_SYMLINK)
-
-#define FILE_TYPE_HAVE_CLASS (FILE_TYPE_TLS_LIB | \
- FILE_TYPE_TLS_SYMLINK)
-
-#define FILE_TYPE_SYMLINK (FILE_TYPE_OPENGL_SYMLINK | \
- FILE_TYPE_CUDA_SYMLINK | \
- FILE_TYPE_XLIB_SYMLINK | \
- FILE_TYPE_TLS_SYMLINK | \
- FILE_TYPE_XMODULE_SYMLINK | \
- FILE_TYPE_GLX_MODULE_SYMLINK | \
- FILE_TYPE_UTILITY_LIB_SYMLINK| \
- FILE_TYPE_UTILITY_BIN_SYMLINK| \
- FILE_TYPE_VDPAU_SYMLINK | \
- FILE_TYPE_NVCUVID_SYMLINK | \
- FILE_TYPE_ENCODEAPI_SYMLINK | \
- FILE_TYPE_VGX_SYMLINK)
-
-#define FILE_TYPE_NEWSYM (FILE_TYPE_XMODULE_NEWSYM)
-
-#define FILE_TYPE_HAVE_TARGET (FILE_TYPE_SYMLINK | \
- FILE_TYPE_NEWSYM)
-
-#define FILE_TYPE_RTLD_CHECKED (FILE_TYPE_OPENGL_LIB | \
- FILE_TYPE_TLS_LIB)
-
-#define FILE_TYPE_SHARED_LIB (FILE_TYPE_OPENGL_LIB | \
- FILE_TYPE_CUDA_LIB | \
- FILE_TYPE_XLIB_SHARED_LIB | \
- FILE_TYPE_TLS_LIB | \
- FILE_TYPE_XMODULE_SHARED_LIB | \
- FILE_TYPE_GLX_MODULE_SHARED_LIB | \
- FILE_TYPE_UTILITY_LIB | \
- FILE_TYPE_VDPAU_LIB | \
- FILE_TYPE_NVCUVID_LIB | \
- FILE_TYPE_ENCODEAPI_LIB | \
- FILE_TYPE_VGX_LIB)
-
-#define FILE_TYPE_OPENGL_FILE (FILE_TYPE_OPENGL_HEADER | \
- FILE_TYPE_OPENGL_LIB | \
- FILE_TYPE_OPENGL_SYMLINK | \
- FILE_TYPE_LIBGL_LA | \
- FILE_TYPE_TLS_LIB | \
- FILE_TYPE_TLS_SYMLINK | \
- FILE_TYPE_GLX_MODULE_SHARED_LIB | \
- FILE_TYPE_GLX_MODULE_SYMLINK)
-
#define TLS_LIB_TYPE_FORCED 0x0001
#define TLS_LIB_NEW_TLS 0x0002
#define TLS_LIB_CLASSIC_TLS 0x0004
@@ -445,6 +385,8 @@ typedef struct __package {
#define PERM_MASK (S_IRWXU|S_IRWXG|S_IRWXO)
#define PRECOMPILED_KERNEL_INTERFACE_FILENAME "precompiled-nv-linux.o"
+#define KERNEL_MODULE_CHECKSUM_FILENAME "nvidia-module-checksum"
+#define DETACHED_SIGNATURE_FILENAME "nvidia-detached-module-signature"
/*
@@ -454,10 +396,11 @@ typedef struct __package {
* is detected, all prefixes/paths can be overriden from the
* command line.
*/
-#define DEFAULT_OPENGL_PREFIX "/usr"
-#define DEFAULT_X_PREFIX "/usr/X11R6"
-#define DEFAULT_UTILITY_PREFIX "/usr"
-#define DEFAULT_DOCUMENTATION_PREFIX "/usr"
+#define DEFAULT_OPENGL_PREFIX "/usr"
+#define DEFAULT_X_PREFIX "/usr/X11R6"
+#define DEFAULT_UTILITY_PREFIX "/usr"
+#define DEFAULT_DOCUMENTATION_PREFIX "/usr"
+#define DEFAULT_APPLICATION_PROFILE_PATH "/usr/share/nvidia"
#define DEFAULT_LIBDIR "lib"
#define DEFAULT_64BIT_LIBDIR "lib64"
@@ -468,6 +411,7 @@ typedef struct __package {
#define DEFAULT_DOCDIR "share/doc"
#define DEFAULT_MANDIR "share/man"
+#define DEFAULT_MODULE_SIGNING_KEY_PATH "/usr/share/nvidia"
#define DEFAULT_KERNEL_MODULE_SRC_PREFIX "/usr/src"
/*
@@ -537,8 +481,7 @@ typedef struct __package {
/* prototypes of functions used throughout the installer */
void log_init(Options *op, int argc, char * const argv[]);
-void log_printf(Options *op, const int wb,
- const char *prefix, const char *fmt, ...);
+void log_printf(Options *op, const char *prefix, const char *fmt, ...) NV_ATTRIBUTE_PRINTF(3, 4);
int install_from_cwd(Options *op);
int add_this_kernel(Options *op);
@@ -549,7 +492,8 @@ void add_package_entry(Package *p,
char *name,
char *target,
char *dst,
- uint64_t flags,
+ PackageEntryFileType type,
+ PackageEntryFileTlsClass tls_class,
mode_t mode);
/* XXX */
diff --git a/option_table.h b/option_table.h
index ab3b115..a5854ae 100644
--- a/option_table.h
+++ b/option_table.h
@@ -47,6 +47,7 @@ enum {
HELP_ARGS_ONLY_OPTION,
TMPDIR_OPTION,
OPENGL_HEADERS_OPTION,
+ NO_NVIDIA_MODPROBE_OPTION,
INSTALLER_PREFIX_OPTION,
FORCE_TLS_OPTION,
SANITY_OPTION,
@@ -74,6 +75,7 @@ enum {
NO_SIGWINCH_WORKAROUND_OPTION,
X_MODULE_PATH_OPTION,
DOCUMENTATION_PREFIX_OPTION,
+ APPLICATION_PROFILE_PATH_OPTION,
X_LIBRARY_PATH_OPTION,
NO_KERNEL_MODULE_OPTION,
NO_X_CHECK_OPTION,
@@ -84,6 +86,11 @@ enum {
KERNEL_MODULE_SOURCE_DIR_OPTION,
NO_KERNEL_MODULE_SOURCE_OPTION,
DKMS_OPTION,
+ MODULE_SIGNING_SECRET_KEY_OPTION,
+ MODULE_SIGNING_PUBLIC_KEY_OPTION,
+ MODULE_SIGNING_SCRIPT_OPTION,
+ MODULE_SIGNING_KEY_PATH_OPTION,
+ MODULE_SIGNING_HASH_OPTION
};
static const NVGetoptOption __options[] = {
@@ -247,6 +254,12 @@ static const NVGetoptOption __options[] = {
"driver will be installed. The default is: '"
DEFAULT_DOCUMENTATION_PREFIX "'." },
+ { "application-profile-path", APPLICATION_PROFILE_PATH_OPTION,
+ NVGETOPT_STRING_ARGUMENT, NULL,
+ "The directory under which default application profiles for the NVIDIA "
+ "driver will be installed. The default is: '"
+ DEFAULT_APPLICATION_PROFILE_PATH "'." },
+
{ "kernel-include-path", KERNEL_INCLUDE_PATH_OPTION,
NVGETOPT_STRING_ARGUMENT, NULL,
"The directory containing the kernel include files that "
@@ -338,6 +351,16 @@ static const NVGetoptOption __options[] = {
"a glx.h or gl.h. Until that is resolved, NVIDIA's OpenGL "
"header files can still be chosen, through this installer option." },
+ { "no-nvidia-modprobe", NO_NVIDIA_MODPROBE_OPTION, 0, NULL,
+ "Skip installation of 'nvidia-modprobe', a setuid root utility which "
+ "nvidia-installer installs by default. nvidia-modprobe can be used by "
+ "user-space NVIDIA driver components to load the NVIDIA kernel module, "
+ "and create the NVIDIA device files, when those components run without "
+ "sufficient privileges to do so on their own, e.g., the CUDA driver run "
+ "within the permissions of a non-privileged user. This utility is only "
+ "needed if other means of loading the NVIDIA kernel module and creating "
+ "the NVIDIA device files are unavailable." },
+
{ "force-tls", FORCE_TLS_OPTION, NVGETOPT_STRING_ARGUMENT, NULL,
"NVIDIA's OpenGL libraries are compiled with one of two "
"different thread local storage (TLS) mechanisms: 'classic tls' "
@@ -539,6 +562,40 @@ static const NVGetoptOption __options[] = {
"'--no-questions' or '--silent' options, which assume the default "
"values for all questions." },
+ { "module-signing-secret-key", MODULE_SIGNING_SECRET_KEY_OPTION,
+ NVGETOPT_STRING_ARGUMENT, NULL,
+ "Specify a path to a private key to use for signing the NVIDIA kernel "
+ "module. The corresponding public key must also be provided." },
+
+ { "module-signing-public-key", MODULE_SIGNING_PUBLIC_KEY_OPTION,
+ NVGETOPT_STRING_ARGUMENT, NULL,
+ "Specify a path to a public key to use for verifying the signature of "
+ "the NVIDIA kernel module. The corresponding private key must also be "
+ "provided." },
+
+ { "module-signing-script", MODULE_SIGNING_SCRIPT_OPTION,
+ NVGETOPT_STRING_ARGUMENT, NULL,
+ "Specify a path to a program to use for signing the NVIDIA kernel "
+ "module. The program will be called with the arguments: program-name "
+ "<HASH> <PRIVATEKEY> <PUBLICKEY> <MODULE>; if the program returns an "
+ "error status, it will be called again with the arguments: program-name "
+ "<PRIVATEKEY> <PUBLICKEY> <MODULE>. Default: use the \"sign-file\" "
+ "script in the kernel source directory." },
+
+ { "module-signing-key-path", MODULE_SIGNING_KEY_PATH_OPTION,
+ NVGETOPT_STRING_ARGUMENT, NULL,
+ "Specify a path where signing keys generated by nvidia-installer will "
+ "be installed. Default: install keys to '" DEFAULT_MODULE_SIGNING_KEY_PATH
+ "'." },
+
+ { "module-signing-hash", MODULE_SIGNING_HASH_OPTION,
+ NVGETOPT_STRING_ARGUMENT, NULL,
+ "Specify a cryptographic hash algorithm to use for signing kernel "
+ "modules. This requires a module signing tool that allows explicit "
+ "selection of the hash algorithm, and the hash algorithm name must "
+ "be recognizable by the module signing tool. Default: select a hash "
+ "algorithm automatically, based on the kernel's configuration." },
+
/* Orphaned options: These options were in the long_options table in
* nvidia-installer.c but not in the help. */
{ "debug", 'd', 0, NULL,NULL },
diff --git a/precompiled.c b/precompiled.c
index 647ae69..ae1ab91 100644
--- a/precompiled.c
+++ b/precompiled.c
@@ -152,8 +152,9 @@ PrecompiledInfo *precompiled_unpack(Options *op,
{
int dst_fd, fd, offset, len = 0;
char *buf, *dst;
- uint32 crc, val, size;
- char *version, *description, *proc_version_string;
+ uint32 crc, val, size, linked_module_crc;
+ char *version, *description, *proc_version_string,
+ *detached_signature = NULL;
struct stat stat_buf;
PrecompiledInfo *info = NULL;
@@ -265,6 +266,45 @@ PrecompiledInfo *precompiled_unpack(Options *op,
offset += val;
proc_version_string[val] = '\0';
+ /* if this interface appears to have been packaged by nvidia-installer,
+ * get the linked module crc and path to the detached signature. */
+
+ if (strstr(filename, PRECOMPILED_KERNEL_INTERFACE_FILENAME) ==
+ strrchr(filename, '/') + 1) {
+ char *suffix, *dirname, *tmp, *crc_file_path;
+
+ dirname = nvstrdup(filename);
+ tmp = strrchr(dirname, '/');
+ *tmp = '\0';
+
+ suffix = nvstrdup(strrchr(filename, '/') + 1 +
+ strlen(PRECOMPILED_KERNEL_INTERFACE_FILENAME));
+
+ detached_signature = nvstrcat(dirname, "/", DETACHED_SIGNATURE_FILENAME,
+ suffix, NULL);
+ crc_file_path = nvstrcat(dirname, "/", KERNEL_MODULE_CHECKSUM_FILENAME,
+ suffix, NULL);
+
+ if (access(detached_signature, F_OK | R_OK) == 0 &&
+ access(crc_file_path, F_OK | R_OK) == 0) {
+ FILE *crc_file;
+
+ crc_file = fopen(crc_file_path, "r");
+ if (crc_file) {
+ int items_read = fread(&linked_module_crc,
+ sizeof(linked_module_crc), 1, crc_file);
+ if (items_read != 1) {
+ ui_warn(op, "A checksum file for a linked kernel module "
+ "was found, but reading the checksum failed.");
+ detached_signature = NULL;
+ }
+ fclose(crc_file);
+ }
+ } else {
+ detached_signature = NULL;
+ }
+ }
+
/* check if the running kernel matches */
if (strcmp(real_proc_version_string, proc_version_string) != 0) {
@@ -317,13 +357,15 @@ PrecompiledInfo *precompiled_unpack(Options *op,
info->version = version;
info->proc_version_string = proc_version_string;
info->description = description;
+ info->detached_signature = detached_signature;
+ info->linked_module_crc = linked_module_crc;
/*
- * XXX so that the proc version and description strings aren't
- * freed below
+ * XXX so that the proc version, description, and detached_signature strings
+ * aren't freed below
*/
- proc_version_string = description = NULL;
+ proc_version_string = description = detached_signature = NULL;
done:
@@ -335,7 +377,20 @@ PrecompiledInfo *precompiled_unpack(Options *op,
if (dst_fd > 0) close(dst_fd);
if (description) free(description);
if (proc_version_string) free(proc_version_string);
+ if (detached_signature) free(detached_signature);
return info;
} /* mkprecompiled_unpack() */
+
+/*
+ * free_precompiled() - free any malloced strings stored in a PrecompiledInfo,
+ * then free the PrecompiledInfo.
+ */
+void free_precompiled(PrecompiledInfo *info)
+{
+ nvfree(info->description);
+ nvfree(info->proc_version_string);
+ nvfree(info->detached_signature);
+ nvfree(info);
+}
diff --git a/precompiled.h b/precompiled.h
index d760074..999208b 100644
--- a/precompiled.h
+++ b/precompiled.h
@@ -31,6 +31,8 @@ typedef struct {
char *version;
char *proc_version_string;
char *description;
+ char *detached_signature;
+ uint32 linked_module_crc;
} PrecompiledInfo;
@@ -42,6 +44,7 @@ PrecompiledInfo *precompiled_unpack(Options *op,
const char *output_filename,
const char *real_proc_version_string,
const char *package_version);
+void free_precompiled(PrecompiledInfo *info);
#endif /* __NVIDIA_INSTALLER_PRECOMPILED_H__ */
diff --git a/user-interface.c b/user-interface.c
index aff75a0..ea21045 100644
--- a/user-interface.c
+++ b/user-interface.c
@@ -105,7 +105,7 @@ int ui_init(Options *op)
}
if (i == ARRAY_LEN(ui_list)) {
- log_printf(op, TRUE, NULL, "Invalid \"ui\" option: %s", op->ui_str);
+ log_printf(op, NULL, "Invalid \"ui\" option: %s", op->ui_str);
i = 0;
}
} else {
@@ -125,20 +125,18 @@ int ui_init(Options *op)
if (handle) {
__ui = dlsym(handle, "ui_dispatch_table");
if (__ui && __ui->detect(op)) {
- log_printf(op, TRUE, NULL, "Using: %s",
- ui_list[i].descr);
+ log_printf(op, NULL, "Using: %s", ui_list[i].descr);
__extracted_user_interface_filename = ui_list[i].filename;
break;
} else {
- log_printf(op, TRUE, NULL, "Unable to initialize: %s",
+ log_printf(op, NULL, "Unable to initialize: %s",
ui_list[i].descr);
dlclose(handle);
__ui = NULL;
}
} else {
- log_printf(op, TRUE, NULL, "Unable to load: %s",
- ui_list[i].descr);
- log_printf(op, TRUE, NULL, "");
+ log_printf(op, NULL, "Unable to load: %s", ui_list[i].descr);
+ log_printf(op, NULL, "");
}
}
@@ -146,7 +144,7 @@ int ui_init(Options *op)
if (!__ui) {
__ui = &stream_ui_dispatch_table;
- log_printf(op, TRUE, NULL, "Using built-in stream user interface");
+ log_printf(op, NULL, "Using built-in stream user interface");
}
/*
@@ -216,7 +214,7 @@ char *ui_get_input(Options *op, const char *def, const char *fmt, ...)
ret = __ui->get_input(op, def, msg);
tmp = nvstrcat(msg, " (Answer: '", ret, "')", NULL);
}
- log_printf(op, TRUE, NV_BULLET_STR, tmp);
+ log_printf(op, NV_BULLET_STR, tmp);
nvfree(msg);
nvfree(tmp);
@@ -251,7 +249,7 @@ void ui_error(Options *op, const char *fmt, ...)
NV_VSNPRINTF(msg, fmt);
__ui->message(op, NV_MSG_LEVEL_ERROR, msg);
- log_printf(op, TRUE, "ERROR: ", msg);
+ log_printf(op, "ERROR: ", msg);
free(msg);
@@ -266,7 +264,7 @@ void ui_warn(Options *op, const char *fmt, ...)
NV_VSNPRINTF(msg, fmt);
__ui->message(op, NV_MSG_LEVEL_WARNING, msg);
- log_printf(op, TRUE, "WARNING: ", msg);
+ log_printf(op, "WARNING: ", msg);
free(msg);
@@ -282,7 +280,7 @@ void ui_message(Options *op, const char *fmt, ...)
if (!op->silent) __ui->message(op, NV_MSG_LEVEL_MESSAGE, msg);
- log_printf(op, TRUE, NV_BULLET_STR, msg);
+ log_printf(op, NV_BULLET_STR, msg);
free(msg);
@@ -296,7 +294,7 @@ void ui_log(Options *op, const char *fmt, ...)
NV_VSNPRINTF(msg, fmt);
if (!op->silent) __ui->message(op, NV_MSG_LEVEL_LOG, msg);
- log_printf(op, TRUE, NV_BULLET_STR, msg);
+ log_printf(op, NV_BULLET_STR, msg);
free(msg);
@@ -317,7 +315,7 @@ void ui_expert(Options *op, const char *fmt, ...)
NV_VSNPRINTF(msg, fmt);
if (!op->silent) __ui->message(op, NV_MSG_LEVEL_LOG, msg);
- log_printf(op, FALSE, NV_BULLET_STR, msg);
+ log_printf(op, NV_BULLET_STR, msg);
free (msg);
@@ -333,7 +331,7 @@ void ui_command_output(Options *op, const char *fmt, ...)
if (!op->silent) __ui->command_output(op, msg);
- log_printf(op, FALSE, NV_CMD_OUT_PREFIX, "%s", msg);
+ log_printf(op, NV_CMD_OUT_PREFIX, "%s", msg);
free(msg);
@@ -387,7 +385,7 @@ int ui_yes_no (Options *op, const int def, const char *fmt, ...)
tmp = nvstrcat(msg, " (Answer: ", (ret ? "Yes" : "No"), ")", NULL);
}
- log_printf(op, FALSE, NV_BULLET_STR, tmp);
+ log_printf(op, NV_BULLET_STR, tmp);
nvfree(msg);
nvfree(tmp);
@@ -401,7 +399,7 @@ void ui_status_begin(Options *op, const char *title, const char *fmt, ...)
{
char *msg;
- log_printf(op, TRUE, NV_BULLET_STR, title);
+ log_printf(op, NV_BULLET_STR, title);
if (op->silent) return;
@@ -434,7 +432,7 @@ void ui_status_end(Options *op, const char *fmt, ...)
NV_VSNPRINTF(msg, fmt);
if (!op->silent) __ui->status_end(op, msg);
- log_printf(op, TRUE, NV_BULLET_STR, msg);
+ log_printf(op, NV_BULLET_STR, msg);
free(msg);
}
@@ -480,7 +478,7 @@ static int extract_user_interface(Options *op, user_interface_attribute_t *ui)
/* check that this ui is present in the binary */
if ((ui->data_array == NULL) || (ui->data_array_size == 0)) {
- log_printf(op, TRUE, NULL, "%s: not present.", ui->descr);
+ log_printf(op, NULL, "%s: not present.", ui->descr);
return FALSE;
}
@@ -490,7 +488,7 @@ static int extract_user_interface(Options *op, user_interface_attribute_t *ui)
fd = mkstemp(ui->filename);
if (fd == -1) {
- log_printf(op, TRUE, NULL, "unable to create temporary file (%s)",
+ log_printf(op, NULL, "unable to create temporary file (%s)",
strerror(errno));
goto failed;
}
@@ -498,12 +496,12 @@ static int extract_user_interface(Options *op, user_interface_attribute_t *ui)
/* set the temporary file's size */
if (lseek(fd, ui->data_array_size - 1, SEEK_SET) == -1) {
- log_printf(op, TRUE, NULL, "Unable to set file size for '%s' (%s)",
+ log_printf(op, NULL, "Unable to set file size for '%s' (%s)",
ui->filename, strerror(errno));
goto failed;
}
if (write(fd, "", 1) != 1) {
- log_printf(op, TRUE, NULL, "Unable to write file size for '%s' (%s)",
+ log_printf(op, NULL, "Unable to write file size for '%s' (%s)",
ui->filename, strerror(errno));
goto failed;
}
@@ -512,7 +510,7 @@ static int extract_user_interface(Options *op, user_interface_attribute_t *ui)
if ((dst = mmap(0, ui->data_array_size, PROT_READ | PROT_WRITE,
MAP_FILE | MAP_SHARED, fd, 0)) == (void *) -1) {
- log_printf(op, TRUE, NULL, "Unable to map destination file '%s' "
+ log_printf(op, NULL, "Unable to map destination file '%s' "
"for copying (%s)", ui->filename, strerror(errno));
goto failed;
}
@@ -524,7 +522,7 @@ static int extract_user_interface(Options *op, user_interface_attribute_t *ui)
/* unmap the temporary file */
if (munmap(dst, ui->data_array_size) == -1) {
- log_printf(op, TRUE, NULL, "Unable to unmap destination file '%s' "
+ log_printf(op, NULL, "Unable to unmap destination file '%s' "
"(%s)", ui->filename, strerror(errno));
goto failed;
}
diff --git a/user-interface.h b/user-interface.h
index 88a68a2..bcf5dbb 100644
--- a/user-interface.h
+++ b/user-interface.h
@@ -27,20 +27,20 @@
#include "command-list.h"
int ui_init (Options*);
-void ui_set_title (Options*, const char*, ...);
-char *ui_get_input (Options*, const char*, const char*, ...);
+void ui_set_title (Options*, const char*, ...) NV_ATTRIBUTE_PRINTF(2, 3);
+char *ui_get_input (Options*, const char*, const char*, ...) NV_ATTRIBUTE_PRINTF(3, 4);
int ui_display_license (Options*, const char*);
-void ui_error (Options*, const char*, ...);
-void ui_warn (Options*, const char*, ...);
-void ui_message (Options*, const char*, ...);
-void ui_log (Options*, const char*, ...);
-void ui_expert (Options*, const char*, ...);
-void ui_command_output (Options*, const char*, ...);
-int ui_approve_command_list(Options*, CommandList*,const char*, ...);
-int ui_yes_no (Options*, const int, const char*, ...);
-void ui_status_begin (Options*, const char*, const char*, ...);
-void ui_status_update (Options*, const float, const char*, ...);
-void ui_status_end (Options*, const char*, ...);
+void ui_error (Options*, const char*, ...) NV_ATTRIBUTE_PRINTF(2, 3);
+void ui_warn (Options*, const char*, ...) NV_ATTRIBUTE_PRINTF(2, 3);
+void ui_message (Options*, const char*, ...) NV_ATTRIBUTE_PRINTF(2, 3);
+void ui_log (Options*, const char*, ...) NV_ATTRIBUTE_PRINTF(2, 3);
+void ui_expert (Options*, const char*, ...) NV_ATTRIBUTE_PRINTF(2, 3);
+void ui_command_output (Options*, const char*, ...) NV_ATTRIBUTE_PRINTF(2, 3);
+int ui_approve_command_list(Options*, CommandList*,const char*, ...) NV_ATTRIBUTE_PRINTF(3, 4);
+int ui_yes_no (Options*, const int, const char*, ...) NV_ATTRIBUTE_PRINTF(3, 4);
+void ui_status_begin (Options*, const char*, const char*, ...) NV_ATTRIBUTE_PRINTF(3, 4);
+void ui_status_update (Options*, const float, const char*, ...) NV_ATTRIBUTE_PRINTF(3, 4);
+void ui_status_end (Options*, const char*, ...) NV_ATTRIBUTE_PRINTF(2, 3);
void ui_close (Options*);
#endif /* __NVIDIA_INSTALLER_USER_INTERFACE_H__ */
diff --git a/utils.mk b/utils.mk
index 6e5ec42..54b76d6 100644
--- a/utils.mk
+++ b/utils.mk
@@ -29,7 +29,7 @@
CC ?= gcc
LD ?= ld
# only set these warnings and optimizations if CFLAGS is unset
-CFLAGS ?= -Wall -Wno-unused-parameter -O2
+CFLAGS ?= -Wall -O2
# always set these -f CFLAGS
CFLAGS += -fno-strict-aliasing -fno-omit-frame-pointer
CC_ONLY_CFLAGS ?=
@@ -42,6 +42,10 @@ HOST_CFLAGS ?= $(CFLAGS)
HOST_LDFLAGS ?= $(LDFLAGS)
HOST_BIN_LDFLAGS ?=
+# always disable warnings that will break the build
+CFLAGS += -Wno-unused-parameter -Wno-format-zero-length
+HOST_CFLAGS += -Wno-unused-parameter -Wno-format-zero-length
+
ifeq ($(DEBUG),1)
STRIP_CMD ?= true
CFLAGS += -O0 -g
diff --git a/version.mk b/version.mk
index d8ad3ea..69efa2d 100644
--- a/version.mk
+++ b/version.mk
@@ -1 +1 @@
-NVIDIA_VERSION = 313.30
+NVIDIA_VERSION = 319.12