diff -Nur modutils-2.3.19/ChangeLog modutils-2.3.20/ChangeLog --- modutils-2.3.19/ChangeLog Sun Oct 22 15:54:01 2000 +++ modutils-2.3.20/ChangeLog Thu Nov 16 11:40:09 2000 @@ -1,3 +1,27 @@ +2000-11-16 Keith Owens + + modutils 2.3.20 + + * Rewrite table generation code to make it easier to add new tables. + * usbmap uses zero vendor as wildcard, test more fields to find end of + table. Adam J. Richter. + * Off by one error in relocations. Jean-Francois Moine. + * Use tgt_long to handle different sizes in combined 32/64 bit + systems. Original patch by Dave Miller. + * Include module type in headers of generated files. Randy Dunlap. + * Add insmod -S (force kallsyms), clean up insmod parameters, man page. + * Clean up messages. + * Verify MODULE_PARM strings. + * Check for multiple well known symbols to get prefix. + * Security cleanup. Triggered by Bugtraq exploits by Michal Zalewski, + Sebastian Krahmer, Chris Evans. It is still the kernel's fault for + passing user data unchanged to a program running as root. + * Add missing s/390 arch_finalize_section_address. Roger Luethi. + * depmod -F supports strange sparc __export_priv_. Dave Miller. + * Sparc64 relocation patch. Redhat (not that they bothered to tell me). + * Sparc64 compile and link fixes. Me, with thanks to Dave Miller for + making a machine available. + 2000-10-22 Keith Owens modutils 2.3.19 diff -Nur modutils-2.3.19/depmod/depmod.c modutils-2.3.20/depmod/depmod.c --- modutils-2.3.19/depmod/depmod.c Sat Oct 21 15:17:56 2000 +++ modutils-2.3.20/depmod/depmod.c Thu Nov 16 11:40:09 2000 @@ -37,7 +37,7 @@ Keith Owens April 2000. */ -#ident "$Id: depmod.c 1.26 Sat, 21 Oct 2000 15:17:56 +1100 kaos $" +#ident "$Id: depmod.c 1.31.1.3 Thu, 16 Nov 2000 11:40:09 +1100 kaos $" #include #include @@ -81,20 +81,20 @@ unsigned int vendor, device; /* Vendor and device ID or PCI_ANY_ID */ unsigned int subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */ unsigned int class, class_mask; /* (class,subclass,prog-if) triplet */ - unsigned long driver_data; /* Data private to the driver */ + unsigned tgt_long driver_data; /* Data private to the driver */ }; /* Extracted from 2.4.0-test10-pre1 /include/linux/isapnp.h */ struct isapnp_device_id { unsigned short card_vendor, card_device; unsigned short vendor, function; - unsigned long driver_data; /* data private to the driver */ + unsigned tgt_long driver_data; /* data private to the driver */ }; /* Extracted from 2.4.0-test10-pre1 /include/linux/isapnp.h */ #define ISAPNP_CARD_DEVS 8 struct isapnp_card_id { - unsigned long driver_data; /* data private to the driver */ + unsigned tgt_long driver_data; /* data private to the driver */ unsigned short card_vendor, card_device; struct { unsigned short vendor, function; @@ -149,7 +149,7 @@ /* * for driver's use; not involved in driver matching. */ - unsigned long driver_info; + unsigned tgt_long driver_info; }; typedef struct MODULE { @@ -363,7 +363,7 @@ struct pci_device_id pci_device; ElfW(Addr) ref_pci; ElfW(Addr) ref_ref_pci; - unsigned long pci_device_size; + unsigned tgt_long pci_device_size; ref_pci = obj_symbol_final_value(f, obj_find_symbol(f, "__module_pci_device_size")); /* Kernels before 2.4.0-test10-pre1 do not have __module_pci_device_size */ if (ref_pci) { @@ -374,7 +374,8 @@ else pci_device_size = sizeof(pci_device); if (pci_device_size != sizeof(pci_device)) { - error("Unexpected value (%ld) for pci_device_size%s", pci_device_size, has_kernel_changed); + error("Unexpected value (%" tgt_long_fmt "d) in '%s' for pci_device_size%s", + pci_device_size, f->filename, has_kernel_changed); exit(-1); } ref_ref_pci = obj_symbol_final_value(f, obj_find_symbol(f, "__module_pci_device_table")); @@ -399,13 +400,14 @@ { struct isapnp_device_id isapnp_device; ElfW(Addr) ref_isapnp, ref_ref_isapnp; - unsigned long isapnp_device_size; + unsigned tgt_long isapnp_device_size; ref_isapnp = obj_symbol_final_value(f, obj_find_symbol(f, "__module_isapnp_device_size")); if (!in_range(f, m_size, ref_isapnp, sizeof(isapnp_device_size))) return; memcpy(&isapnp_device_size, (char *)image + ref_isapnp - f->baseaddr, sizeof(isapnp_device_size)); if (isapnp_device_size != sizeof(isapnp_device)) { - error("Unexpected value (%ld) for isapnp_device_size%s", isapnp_device_size, has_kernel_changed); + error("Unexpected value (%" tgt_long_fmt "d) in '%s' for isapnp_device_size%s", + isapnp_device_size, f->filename, has_kernel_changed); exit(-1); } ref_ref_isapnp = obj_symbol_final_value(f, obj_find_symbol(f, "__module_isapnp_device_table")); @@ -430,13 +432,14 @@ { struct isapnp_card_id isapnp_card; ElfW(Addr) ref_isapnp, ref_ref_isapnp; - unsigned long isapnp_card_size; + unsigned tgt_long isapnp_card_size; ref_isapnp = obj_symbol_final_value(f, obj_find_symbol(f, "__module_isapnp_card_size")); if (!in_range(f, m_size, ref_isapnp, sizeof(isapnp_card_size))) return; memcpy(&isapnp_card_size, (char *)image + ref_isapnp - f->baseaddr, sizeof(isapnp_card_size)); if (isapnp_card_size != sizeof(isapnp_card)) { - error("Unexpected value (%ld) for isapnp_card_size%s", isapnp_card_size, has_kernel_changed); + error("Unexpected value (%" tgt_long_fmt "d) in '%s' for isapnp_card_size%s", + isapnp_card_size, f->filename, has_kernel_changed); exit(-1); } ref_ref_isapnp = obj_symbol_final_value(f, obj_find_symbol(f, "__module_isapnp_card_table")); @@ -461,13 +464,14 @@ { struct usb_device_id usb_device; ElfW(Addr) ref_usb, ref_ref_usb; - unsigned long usb_device_size; + unsigned tgt_long usb_device_size; ref_usb = obj_symbol_final_value(f, obj_find_symbol(f, "__module_usb_device_size")); if (!in_range(f, m_size, ref_usb, sizeof(usb_device_size))) return; memcpy(&usb_device_size, (char *)image + ref_usb - f->baseaddr, sizeof(usb_device_size)); if (usb_device_size != sizeof(usb_device)) { - error("Unexpected value (%ld) for usb_device_size%s", usb_device_size, has_kernel_changed); + error("Unexpected value (%" tgt_long_fmt "d) in '%s' for usb_device_size%s", + usb_device_size, f->filename, has_kernel_changed); exit(-1); } ref_ref_usb = obj_symbol_final_value(f, obj_find_symbol(f, "__module_usb_device_table")); @@ -477,7 +481,7 @@ while (in_range(f, m_size, ref_usb, sizeof(usb_device))) { memcpy(&usb_device, (char *)image + ref_usb - f->baseaddr, sizeof(usb_device)); ref_usb += sizeof(usb_device); - if (!usb_device.idVendor) + if (!usb_device.idVendor && !usb_device.bDeviceClass && !usb_device.bInterfaceClass && !usb_device.driver_info) break; mod->usb_device = xrealloc(mod->usb_device, ++(mod->n_usb_device)*sizeof(*(mod->usb_device))); mod->usb_device[mod->n_usb_device-1] = usb_device; @@ -759,9 +763,23 @@ if (*p != '?') continue; p = strtok(NULL, " \t\n"); - if (strncmp(p, "__kstrtab_", 10)) + if (!strncmp(p, "__kstrtab_", 10)) + p += 10; + else if (!strncmp(p, "__export_priv_", 14)) { + /* Sparc has some weird exported symbols marked + * __export_priv_ instead of the normal __kstrtab_. + * Replace the 'v' with '_' and point at the start of + * the '__' before the name. I see no good reason + * to use __export_priv_, but for compatibility with + * old sparc kernels, it is supported. Try to remove + * __export_priv_ from sparc and remove this code + * four releases after the last kernel that uses + * __export_priv_. + */ + p += 12; + *p = '_'; + } else continue; - p += 10; } assert(n_syms < MAX_MAP_SYM); symtab[n_syms++] = addsym(p, mod, SYM_DEFINED, 0); @@ -785,18 +803,51 @@ return 0; } +/* Open a generated file for output */ +static FILE *gen_file_open(const struct gen_files *gf) +{ + FILE *f = fopen(gf->name, "w"); + if (!f) { + error("Can't open %s for writing", gf->name); + exit(-1); + } + return(f); +} + +static +char *shortname(const char *name) +{ + char *name2 = xstrdup(name); + char *s = strrchr(name2, '/'); + int l; + if (s) { + ++s; + l = strlen(s); + if (l > 3 && strcmp(s+l-3, ".gz") == 0) { + *(s+l-3) = '\0'; + l -= 3; + } + if (l > 2 && strcmp(s+l-2, ".o") == 0) { + *(s+l-2) = '\0'; + l -= 2; + } else if (l > 4 && strcmp(s+l-4, ".mod") == 0) { + *(s+l-4) = '\0'; + l -= 4; + } + } + else + s = name2; /* No '/' in name, strange */ + return(s); +} + /* * Format the dependancy list of a module into a simple makefile. - * Print the dependancies in the depfile (or stdout if depfile is NULL). - * Print the pcimap in the pcimapfile (or stdout if pcimapfile is NULL). - * Print the isapnpmap in the isapnpmapfile (or stdout if isapnpmapfile is NULL). - * Print the usbmap in the usbmapfile (or stdout if usbmapfile is NULL). + * Print the dependancies in the depfile (or stdout if nflag is true). + * Print the pcimap in the pcimapfile (or stdout if nflag is true). + * Print the isapnpmap in the isapnpmapfile (or stdout if nflag is true). + * Print the usbmap in the usbmapfile (or stdout if nflag is true). */ -static void prtdepend(char *base_dir, - const char *pdepfile, - const char *ppcimapfile, - const char *pisapnpmapfile, - const char *pusbmapfile) +static void prtdepend(char *base_dir, int nflag) { FILE *dep = stdout; FILE *pcimap = stdout; @@ -807,32 +858,11 @@ int i; int skipchars; /* For depmod -a in image of a tree */ - if (pdepfile != NULL) { - if ((dep = fopen(pdepfile, "w")) == NULL) { - error("Can't open %s for writing", pdepfile); - exit(-1); - } - } - - if (ppcimapfile != NULL) { - if ((pcimap = fopen(ppcimapfile, "w")) == NULL) { - error("Can't open %s for writing", ppcimapfile); - exit(-1); - } - } - - if (pisapnpmapfile != NULL) { - if ((isapnpmap = fopen(pisapnpmapfile, "w")) == NULL) { - error("Can't open %s for writing", pisapnpmapfile); - exit(-1); - } - } - - if (pusbmapfile != NULL) { - if ((usbmap = fopen(pusbmapfile, "w")) == NULL) { - error("Can't open %s for writing", pusbmapfile); - exit(-1); - } + if (!nflag) { + dep = gen_file_open(gen_file+GEN_DEPFILE); + pcimap = gen_file_open(gen_file+GEN_PCIMAPFILE); + isapnpmap = gen_file_open(gen_file+GEN_ISAPNPMAPFILE); + usbmap = gen_file_open(gen_file+GEN_USBMAPFILE); } skipchars = strlen(base_dir); @@ -889,35 +919,15 @@ } ptmod = modules; - fprintf(pcimap, "# module vendor device subvendor subdevice class class_mask driver_data\n"); + fprintf(pcimap, "# pci module vendor device subvendor subdevice class class_mask driver_data\n"); for (i = 0; i < n_modules; i++, ptmod++) { - int j, l; + int j; struct pci_device_id *pci_device = ptmod->pci_device; - char *name, *shortname; if (!ptmod->n_pci_device) continue; - name = xstrdup(ptmod->name); - shortname = strrchr(name, '/'); - if (!shortname) - shortname = name; /* should never happen */ - else { - ++shortname; - l = strlen(shortname); - if (l > 3 && strcmp(shortname+l-3, ".gz") == 0) { - *(shortname+l-3) = '\0'; - l -= 3; - } - if (l > 2 && strcmp(shortname+l-2, ".o") == 0) { - *(shortname+l-2) = '\0'; - l -= 2; - } else if (l > 4 && strcmp(shortname+l-4, ".mod") == 0) { - *(shortname+l-4) = '\0'; - l -= 4; - } - } for (j = 0; j < ptmod->n_pci_device; j++, pci_device++) { - fprintf(pcimap, "%-20s 0x%0*x 0x%0*x 0x%0*x 0x%0*x 0x%0*x 0x%0*x 0x%0*lx\n", - shortname, + fprintf(pcimap, "%-20s 0x%0*x 0x%0*x 0x%0*x 0x%0*x 0x%0*x 0x%0*x 0x%0*" tgt_long_fmt "x\n", + shortname(ptmod->name), 2*sizeof(pci_device->vendor), pci_device->vendor, 2*sizeof(pci_device->device), pci_device->device, 2*sizeof(pci_device->subvendor), pci_device->subvendor, @@ -926,40 +936,19 @@ 2*sizeof(pci_device->class_mask), pci_device->class_mask, 2*sizeof(pci_device->driver_data), pci_device->driver_data); } - free(name); } ptmod = modules; - fprintf(isapnpmap, "# module cardvendor carddevice driver_data vendor function ...\n"); + fprintf(isapnpmap, "# isapnp module cardvendor carddevice driver_data vendor function ...\n"); for (i = 0; i < n_modules; i++, ptmod++) { int j, l; struct isapnp_device_id *isapnp_device = ptmod->isapnp_device; struct isapnp_card_id *isapnp_card = ptmod->isapnp_card; - char *name, *shortname; if (!ptmod->n_isapnp_device && !ptmod->n_isapnp_card) continue; - name = xstrdup(ptmod->name); - shortname = strrchr(name, '/'); - if (!shortname) - shortname = name; /* should never happen */ - else { - ++shortname; - l = strlen(shortname); - if (l > 3 && strcmp(shortname+l-3, ".gz") == 0) { - *(shortname+l-3) = '\0'; - l -= 3; - } - if (l > 2 && strcmp(shortname+l-2, ".o") == 0) { - *(shortname+l-2) = '\0'; - l -= 2; - } else if (l > 4 && strcmp(shortname+l-4, ".mod") == 0) { - *(shortname+l-4) = '\0'; - l -= 4; - } - } for (j = 0; j < ptmod->n_isapnp_device; j++, isapnp_device++) { - fprintf(isapnpmap, "%-20s 0x%0*x 0x%0*x 0x%0*lx 0x%0*x 0x%0*x\n", - shortname, + fprintf(isapnpmap, "%-20s 0x%0*x 0x%0*x 0x%0*" tgt_long_fmt "x 0x%0*x 0x%0*x\n", + shortname(ptmod->name), 2*sizeof(isapnp_device->card_vendor), isapnp_device->card_vendor, 2*sizeof(isapnp_device->card_device), isapnp_device->card_device, 2*sizeof(isapnp_device->driver_data), isapnp_device->driver_data, @@ -967,8 +956,8 @@ 2*sizeof(isapnp_device->function), isapnp_device->function); } for (j = 0; j < ptmod->n_isapnp_card; j++, isapnp_card++) { - fprintf(isapnpmap, "%-20s 0x%0*x 0x%0*x 0x%0*lx ", - shortname, + fprintf(isapnpmap, "%-20s 0x%0*x 0x%0*x 0x%0*" tgt_long_fmt "x ", + shortname(ptmod->name), 2*sizeof(isapnp_card->card_vendor), isapnp_card->card_vendor, 2*sizeof(isapnp_card->card_device), isapnp_card->card_device, 2*sizeof(isapnp_card->driver_data), isapnp_card->driver_data); @@ -981,43 +970,22 @@ } fprintf(isapnpmap, "\n"); } - free(name); } ptmod = modules; - fprintf(usbmap, "# module idVendor idProduct bcdDevice_lo bcdDevice_hi" + fprintf(usbmap, "# usb module idVendor idProduct bcdDevice_lo bcdDevice_hi" " bDeviceClass bDeviceSubClass bDeviceProtocol bInterfaceClass bInterfaceSubClass" " bInterfaceProtocol driver_info\n"); for (i = 0; i < n_modules; i++, ptmod++) { - int j, l; + int j; struct usb_device_id *usb_device = ptmod->usb_device; - char *name, *shortname; if (!ptmod->n_usb_device) continue; - name = xstrdup(ptmod->name); - shortname = strrchr(name, '/'); - if (!shortname) - shortname = name; /* should never happen */ - else { - ++shortname; - l = strlen(shortname); - if (l > 3 && strcmp(shortname+l-3, ".gz") == 0) { - *(shortname+l-3) = '\0'; - l -= 3; - } - if (l > 2 && strcmp(shortname+l-2, ".o") == 0) { - *(shortname+l-2) = '\0'; - l -= 2; - } else if (l > 4 && strcmp(shortname+l-4, ".mod") == 0) { - *(shortname+l-4) = '\0'; - l -= 4; - } - } for (j = 0; j < ptmod->n_usb_device; j++, usb_device++) { fprintf(usbmap, "%-20s 0x%0*x 0x%0*x 0x%0*x 0x%0*x " "0x%0*x 0x%0*x 0x%0*x 0x%0*x 0x%0*x " - "0x%0*x 0x%0*lx\n", - shortname, + "0x%0*x 0x%0*" tgt_long_fmt "x\n", + shortname(ptmod->name), 2*sizeof(usb_device->idVendor), usb_device->idVendor, 2*sizeof(usb_device->idProduct), usb_device->idProduct, 2*sizeof(usb_device->bcdDevice_lo), usb_device->bcdDevice_lo, @@ -1030,17 +998,16 @@ 2*sizeof(usb_device->bInterfaceProtocol), usb_device->bInterfaceProtocol, 2*sizeof(usb_device->driver_info), usb_device->driver_info); } - free(name); } - /* Close depfile last, critical timestamp */ - if (ppcimapfile != NULL) + if (pcimap != stdout) fclose(pcimap); - if (pisapnpmapfile != NULL) + if (isapnpmap != stdout) fclose(isapnpmap); - if (pusbmapfile != NULL) + if (usbmap != stdout) fclose(usbmap); - if (pdepfile != NULL) + /* Close depfile last, it's timestamp is critical */ + if (dep != stdout) fclose(dep); } @@ -1217,7 +1184,7 @@ /* option -a is the default without arguments */ if (argc > 0) { if (config_read(0, *argv, base_dir, conf_file) == -1) { - error("%s does not exist", depfile); + error("%s does not exist", gen_file[GEN_DEPFILE].name); return -1; } } else if (config_read(0, NULL, base_dir, conf_file) == -1) { @@ -1230,11 +1197,7 @@ for (i = 0; g && i < g->pathc; i++) loadobj(g->pathv[i], ignore_suffix); resolve(); - prtdepend(base_dir, - nflag ? NULL : depfile, - nflag ? NULL : pcimapfile, - nflag ? NULL : isapnpmapfile, - nflag ? NULL : usbmapfile); + prtdepend(base_dir, nflag); } } else { /* not stdmode */ @@ -1242,7 +1205,7 @@ for (; argc > 0 && ret != -1; ++argv, --argc) loadobj(*argv, ignore_suffix); resolve(); - prtdepend(base_dir, NULL, NULL, NULL, NULL); + prtdepend(base_dir, 1); } } diff -Nur modutils-2.3.19/include/config.h modutils-2.3.20/include/config.h --- modutils-2.3.19/include/config.h Sat Oct 21 15:17:56 2000 +++ modutils-2.3.20/include/config.h Mon Oct 23 00:21:54 2000 @@ -63,10 +63,6 @@ extern struct EXEC_TYPE *execs; extern int nexecs; extern char *insmod_opt; -extern char *depfile; -extern char *pcimapfile; -extern char *isapnpmapfile; -extern char *usbmapfile; extern char *config_file; extern char *optlist[]; extern char *prune[]; @@ -79,6 +75,23 @@ extern OPT_LIST *aliases; extern time_t config_mtime; extern int root_check_off; /* Check modules are owned by root? */ + +/* Information about generated files */ +struct gen_files { + char *base; /* xxx in /lib/modules/`uname -r`/modules.xxx */ + char *name; /* name actually used */ + time_t mtime; +}; + +extern struct gen_files gen_file[]; +extern const int gen_file_count; +/* The enum order must match the gen_file initialization order in config.c */ +enum gen_file_enum { + GEN_PCIMAPFILE, + GEN_ISAPNPMAPFILE, + GEN_USBMAPFILE, + GEN_DEPFILE, +}; char *fgets_strip(char *buf, int sizebuf, FILE * fin, int *lineno); int config_read(int all, char *force_ver, char *base_dir, char *conf_file); diff -Nur modutils-2.3.19/include/module.h modutils-2.3.20/include/module.h --- modutils-2.3.19/include/module.h Wed Aug 30 13:52:44 2000 +++ modutils-2.3.20/include/module.h Thu Nov 16 11:40:09 2000 @@ -23,7 +23,7 @@ #ifndef MODUTILS_MODULE_H #define MODUTILS_MODULE_H 1 -#ident "$Id: module.h 1.5 Wed, 30 Aug 2000 13:52:44 +1100 kaos $" +#ident "$Id: module.h 1.5.1.3 Thu, 16 Nov 2000 11:40:09 +1100 kaos $" /* This file contains the structures used by the 2.0 and 2.1 kernels. We do not use the kernel headers directly because we do not wish @@ -97,16 +97,23 @@ #define tgt_sizeof_char_p sizeof(char *) #define tgt_sizeof_void_p sizeof(void *) #define tgt_long long +#define tgt_long_fmt "l" -#if defined(__sparc__) && !defined(__sparc_v9__) && defined(ARCH_sparc64) +/* This assumes that long long on a 32 bit system is equivalent to long on the + * equivalent 64 bit system. Also that void and char pointers are 8 bytes on + * all 64 bit systems. Add per system tweaks if it ever becomes necessary. + */ +#if defined(COMMON_3264) && defined(ONLY_64) +#undef tgt_long +#undef tgt_long_fmt #undef tgt_sizeof_long #undef tgt_sizeof_char_p #undef tgt_sizeof_void_p -#undef tgt_long -#define tgt_sizeof_long 8 -#define tgt_sizeof_char_p 8 -#define tgt_sizeof_void_p 8 -#define tgt_long long long +#define tgt_long long long +#define tgt_long_fmt "ll" +#define tgt_sizeof_long 8 +#define tgt_sizeof_char_p 8 +#define tgt_sizeof_void_p 8 #endif /*======================================================================*/ @@ -197,5 +204,9 @@ unsigned long create_module(const char *, size_t); int delete_module(const char *); +/* In safe mode the last parameter is forced to be a module name and meta + * expansion is not allowed on that name. + */ +extern unsigned long safemode; #endif /* module.h */ diff -Nur modutils-2.3.19/include/obj.h modutils-2.3.20/include/obj.h --- modutils-2.3.19/include/obj.h Fri Sep 8 16:46:27 2000 +++ modutils-2.3.20/include/obj.h Tue Nov 14 23:08:54 2000 @@ -24,7 +24,7 @@ #ifndef MODUTILS_OBJ_H #define MODUTILS_OBJ_H 1 -#ident "$Id: obj.h 1.11 Fri, 08 Sep 2000 16:46:27 +1100 kaos $" +#ident "$Id: obj.h 1.11.1.1 Tue, 14 Nov 2000 23:08:54 +1100 kaos $" /* The relocatable object is manipulated using elfin types. */ @@ -42,14 +42,14 @@ # endif #endif -#if defined(__sparc__) && !defined(__sparc_v9__) -# if ELFCLASSM == ELFCLASS32 +#if defined(COMMON_3264) && defined(ONLY_32) # define ObjW(x) obj32_ ## x -# else -# define ObjW(x) obj64_ ## x -# endif #else -#define ObjW(x) obj_ ## x +# if defined(COMMON_3264) && defined(ONLY_64) +# define ObjW(x) obj64_ ## x +# else +# define ObjW(x) obj_ ## x +# endif #endif /* For some reason this is missing from lib5. */ diff -Nur modutils-2.3.19/include/util.h modutils-2.3.20/include/util.h --- modutils-2.3.19/include/util.h Mon Aug 7 01:20:16 2000 +++ modutils-2.3.20/include/util.h Thu Nov 16 09:29:06 2000 @@ -23,8 +23,9 @@ #ifndef MODUTILS_UTIL_H #define MODUTILS_UTIL_H 1 -#ident "$Id: util.h 1.6 Mon, 07 Aug 2000 01:20:16 +1000 kaos $" +#ident "$Id: util.h 1.6.1.3 Thu, 16 Nov 2000 09:29:06 +1100 kaos $" +#include #include #define SHELL_META "&();|<>$`\"'\\!{}[]~=+:?*" /* Sum of bj0rn and Debian */ @@ -32,6 +33,8 @@ void *xmalloc(size_t); void *xrealloc(void *, size_t); char *xstrdup(const char *); +char *xstrcat(char *, const char *, size_t); +int xsystem(const char *, char *const[]); int arch64(void); typedef int (*xftw_func_t)(const char *, const struct stat *); @@ -66,7 +69,11 @@ int pathc; /* Count of paths matched so far */ char **pathv; /* List of matched pathnames. */ } GLOB_LIST; -int meta_expand(char *pt, GLOB_LIST *g, char *base_dir, char *version); +int meta_expand(char *pt, GLOB_LIST *g, char *base_dir, char *version, int type); +#define ME_BUILTIN_COMMAND 1 +#define ME_SHELL_COMMAND 2 +#define ME_GLOB 4 +#define ME_ALL (ME_GLOB|ME_SHELL_COMMAND|ME_BUILTIN_COMMAND) extern void snap_shot(const char *module_name, int number); @@ -86,5 +93,7 @@ #define gzf_close close #endif /* CONFIG_USE_ZLIB */ + +static const char symprefix[] = "__insmod_"; #endif /* util.h */ diff -Nur modutils-2.3.19/include/version.h modutils-2.3.20/include/version.h --- modutils-2.3.19/include/version.h Fri Oct 13 12:25:49 2000 +++ modutils-2.3.20/include/version.h Sun Oct 22 20:18:08 2000 @@ -1 +1 @@ -#define MODUTILS_VERSION "2.3.19" +#define MODUTILS_VERSION "2.3.20" diff -Nur modutils-2.3.19/insmod/insmod.c modutils-2.3.20/insmod/insmod.c --- modutils-2.3.19/insmod/insmod.c Sat Oct 21 15:31:41 2000 +++ modutils-2.3.20/insmod/insmod.c Tue Nov 14 23:36:27 2000 @@ -50,9 +50,11 @@ Keith Owens August 2000. Add insmod -O, move print map before sys_init_module. Keith Owens October 2000. + Add insmod -S. + Keith Owens November 2000. */ -#ident "$Id: insmod.c 1.29 Sat, 21 Oct 2000 15:31:41 +1100 kaos $" +#ident "$Id: insmod.c 1.30.1.2 Tue, 14 Nov 2000 23:36:27 +1100 kaos $" #include #include @@ -81,7 +83,7 @@ /*======================================================================*/ static int flag_force_load = 0; -static int flag_silent_poll = 0; +static int flag_silent_probe = 0; static int flag_export = 1; static int flag_load_map = 0; static int flag_ksymoops = 1; @@ -137,9 +139,11 @@ static void set_ncv_prefix(char *prefix) { static char derived_prefix[256]; - static const char well_known_symbol[] = "get_module_symbol_R"; + static const char *well_known_symbol[] = { "get_module_symbol_R", + "inter_module_get_R", + }; struct module_symbol *s; - int i, l, pl; + int i, j, l, m, pl; const char *name; char *p; @@ -149,18 +153,22 @@ if (prefix) ncv_prefix = prefix; else { - /* Extract the prefix (if any) from the well known symbol */ + /* Extract the prefix (if any) from well known symbols */ for (i = 0, s = ksyms; i < nksyms; ++i, ++s) { name = (char *) s->name; - if (strncmp(name, well_known_symbol, sizeof(well_known_symbol)-1) == 0) { - l = strlen(name); - pl = l - sizeof(well_known_symbol) - 7; - if (pl < 0 || pl > sizeof(derived_prefix)-1) + l = strlen(name); + for (j = 0; j < sizeof(well_known_symbol)/sizeof(well_known_symbol[0]); ++j) { + m = strlen(well_known_symbol[j]); + if (m + 8 > l || + strncmp(name, well_known_symbol[j], m)) + continue; + pl = l - m - 8; + if (pl > sizeof(derived_prefix)-1) continue; /* Prefix is wrong length */ /* Must end with 8 hex digits */ (void) strtoul(name+l-8, &p, 16); if (*p == 0) { - strncpy(derived_prefix, name+sizeof(well_known_symbol)-1, pl); + strncpy(derived_prefix, name+m, pl); *(derived_prefix+pl) = '\0'; ncv_prefix = derived_prefix; break; @@ -177,7 +185,7 @@ } ncv_plen = strlen(ncv_prefix); if (flag_verbose) - printf("Symbol version prefix '%s'\n", ncv_prefix); + lprintf("Symbol version prefix '%s'", ncv_prefix); } static int ncv_strcmp(const char *a, const char *b) @@ -617,7 +625,6 @@ struct obj_symbol *sym; char *name, *absolute_filename; char str[STRVERSIONLEN], real[PATH_MAX]; - const char symprefix[] = "__insmod_"; int i, l, lm_name, lfilename, use_ksymtab, version; struct stat statbuf; @@ -871,13 +878,13 @@ charssize = strtoul(fmt + 1, (char **) NULL, 10); /* Check length */ - if (strlen(str) >= charssize) { + if (strlen(str) >= charssize-1) { error("string too long for %s (max %ld)", key, charssize - 1); return 0; } /* Copy to location */ - strcpy((char *) loc, str); + strcpy((char *) loc, str); /* safe, see check above */ loc += charssize; } /* @@ -945,7 +952,7 @@ /* Add a kallsyms section if the kernel supports all symbols. */ static int add_kallsyms(struct obj_file *f, - struct obj_section **module_kallsyms) + struct obj_section **module_kallsyms, int force_kallsyms) { struct module_symbol *s; struct obj_file *f_kallsyms; @@ -968,7 +975,7 @@ stop = s->value; } - if (start >= stop) + if (start >= stop && !force_kallsyms) return(0); /* The kernel contains all symbols, do the same for this module. */ @@ -1238,28 +1245,28 @@ void insmod_usage(void) { fputs("Usage:\n" - "insmod [-fhkmopqsvVxXyY] [-o name] [-P prefix] module [[sym=value]...]\n" - + "insmod [-fhkLmnpqrsSvVxXyY] [-o module_name] [-O blob_name] [-P prefix] module [ symbol=value ... ]\n" "\n" - " module Filename of a loadable kernel module (*.o)\n" + " module Name of a loadable kernel module ('.o' can be omitted)\n" " -f, --force Force loading under wrong kernel version\n" - " -h, --help Print this message.\n" + " -h, --help Print this message\n" " -k, --autoclean Make module autoclean-able\n" + " -L, --lock Prevent simultaneous loads of the same module\n" " -m, --map Generate load map (so crashes can be traced)\n" " -n, --noload Don't load, just show\n" - " -o NAME, --name=NAME Set internal module name to NAME\n" - " -O NAME, --blob=NAME Save the object as a binary blob in NAME\n" - " -p, --poll Poll mode; check if the module matches the kernel\n" + " -p, --probe Probe mode; check if the module matches the kernel\n" " -q, --quiet Don't print unresolved symbols\n" + " -r, --root Allow root to load modules not owned by root\n" " -s, --syslog Report errors via syslog\n" + " -S, --kallsyms Force kallsyms on module\n" " -v, --verbose Verbose output\n" - " -L, --lock Prevent simultaneous loads of the same module\n" " -V, --version Show version\n" " -x, --noexport Do not export externs\n" " -X, --export Do export externs (default)\n" " -y, --noksymoops Do not add ksymoops symbols\n" " -Y, --ksymoops Do add ksymoops symbols (default)\n" - " -r, --root Allow root to load modules not owned by root\n" + " -o NAME, --name=NAME Set internal module name to NAME\n" + " -O NAME, --blob=NAME Save the object as a binary blob in NAME\n" " -P PREFIX\n" " --prefix=PREFIX Prefix for kernel or module symbols\n" ,stderr); @@ -1282,24 +1289,26 @@ char k_strversion[STRVERSIONLEN]; struct option long_opts[] = { {"force", 0, 0, 'f'}, + {"help", 0, 0, 'h'}, {"autoclean", 0, 0, 'k'}, + {"lock", 0, 0, 'L'}, {"map", 0, 0, 'm'}, {"noload", 0, 0, 'n'}, - {"name", 1, 0, 'o'}, - {"blob", 1, 0, 'O'}, - {"poll", 0, 0, 'p'}, + {"probe", 0, 0, 'p'}, + {"poll", 0, 0, 'p'}, /* poll is deprecated, remove in 2.5 */ + {"quiet", 0, 0, 'q'}, + {"root", 0, 0, 'r'}, {"syslog", 0, 0, 's'}, + {"kallsyms", 0, 0, 'S'}, {"verbose", 0, 0, 'v'}, {"version", 0, 0, 'V'}, - {"lock", 0, 0, 'L'}, - {"prefix", 1, 0, 'P'}, {"noexport", 0, 0, 'x'}, {"export", 0, 0, 'X'}, - {"quiet", 0, 0, 'q'}, {"noksymoops", 0, 0, 'y'}, {"ksymoops", 0, 0, 'Y'}, - {"root", 0, 0, 'r'}, - {"help", 0, 0, 'h'}, + {"name", 1, 0, 'o'}, + {"blob", 1, 0, 'O'}, + {"prefix", 1, 0, 'P'}, {0, 0, 0, 0} }; char *m_name = NULL; @@ -1318,6 +1327,7 @@ int dolock = 1; /*Note: was: 0; */ int quiet = 0; int exit_status = 1; + int force_kallsyms = 0; int i; error_file = "insmod"; @@ -1326,12 +1336,15 @@ errors = optind = 0; /* Process the command line. */ - while ((o = getopt_long(argc, argv, "fhkmno:O:pqsvVxXLP:yYr", + while ((o = getopt_long(argc, argv, "fhkLmnpqrsSvVxXyYo:O:P:", &long_opts[0], NULL)) != EOF) switch (o) { case 'f': /* force loading */ flag_force_load = 1; break; + case 'h': /* Print the usage message. */ + insmod_usage(); + break; case 'k': /* module loaded by kerneld, auto-cleanable */ flag_autoclean = 1; break; @@ -1344,21 +1357,21 @@ case 'n': /* don't load, just check */ noload = 1; break; - case 'o': /* name the output module */ - m_name = optarg; - break; - case 'O': /* save the output module object */ - blob_name = optarg; - break; - case 'p': /* silent poll mode */ - flag_silent_poll = 1; + case 'p': /* silent probe mode */ + flag_silent_probe = 1; break; case 'q': /* Don't print unresolved symbols */ quiet = 1; break; + case 'r': /* allow root to load non-root modules */ + root_check_off = !root_check_off; + break; case 's': /* start syslog */ setsyslog("insmod"); break; + case 'S': /* Force kallsyms */ + force_kallsyms = 1; + break; case 'v': /* verbose output */ flag_verbose = 1; break; @@ -1377,13 +1390,17 @@ case 'Y': /* do define ksymoops symbols */ flag_ksymoops = 1; break; - case 'r': /* allow root to load non-root modules */ - root_check_off = !root_check_off; + + case 'o': /* name the output module */ + m_name = optarg; + break; + case 'O': /* save the output module object */ + blob_name = optarg; break; case 'P': /* use prefix on crc */ set_ncv_prefix(optarg); break; - case 'h': /* Print the usage message. */ + default: insmod_usage(); break; @@ -1430,9 +1447,9 @@ return 1; } filename = tmp; - printf("Using %s\n", filename); + lprintf("Using %s", filename); } else if (flag_verbose) - printf("Using %s\n", filename); + lprintf("Using %s", filename); /* And open it. */ if ((fp = gzf_open(filename, O_RDONLY)) == -1) { @@ -1479,7 +1496,7 @@ if (flag_force_load) { lprintf("Warning: kernel-module version mismatch\n" "\t%s was compiled for kernel version %s\n" - "\twhile this kernel is version %s\n", + "\twhile this kernel is version %s", filename, m_strversion, k_strversion); } else { if (!quiet) @@ -1534,7 +1551,7 @@ goto out; /* kallsyms based on relocatable addresses */ - if (add_kallsyms(f, &kallsyms)) + if (add_kallsyms(f, &kallsyms, force_kallsyms)) goto out; /**** No symbols or sections to be changed after kallsyms above ***/ @@ -1542,7 +1559,7 @@ goto out; /* If we were just checking, we made it. */ - if (flag_silent_poll) { + if (flag_silent_probe) { exit_status = 0; goto out; } @@ -1591,7 +1608,7 @@ goto out; /* Do kallsyms again, this time we have the final addresses */ - if (add_kallsyms(f, &kallsyms)) + if (add_kallsyms(f, &kallsyms, force_kallsyms)) goto out; #ifdef COMPAT_2_0 @@ -1674,14 +1691,14 @@ for (i = 0; i < MAINS_NO; ++i) { if (i) { - strcat(error_id1, "/"); + xstrcat(error_id1, "/", sizeof(error_id1)); if (i == MAINS_NO-1) - strcat(error_id2, " or "); + xstrcat(error_id2, " or ", sizeof(error_id2)); else - strcat(error_id2, ", "); + xstrcat(error_id2, ", ", sizeof(error_id2)); } - strcat(error_id1, mains[i].name); - strcat(error_id2, mains[i].name); + xstrcat(error_id1, mains[i].name, sizeof(error_id1)); + xstrcat(error_id2, mains[i].name, sizeof(error_id2)); if (strstr(p, mains[i].name)) { ++mains_match; mains_which = i; @@ -1690,8 +1707,8 @@ /* Finish the error identifiers */ if (MAINS_NO != 1) - strcat(error_id1, " combined"); - strcat(error_id1, " binary"); + xstrcat(error_id1, " combined", sizeof(error_id1)); + xstrcat(error_id1, " binary", sizeof(error_id1)); if (mains_match == 0 && MAINS_NO == 1) ++mains_match; /* Not combined, any name will do */ diff -Nur modutils-2.3.19/insmod/modinfo.c modutils-2.3.20/insmod/modinfo.c --- modutils-2.3.19/insmod/modinfo.c Sun Aug 13 23:45:56 2000 +++ modutils-2.3.20/insmod/modinfo.c Tue Nov 14 23:36:27 2000 @@ -31,7 +31,7 @@ * Keith Owens December 1999. */ -#ident "$Id: modinfo.c 1.11 Sun, 13 Aug 2000 23:45:56 +1000 kaos $" +#ident "$Id: modinfo.c 1.11.1.2 Tue, 14 Nov 2000 23:36:27 +1100 kaos $" #include #include @@ -263,6 +263,10 @@ switch (*p) { case 'c': printf("char"); + if (!isdigit(p[1])) + printf(" *** missing string size ***"); + else while (isdigit(p[1])) + ++p; /* swallow c array size */ break; case 'b': printf("byte"); @@ -283,7 +287,7 @@ printf("no format character!\n"); return; default: - printf("unknown format character %c", *p); + printf("unknown format character '%c'", *p); return; } @@ -322,7 +326,7 @@ strncpy(pname, ptr + 5, namelen - 5); pname[namelen - 5] = '\0'; - strcpy(desckey, "parm_desc_"); + strcpy(desckey, "parm_desc_"); /* safe, xmalloc */ strncat(desckey, ptr + 5, namelen - 5); desckey[namelen + 5] = '\0'; diff -Nur modutils-2.3.19/insmod/modprobe.c modutils-2.3.20/insmod/modprobe.c --- modutils-2.3.19/insmod/modprobe.c Sun Sep 10 11:25:29 2000 +++ modutils-2.3.20/insmod/modprobe.c Thu Nov 16 10:09:34 2000 @@ -539,11 +539,11 @@ return g; } /* else */ - sprintf(match_o, "%s.o", match); + snprintf(match_o, sizeof(match_o), "%s.o", match); g = config_lstmod(match_o, type, 0); if (g == NULL || g->pathc == 0) { #ifdef CONFIG_USE_ZLIB - sprintf(match_o, "%s.o.gz", match); + snprintf(match_o, sizeof(match_o), "%s.o.gz", match); g = config_lstmod(match_o, type, 0); if (g == NULL || g->pathc == 0) #endif @@ -693,6 +693,10 @@ printf("%s %s\n", execs[i].module, execs[i].cmd); } } + + puts("# Miscellaneous file and directory names"); + for (i = 0; i < gen_file_count; ++i) + printf("%s=%s\n", gen_file[i].base, gen_file[i].name); } /* @@ -768,23 +772,7 @@ int ret = 0; int line_no; char buf[3000]; - - if (depfile == NULL) { - /* - * The default value for the depfile parameter is: - * - * depfile=/lib/modules/`uname -r`/modules.dep - * - * If the config file exist but doesn't have a depfile - * specification, the default is used since modprobe - * can't work without one. - */ - char depfile_tmp[PATH_MAX]; - - sprintf(depfile_tmp, "/lib/modules/%s/modules.dep", - uts_info.release); /* CHECKME */ - depfile = xstrdup(depfile_tmp); - } /* else: depfile previously defined in config_read() */ + const char *depfile = gen_file[GEN_DEPFILE].name; if ((fin = fopen(depfile, "r")) == NULL) { error("Can't open dependencies file %s (%s)", @@ -803,14 +791,14 @@ while (fgets_strip(buf, sizeof(buf) - 1, fin, &line_no) != NULL) { NODE *nod; - char line[3000]; + char line[sizeof(buf)]; char *pt; char *modname; int len = strlen(buf); pt = line + len-1; - strcpy(line, buf); + strcpy(line, buf); /* safe, same size */ while (len > 0 && isspace(*pt)) { *pt-- = '\0'; len --; @@ -833,34 +821,6 @@ *pt++ = '\0'; nod = new_NODE(stripo(modname), modname, &in_depfile); -#if 0 /* Not yet, this needs a lot more thought... */ - /* Check for extra module info */ - while (isspace(*pt)) - pt++; - if (*pt == '[') { - for (++pt; *pt && *pt != ']'; ++pt) { - if (isspace(*pt)) - continue; - - if (strncmp(pt, "device=", 7) == 0) { - char val[100]; - char *valp = val; - pt += 7; - while (*pt && !isspace(*pt) && *pt!=']') - *valp++ = *pt++; - *valp = '\0'; - if (any_alias(val) == NULL) { - } - } else if (strncmp(pt, "type=", 5) == 0) { - pt += 4; /* ignore, for now */ - } - if (*pt == '\0' || *pt == ']') - break; - } - if (*pt) - ++pt; - } -#endif /* Parse the list of modules */ while (*pt != '\0') { while (isspace(*pt)) @@ -920,6 +880,27 @@ if (i == n_module_stat) return 0; /* It is not even loaded! Easy removal job :-) */ + /* The code below uses system() for commands read from the configuration + * file. It has to use system() because the commands are arbitrary and + * may require shell expansion. + * + * When running as a normal user, you can specify -C config.file and + * that file can contain any commands. The commands are executed with + * the normal authority of the user, there is no security exposure. + * + * When invoked out of kmod, modprobe runs with root authority. If the + * kernel lets user parameters through unchanged then the user could + * pass explot strings to modprobe. The string could start with '-C' to + * specify a user config file, modprobe would then issue user commands + * as root. To prevent the use of spurious config files, modprobe run + * from kmod runs in safemode and treats the last parameter as a module + * name, even if it starts with '-'. Therefore the user cannot specify + * any options to modprobe, only a module name. When invoked from kmod, + * modprobe will only read commands from /etc/modules.conf. As long as + * that file is secure (and we have to assume that it is) then using + * system() to invoke commands from the config file is safe. + */ + /* * OK to delete! */ @@ -927,6 +908,7 @@ const char *name = p->item.s; if ((ex = exec_cmd(EXEC_PRE_REMOVE, name)) != NULL) { verbose("# pre-remove %s:\n%s\n", name, ex); + /* Trusting commands from config file */ if (runit && system(ex) != 0) { if (!quiet && complain) error("pre-remove %s failed", name); @@ -939,6 +921,7 @@ const char *name = p->item.s; if ((ex = exec_cmd(EXEC_REMOVE, kname)) != NULL) { verbose("# remove %s:\n%s\n", name, ex); + /* Trusting commands from config file */ if (runit && (ret = system(ex)) != 0) { if (!quiet && complain) error("remove %s failed", name); @@ -959,6 +942,7 @@ const char *name = p->item.s; if ((ex = exec_cmd(EXEC_POST_REMOVE, name)) != NULL) { verbose("# post-remove %s:\n%s\n", name, ex); + /* Trusting commands from config file */ if (runit && system(ex) != 0) { if (!quiet && complain) error("post-remove %s failed", name); @@ -999,6 +983,7 @@ const char *name = p->item.s; if ((ex = exec_cmd(EXEC_PRE_INSTALL, name)) != NULL) { verbose("# pre-install %s:\n%s\n", name, ex); + /* Trusting commands from config file */ if (runit && (ret = system(ex)) != 0) error("pre-install %s failed", name); } @@ -1012,6 +997,7 @@ if ((ex = exec_cmd(EXEC_INSTALL, name)) != NULL) { verbose("# install %s:\n%s\n", name, ex); used_ex = 1; + /* Trusting commands from config file */ if (runit && (ret = system(ex)) != 0) error("install %s failed", name); } @@ -1039,11 +1025,19 @@ char *opt = strtok(xopts, " \t"); while (opt) { + if (my_argc >= sizeof(my_argv)/sizeof(my_argv[0])) { + error("Too many arguments for insmod"); + exit(1); + } my_argv[my_argc++] = opt; opt = strtok(NULL, " \t"); } } + if (my_argc >= sizeof(my_argv)/sizeof(my_argv[0])) { + error("Too many arguments for insmod"); + exit(1); + } my_argv[my_argc++] = desc->nod->str; modopts = my_argc; /* index of first module option */ /* @@ -1073,6 +1067,10 @@ if (j != my_argc) continue; /* else new option */ + if (my_argc >= sizeof(my_argv)/sizeof(my_argv[0])) { + error("Too many arguments for insmod"); + exit(1); + } my_argv[my_argc++] = "-o"; } else if ((optend = strchr(opts, '='))) { int l = optend - opts + 1; @@ -1090,6 +1088,10 @@ } else break; + if (my_argc >= sizeof(my_argv)/sizeof(my_argv[0])) { + error("Too many arguments for insmod"); + exit(1); + } my_argv[my_argc++] = opts; } } @@ -1125,24 +1127,36 @@ } } - if (j == my_argc) /* new option */ + if (j == my_argc) /* new option */ { + if (my_argc >= sizeof(my_argv)/sizeof(my_argv[0])) { + error("Too many arguments for insmod"); + exit(1); + } my_argv[my_argc++] = options[nopt]; + } } } -#ifdef COMBINE_modprobe + if (my_argc >= sizeof(my_argv)/sizeof(my_argv[0])) { + error("Too many arguments for insmod"); + exit(1); + } + my_argv[my_argc] = NULL; /* for execvp */ + if (verbose) { int i; char cmd[2000]; /* hardcoded, but big enough... */ cmd[0] = '\0'; for (i = 0; i < my_argc; ++i) { - strcat(cmd, my_argv[i]); + xstrcat(cmd, my_argv[i], sizeof(cmd)); if (i != my_argc - 1) - strcat(cmd, " "); + xstrcat(cmd, " ", sizeof(cmd)); } verbose("%s\n", cmd); } + +#ifdef COMBINE_modprobe if (runit) { int insmod_main(int argc, char **argv); int flag_autoclean_save = flag_autoclean; @@ -1152,20 +1166,8 @@ flag_autoclean = flag_autoclean_save; } #else - if (runit || verbose) { - int i; - char cmd[2000]; /* hardcoded, but big enough... */ - - cmd[0] = '\0'; - for (i = 0; i < my_argc; ++i) { - strcat(cmd, my_argv[i]); - if (i != my_argc - 1) - strcat(cmd, " "); - } - verbose("%s\n", cmd); - if (runit) - ret = system(cmd); - } + if (runit) + ret = xsystem(my_argv[0], my_argv); #endif /* COMBINE_modprobe */ if (!quiet && ret != 0) error("insmod %s failed", desc->nod->str); @@ -1178,6 +1180,7 @@ const char *name = p->item.s; if ((ex = exec_cmd(EXEC_POST_INSTALL, name)) != NULL) { verbose("# post-install %s:\n%s\n", name, ex); + /* Trusting commands from config file */ if (runit && (ret = system(ex)) != 0) error("post-install %s failed", name); } @@ -1356,8 +1359,10 @@ int alt = 0; g = config_locate(name, type); - if (!g || g->pathc == 0) + if (!g || g->pathc == 0) { + ret = -2; /* unknown module */ continue; + } do { desc = NULL; @@ -1470,6 +1475,7 @@ int showconfig = 0; int list = 0; int o; + char **env; struct option long_opts[] = { {"type", 1, 0, 't'}, {"all", 0, 0, 'a'}, @@ -1490,6 +1496,44 @@ error_file = "modprobe"; + /* Check for safemode before doing anything else, it affects the + * meaning of the parameters. If the environment contains exactly + * "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin" + * then assume modprobe was invoked from kmod and default to safemode, + * this should handle existing 2.2 and 2.4 kernels. + * + * If MOD_SAFEMODE=1 is present then use safe mode. + * + * Otherwise assume that we are invoked by a real user, use unsafe + * mode with their authority. + * + * In safe mode the last parameter _must_ be a module name. No other + * module names or variable=value strings are allowed in safe mode. + */ + safemode = 1; + for (env = environ; *env; ++env) { + if (strcmp(*env, "HOME=/") == 0) + continue; + if (strcmp(*env, "TERM=linux") == 0) + continue; + if (strcmp(*env, "PATH=sbin:/usr/sbin:/bin:/usr/bin") == 0) + continue; + safemode = 0; + break; + } + if (!safemode) { + char *p = getenv("MOD_SAFEMODE"); + if (p) { + safemode = strtoul(p, &p, 0); + if (*p) { + error("Invalid number in MOD_SAFEMODE=%s", getenv("MOD_SAFEMODE")); + exit(1); + } + } + } + if (safemode) + --argc; /* Do not scan last parameter in getopt */ + while ((o = getopt_long(argc, argv, "t:acdhlnqrvksC:V", &long_opts[0], NULL)) != EOF) { switch (o) { @@ -1575,6 +1619,22 @@ argc -= optind; argv += optind; + if (safemode) { + /* Now scan the last parameter, as a module name */ + if (++argc != 1) { + error("Safe mode has more than one parameter"); + exit(1); + } + if (**argv == '-') { + error("Safe mode parameter starts with '-'"); + exit(1); + } + if (strchr(*argv, '=')) { + error("Safe mode parameter contains '='"); + exit(1); + } + } + /* * argv now points to the first non-option argument * argc is the remaining argument count diff -Nur modutils-2.3.19/man/insmod.8 modutils-2.3.20/man/insmod.8 --- modutils-2.3.19/man/insmod.8 Sun Oct 15 11:31:12 2000 +++ modutils-2.3.20/man/insmod.8 Fri Nov 10 20:43:01 2000 @@ -1,20 +1,20 @@ .\" Copyright (c) 1996 Free Software Foundation, Inc. .\" This program is distributed according to the Gnu General Public License. .\" See the file COPYING in the kernel source directory. -.\" $Id: insmod.8 1.10 Sun, 15 Oct 2000 11:31:12 +1100 kaos $ +.\" $Id: insmod.8 1.11 Fri, 10 Nov 2000 20:43:01 +1100 kaos $ .\" -.TH INSMOD 8 "October 15 2000" Linux "Linux Module Support" +.TH INSMOD 8 "November 10 2000" Linux "Linux Module Support" .SH NAME insmod \- install loadable kernel module .SH SYNOPSIS .B insmod -[\-fkmpqrsxXvyY] [\-P\ prefix] [\-o\ module_name] -object_file [\ symbol=value\ ...\ ] +[\-fhkLmnpqrsSvVxXyY] [\-o\ module_name] [\-O\ blob_name] [\-P\ prefix] +module [\ symbol=value\ ...\ ] .SH DESCRIPTION -.B Insmod +.B insmod installs a loadable module in the running kernel. .PP -.B Insmod +.B insmod tries to link a module into the running kernel by resolving all symbols from the kernel's exported symbol table. .PP @@ -31,43 +31,52 @@ This environment variable will override all the definitions above. .SS OPTIONS .TP -.I \-f +.I "-f --force" Attempt load the module even if the version of the running kernel and the version of the kernel for which the module was compiled do not match. +This only overrides the kernel version check, it has no effect on +symbol name checks. If the symbol names in the module do not match the +kernel then there is no way to force +.I insmod +to load the module. .TP -.I \-k +.I "-h --help" +Print the help text. +.TP +.I "-k --autoclean" Set the auto-clean flag on the module. This flag will be used by \fBkerneld\fP(8) to remove modules that have not been used in some period of time \(em usually one minute. .TP -.I \-m -Output a load map, making it easier to debug the module in the event -of a kernel panic. +.I "-L --lock" +Use \fBflock\fR(2) to prevent simultaneous loads of the same module. .TP -.I "\-o \fRmodule_name" -Explicitly name the module, rather than deriving the name from the -base name of the source object file. -.TP -.I "\-O \fRfilename" -Save the binary object in -.IR filename . -The result is a binary blob (no ELF headers) showing exactly what is -loaded into the kernel, after section manipulation and relocation. -Option +.I "-m --map" +Output a load map on stdout, making it easier to debug the module in +the event of a kernel panic. +.TP +.I "-n --noload" +Dummy run, do everything except load the module into the kernel. If +requested by .I -m -is recommended to get a map of the object. +or +.IR -O , +the run will produce a map or blob file. Since the module is not +loaded, the real kernel load address is unknown so the map and blob +file are based on an arbitrary load address of 0x12340000. .TP -.I \-p +.I "-p --probe" Probe the module to see if it could be successfully loaded. This includes locating the object file in the module path, checking -version numbers, and resolving symbols. +version numbers, and resolving symbols. It does not check the +relocations nor does it produce a map or blob file. .TP -.I \-q +.I "-q --quiet" Do not print a list of any unresolved symbols. Do not complain about version mismatch. The problem will only be reflected in the exit status of insmod. .TP -.I \-r +.I "-r --root" Some users compile modules under a non-root userid then install the modules as root. This process can leave the modules owned by the non-root userid, even though the modules directory is owned by root. @@ -90,19 +99,25 @@ at configuration time is a major security exposure and is not recommended.\fR .TP -.I \-s +.I "-s --syslog" Output everything to \fBsyslog\fP(3) instead of the terminal. .TP -.I \-v +.I "-S --kallsyms" +Force the loaded module to have kallsyms data, even if the kernel does +not support it. This option is for small systems where the kernel is +loaded without kallsyms data but selected modules need kallsyms for +debugging. +.TP +.I "-v --verbose" Be verbose. .TP -.I "\-X, -x" +.I "-X --export, -x --noexport" Do and do not export all of the module's external symbols, respectively. The default is for the symbols to be exported. This option is only effective if the module does not explicitly export its own controlled symbol table, and thus is deprecated. .TP -.I "\-Y, -y" +.I "-Y --ksymoops, -y --noksymoops" Do and do not add ksymoops symbols to ksyms. These symbols are used by ksymoops to provide better debugging if there is an Oops in this module. The default is for the ksymoops symbols to be defined. This @@ -112,9 +127,23 @@ ksymoops symbols add approximately 260 bytes per loaded module. Unless you are really short on kernel space and are trying to reduce ksyms to its minimum size, take the default and get more accurate Oops -debugging. +debugging. ksymoops symbols are required to save persistent module +data during \fBrmmod\fR(8) processing. +.TP +.I "-o \fRmodule_name\fI --name\fR=module_name\fI" +Explicitly name the module, rather than deriving the name from the +base name of the source object file. +.TP +.I "-O \fRblob_name\fI --blob\fR=blob_name\fI" +Save the binary object in +.IR blob_name . +The result is a binary blob (no ELF headers) showing exactly what is +loaded into the kernel, after section manipulation and relocation. +Option +.I -m +is recommended to get a map of the object. .TP -.I "\-P prefix" +.I "-P \fRprefix\fI --prefix\fR=prefix\fI" This option can be used with versioned modules for an SMP or bigmem kernel, since such modules have an extra prefix added in their symbol names. @@ -217,3 +246,5 @@ Extended by Bjorn Ekwall for modutils-2.2.*, March 1999 .br Assistance for ksymoops by Keith Owens , May 1999 +.br +Maintainer: Keith Owens . diff -Nur modutils-2.3.19/man/modprobe.8 modutils-2.3.20/man/modprobe.8 --- modutils-2.3.19/man/modprobe.8 Sun Sep 10 12:56:40 2000 +++ modutils-2.3.20/man/modprobe.8 Thu Nov 16 09:29:06 2000 @@ -2,7 +2,7 @@ .\" Copyright (c) 1995, 1999 Bjorn Ekwall (bj0rn@blox.se) .\" This program is distributed according to the Gnu General Public License. .\" See the file COPYING in the base distribution directory -.\" $Id: modprobe.8 1.6 Sun, 10 Sep 2000 12:56:40 +1100 kaos $ +.\" $Id: modprobe.8 1.8 Thu, 16 Nov 2000 09:29:06 +1100 kaos $ .\" .TH MODPROBE 8 "March 15, 1999" Linux "Linux Module Support" .SH NAME @@ -247,6 +247,33 @@ ksyms(8), rmmod(8), modules(2) +.SH SAFE MODE +If environment variable MOD_SAFEMODE is set to a non-zero value then +modprobe treats its input with extreme suspicion. The last parameter +is always treated as a module name, even if it starts with '-'. There +can only be one module name and options of the form "variable=value" +are forbidden. The module name is always treated as a string, no meta +expansion is performed in safe mode. However meta expansion is still +applied to data read from the config file. +.PP +MOD_SAFEMODE=1 should be set when modprobe is invoked from the kernel. In +an ideal world modprobe could trust the kernel to only pass valid +parameters to modprobe. However at least one local root exploit has +occurred because high level kernel code passed unverified parameters +direct from the user to modprobe. So modprobe no longer trusts kernel +input. +.PP +.ne 8 +.B modprobe +automatically sets safe mode when the environment consists only of these +strings +.nf + HOME=/ + TERM=linux + PATH=/sbin:/usr/sbin:/bin:/usr/bin +.fi +This detects modprobe execution from the kernel on kernels 2.2 though +2.4.0-test11. .SH REQUIRED UTILITIES depmod(8), insmod(8) diff -Nur modutils-2.3.19/man/modules.conf.5 modutils-2.3.20/man/modules.conf.5 --- modutils-2.3.19/man/modules.conf.5 Sat Oct 21 15:17:56 2000 +++ modutils-2.3.20/man/modules.conf.5 Thu Nov 16 09:29:06 2000 @@ -6,6 +6,7 @@ .UC 4 .SH NAME modules.conf \- configuration file for loading kernel modules +.hy 0 .SH DESCRIPTION The behavior of .B modprobe(8) @@ -63,6 +64,18 @@ path[net]=/lib/modules/`uname \-r`/net .fi +.B DANGER: +Applying shell expansion to user supplied input is a major security +risk. Modutils code only does meta expansion via shell commands for +trusted data. Basically this means only for data in the config file. +Even that assumes that the user cannot run modprobe as root while +supplying their own config file. Programs (including the kernel) that +invoke modutils programs as root with user supplied input must pass +exactly one user supplied parameter and must set safe mode or risk +creating local root exploits. See +.I modprobe +for details on safe mode. +.PP Directives may be repeated multiple times. Note that some directives can have an optional prefix: .I add. diff -Nur modutils-2.3.19/modutils.spec modutils-2.3.20/modutils.spec --- modutils-2.3.19/modutils.spec Sun Oct 22 15:54:01 2000 +++ modutils-2.3.20/modutils.spec Sun Oct 22 20:18:08 2000 @@ -1,7 +1,7 @@ Summary: Module utilities Name: modutils -Version: 2.3.19 -Release: 2 +Version: 2.3.20 +Release: 1 Copyright: GPL Group: Utilities/System Source: modutils-%{version}.tar.gz diff -Nur modutils-2.3.19/obj/obj_load.c modutils-2.3.20/obj/obj_load.c --- modutils-2.3.19/obj/obj_load.c Sat Oct 21 16:41:21 2000 +++ modutils-2.3.20/obj/obj_load.c Thu Nov 16 11:40:09 2000 @@ -21,7 +21,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ident "$Id: obj_load.c 1.10 Sat, 21 Oct 2000 16:41:21 +1100 kaos $" +#ident "$Id: obj_load.c 1.12.1.1 Thu, 16 Nov 2000 11:40:09 +1100 kaos $" #include #include @@ -52,7 +52,7 @@ gzf_lseek(fp, 0, SEEK_SET); if (gzf_read(fp, &f->header, sizeof(f->header)) != sizeof(f->header)) { - error("error reading ELF header: %m"); + error("error reading ELF header %s: %m", filename); return NULL; } @@ -69,21 +69,21 @@ || f->header.e_ident[EI_VERSION] != EV_CURRENT || !MATCH_MACHINE(f->header.e_machine)) { - error("ELF file not for this architecture"); + error("ELF file %s not for this architecture", filename); return NULL; } if (f->header.e_type != e_type && e_type != ET_NONE) { switch (e_type) { case ET_REL: - error("ELF file not a relocatable object"); + error("ELF file %s not a relocatable object", filename); break; case ET_EXEC: - error("ELF file not an executable object"); + error("ELF file %s not an executable object", filename); break; default: - error("ELF file has wrong type, expecting %d got %d", - e_type, f->header.e_type); + error("ELF file %s has wrong type, expecting %d got %d", + filename, e_type, f->header.e_type); break; } return NULL; @@ -93,7 +93,8 @@ if (f->header.e_shentsize != sizeof(ElfW(Shdr))) { - error("section header size mismatch: %lu != %lu", + error("section header size mismatch %s: %lu != %lu", + filename, (unsigned long)f->header.e_shentsize, (unsigned long)sizeof(ElfW(Shdr))); return NULL; @@ -107,7 +108,7 @@ gzf_lseek(fp, f->header.e_shoff, SEEK_SET); if (gzf_read(fp, section_headers, sizeof(ElfW(Shdr))*shnum) != sizeof(ElfW(Shdr))*shnum) { - error("error reading ELF section headers: %m"); + error("error reading ELF section headers %s: %m", filename); return NULL; } @@ -141,7 +142,7 @@ gzf_lseek(fp, sec->header.sh_offset, SEEK_SET); if (gzf_read(fp, sec->contents, sec->header.sh_size) != sec->header.sh_size) { - error("error reading ELF section data: %m"); + error("error reading ELF section data %s: %m", filename); return NULL; } } @@ -152,12 +153,12 @@ #if SHT_RELM == SHT_REL case SHT_RELA: if (sec->header.sh_size) - error("RELA relocations not supported on this architecture"); + error("RELA relocations not supported on this architecture %s", filename); return NULL; #else case SHT_REL: if (sec->header.sh_size) - error("REL relocations not supported on this architecture"); + error("REL relocations not supported on this architecture %s", filename); return NULL; #endif @@ -169,8 +170,8 @@ break; } - error("can't handle sections of type %ld", - (long)sec->header.sh_type); + error("can't handle sections of type %ld %s", + (long)sec->header.sh_type, filename); return NULL; } } @@ -208,7 +209,8 @@ if (sec->header.sh_entsize != sizeof(ElfW(Sym))) { - error("symbol size mismatch: %lu != %lu", + error("symbol size mismatch %s: %lu != %lu", + filename, (unsigned long)sec->header.sh_entsize, (unsigned long)sizeof(ElfW(Sym))); return NULL; @@ -255,7 +257,8 @@ char *strtab; if (sec->header.sh_entsize != sizeof(ElfW(RelM))) { - error("relocation entry size mismatch: %lu != %lu", + error("relocation entry size mismatch %s: %lu != %lu", + filename, (unsigned long)sec->header.sh_entsize, (unsigned long)sizeof(ElfW(RelM))); return NULL; @@ -267,7 +270,7 @@ strtab = f->sections[symtab->header.sh_link]->contents; /* Save the relocate type in each symbol entry. */ - for (j = 1, ++rel; j < nrel; ++j, ++rel) + for (j = 0; j < nrel; ++j, ++rel) { ElfW(Sym) *extsym; struct obj_symbol *intsym; diff -Nur modutils-2.3.19/obj/obj_s390.c modutils-2.3.20/obj/obj_s390.c --- modutils-2.3.19/obj/obj_s390.c Wed Aug 23 10:23:26 2000 +++ modutils-2.3.20/obj/obj_s390.c Wed Nov 15 20:47:46 2000 @@ -19,7 +19,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ident "$Id: obj_s390.c 1.3 Wed, 23 Aug 2000 10:23:26 +1000 kaos $" +#ident "$Id: obj_s390.c 1.4 Wed, 15 Nov 2000 20:47:46 +1100 kaos $" #include #include @@ -225,6 +225,17 @@ arch_init_module (struct obj_file *f, struct module *m) { return 1; +} + +int +arch_finalize_section_address(struct obj_file *f, Elf32_Addr base) +{ + int i, n = f->header.e_shnum; + + f->baseaddr = base; + for (i = 0; i < n; ++i) + f->sections[i]->header.sh_addr += base; + return 1; } int diff -Nur modutils-2.3.19/obj/obj_sparc64.c modutils-2.3.20/obj/obj_sparc64.c --- modutils-2.3.19/obj/obj_sparc64.c Wed Aug 23 10:23:26 2000 +++ modutils-2.3.20/obj/obj_sparc64.c Thu Nov 16 10:44:58 2000 @@ -19,7 +19,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ident "$Id: obj_sparc64.c 1.5 Wed, 23 Aug 2000 10:23:26 +1000 kaos $" +#ident "$Id: obj_sparc64.c 1.6 Thu, 16 Nov 2000 10:44:58 +1100 kaos $" #include #include @@ -116,6 +116,9 @@ return 0; } +#define ELF64_R_TYPE_ID(info) ((info) & 0xff) +#define ELF64_R_TYPE_DATA(info) ((info) >> 8) + enum obj_reloc arch_apply_relocation (struct obj_file *ef, struct obj_section *targsec, @@ -129,38 +132,65 @@ enum obj_reloc ret = obj_reloc_ok; - switch (ELF64_R_TYPE(rel->r_info)) + switch (ELF64_R_TYPE_ID(rel->r_info)) { case R_SPARC_NONE: break; - case R_SPARC_8: - if (v > 0xff) - ret = obj_reloc_overflow; - *loc = (*loc & ~0xff) | (v & 0xff); + + case R_SPARC_64: + case R_SPARC_UA64: + if (! ((long) loc & 3)) { + /* Common in .eh_frame */ + ((unsigned int *) loc) [0] = v >> 32; + ((unsigned int *) loc) [1] = v; + break; + } + ((unsigned char *) loc) [0] = v >> 56; + ((unsigned char *) loc) [1] = v >> 48; + ((unsigned char *) loc) [2] = v >> 40; + ((unsigned char *) loc) [3] = v >> 32; + ((unsigned char *) loc) [4] = v >> 24; + ((unsigned char *) loc) [5] = v >> 16; + ((unsigned char *) loc) [6] = v >> 8; + ((unsigned char *) loc) [7] = v; + break; + case R_SPARC_32: + case R_SPARC_UA32: + if (! ((long) loc & 3)) { + *loc = v; + break; + } + ((unsigned char *) loc) [0] = v >> 24; + ((unsigned char *) loc) [1] = v >> 16; + ((unsigned char *) loc) [2] = v >> 8; + ((unsigned char *) loc) [3] = v; break; case R_SPARC_16: if (v > 0xffff) ret = obj_reloc_overflow; *loc = (*loc & ~0xffff) | (v & 0xffff); break; - case R_SPARC_32: - *loc = v; - break; - case R_SPARC_DISP8: - v -= dot; + case R_SPARC_8: if (v > 0xff) - ret = obj_reloc_overflow; + ret = obj_reloc_overflow; *loc = (*loc & ~0xff) | (v & 0xff); break; + + case R_SPARC_DISP32: + v -= dot; + *loc = v; + break; case R_SPARC_DISP16: v -= dot; if (v > 0xffff) ret = obj_reloc_overflow; *loc = (*loc & ~0xffff) | (v & 0xffff); break; - case R_SPARC_DISP32: + case R_SPARC_DISP8: v -= dot; - *loc = v; + if (v > 0xff) + ret = obj_reloc_overflow; + *loc = (*loc & ~0xff) | (v & 0xff); break; case R_SPARC_WDISP30: v -= dot; @@ -168,15 +198,46 @@ ret = obj_reloc_dangerous; *loc = (*loc & ~0x3fffffff) | ((v >> 2) & 0x3fffffff); break; + + /* MEDLOW code model relocs */ + case R_SPARC_LO10: + *loc = (*loc & ~0x3ff) | (v & 0x3ff); + break; + case R_SPARC_HI22: + *loc = (*loc & ~0x3fffff) | (v >> 10); + break; + case R_SPARC_OLO10: + *loc = (*loc & ~0x1fff) | (((v & 0x3ff) + ELF64_R_TYPE_DATA (rel->r_info)) & 0x1fff); + break; + + /* MEDMID code model relocs */ + case R_SPARC_H44: + *loc = (*loc & ~0x3fffff) | (v >> 22); + break; + case R_SPARC_M44: + *loc = (*loc & ~0x3ff) | ((v >> 12) & 0x3ff); + break; + case R_SPARC_L44: + *loc = (*loc & ~0xfff) | (v & 0xfff); + break; + + /* MEDANY code model relocs */ + case R_SPARC_HH22: + *loc = (*loc & ~0x3fffff) | (v >> 42); + break; + case R_SPARC_HM10: + *loc = (*loc & ~0x3ff) | ((v >> 32) & 0x3ff); + break; + case R_SPARC_LM22: + *loc = (*loc & ~0x3fffff) | ((v >> 10) & 0x3fffff); + break; + case R_SPARC_WDISP22: v -= dot; if (v % 4) ret = obj_reloc_dangerous; *loc = (*loc & ~0x3fffff) | ((v >> 2) & 0x3fffff); break; - case R_SPARC_HI22: - *loc = (*loc & ~0x3fffff) | (v >> 10); - break; case R_SPARC_22: if (v > 0x3fffff) ret = obj_reloc_overflow; @@ -187,9 +248,6 @@ ret = obj_reloc_overflow; *loc = (*loc & ~0x1fff) | (v & 0x1fff); break; - case R_SPARC_LO10: - *loc = (*loc & ~0x3ff) | (v & 0x3ff); - break; case R_SPARC_PC10: v -= dot; @@ -200,13 +258,6 @@ *loc = (*loc & ~0x3fffff) | ((v >> 10) & 0x3fffff); break; - case R_SPARC_UA32: - *(((char *)loc) + 0) = (char)(v >> 24); - *(((char *)loc) + 1) = (char)(v >> 16); - *(((char *)loc) + 2) = (char)(v >> 8); - *(((char *)loc) + 3) = (char)v; - break; - #ifdef R_SPARC_10 case R_SPARC_10: if (v > 0x3ff) @@ -220,22 +271,6 @@ break; #ifdef R_SPARC_64 - case R_SPARC_64: - loc[0] = (v >> 32); - loc[1] = v; - break; - case R_SPARC_OLO10: - *loc = (*loc & ~0x3ff) | (v & 0x3ff); - break; - case R_SPARC_HH22: - *loc = (*loc & ~0x3fffff) | (v >> 42); - break; - case R_SPARC_HM10: - *loc = (*loc & ~0x3ff) | ((v >> 32) & 0x3ff); - break; - case R_SPARC_LM22: - *loc = (*loc & ~0x3fffff) | ((v >> 10) & 0x3fffff); - break; case R_SPARC_PC_HH22: v -= dot; *loc = (*loc & ~0x3fffff) | (v >> 42); diff -Nur modutils-2.3.19/util/Makefile.in modutils-2.3.20/util/Makefile.in --- modutils-2.3.19/util/Makefile.in Mon Aug 7 01:20:16 2000 +++ modutils-2.3.20/util/Makefile.in Tue Nov 14 23:36:27 2000 @@ -1,4 +1,4 @@ -# $Id: Makefile.in 1.13 Mon, 07 Aug 2000 01:20:16 +1000 kaos $ +# $Id: Makefile.in 1.13.1.1 Tue, 14 Nov 2000 23:36:27 +1100 kaos $ VPATH = @srcdir@ srcdir = @srcdir@ @@ -14,7 +14,8 @@ all: .depend libutil.a -OBJS = xmalloc.o xrealloc.o xstrdup.o logger.o modstat.o \ +OBJS = xmalloc.o xrealloc.o xstrcat.o xstrdup.o xsystem.o \ + logger.o modstat.o \ meta_expand.o config.o snap_shot.o arch64.o gzfiles.o sys_nim.o \ xftw.o ifneq ($(USE_SYSCALL),n) diff -Nur modutils-2.3.19/util/config.c modutils-2.3.20/util/config.c --- modutils-2.3.19/util/config.c Sat Oct 21 15:17:56 2000 +++ modutils-2.3.20/util/config.c Thu Nov 16 09:29:06 2000 @@ -99,18 +99,26 @@ static int n_aliases; char *insmod_opt = NULL; -char *depfile = NULL; -char *pcimapfile = NULL; -char *isapnpmapfile = NULL; -char *usbmapfile = NULL; char *config_file = NULL; /* Which file was actually used */ time_t config_mtime; int root_check_off = CONFIG_ROOT_CHECK_OFF; /* Default is modules must be owned by root */ static char *config_version; /* Hack for config_add */ int quick = 0; /* Option -A */ +/* The initialization order must match the gen_file_enum order in config.h */ +struct gen_files gen_file[] = { + {"pcimap", NULL, 0}, + {"isapnpmap", NULL, 0}, + {"usbmap", NULL, 0}, + {"dep", NULL, 0}, +}; + +const int gen_file_count = sizeof(gen_file)/sizeof(gen_file[0]); + int flag_verbose; +unsigned long safemode; + void verbose(const char *ctl,...) { if (flag_verbose) { @@ -127,21 +135,19 @@ * Check to see if the existing modules.xxx files need updating, * based on the timestamps of the modules and the config file. */ -static time_t dep_mtime; -static time_t pcimap_mtime; -static time_t isapnpmap_mtime; -static time_t usbmap_mtime; static int check_update (const char *file, const struct stat *sb) { int len = strlen(file); + int i; if (!S_ISREG(sb->st_mode)) return 0; - if (sb->st_mtime <= dep_mtime && - sb->st_mtime <= pcimap_mtime && - sb->st_mtime <= isapnpmap_mtime && - sb->st_mtime <= usbmap_mtime) - return 0; + for (i = 0; i < gen_file_count; ++i) { + if (sb->st_mtime > gen_file[i].mtime) + break; + } + if (i == gen_file_count) + return 0; /* All generated files are up to date */ if (len > 2 && !strcmp(file + len - 2, ".o")) return 1; @@ -156,8 +162,9 @@ static int need_update (const char *force_ver, const char *base_dir) { - struct stat statdep, statpcimap, statisapnpmap, statusbmap, tmp; + struct stat tmp; char dep[PATH_MAX]; + int i; uname (&uts_info); if (!force_ver) force_ver = uts_info.release; @@ -166,29 +173,22 @@ /* That's just silly. */ return 1; - if (stat (depfile, &statdep) || - stat (pcimapfile, &statpcimap) || - stat (isapnpmapfile, &statisapnpmap) || - stat (usbmapfile, &statusbmap)) - /* No dependency file yet, so we need to build it. */ - return 1; + for (i = 0; i < gen_file_count; ++i) { + if (stat(gen_file[i].name, &tmp)) + return 1; /* No dependency file yet, so we need to build it. */ + gen_file[i].mtime = tmp.st_mtime; + } if (stat ("/etc/modules.conf", &tmp) && stat ("/etc/conf.modules", &tmp)) return 1; - if (tmp.st_mtime > statdep.st_mtime || - tmp.st_mtime > statpcimap.st_mtime || - tmp.st_mtime > statisapnpmap.st_mtime || - tmp.st_mtime > statusbmap.st_mtime) - /* Config file is newer. */ - return 1; + for (i = 0; i < gen_file_count; ++i) { + if (tmp.st_mtime > gen_file[i].mtime) + return 1; /* Config file is newer. */ + } - dep_mtime = statdep.st_mtime; - pcimap_mtime = statpcimap.st_mtime; - isapnpmap_mtime = statisapnpmap.st_mtime; - usbmap_mtime = statusbmap.st_mtime; - sprintf (dep, "%s/lib/modules/%s", base_dir, force_ver); + snprintf (dep, sizeof(dep), "%s/lib/modules/%s", base_dir, force_ver); return xftw (dep, check_update); } @@ -245,7 +245,7 @@ while (isspace(*pt)) pt++; if (pt > buf + 1) { - strcpy(buf + 1, pt); + strcpy(buf + 1, pt); /* safe, backward copy */ buf[0] = ' '; end -= (int) (pt - buf) - 1; } else if (pt == buf + 1) { @@ -352,7 +352,7 @@ } else if (!autoclean) (*list)[where].autoclean = 0; pg = (GLOB_LIST *)xmalloc(sizeof(GLOB_LIST)); - meta_expand(arg2, pg, NULL, version); + meta_expand(arg2, pg, NULL, version, ME_ALL); (*list)[where].opts = addlist(prevlist, pg); } @@ -389,7 +389,7 @@ (*out)[i].autoclean = 0; } pg = (GLOB_LIST *)xmalloc(sizeof(GLOB_LIST)); - meta_expand(pt, pg, NULL, version); + meta_expand(pt, pg, NULL, version, ME_ALL); (*out)[i].name = xstrdup(pn); (*out)[i].opts = pg; free(p); @@ -399,6 +399,73 @@ return i; } +/* Environment variables can override defaults, testing only */ +static void gen_file_env(struct gen_files *gf) +{ + char *e = xmalloc(strlen(gf->base)+5), *p1 = gf->base, *p2 = e; + if (safemode) + return; + while ((*p2++ = toupper(*p1++))) ; + strcpy(p2-1, "PATH"); /* safe, xmalloc */ + if ((p2 = getenv(e)) != NULL) { + free(gf->name); + gf->name = xstrdup(p2); + } + free(e); +} + +/* Read a config option for a generated filename */ +static int gen_file_conf(struct gen_files *gf, int assgn, const char *parm, const char *arg) +{ + + int l = strlen(gf->base); + if (assgn && + strncmp(parm, gf->base, l) == 0 && + strcmp(parm+l, "file") == 0 && + !gf->name) { + gf->name = xstrdup(arg); + return(0); + } + return(1); +} + +/* Check we have a name for a generated file */ +static int gen_file_check(struct gen_files *gf, GLOB_LIST *g, + char *base_dir, char *version) +{ + char tmp[PATH_MAX]; + int ret = 0; + if (!gf->name) { + /* + * Specification: config file / no xxxfile parameter + * The default value for generated filename xxx is: + * + * xxxfile=/lib/modules/`uname -r`/modules.xxx + * + * If the config file exists but lacks an xxxfile + * specification, the default value is used since + * the system can't work without one. + */ + snprintf(tmp, sizeof(tmp), "%s/lib/modules/%s/modules.%s", + base_dir, version, gf->base); + gf->name = xstrdup(tmp); + } else { /* xxxfile defined in modules.conf */ + /* + * If we have a xxxfile definition in the configuration file + * we must resolve any shell meta-chars in its value. + */ + if (meta_expand(gf->name, g, base_dir, version, ME_ALL)) + ret = -1; + else if (!g->pathv || g->pathv[0] == NULL) + ret = -1; + else { + free(gf->name); + gf->name = xstrdup(g->pathv[0]); + } + } + return(ret); +} + /* * Read the configuration file. * If parameter "all" == 0 then ignore everything except path info @@ -410,6 +477,7 @@ #define MAX_LEVEL 20 FILE *fin; GLOB_LIST g; + int i; int assgn; int drop_default_paths = 1; int lineno = 0; @@ -422,10 +490,6 @@ char *envpath; char *version; char *type; - char depfile_tmp[PATH_MAX]; - char pcimapfile_tmp[PATH_MAX]; - char isapnpmapfile_tmp[PATH_MAX]; - char usbmapfile_tmp[PATH_MAX]; char **glb; char old_name[] = "/etc/conf.modules"; int conf_file_specified = 0; @@ -579,11 +643,6 @@ config_version = xstrdup(version); - depfile_tmp[0] = '\0'; - pcimapfile_tmp[0] = '\0'; - isapnpmapfile_tmp[0] = '\0'; - usbmapfile_tmp[0] = '\0'; - /* Only read the default entries on the first file */ if (depth == 0) { maxpath = 100; @@ -625,7 +684,7 @@ n_aliases = build_list(aliaslist, &aliases, version, 0); /* Order and priority is now: (MODPATH + modules.conf) || (predefs + modules.conf) */ - if ((envpath = getenv("MODPATH")) != NULL) { + if ((envpath = getenv("MODPATH")) != NULL && !safemode) { size_t len; char *p; char *path; @@ -660,13 +719,13 @@ /* The first entry in the path list */ modpath[nmodpath].type = xstrdup("boot"); - sprintf(tmpline, "%s/lib/modules/boot", base_dir); + snprintf(tmpline, sizeof(tmpline), "%s/lib/modules/boot", base_dir); modpath[nmodpath].path = xstrdup(tmpline); ++nmodpath; /* The second entry in the path list, `uname -r` */ modpath[nmodpath].type = xstrdup("toplevel"); - sprintf(tmpline, "%s/lib/modules/%s", base_dir, version); + snprintf(tmpline, sizeof(tmpline), "%s/lib/modules/%s", base_dir, version); modpath[nmodpath].path = xstrdup(tmpline); ++nmodpath; @@ -676,7 +735,7 @@ if (*k == '.' && ++n == 2) break; } - sprintf(tmpline, "%s/lib/modules/%.*s", base_dir, + snprintf(tmpline, sizeof(tmpline), "%s/lib/modules/%.*s", base_dir, (/* typecast for Alpha */ int)(k - version), version); modpath[nmodpath].path = xstrdup(tmpline); ++nmodpath; @@ -688,8 +747,8 @@ for (type = tbtype; *type; ++type) { char path[100]; - sprintf(path, "%s%s/%s", base_dir, *pathp, *type); - if (meta_expand(path, &g, NULL, version)) + snprintf(path, sizeof(path), "%s%s/%s", base_dir, *pathp, *type); + if (meta_expand(path, &g, NULL, version, ME_ALL)) return -1; for (glb = g.pathv; glb && *glb; ++glb) { @@ -705,30 +764,14 @@ } } - /* DEPPATH is intended for testing only */ - if ((envpath = getenv("DEPPATH")) != NULL) { - strncpy(depfile_tmp, envpath, sizeof(depfile_tmp)); - } - - /* PCIMAPPATH is intended for testing only */ - if ((envpath = getenv("PCIMAPPATH")) != NULL) { - strncpy(pcimapfile_tmp, envpath, sizeof(pcimapfile_tmp)); - } - - /* ISAPNPMAPPATH is intended for testing only */ - if ((envpath = getenv("ISAPNPMAPPATH")) != NULL) { - strncpy(isapnpmapfile_tmp, envpath, sizeof(isapnpmapfile_tmp)); - } - - /* USBMAPPATH is intended for testing only */ - if ((envpath = getenv("USBMAPPATH")) != NULL) { - strncpy(usbmapfile_tmp, envpath, sizeof(usbmapfile_tmp)); - } + /* Environment overrides for testing only, undocumented */ + for (i = 0; i < gen_file_count; ++i) + gen_file_env(gen_file+i); } /* End of depth == 0 */ if (conf_file || - ((conf_file = getenv("MODULECONFIG")) != NULL && *conf_file)) { + ((conf_file = getenv("MODULECONFIG")) != NULL && *conf_file && !safemode)) { if (!(fin = fopen(conf_file, "r"))) { error("Can't open %s", conf_file); return -1; @@ -919,7 +962,7 @@ if (strncmp(arg, "-f", 2) == 0) { char *file = next_word(arg); - meta_expand(file, &g, NULL, version); + meta_expand(file, &g, NULL, version, ME_ALL); if (access(g.pathc ? g.pathv[0] : file, R_OK) == 0) state[level] = !not; else @@ -943,11 +986,11 @@ arg2 = next_word(cmp); - meta_expand(arg, &g, NULL, version); + meta_expand(arg, &g, NULL, version, ME_ALL); if (g.pathc && g.pathv[0]) w1 = g.pathv[0]; - meta_expand(arg2, &g2, NULL, version); + meta_expand(arg2, &g2, NULL, version, ME_ALL); if (g2.pathc && g2.pathv[0]) w2 = g2.pathv[0]; @@ -993,7 +1036,7 @@ * "" or "0" or "false" => false * defined => true */ - if (!meta_expand(arg, &g, NULL, version) && + if (!meta_expand(arg, &g, NULL, version, ME_ALL) && g.pathc > 0 && strcmp(g.pathv[0], "0") != 0 && strcmp(g.pathv[0], "false") != 0 && @@ -1019,8 +1062,8 @@ char env[PATH_MAX]; arg2 = next_word(arg); - meta_expand(arg2, &g, NULL, version); - sprintf(env, "%s=%s", arg, (g.pathc ? g.pathv[0] : "")); + meta_expand(arg2, &g, NULL, version, ME_ALL); + snprintf(env, sizeof(env), "%s=%s", arg, (g.pathc ? g.pathv[0] : "")); putenv(env); one_err = 0; } @@ -1029,7 +1072,7 @@ * include */ if (!assgn && strcmp(parm, "include") == 0) { - meta_expand(arg, &g, NULL, version); + meta_expand(arg, &g, NULL, version, ME_ALL); if (!do_read(all, version, base_dir, g.pathc ? g.pathv[0] : arg, depth+1)) one_err = 0; @@ -1167,78 +1210,6 @@ } /* - * depfile= - */ - else if (assgn && (strcmp(parm, "depfile") == 0) && - (depfile_tmp[0] == '\0')) { - /* - * The default value for the depfile parameter is: - * - * depfile=/lib/modules/`uname -r`/modules.dep - * - * If the config file exist but doesn't have a depfile - * specification, the default is used since modprobe - * can't work without one. - */ - strcpy(depfile_tmp, arg); - one_err = 0; - } - - /* - * pcimapfile= - */ - else if (assgn && (strcmp(parm, "pcimapfile") == 0) && - (pcimapfile_tmp[0] == '\0')) { - /* - * The default value for the pcimapfile parameter is: - * - * pcimapfile=/lib/modules/`uname -r`/modules.pcimap - * - * If the config file exist but doesn't have a pcimapfile - * specification, the default is used since modprobe - * can't work without one. - */ - strcpy(pcimapfile_tmp, arg); - one_err = 0; - } - - /* - * isapnpmapfile= - */ - else if (assgn && (strcmp(parm, "isapnpmapfile") == 0) && - (isapnpmapfile_tmp[0] == '\0')) { - /* - * The default value for the isapnpmapfile parameter is: - * - * isapnpmapfile=/lib/modules/`uname -r`/modules.isapnpmap - * - * If the config file exist but doesn't have a isapnpmapfile - * specification, the default is used since modprobe - * can't work without one. - */ - strcpy(isapnpmapfile_tmp, arg); - one_err = 0; - } - - /* - * usbmapfile= - */ - else if (assgn && (strcmp(parm, "usbmapfile") == 0) && - (usbmapfile_tmp[0] == '\0')) { - /* - * The default value for the usbmapfile parameter is: - * - * usbmapfile=/lib/modules/`uname -r`/modules.usbmap - * - * If the config file exist but doesn't have a usbmapfile - * specification, the default is used since modprobe - * can't work without one. - */ - strcpy(usbmapfile_tmp, arg); - one_err = 0; - } - - /* * keep */ else if (!assgn && (strcmp(parm, "keep") == 0)) { @@ -1319,7 +1290,7 @@ /* * Handle the actual path description */ - if (meta_expand(arg, &g, base_dir, version)) + if (meta_expand(arg, &g, base_dir, version, ME_ALL)) return -1; for (glb = g.pathv; glb && *glb; ++glb) { modpath[nmodpath].type = xstrdup(type); @@ -1333,6 +1304,10 @@ one_err = 0; } + /* Names for generated files in config file */ + for (i = 0; one_err && i < gen_file_count; ++i) + one_err = gen_file_conf(gen_file+i, assgn, parm, arg); + /* * any errors so far? */ @@ -1352,129 +1327,13 @@ ret = -1; } - if (ret == -1) + if (ret) return ret; /* else */ - /* - * Make sure we have a definition of "depfile" - */ - if (depfile_tmp[0] == '\0') { - /* - * Specification: config file / no depfile parameter - * The default value for the depfile parameter is: - * - * depfile=/lib/modules/`uname -r`/modules.dep - * - * If the config file exists but lack a depfile - * specification, the default value is used since - * the system can't work without one. - */ - sprintf(depfile_tmp, "%s/lib/modules/%s/modules.dep", - base_dir, version); - depfile = xstrdup(depfile_tmp); - } else { /* depfile defined in modules.conf */ - /* - * If we have a depfile definition in the configuration file - * we must resolve any shell meta-chars in its value. - */ - if (meta_expand(depfile_tmp, &g, base_dir, version)) - ret = -1; - else if (!g.pathv || g.pathv[0] == NULL) - ret = -1; - else - depfile = g.pathv[0]; - } - - /* - * Make sure we have a definition of "pcimapfile" - */ - if (pcimapfile_tmp[0] == '\0') { - /* - * Specification: config file / no pcimapfile parameter - * The default value for the pcimapfile parameter is: - * - * pcimapfile=/lib/modules/`uname -r`/modules.pcimap - * - * If the config file exists but lack a pcimapfile - * specification, the default value is used since - * the system can't work without one. - */ - sprintf(pcimapfile_tmp, "%s/lib/modules/%s/modules.pcimap", - base_dir, version); - pcimapfile = xstrdup(pcimapfile_tmp); - } else { /* pcimapfile defined in modules.conf */ - /* - * If we have a pcimapfile definition in the configuration file - * we must resolve any shell meta-chars in its value. - */ - if (meta_expand(pcimapfile_tmp, &g, base_dir, version)) - ret = -1; - else if (!g.pathv || g.pathv[0] == NULL) - ret = -1; - else - pcimapfile = g.pathv[0]; - } - - /* - * Make sure we have a definition of "isapnpmapfile" - */ - if (isapnpmapfile_tmp[0] == '\0') { - /* - * Specification: config file / no isapnpmapfile parameter - * The default value for the isapnpmapfile parameter is: - * - * isapnpmapfile=/lib/modules/`uname -r`/modules.isapnpmap - * - * If the config file exists but lack a isapnpmapfile - * specification, the default value is used since - * the system can't work without one. - */ - sprintf(isapnpmapfile_tmp, "%s/lib/modules/%s/modules.isapnpmap", - base_dir, version); - isapnpmapfile = xstrdup(isapnpmapfile_tmp); - } else { /* isapnpmapfile defined in modules.conf */ - /* - * If we have a isapnpmapfile definition in the configuration file - * we must resolve any shell meta-chars in its value. - */ - if (meta_expand(isapnpmapfile_tmp, &g, base_dir, version)) - ret = -1; - else if (!g.pathv || g.pathv[0] == NULL) - ret = -1; - else - isapnpmapfile = g.pathv[0]; - } - - /* - * Make sure we have a definition of "usbmapfile" - */ - if (usbmapfile_tmp[0] == '\0') { - /* - * Specification: config file / no usbmapfile parameter - * The default value for the usbmapfile parameter is: - * - * usbmapfile=/lib/modules/`uname -r`/modules.usbmap - * - * If the config file exists but lack a usbmapfile - * specification, the default value is used since - * the system can't work without one. - */ - sprintf(usbmapfile_tmp, "%s/lib/modules/%s/modules.usbmap", - base_dir, version); - usbmapfile = xstrdup(usbmapfile_tmp); - } else { /* usbmapfile defined in modules.conf */ - /* - * If we have a usbmapfile definition in the configuration file - * we must resolve any shell meta-chars in its value. - */ - if (meta_expand(usbmapfile_tmp, &g, base_dir, version)) - ret = -1; - else if (!g.pathv || g.pathv[0] == NULL) - ret = -1; - else - usbmapfile = g.pathv[0]; - } + /* Check we have names for generated files */ + for (i = 0; !ret && i < gen_file_count; ++i) + ret = gen_file_check(gen_file+i, &g, base_dir, version); return ret; } @@ -1500,12 +1359,12 @@ /****************************************************************************/ /* - * Add conditionally a file name if it exist + * FIXME: Far too much global state. KAO. */ static int found; static int favail; static int one_only; -static int need_meta_expand; +static int meta_expand_type; char **list; static const char *filter_by_file; static char *filter_by_dir; @@ -1519,17 +1378,17 @@ int npaths = 0; char **paths = NULL; - if (need_meta_expand) { + if (meta_expand_type) { GLOB_LIST g; char **p; char full[PATH_MAX]; - sprintf(full, "%s/%s", file, filter_by_file); + snprintf(full, sizeof(full), "%s/%s", file, filter_by_file); if (filter_by_dir && !strstr(full, filter_by_dir)) return 0; - if (meta_expand(full, &g, NULL, config_version)) + if (meta_expand(full, &g, NULL, config_version, meta_expand_type)) return 1; for (p = g.pathv; p && *p; ++p) { paths = (char **)xrealloc(paths, @@ -1621,7 +1480,7 @@ struct stat sb; int i; int ret = 0; - char *path; + char *path = NULL; char this[PATH_MAX]; if (!match) @@ -1632,41 +1491,44 @@ filter_by_dir = NULL; if (type) { char tmpdir[PATH_MAX]; - sprintf(tmpdir, "/%s/", type); + snprintf(tmpdir, sizeof(tmpdir), "/%s/", type); filter_by_dir = xstrdup(tmpdir); } - need_meta_expand = strpbrk(match, SHELL_META) && strcmp(match, "*"); + /* In safe mode, the module name is always handled as is, without meta + * expansion. It might have come from an end user via kmod and must + * not be trusted. Even in unsafe mode, only apply globbing to the + * module name, not command expansion. We trust config file input so + * applying command expansion is safe, we do not trust command line input. + * This assumes that the only time the user can specify -C config file + * is when they run under their own authority. In particular all + * mechanisms that call modprobe as root on behalf of the user must + * run in safe mode, without letting the user supply a config filename. + */ + meta_expand_type = 0; + if (strpbrk(match, SHELL_META) && strcmp(match, "*") && !safemode) + meta_expand_type = ME_GLOB|ME_BUILTIN_COMMAND; list = (char **)xmalloc((favail = 100) * sizeof(char *)); for (i = 0; i < nmodpath; i++) { + path = modpath[i].path; /* Special case: insmod: handle single, non-wildcard match */ if (first_only && strpbrk(match, SHELL_META) == NULL) { /* Fix for "2.1.121 syntax */ - sprintf(this, "%s/%s/%s", modpath[i].path, + snprintf(this, sizeof(this), "%s/%s/%s", path, modpath[i].type, match); if (stat(this, &sb) == 0 && config_add(this, &sb)) break; /* End fix for "2.1.121 syntax */ - sprintf(this, "%s/%s", modpath[i].path, match); + snprintf(this, sizeof(this), "%s/%s", path, match); if (stat(this, &sb) == 0 && config_add(this, &sb)) break; } /* Start looking */ -#if 0 - /* Fix for "2.1.121 syntax */ - sprintf(this, "%s/%s", modpath[i].path, modpath[i].type); - if (stat(this, &sb) == 0 && S_ISDIR(sb->st_mode)) - path = this; - else - /* End fix for "2.1.121 syntax */ -#endif - path = modpath[i].path; - if ((ret = xftw(path, config_add))) { break; } @@ -1695,11 +1557,11 @@ if (g == NULL || g->pathc == 0) { char base_o[PATH_MAX]; - sprintf(base_o, "%s.o", base); + snprintf(base_o, sizeof(base_o), "%s.o", base); g = config_lstmod(base_o, NULL, 1); #ifdef CONFIG_USE_ZLIB if (g == NULL || g->pathc == 0) { - sprintf(base_o, "%s.o.gz", base); + snprintf(base_o, sizeof(base_o), "%s.o.gz", base); g = config_lstmod(base_o, NULL, 1); } #endif diff -Nur modutils-2.3.19/util/meta_expand.c modutils-2.3.20/util/meta_expand.c --- modutils-2.3.19/util/meta_expand.c Sun Sep 10 12:56:40 2000 +++ modutils-2.3.20/util/meta_expand.c Thu Nov 16 09:29:06 2000 @@ -154,14 +154,14 @@ * * Return 0 if OK else -1 */ -int meta_expand(char *pt, GLOB_LIST *g, char *base_dir, char *version) +int meta_expand(char *pt, GLOB_LIST *g, char *base_dir, char *version, int type) { FILE *fin; int len = 0; char *line = NULL; - char *p; + char *p, *p1; char tmpline[PATH_MAX + 1]; - char tmpcmd[PATH_MAX + 11]; + char tmpcmd[2*sizeof(tmpline)+20]; /* room for /bin/echo "text" */ g->pathc = 0; g->pathv = NULL; @@ -170,9 +170,9 @@ * Take care of version dependent expansions * Needed for forced version handling */ - if ((p = strchr(pt, '`')) != NULL) { + if ((p = strchr(pt, '`')) != NULL && (type & ME_BUILTIN_COMMAND)) { do { - char wrk[PATH_MAX + 1]; + char wrk[sizeof(tmpline)]; char *s; for (s = p + 1; isspace(*s); ++s) @@ -183,13 +183,13 @@ ++s; if (*s == '`') { *p = '\0'; - sprintf(wrk, "%s%s%s", + snprintf(wrk, sizeof(wrk), "%s%s%s", pt, version, s + 1); *p = '`'; } - strcpy(tmpline, wrk); + strcpy(tmpline, wrk); /* safe, same size */ pt = tmpline; } else if (strncmp(s, "kernelversion", 13) == 0) { while (*s && (*s != '`')) @@ -203,14 +203,14 @@ if (*k == '.' && ++n == 2) break; } - sprintf(wrk, "%s%.*s%s", + snprintf(wrk, sizeof(wrk), "%s%.*s%s", pt, /* typecast for Alpha */ (int)(k - version), version, s + 1); *p = '`'; - strcpy(tmpline, wrk); + strcpy(tmpline, wrk); /* safe, same size */ pt = tmpline; } } else @@ -226,7 +226,7 @@ * No meta-chars. * Split into words, delimited by whitespace. */ - sprintf(tmpline, "%s%s", (base_dir ? base_dir : ""), pt); + snprintf(tmpline, sizeof(tmpline), "%s%s", (base_dir ? base_dir : ""), pt); if ((p = strtok(tmpline, " \t\n")) != NULL) { while (p) { g->pathv = (char **)xrealloc(g->pathv, @@ -270,7 +270,7 @@ if (strpbrk(pt, "&();|<>$`\"'\\!{}~=+:") == NULL && strpbrk(pt, "[]~?*")) #endif - if (glob_it(pt, g) == 0) + if ((type & ME_GLOB) && glob_it(pt, g) == 0) return 0; if (strpbrk(pt, "&();|<>$`\"'\\!{}~+:[]~?*") == NULL) { @@ -280,10 +280,32 @@ } /* - * Last resort: Use "echo" + * Last resort: Use "echo". + * DANGER: Applying shell expansion to user supplied input is a + * major security risk. Modutils code should only do meta + * expansion via shell commands for trusted data. Basically + * this means only for data in the config file. Even that + * assumes that the user cannot run modprobe as root with + * their own config file. Programs (including the kernel) + * that invoke modprobe as root with user supplied input must + * pass exactly one user supplied parameter and must set + * safe mode. */ - sprintf(tmpline, "%s%s", (base_dir ? base_dir : ""), pt); - sprintf(tmpcmd, "/bin/echo %s", tmpline); + if (!(type & ME_SHELL_COMMAND)) + return 0; + snprintf(tmpline, sizeof(tmpline), "%s%s", (base_dir ? base_dir : ""), pt); + snprintf(tmpcmd, sizeof(tmpcmd), "/bin/echo \""); + for (p = tmpline, p1 = tmpcmd + strlen(tmpcmd); *p; ++p, ++p1) { + if (*p == '"' || *p == '\\') + *p1++ = '\\'; + *p1 = *p; + } + *p1++ = '"'; + *p1++ = '\0'; + if (p1 - tmpcmd > sizeof(tmpcmd)) { + error("tmpcmd overflow, should never happen"); + exit(1); + } if ((fin = popen(tmpcmd, "r")) == NULL) { error("Can't execute: %s", tmpcmd); return -1; @@ -298,14 +320,14 @@ line = (char *)xrealloc(line, len + l + 1); line[len] = '\0'; - strcat(line + len, tmpcmd); + strcat(line + len, tmpcmd); /* safe, realloc */ len += l; } pclose(fin); if (line) { /* Ignore result if no expansion occurred */ - strcat(tmpline, "\n"); + xstrcat(tmpline, "\n", sizeof(tmpline)); if (strcmp(tmpline, line)) split_line(g, line, 0); free(line); diff -Nur modutils-2.3.19/util/modstat.c modutils-2.3.20/util/modstat.c --- modutils-2.3.19/util/modstat.c Wed Mar 15 20:57:16 2000 +++ modutils-2.3.20/util/modstat.c Tue Nov 14 23:36:27 2000 @@ -280,7 +280,7 @@ module_name_list = xrealloc(module_name_list, l_module_name_list + i); - strcpy(module_name_list+l_module_name_list, + strcpy(module_name_list+l_module_name_list, /* safe, xrealloc */ k->name+1); l_module_name_list += i; /* NUL separated strings */ } diff -Nur modutils-2.3.19/util/xftw.c modutils-2.3.20/util/xftw.c --- modutils-2.3.19/util/xftw.c Mon Aug 7 18:07:12 2000 +++ modutils-2.3.20/util/xftw.c Tue Nov 14 23:36:27 2000 @@ -160,11 +160,11 @@ i += strlen(entry); i += 2; name = xmalloc(i); - strcpy(name, directory); + strcpy(name, directory); /* safe, xmalloc */ if (*directory && entry) - strcat(name, "/"); + strcat(name, "/"); /* safe, xmalloc */ if (entry) - strcat(name, entry); + strcat(name, entry); /* safe, xmalloc */ return(name); } diff -Nur modutils-2.3.19/util/xstrcat.c modutils-2.3.20/util/xstrcat.c --- modutils-2.3.19/util/xstrcat.c Thu Jan 1 10:00:00 1970 +++ modutils-2.3.20/util/xstrcat.c Thu Nov 16 09:29:06 2000 @@ -0,0 +1,39 @@ +/* Misc utility functions. + Copyright 2000 Keith Owens + + This file is part of the Linux modutils. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ident "$Id" + +#include +#include "util.h" + + +/*======================================================================*/ + +char * +xstrcat(char *dest, const char *src, size_t size) +{ + int ldest = strlen(dest); + int lsrc = strlen(src); + if ((size - ldest - 1) < lsrc) { + error("xstrcat: destination overflow"); + exit(1); + } + memcpy(dest+ldest, src, lsrc+1); + return(dest); +} diff -Nur modutils-2.3.19/util/xsystem.c modutils-2.3.20/util/xsystem.c --- modutils-2.3.19/util/xsystem.c Thu Jan 1 10:00:00 1970 +++ modutils-2.3.20/util/xsystem.c Thu Nov 16 09:29:06 2000 @@ -0,0 +1,51 @@ +/* Misc utility functions. + Copyright 2000 Keith Owens + + This file is part of the Linux modutils. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ident "$Id" + +#include +#include +#include +#include + + +/*======================================================================*/ + +/* Clone of the system() function From Steven's Advanced Programming in a Unix + * Environment. Modified to use *argv[] and execvp to avoid shell expansion + * problems, modutils runs as root so system() is unsafe. + */ + +int +xsystem(const char *file, char *const argv[]) +{ + pid_t pid; + int status; + if ((pid = fork()) < 0) + return(-1); + if (pid == 0) { + execvp(file, argv); + _exit(127); + } + while (waitpid(pid, &status, 0) < 0) { + if (errno != EINTR) + return(-1); + } + return(status); +}