~ubuntu-branches/ubuntu/quantal/linux-lowlatency/quantal

« back to all changes in this revision

Viewing changes to ubuntu/ndiswrapper/pe_linker.c

  • Committer: Package Import Robot
  • Author(s): Luke Yelavich, Andy Whitcroft, Chase Douglas, Eugeni Dodonov, Ingo Molnar, Johannes Berg, John Johansen, Kees Cook, Leann Ogasawara, Robert Hooker, Seth Heasley, Tim Gardner, Luke Yelavich, Upstream Kernel Changes
  • Date: 2012-03-09 10:21:12 UTC
  • Revision ID: package-import@ubuntu.com-20120309102112-s1abu8w051stx2rl
Tags: 3.2.0-18.26
[ Andy Whitcroft ]

* [Config] clean up the human consumable package descriptions
* [Config] fix generic flavour description
* [Config] clean up linux-tools package descriptions
  - LP: #593107
* deviations -- note the source of the Hyper-V updates
* SAUCE: ata_piix: defer to the Hyper-V drivers by default
  - LP: #929545
* ubuntu: AUFS -- adapt to the new changelog handling
* ubuntu: AUFS -- sort out the relative header paths
* ubuntu: AUFS -- update to d266b0c5d0693d6383976ee54b9e2c0fa9a3f5b0

[ Chase Douglas ]

* SAUCE: (drop after 3.3) HID: hid-magicmouse: Add pointer and buttonpad
  properties for Magic Trackpad
* SAUCE: Input: synaptics - add second variant of two-button clickpad
* SAUCE: Input: synapticss - Set buttonpad property for all clickpads

[ Eugeni Dodonov ]

* SAUCE: drm/i915: do not enable RC6p on Sandy Bridge
* SAUCE: drm/i915: fix operator precedence when enabling RC6p

[ Ingo Molnar ]

* ubuntu: nx-emu - i386: NX emulation

[ Johannes Berg ]

* SAUCE: iwlwifi: fix key removal
  - LP: #911059

[ John Johansen ]

* Revert "SAUCE: AppArmor: Fix unpack of network tables."
* Revert "SAUCE: AppArmor: Allow dfa backward compatibility with broken
  userspace"
* SAUCE: AppArmor: Add mising end of structure test to caps unpacking
* SAUCE: AppArmor: Fix dropping of allowed operations that are force
  audited
* SAUCE: AppArmor: Fix underflow in xindex calculation
* SAUCE: AppArmor: fix mapping of META_READ to audit and quiet flags
* SAUCE: AppArmor: Fix the error case for chroot relative path name
  lookup
  - LP: #925028
* SAUCE: AppArmor: Retrieve the dentry_path for error reporting when path
  lookup fails
  - LP: #925028
* SAUCE: AppArmor: Minor cleanup of d_namespace_path to consolidate error
  handling
* SAUCE: AppArmor: Update dfa matching routines.
* SAUCE: AppArmor: Move path failure information into aa_get_name and
  rename
* SAUCE: AppArmor: Make chroot relative the default path lookup type
* SAUCE: AppArmor: Add ability to load extended policy
* SAUCE: AppArmor: basic networking rules
* SAUCE: AppArmor: Add profile introspection file to interface
* SAUCE: AppArmor: Add the ability to mediate mount
* SAUCE: AppArmor: Add mount information to apparmorfs

[ Kees Cook ]

* SAUCE: (drop after 3.3) security: create task_free security callback
* SAUCE: (drop after 3.3) security: Yama LSM
* SAUCE: (drop after 3.3) Yama: add PR_SET_PTRACER_ANY
* SAUCE: Yama: add link restrictions
* SAUCE: security: unconditionally chain to Yama LSM
* SAUCE: AppArmor: refactor securityfs to use structures
* SAUCE: AppArmor: add initial "features" directory to securityfs
* SAUCE: AppArmor: add "file" details to securityfs
* SAUCE: AppArmor: export known rlimit names/value mappings in securityfs
* ubuntu: Yama - LSM hooks
* ubuntu: Yama - add ptrace relationship tracking interface
* ubuntu: Yama - unconditionally chain to Yama LSM

[ Leann Ogasawara ]

* Revert "[Config] Enable CONFIG_NVRAM=m"
  - LP: #942193
* Drop ndiswrapper
* Ubuntu-3.2.0-17.26
* Ubuntu-3.2.0-17.27
* Rebase to v3.2.7
* [Config] Enable CONFIG_USB_SERIAL_QUATECH2=m on arm and powerpc
* [Config] Enable CONFIG_USB_SERIAL_QUATECH_USB2=m on arm and powerpc
* [Config] Add CONFIG_NVRAM to config enforcer
  - LP: #942193
* [Config] Enable CONFIG_SCSI_IBMVSCSI=m for powerpc
  - LP: #943090
* [Config] Enable CONFIG_SCSI_IPR=m for powerpc
  - LP: #943090
* provide ipmi udeb
  - LP: #942926
* Rebase to v3.2.9
* Add ibmveth to d-i/modules-powerpc/nic-modules
  - LP: #712188
* [Config] Enable CONFIG_SCSI_IBMVFC=m for powerpc
  - LP: #712188
* Add ibmvfc and ibmvscsic to d-i/modules-powerpc/nic-modules
  - LP: #712188
* Ubuntu-3.2.0-18.28

[ Robert Hooker ]

* SAUCE: drm/i915: Enable RC6 by default on sandybridge.

[ Seth Heasley ]

* SAUCE: ALSA: hda - Add Lynx Point HD Audio Controller DeviceIDs
  - LP: #900119
* SAUCE: ahci: AHCI-mode SATA patch for Intel Lynx Point DeviceIDs
  - LP: #900119
* SAUCE: ata_piix: IDE-mode SATA patch for Intel Lynx Point DeviceIDs
  - LP: #900119
* SAUCE: i2c-i801: Add device IDs for Intel Lynx Point
  - LP: #900119

[ Tim Gardner ]

* dropped hv_mouse
* [Config] CONFIG_X86_NUMACHIP=y
* [Config] updateconfigs after apparmor patches
* [Config] Added hv_netvsc and hv_storvsc to -virtual
  - LP: #942256
* [Config] Enable aufs
  - LP: #943119
* SAUCE: Made kernel irq-threaded by default

[ Luke Yelavich ]

* UBUNTU: Depend on crda (>=1.1.1-1ubuntu2) | wireless-crda as per precise
  mainline packaging

[ Upstream Kernel Changes ]

* Revert "Revert "ath9k_hw: fix interpretation of the rx KeyMiss flag""
* Revert "AppArmor: compatibility patch for v5 interface"
* Revert "AppArmor: compatibility patch for v5 network controll"
* Staging: hv: vmbus: Support building the vmbus driver as part of the
  kernel
* hv: Add Kconfig menu entry
* Drivers: hv: Fix a memory leak
* Drivers: hv: Make the vmbus driver unloadable
* Drivers: hv: Get rid of an unnecessary check in hv.c
* Staging: hv: mousevsc: Make boolean states boolean
* Staging: hv: mousevsc: Inline the code for mousevsc_on_device_add()
* Staging: hv: mousevsc: Inline the code for reportdesc_callback()
* Staging: hv: mousevsc: Cleanup mousevsc_on_channel_callback()
* Staging: hv: mousevsc: Add a new line to a debug string
* Staging: hv: mousevsc: Get rid of unnecessary include files
* Staging: hv: mousevsc: Address some style issues
* Staging: hv: mousevsc: Add a check to prevent memory corruption
* Staging: hv: mousevsc: Use the KBUILD_MODNAME macro
* Staging: hv: storvsc: Use mempools to allocate struct
  storvsc_cmd_request
* Staging: hv: storvsc: Cleanup error handling in the probe function
* Staging: hv: storvsc: Fixup the error when processing SET_WINDOW
  command
* Staging: hv: storvsc: Fix error handling storvsc_host_reset()
* Staging: hv: storvsc: Use the accessor function shost_priv()
* Staging: hv: storvsc: Use the unlocked version queuecommand
* Staging: hv: storvsc: use the macro KBUILD_MODNAME
* Staging: hv: storvsc: Get rid of an unnecessary forward declaration
* Staging: hv: storvsc: Upgrade the vmstor protocol version
* Staging: hv: storvsc: Support hot add of scsi disks
* Staging: hv: storvsc: Support hot-removing of scsi devices
* staging: hv: Use kmemdup rather than duplicating its implementation
* staging: hv: move hv_netvsc out of staging area
* Staging: hv: mousevsc: Properly add the hid device
* Staging: hv: storvsc: Disable clustering
* Staging: hv: storvsc: Cleanup storvsc_device_alloc()
* Staging: hv: storvsc: Fix a bug in storvsc_command_completion()
* Staging: hv: storvsc: Fix a bug in copy_from_bounce_buffer()
* Staging: hv: storvsc: Implement per device memory pools
* Staging: hv: remove hv_mouse driver as it's now in the hid directory
* Staging: hv: update TODO file
* Staging: hv: storvsc: Fix a bug in create_bounce_buffer()
* net/hyperv: Fix long lines in netvsc.c
* net/hyperv: Add support for promiscuous mode setting
* net/hyperv: Fix the stop/wake queue mechanism
* net/hyperv: Remove unnecessary kmap_atomic in netvsc driver
* net/hyperv: Add NETVSP protocol version negotiation
* net/hyperv: Add support for jumbo frame up to 64KB
* net/hyperv: fix possible memory leak in do_set_multicast()
* net/hyperv: rx_bytes should account the ether header size
* net/hyperv: fix the issue that large packets be dropped under bridge
* net/hyperv: Use netif_tx_disable() instead of netif_stop_queue() when
  necessary
* net/hyperv: Fix the page buffer when an RNDIS message goes beyond page
  boundary
* HID: Move the hid-hyperv driver out of staging
* HID: hv_mouse: Properly add the hid device
* HID: hyperv: Properly disconnect the input device
* Staging: hv: storvsc: Cleanup some comments
* Staging: hv: storvsc: Cleanup storvsc_probe()
* Staging: hv: storvsc: Cleanup storvsc_queuecommand()
* Staging: hv: storvsc: Introduce defines for srb status codes
* Staging: hv: storvsc: Cleanup storvsc_host_reset_handler()
* Staging: hv: storvsc: Move and cleanup storvsc_remove()
* Staging: hv: storvsc: Add a comment to explain life-cycle management
* Staging: hv: storvsc: Get rid of the on_io_completion in
  hv_storvsc_request
* Staging: hv: storvsc: Rename the context field in hv_storvsc_request
* Staging: hv: storvsc: Miscellaneous cleanup of storvsc driver
* Staging: hv: storvsc: Cleanup the code for generating protocol version
* Staging: hv: storvsc: Cleanup some protocol related constants
* Staging: hv: storvsc: Get rid of some unused defines
* Staging: hv: storvsc: Consolidate the request structure
* Staging: hv: storvsc: Consolidate all the wire protocol definitions
* Staging: hv: storvsc: Move the storage driver out of the staging area
* x86: Make flat_init_apic_ldr() available
* x86: Add x86_init platform override to fix up NUMA core numbering
* x86: Add NumaChip support
* x86/numachip: Drop unnecessary conflict with EDAC
* Input: bcm5974 - set BUTTONPAD property
* Ubuntu: Rebase to v3.2.8
* ACPI / PM: Do not save/restore NVS on Asus K54C/K54HR
  - LP: #898503
* Add low latency source

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 *  Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani
3
 
 *
4
 
 *  This program is free software; you can redistribute it and/or modify
5
 
 *  it under the terms of the GNU General Public License as published by
6
 
 *  the Free Software Foundation; either version 2 of the License, or
7
 
 *  (at your option) any later version.
8
 
 *
9
 
 *  This program is distributed in the hope that it will be useful,
10
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
 
 *  GNU General Public License for more details.
13
 
 *
14
 
 */
15
 
 
16
 
#ifdef TEST_LOADER
17
 
 
18
 
#include "usr_linker.h"
19
 
 
20
 
#else
21
 
 
22
 
#include <linux/types.h>
23
 
#include <asm/errno.h>
24
 
 
25
 
//#define DEBUGLINKER 2
26
 
 
27
 
#include "ntoskernel.h"
28
 
 
29
 
#endif
30
 
 
31
 
struct pe_exports {
32
 
        char *dll;
33
 
        char *name;
34
 
        generic_func addr;
35
 
};
36
 
 
37
 
static struct pe_exports pe_exports[40];
38
 
static int num_pe_exports;
39
 
 
40
 
#define RVA2VA(image, rva, type) (type)(ULONG_PTR)((void *)image + rva)
41
 
#define CHECK_SZ(a,b) { if (sizeof(a) != b) {                           \
42
 
                        ERROR("%s is bad, got %zd, expected %d",        \
43
 
                              #a , sizeof(a), (b)); return -EINVAL; } }
44
 
 
45
 
#if defined(DEBUGLINKER) && DEBUGLINKER > 0
46
 
#define DBGLINKER(fmt, ...) printk(KERN_INFO "%s (%s:%d): " fmt "\n",   \
47
 
                                   DRIVER_NAME, __func__,               \
48
 
                                   __LINE__ , ## __VA_ARGS__);
49
 
static const char *image_directory_name[] = {
50
 
        "EXPORT",
51
 
        "IMPORT",
52
 
        "RESOURCE",
53
 
        "EXCEPTION",
54
 
        "SECURITY",
55
 
        "BASERELOC",
56
 
        "DEBUG",
57
 
        "COPYRIGHT",
58
 
        "GLOBALPTR",
59
 
        "TLS",
60
 
        "LOAD_CONFIG",
61
 
        "BOUND_IMPORT",
62
 
        "IAT",
63
 
        "DELAY_IMPORT",
64
 
        "COM_DESCRIPTOR" };
65
 
#else
66
 
#define DBGLINKER(fmt, ...) do { } while (0)
67
 
#endif
68
 
 
69
 
#ifndef TEST_LOADER
70
 
extern struct wrap_export ntoskernel_exports[], ntoskernel_io_exports[],
71
 
        ndis_exports[], crt_exports[], hal_exports[], rtl_exports[];
72
 
#ifdef ENABLE_USB
73
 
extern struct wrap_export usb_exports[];
74
 
#endif
75
 
 
76
 
static int get_export(char *name, generic_func *func)
77
 
{
78
 
        int i, j;
79
 
 
80
 
        struct wrap_export *exports[] = {
81
 
                ntoskernel_exports,
82
 
                ntoskernel_io_exports,
83
 
                ndis_exports,
84
 
                crt_exports,
85
 
                hal_exports,
86
 
                rtl_exports,
87
 
#ifdef ENABLE_USB
88
 
                usb_exports,
89
 
#endif
90
 
        };
91
 
 
92
 
        for (j = 0; j < ARRAY_SIZE(exports); j++)
93
 
                for (i = 0; exports[j][i].name != NULL; i++)
94
 
                        if (strcmp(exports[j][i].name, name) == 0) {
95
 
                                *func = exports[j][i].func;
96
 
                                return 0;
97
 
                        }
98
 
 
99
 
        for (i = 0; i < num_pe_exports; i++)
100
 
                if (strcmp(pe_exports[i].name, name) == 0) {
101
 
                        *func = pe_exports[i].addr;
102
 
                        return 0;
103
 
                }
104
 
 
105
 
        return -1;
106
 
}
107
 
#endif // TEST_LOADER
108
 
 
109
 
static void *get_dll_init(char *name)
110
 
{
111
 
        int i;
112
 
        for (i = 0; i < num_pe_exports; i++)
113
 
                if ((strcmp(pe_exports[i].dll, name) == 0) &&
114
 
                    (strcmp(pe_exports[i].name, "DllInitialize") == 0))
115
 
                        return (void *)pe_exports[i].addr;
116
 
        return NULL;
117
 
}
118
 
 
119
 
/*
120
 
 * Find and validate the coff header
121
 
 *
122
 
 */
123
 
static int check_nt_hdr(IMAGE_NT_HEADERS *nt_hdr)
124
 
{
125
 
        int i;
126
 
        WORD attr;
127
 
        PIMAGE_OPTIONAL_HEADER opt_hdr;
128
 
 
129
 
        /* Validate the "PE\0\0" signature */
130
 
        if (nt_hdr->Signature != IMAGE_NT_SIGNATURE) {
131
 
                ERROR("is this driver file? bad signature %08x",
132
 
                      nt_hdr->Signature);
133
 
                return -EINVAL;
134
 
        }
135
 
 
136
 
        opt_hdr = &nt_hdr->OptionalHeader;
137
 
        /* Make sure Image is PE32 or PE32+ */
138
 
#ifdef CONFIG_X86_64
139
 
        if (opt_hdr->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
140
 
                ERROR("kernel is 64-bit, but Windows driver is not 64-bit;"
141
 
                      "bad magic: %04X", opt_hdr->Magic);
142
 
                return -EINVAL;
143
 
        }
144
 
#else
145
 
        if (opt_hdr->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
146
 
                ERROR("kernel is 32-bit, but Windows driver is not 32-bit;"
147
 
                      "bad magic: %04X", opt_hdr->Magic);
148
 
                return -EINVAL;
149
 
        }
150
 
#endif
151
 
 
152
 
        /* Validate the image for the current architecture. */
153
 
#ifdef CONFIG_X86_64
154
 
        if (nt_hdr->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64) {
155
 
                ERROR("kernel is 64-bit, but Windows driver is not 64-bit;"
156
 
                      " (PE signature is %04X)", nt_hdr->FileHeader.Machine);
157
 
                return -EINVAL;
158
 
        }
159
 
#else
160
 
        if (nt_hdr->FileHeader.Machine != IMAGE_FILE_MACHINE_I386) {
161
 
                ERROR("kernel is 32-bit, but Windows driver is not 32-bit;"
162
 
                      " (PE signature is %04X)", nt_hdr->FileHeader.Machine);
163
 
                return -EINVAL;
164
 
        }
165
 
#endif
166
 
 
167
 
        /* Must have attributes */
168
 
#ifdef CONFIG_X86_64
169
 
        attr = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LARGE_ADDRESS_AWARE;
170
 
#else
171
 
        attr = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_32BIT_MACHINE;
172
 
#endif
173
 
        if ((nt_hdr->FileHeader.Characteristics & attr) != attr)
174
 
                return -EINVAL;
175
 
 
176
 
        /* Must be relocatable */
177
 
        attr = IMAGE_FILE_RELOCS_STRIPPED;
178
 
        if ((nt_hdr->FileHeader.Characteristics & attr))
179
 
                return -EINVAL;
180
 
 
181
 
        /* Make sure we have at least one section */
182
 
        if (nt_hdr->FileHeader.NumberOfSections == 0)
183
 
                return -EINVAL;
184
 
 
185
 
        if (opt_hdr->SectionAlignment < opt_hdr->FileAlignment) {
186
 
                ERROR("alignment mismatch: secion: 0x%x, file: 0x%x",
187
 
                      opt_hdr->SectionAlignment, opt_hdr->FileAlignment);
188
 
                return -EINVAL;
189
 
        }
190
 
 
191
 
        DBGLINKER("number of datadictionary entries %d",
192
 
                  opt_hdr->NumberOfRvaAndSizes);
193
 
        for (i = 0; i < opt_hdr->NumberOfRvaAndSizes; i++) {
194
 
                DBGLINKER("datadirectory %s RVA:%X Size:%d",
195
 
                          (i<=IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)?
196
 
                          image_directory_name[i] : "unknown",
197
 
                          opt_hdr->DataDirectory[i].VirtualAddress,
198
 
                          opt_hdr->DataDirectory[i].Size);
199
 
        }
200
 
 
201
 
        if ((nt_hdr->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE))
202
 
                return IMAGE_FILE_EXECUTABLE_IMAGE;
203
 
        if ((nt_hdr->FileHeader.Characteristics & IMAGE_FILE_DLL))
204
 
                return IMAGE_FILE_DLL;
205
 
        return -EINVAL;
206
 
}
207
 
 
208
 
static int import(void *image, IMAGE_IMPORT_DESCRIPTOR *dirent, char *dll)
209
 
{
210
 
        ULONG_PTR *lookup_tbl, *address_tbl;
211
 
        char *symname = NULL;
212
 
        int i;
213
 
        int ret = 0;
214
 
        generic_func adr;
215
 
 
216
 
        lookup_tbl  = RVA2VA(image, dirent->u.OriginalFirstThunk, ULONG_PTR *);
217
 
        address_tbl = RVA2VA(image, dirent->FirstThunk, ULONG_PTR *);
218
 
 
219
 
        for (i = 0; lookup_tbl[i]; i++) {
220
 
                if (IMAGE_SNAP_BY_ORDINAL(lookup_tbl[i])) {
221
 
                        ERROR("ordinal import not supported: %Lu",
222
 
                              (uint64_t)lookup_tbl[i]);
223
 
                        return -1;
224
 
                }
225
 
                else {
226
 
                        symname = RVA2VA(image,
227
 
                                         ((lookup_tbl[i] &
228
 
                                           ~IMAGE_ORDINAL_FLAG) + 2), char *);
229
 
                }
230
 
 
231
 
                ret = get_export(symname, &adr);
232
 
                if (ret < 0) {
233
 
                        ERROR("unknown symbol: %s:'%s'", dll, symname);
234
 
                } else {
235
 
                        DBGLINKER("found symbol: %s:%s: addr: %p, rva = %Lu",
236
 
                                  dll, symname, adr, (uint64_t)address_tbl[i]);
237
 
                        address_tbl[i] = (ULONG_PTR)adr;
238
 
                }
239
 
        }
240
 
        return ret;
241
 
}
242
 
 
243
 
static int read_exports(struct pe_image *pe)
244
 
{
245
 
        IMAGE_EXPORT_DIRECTORY *export_dir_table;
246
 
        uint32_t *export_addr_table;
247
 
        int i;
248
 
        uint32_t *name_table;
249
 
        PIMAGE_OPTIONAL_HEADER opt_hdr;
250
 
        IMAGE_DATA_DIRECTORY *export_data_dir;
251
 
 
252
 
        opt_hdr = &pe->nt_hdr->OptionalHeader;
253
 
        export_data_dir =
254
 
                &opt_hdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
255
 
 
256
 
        if (export_data_dir->Size == 0) {
257
 
                DBGLINKER("no exports");
258
 
                return 0;
259
 
        }
260
 
 
261
 
        export_dir_table =
262
 
                RVA2VA(pe->image, export_data_dir->VirtualAddress,
263
 
                       IMAGE_EXPORT_DIRECTORY *);
264
 
 
265
 
        name_table = (unsigned int *)(pe->image +
266
 
                                      export_dir_table->AddressOfNames);
267
 
        export_addr_table = (uint32_t *)
268
 
                (pe->image + export_dir_table->AddressOfFunctions);
269
 
 
270
 
        for (i = 0; i < export_dir_table->NumberOfNames; i++) {
271
 
 
272
 
                if (export_data_dir->VirtualAddress <= *export_addr_table ||
273
 
                    *export_addr_table >= (export_data_dir->VirtualAddress +
274
 
                                           export_data_dir->Size))
275
 
                        DBGLINKER("forwarder rva");
276
 
 
277
 
                DBGLINKER("export symbol: %s, at %p",
278
 
                          (char *)(pe->image + *name_table),
279
 
                          pe->image + *export_addr_table);
280
 
 
281
 
                pe_exports[num_pe_exports].dll = pe->name;
282
 
                pe_exports[num_pe_exports].name = pe->image + *name_table;
283
 
                pe_exports[num_pe_exports].addr =
284
 
                        pe->image + *export_addr_table;
285
 
 
286
 
                num_pe_exports++;
287
 
                name_table++;
288
 
                export_addr_table++;
289
 
        }
290
 
        return 0;
291
 
}
292
 
 
293
 
static int fixup_imports(void *image, IMAGE_NT_HEADERS *nt_hdr)
294
 
{
295
 
        int i;
296
 
        char *name;
297
 
        int ret = 0;
298
 
        IMAGE_IMPORT_DESCRIPTOR *dirent;
299
 
        IMAGE_DATA_DIRECTORY *import_data_dir;
300
 
        PIMAGE_OPTIONAL_HEADER opt_hdr;
301
 
 
302
 
        opt_hdr = &nt_hdr->OptionalHeader;
303
 
        import_data_dir =
304
 
                &opt_hdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
305
 
        dirent = RVA2VA(image, import_data_dir->VirtualAddress,
306
 
                        IMAGE_IMPORT_DESCRIPTOR *);
307
 
 
308
 
        for (i = 0; dirent[i].Name; i++) {
309
 
                name = RVA2VA(image, dirent[i].Name, char*);
310
 
 
311
 
                DBGLINKER("imports from dll: %s", name);
312
 
                ret += import(image, &dirent[i], name);
313
 
        }
314
 
        return ret;
315
 
}
316
 
 
317
 
static int fixup_reloc(void *image, IMAGE_NT_HEADERS *nt_hdr)
318
 
{
319
 
        ULONG_PTR base;
320
 
        ULONG_PTR size;
321
 
        IMAGE_BASE_RELOCATION *fixup_block;
322
 
        IMAGE_DATA_DIRECTORY *base_reloc_data_dir;
323
 
        PIMAGE_OPTIONAL_HEADER opt_hdr;
324
 
 
325
 
        opt_hdr = &nt_hdr->OptionalHeader;
326
 
        base = opt_hdr->ImageBase;
327
 
        base_reloc_data_dir =
328
 
                &opt_hdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
329
 
        if (base_reloc_data_dir->Size == 0)
330
 
                return 0;
331
 
 
332
 
        fixup_block = RVA2VA(image, base_reloc_data_dir->VirtualAddress,
333
 
                             IMAGE_BASE_RELOCATION *);
334
 
        DBGLINKER("fixup_block=%p, image=%p", fixup_block, image);
335
 
        DBGLINKER("fixup_block info: %x %d",
336
 
                  fixup_block->VirtualAddress, fixup_block->SizeOfBlock);
337
 
 
338
 
        while (fixup_block->SizeOfBlock) {
339
 
                int i;
340
 
                WORD fixup, offset;
341
 
 
342
 
                size = (fixup_block->SizeOfBlock -
343
 
                        sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
344
 
                DBGLINKER("found %Lu relocations in this block",
345
 
                          (uint64_t)size);
346
 
 
347
 
                for (i = 0; i < size; i++) {
348
 
                        fixup = fixup_block->TypeOffset[i];
349
 
                        offset = fixup & 0xfff;
350
 
                        switch ((fixup >> 12) & 0x0f) {
351
 
                        case IMAGE_REL_BASED_ABSOLUTE:
352
 
                                break;
353
 
 
354
 
                        case IMAGE_REL_BASED_HIGHLOW: {
355
 
                                uint32_t addr;
356
 
                                uint32_t *loc =
357
 
                                        RVA2VA(image,
358
 
                                               fixup_block->VirtualAddress +
359
 
                                               offset, uint32_t *);
360
 
                                addr = RVA2VA(image, (*loc - base), uint32_t);
361
 
                                DBGLINKER("relocation: *%p (Val:%X)= %X",
362
 
                                          loc, *loc, addr);
363
 
                                *loc = addr;
364
 
                        }
365
 
                                break;
366
 
 
367
 
                        case IMAGE_REL_BASED_DIR64: {
368
 
                                uint64_t addr;
369
 
                                uint64_t *loc =
370
 
                                        RVA2VA(image,
371
 
                                               fixup_block->VirtualAddress +
372
 
                                               offset, uint64_t *);
373
 
                                addr = RVA2VA(image, (*loc - base), uint64_t);
374
 
                                DBGLINKER("relocation: *%p (Val:%llX)= %llx",
375
 
                                          loc, *loc, addr);
376
 
                                *loc = addr;
377
 
                        }
378
 
                                break;
379
 
 
380
 
                        default:
381
 
                                ERROR("unknown fixup: %08X",
382
 
                                      (fixup >> 12) & 0x0f);
383
 
                                return -EOPNOTSUPP;
384
 
                                break;
385
 
                        }
386
 
                }
387
 
                DBGLINKER("finished relocating block");
388
 
 
389
 
                fixup_block = (IMAGE_BASE_RELOCATION *)
390
 
                        ((void *)fixup_block + fixup_block->SizeOfBlock);
391
 
        };
392
 
        DBGLINKER("done relocating all");
393
 
 
394
 
        return 0;
395
 
}
396
 
 
397
 
/* Expand the image in memroy if necessary. The image on disk does not
398
 
 * necessarily maps the image of the driver in memory, so we have to
399
 
 * re-write it in order to fullfill the sections alignements. The
400
 
 * advantage to do that is that rva_to_va becomes a simple
401
 
 * addition. */
402
 
static int fix_pe_image(struct pe_image *pe)
403
 
{
404
 
        void *image;
405
 
        IMAGE_SECTION_HEADER *sect_hdr;
406
 
        int i, sections;
407
 
        int image_size;
408
 
 
409
 
        if (pe->size == pe->opt_hdr->SizeOfImage) {
410
 
                /* Nothing to do */
411
 
                return 0;
412
 
        }
413
 
 
414
 
        image_size = pe->opt_hdr->SizeOfImage;
415
 
#ifdef CONFIG_X86_64
416
 
#ifdef PAGE_KERNEL_EXECUTABLE
417
 
        image = __vmalloc(image_size, GFP_KERNEL | __GFP_HIGHMEM,
418
 
                          PAGE_KERNEL_EXECUTABLE);
419
 
#elif defined PAGE_KERNEL_EXEC
420
 
        image = __vmalloc(image_size, GFP_KERNEL | __GFP_HIGHMEM,
421
 
                          PAGE_KERNEL_EXEC);
422
 
#else
423
 
#error x86_64 should have either PAGE_KERNEL_EXECUTABLE or PAGE_KERNEL_EXEC
424
 
#endif
425
 
#else
426
 
#ifdef cpu_has_nx
427
 
        /* hate to play with kernel macros, but PAGE_KERNEL_EXEC is
428
 
         * not available to modules! */
429
 
        if (cpu_has_nx)
430
 
                image = __vmalloc(image_size, GFP_KERNEL | __GFP_HIGHMEM,
431
 
                                  __pgprot(__PAGE_KERNEL & ~_PAGE_NX));
432
 
        else
433
 
                image = vmalloc(image_size);
434
 
#else
435
 
                image = vmalloc(image_size);
436
 
#endif
437
 
#endif
438
 
        if (image == NULL) {
439
 
                ERROR("failed to allocate enough space for new image:"
440
 
                      " %d bytes", image_size);
441
 
                return -ENOMEM;
442
 
        }
443
 
 
444
 
        /* Copy all the headers, ie everything before the first section. */
445
 
 
446
 
        sections = pe->nt_hdr->FileHeader.NumberOfSections;
447
 
        sect_hdr = IMAGE_FIRST_SECTION(pe->nt_hdr);
448
 
 
449
 
        DBGLINKER("copying headers: %u bytes", sect_hdr->PointerToRawData);
450
 
 
451
 
        memcpy(image, pe->image, sect_hdr->PointerToRawData);
452
 
 
453
 
        /* Copy all the sections */
454
 
        for (i = 0; i < sections; i++) {
455
 
                DBGLINKER("Copy section %s from %x to %x",
456
 
                          sect_hdr->Name, sect_hdr->PointerToRawData,
457
 
                          sect_hdr->VirtualAddress);
458
 
                if (sect_hdr->VirtualAddress+sect_hdr->SizeOfRawData >
459
 
                    image_size) {
460
 
                        ERROR("Invalid section %s in driver", sect_hdr->Name);
461
 
                        vfree(image);
462
 
                        return -EINVAL;
463
 
                }
464
 
 
465
 
                memcpy(image+sect_hdr->VirtualAddress,
466
 
                       pe->image + sect_hdr->PointerToRawData,
467
 
                       sect_hdr->SizeOfRawData);
468
 
                sect_hdr++;
469
 
        }
470
 
 
471
 
        vfree(pe->image);
472
 
        pe->image = image;
473
 
        pe->size = image_size;
474
 
 
475
 
        /* Update our internal pointers */
476
 
        pe->nt_hdr = (IMAGE_NT_HEADERS *)
477
 
                (pe->image + ((IMAGE_DOS_HEADER *)pe->image)->e_lfanew);
478
 
        pe->opt_hdr = &pe->nt_hdr->OptionalHeader;
479
 
 
480
 
        DBGLINKER("set nt headers: nt_hdr=%p, opt_hdr=%p, image=%p",
481
 
                  pe->nt_hdr, pe->opt_hdr, pe->image);
482
 
 
483
 
        return 0;
484
 
}
485
 
 
486
 
#if defined(CONFIG_X86_64)
487
 
static void fix_user_shared_data_addr(char *driver, unsigned long length)
488
 
{
489
 
        unsigned long i, n, max_addr, *addr;
490
 
 
491
 
        n = length - sizeof(unsigned long);
492
 
        max_addr = KI_USER_SHARED_DATA + sizeof(kuser_shared_data);
493
 
        for (i = 0; i < n; i++) {
494
 
                addr = (unsigned long *)(driver + i);
495
 
                if (*addr >= KI_USER_SHARED_DATA && *addr < max_addr) {
496
 
                        *addr -= KI_USER_SHARED_DATA;
497
 
                        *addr += (unsigned long)&kuser_shared_data;
498
 
                        kuser_shared_data.reserved1 = 1;
499
 
                }
500
 
        }
501
 
}
502
 
#endif
503
 
 
504
 
int link_pe_images(struct pe_image *pe_image, unsigned short n)
505
 
{
506
 
        int i;
507
 
        struct pe_image *pe;
508
 
 
509
 
#ifdef DEBUG
510
 
        /* Sanity checkings */
511
 
        CHECK_SZ(IMAGE_SECTION_HEADER, IMAGE_SIZEOF_SECTION_HEADER);
512
 
        CHECK_SZ(IMAGE_FILE_HEADER, IMAGE_SIZEOF_FILE_HEADER);
513
 
        CHECK_SZ(IMAGE_OPTIONAL_HEADER, IMAGE_SIZEOF_NT_OPTIONAL_HEADER);
514
 
        CHECK_SZ(IMAGE_NT_HEADERS, 4 + IMAGE_SIZEOF_FILE_HEADER +
515
 
                 IMAGE_SIZEOF_NT_OPTIONAL_HEADER);
516
 
        CHECK_SZ(IMAGE_DOS_HEADER, 0x40);
517
 
        CHECK_SZ(IMAGE_EXPORT_DIRECTORY, 40);
518
 
        CHECK_SZ(IMAGE_BASE_RELOCATION, 8);
519
 
        CHECK_SZ(IMAGE_IMPORT_DESCRIPTOR, 20);
520
 
#endif
521
 
 
522
 
        for (i = 0; i < n; i++) {
523
 
                IMAGE_DOS_HEADER *dos_hdr;
524
 
                pe = &pe_image[i];
525
 
                dos_hdr = pe->image;
526
 
 
527
 
                if (pe->size < sizeof(IMAGE_DOS_HEADER)) {
528
 
                        TRACE1("image too small: %d", pe->size);
529
 
                        return -EINVAL;
530
 
                }
531
 
 
532
 
                pe->nt_hdr =
533
 
                        (IMAGE_NT_HEADERS *)(pe->image + dos_hdr->e_lfanew);
534
 
                pe->opt_hdr = &pe->nt_hdr->OptionalHeader;
535
 
 
536
 
                pe->type = check_nt_hdr(pe->nt_hdr);
537
 
                if (pe->type <= 0) {
538
 
                        TRACE1("type <= 0");
539
 
                        return -EINVAL;
540
 
                }
541
 
 
542
 
                if (fix_pe_image(pe)) {
543
 
                        TRACE1("bad PE image");
544
 
                        return -EINVAL;
545
 
                }
546
 
 
547
 
                if (read_exports(pe)) {
548
 
                        TRACE1("read exports failed");
549
 
                        return -EINVAL;
550
 
                }
551
 
        }
552
 
 
553
 
        for (i = 0; i < n; i++) {
554
 
                pe = &pe_image[i];
555
 
 
556
 
                if (fixup_reloc(pe->image, pe->nt_hdr)) {
557
 
                        TRACE1("fixup reloc failed");
558
 
                        return -EINVAL;
559
 
                }
560
 
                if (fixup_imports(pe->image, pe->nt_hdr)) {
561
 
                        TRACE1("fixup imports failed");
562
 
                        return -EINVAL;
563
 
                }
564
 
#if defined(CONFIG_X86_64)
565
 
                INFO("fixing KI_USER_SHARED_DATA address in the driver");
566
 
                fix_user_shared_data_addr(pe_image[i].image, pe_image[i].size);
567
 
#endif
568
 
                flush_icache_range(pe->image, pe->size);
569
 
 
570
 
                pe->entry =
571
 
                        RVA2VA(pe->image,
572
 
                               pe->opt_hdr->AddressOfEntryPoint, void *);
573
 
                TRACE1("entry is at %p, rva at %08X", pe->entry,
574
 
                       pe->opt_hdr->AddressOfEntryPoint);
575
 
        }
576
 
 
577
 
        for (i = 0; i < n; i++) {
578
 
                pe = &pe_image[i];
579
 
 
580
 
                if (pe->type == IMAGE_FILE_DLL) {
581
 
                        struct unicode_string ustring;
582
 
                        char *buf = "0/0t0m0p00";
583
 
                        int (*dll_entry)(struct unicode_string *ustring)
584
 
                                wstdcall;
585
 
 
586
 
                        memset(&ustring, 0, sizeof(ustring));
587
 
                        ustring.buf = (wchar_t *)buf;
588
 
                        dll_entry = (void *)get_dll_init(pe->name);
589
 
 
590
 
                        TRACE1("calling dll_init at %p", dll_entry);
591
 
                        if (!dll_entry || dll_entry(&ustring))
592
 
                                ERROR("DLL initialize failed for %s",
593
 
                                      pe->name);
594
 
                }
595
 
                else if (pe->type != IMAGE_FILE_EXECUTABLE_IMAGE)
596
 
                        ERROR("illegal image type: %d", pe->type);
597
 
        }
598
 
        return 0;
599
 
}