From 8c0f9be0d1ace6437d4c604b9af79b7b0006dec4 Mon Sep 17 00:00:00 2001 From: Lars Ingebrigtsen Date: Tue, 14 Dec 2021 09:29:06 +0100 Subject: [PATCH] Only allow SQLite extensions from an allowlist * src/sqlite.c (Fsqlite_load_extension): Only allow extensions from an allowlist. --- src/sqlite.c | 36 +++++++++++++++++++++++++++++++----- test/src/sqlite-tests.el | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/src/sqlite.c b/src/sqlite.c index 248ad478d57..428b84b21e7 100644 --- a/src/sqlite.c +++ b/src/sqlite.c @@ -591,16 +591,42 @@ DEFUN ("sqlite-load-extension", Fsqlite_load_extension, doc: /* Load an SQlite MODULE into DB. MODULE should be the name of an SQlite module's file, a shared library in the system-dependent format and having a -system-dependent file-name extension. */) +system-dependent file-name extension. + +Only modules on Emacs' list of allowed modules can be loaded. */) (Lisp_Object db, Lisp_Object module) { check_sqlite (db, false); CHECK_STRING (module); - Lisp_Object module_encoded = ENCODE_FILE (Fexpand_file_name (module, Qnil)); - sqlite3 *sdb = XSQLITE (db)->db; - int result = sqlite3_load_extension (sdb, SSDATA (module_encoded), - NULL, NULL); + /* Add names of useful and free modules here. */ + const char *allowlist[3] = { "pcre", "csvtable", NULL }; + char *name = SSDATA (Ffile_name_nondirectory (module)); + /* Possibly skip past a common prefix. */ + const char *prefix = "libsqlite3_mod_"; + if (!strncmp (name, prefix, strlen (prefix))) + name += strlen (prefix); + + bool do_allow = false; + for (const char **allow = allowlist; *allow; allow++) + { + if (strlen (*allow) < strlen (name) + && !strncmp (*allow, name, strlen (*allow)) + && (!strcmp (name + strlen (*allow), ".so") + || !strcmp (name + strlen (*allow), ".DLL"))) + { + do_allow = true; + break; + } + } + + if (!do_allow) + xsignal (Qerror, build_string ("Module name not on allowlist")); + + int result = sqlite3_load_extension + (XSQLITE (db)->db, + SSDATA (ENCODE_FILE (Fexpand_file_name (module, Qnil))), + NULL, NULL); if (result == SQLITE_OK) return Qt; return Qnil; diff --git a/test/src/sqlite-tests.el b/test/src/sqlite-tests.el index 6a88f0fd6ca..d1076e481c4 100644 --- a/test/src/sqlite-tests.el +++ b/test/src/sqlite-tests.el @@ -182,4 +182,36 @@ (sqlite-close db) (should-error (sqlite-select db "select * from test6")))) +(ert-deftest sqlite-load-extension () + (skip-unless (sqlite-available-p)) + (let (db) + (setq db (sqlite-open)) + (should-error + (sqlite-load-extension db "/usr/lib/sqlite3/notpcre.so")) + (should-error + (sqlite-load-extension db "/usr/lib/sqlite3/n")) + (should-error + (sqlite-load-extension db "/usr/lib/sqlite3/")) + (should-error + (sqlite-load-extension db "/usr/lib/sqlite3")) + (should + (memq + (sqlite-load-extension db "/usr/lib/sqlite3/pcre.so") + '(nil t))) + + (should-error + (sqlite-load-extension + db "/usr/lib/x86_64-linux-gnu/libsqlite3_mod_notcsvtable.so")) + (should-error + (sqlite-load-extension + db "/usr/lib/x86_64-linux-gnu/libsqlite3_mod_csvtablen.so")) + (should-error + (sqlite-load-extension + db "/usr/lib/x86_64-linux-gnu/libsqlite3_mod_csvtable")) + (should + (memq + (sqlite-load-extension + db "/usr/lib/x86_64-linux-gnu/libsqlite3_mod_csvtable.so") + '(nil t))))) + ;;; sqlite-tests.el ends here -- 2.39.5