Is it possible to vmap kernel module's memory? - memory-management
Is there any constraint to the mapping kernel module's memory via the vmap? On my system I write a simple KMOD, that maps a kernel-function (printk) and a module-function (printx) and check if mappings are equals. The result shows me that there is a problem with mapping module's printx - the mapping and the function's code does not equals. Could someone explain me what I do wrong? And here is the code:
// vmap-test.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mm.h>
int printx(void)
{
return 0;
}
void vmap_action(unsigned long address)
{
void * mapping;
struct page * page;
page = virt_to_page(address);
mapping = vmap(&page, 1, VM_MAP, PAGE_KERNEL);
if (mapping) {
int i = 0;
void * data = mapping + offset_in_page(address);
printk("VMAP: src %p -> dst %p\n", (void *)address, data);
for (i=0; i<16; i++) {
printk("%.02x %.02x\n", ((u8 *)address)[i], ((u8 *)data)[i]);
}
vunmap(mapping);
}
}
int my_module_init(void)
{
vmap_action((unsigned long)printk);
vmap_action((unsigned long)printx);
return 0;
}
module_init(my_module_init);
void my_module_exit(void)
{
}
module_exit(my_module_exit);
And the result with dmesg is:
vmap(printk)
[88107.398146] VMAP: src ffffffff813dfaef -> dst ffffc900117ddaef
[88107.398148] 55 55
[88107.398149] 48 48
[88107.398150] 89 89
[88107.398151] e5 e5
[88107.398152] 48 48
[88107.398153] 83 83
[88107.398154] ec ec
[88107.398155] 50 50
[88107.398156] 0f 0f
[88107.398156] 1f 1f
[88107.398157] 44 44
[88107.398158] 00 00
[88107.398159] 00 00
[88107.398160] 48 48
[88107.398161] 8d 8d
[88107.398162] 45 45
vmap(printx)
[88107.398164] VMAP: src ffffffffa009a010 -> dst ffffc900117fd010
[88107.398166] 55 35
[88107.398167] 48 fb
[88107.398168] 89 53
[88107.398169] e5 d5
[88107.398170] 0f f7
[88107.398171] 1f 97
[88107.398171] 44 ee
[88107.398172] 00 fd
[88107.398173] 00 d5
[88107.398174] 31 2d
[88107.398175] c0 bf
[88107.398176] 5d f6
[88107.398177] c3 2d
[88107.398178] 0f bd
[88107.398179] 1f b7
[88107.398180] 00 99
Any suggestions are welcome :) Thanks.
Well, I found that similar function is implemented in KSplice project and here is it:
/*
* map_writable creates a shadow page mapping of the range
* [addr, addr + len) so that we can write to code mapped read-only.
*
* It is similar to a generalized version of x86's text_poke. But
* because one cannot use vmalloc/vfree() inside stop_machine, we use
* map_writable to map the pages before stop_machine, then use the
* mapping inside stop_machine, and unmap the pages afterwards.
*/
static void *map_writable(void *addr, size_t len)
{
void *vaddr;
int nr_pages = DIV_ROUND_UP(offset_in_page(addr) + len, PAGE_SIZE);
struct page **pages = kmalloc(nr_pages * sizeof(*pages), GFP_KERNEL);
void *page_addr = (void *)((unsigned long)addr & PAGE_MASK);
int i;
if (pages == NULL)
return NULL;
for (i = 0; i < nr_pages; i++) {
if (__module_address((unsigned long)page_addr) == NULL) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) || !defined(CONFIG_X86_64)
pages[i] = virt_to_page(page_addr);
#else /* LINUX_VERSION_CODE < && CONFIG_X86_64 */
/* e3ebadd95cb621e2c7436f3d3646447ac9d5c16d was after 2.6.21
* This works around a broken virt_to_page() from the RHEL 5 backport
* of x86-64 relocatable kernel support.
*/
pages[i] =
pfn_to_page(__pa_symbol(page_addr) >> PAGE_SHIFT);
#endif /* LINUX_VERSION_CODE || !CONFIG_X86_64 */
WARN_ON(!PageReserved(pages[i]));
} else {
pages[i] = vmalloc_to_page(addr);
}
if (pages[i] == NULL) {
kfree(pages);
return NULL;
}
page_addr += PAGE_SIZE;
}
vaddr = vmap(pages, nr_pages, VM_MAP, PAGE_KERNEL);
kfree(pages);
if (vaddr == NULL)
return NULL;
return vaddr + offset_in_page(addr);
}
So, as it comes there is a different handling of kernel's and module's memory. If the page is not belongs to any module then vmalloc_to_page rather then virt_to_phys used. I'll check if it helps and post the result later.
Related
How to convert a message's value from hexadecimal to decimal?
I need to write a function that converts a message's byte (this.byte(2)) from hexadecimal to decimal, from a message I receive on the CAN bus. For example i have the following message on the CAN bus "F1 02 1A 13 00 00 00 00" The function should then returns the value 26 for this.byte(2) "1A". I followed some examples found on the internet but I still don't get the right value. What is then wrong with my function ? variables { char hexa[2]; long decimal, place; int val, len; } int HexToDec(char hexa[]) { decimal = 0; i=0; place = 1; len = strlen(hexa); len--; for(i=0; hexa[i]!='\0'; i++) { if(hexa[i]>='0' && hexa[i]<='9') { val = hexa[i] - 48; } else if(hexa[i]>='a' && hexa[i]<='f') { val = hexa[i] - 97 + 10; } else if(hexa[i]>='A' && hexa[i]<='F') { val = hexa[i] - 65 + 10; } decimal += val * _pow(16, len); len--; } write("Hexadecimal number = %s\n", hexa); write("Decimal number = %lld", decimal); return 0; } on message * { HexToDec(this.BYTE(2)); // for example 1A in hexadecimal }
Your requirement "convert hex to decimal" is a wrong statement. Because both Hexadecimal and Decimal are numbers. Your function HexToDec is taking string as input and not a number. If you want to print this.BYTE(2) as a decimal value, you just have to write write("Hex - %X", this.BYTE(2)); write("Dec - %d", this.BYTE(2));
When using get_unaligned_leX() what is the purpose of adding a value to the argument?
For example, in /crypto/nhpoly1305.c: 42 static void nh_generic(const u32 *key, const u8 *message, size_t message_len, 43 __le64 hash[NH_NUM_PASSES]) 44 { 45 u64 sums[4] = { 0, 0, 0, 0 }; 46 47 BUILD_BUG_ON(NH_PAIR_STRIDE != 2); 48 BUILD_BUG_ON(NH_NUM_PASSES != 4); 49 50 while (message_len) { 51 u32 m0 = get_unaligned_le32(message + 0); 52 u32 m1 = get_unaligned_le32(message + 4); 53 u32 m2 = get_unaligned_le32(message + 8); 54 u32 m3 = get_unaligned_le32(message + 12); What is the meaning of these values added to the argument? I assume it has something to do with bits/bytes...
C getting a raw keypress with no stdlib
I am working an a very basic operating system for a learning experience, and I am trying to start with key presses. I am making a freestanding executable, so no standard library. How would I go about taking input from a keyboard? I have figured out how to print to the screen through video memory. /* * kernel.c * */ void cls(int line) { // clear the screen char *vidptr = (char*) 0xb8000; /* 25 lines each of 80 columns; each element takes 2 bytes */ unsigned int x = 0; while (x < 80 * 25 * 2) { // blank character vidptr[x] = ' '; // attribute-byte - light grey on black screen x += 1; vidptr[x] = 0x07; x += 1; } line = 0; } void printf(const char *str, int line, char attr) { // write a string to video memory char *vidptr = (char*) 0xb8000; unsigned int y =0, x = 0; while (str[y] != '\0') { // the character's ascii vidptr[x] = str[y]; x++; // attribute byte - give character black bg and light gray fg vidptr[x+1] = attr; x++; y++; } } void kmain(void) { unsigned int line = 0; cls(line); printf("Testing the Kernel", line, 0x0a); } and my assembly: ;; entry point bits 32 ; nasm directive - 32 bit global entry extern _kmain ; kmain is defined in the c file section .text entry: jmp start ;multiboot spec align 4 dd 0x1BADB002 ; black magic dd 0x00 ; flags dd -(0x1BADB002 + 0x00) ; checksum. m+f+c should be zero start: cli ; block interrupts mov esp, stack_space ; set stack pointer call _kmain hlt ; halt the CPU section .bss resb 8192 ; 8KB for stack stack_space:
C++ CLI Serial port missing data received
I have a problem with missing data in serialport. When I run first time code all data is correct. But every next time data is missing. For example : First time : 01 00 00 00 01 0A CA - CORRECT Second time : 0A CA - MISSING DATA Third time : CA - MISSING DATA private: System::Void serialPort1_DataReceived(System::Object^ sender, System::IO::Ports::SerialDataReceivedEventArgs^ e) { numbytes = serialPort1->BytesToRead; encodedBytes = gcnew array<Byte>(numbytes); for (ck = 0; ck < numbytes; ck++){ encodedBytes[ck] = serialPort1->ReadByte(); } this->Invoke(gcnew EventHandler(this,&MyForm3::SetTextCallback)); } private: System::Void SetTextCallback(System::Object^ sender, System::EventArgs^ e){ textBox9->Text = ""; for (ck = 0; ck <numbytes; ck++){ this->textBox9->AppendText((encodedBytes[ck].ToString("X2"))); } numbytes = 0; ck = 0; }
macos: CCCrypt() decrypt output does not match original plaintext
In the code below, the decrypted text does not match the original plaintext. The first 12 bytes are messed up. Note that block cipher padding has been disabled. I have tried different values for BUF_SIZE, all multiples of 16 - every time the first 12 bytes of the decrypted data is wrong. Here's the output: plain buf[32]: 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 outlen=32 outlen=32 dec buf[32]: 0C 08 01 46 6D 3D FC E9 98 0A 2D E1 AF A3 95 3A 0B 31 1B 9D 11 11 11 11 11 11 11 11 11 11 11 11 Here's the code: #include <stdio.h> #include <string.h> #include <CommonCrypto/CommonCryptor.h> static void dumpbuf(const char* label, const unsigned char* pkt, unsigned int len) { const int bytesPerLine = 16; if (label) { printf("%s[%d]:\n", label, len); } for (int i = 0; i < int(len); i++) { if (i && ((i % bytesPerLine) == 0)) { printf("\n"); } unsigned int c = (unsigned int)pkt[i] & 0xFFu; printf("%02X ", c); } printf("\n"); } int main(int argc, char* argv[]) { unsigned char key[16]; unsigned char iv[16]; memset(key, 0x22, sizeof(key)); memset(iv, 0x33, sizeof(iv)); #define BUF_SIZE 32 unsigned char plainBuf[BUF_SIZE]; unsigned char encBuf[BUF_SIZE]; memset(plainBuf, 0x11, sizeof(plainBuf)); dumpbuf("plain buf", plainBuf, sizeof(plainBuf)); int outlen; CCCryptorStatus status; status = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, 0, key, kCCKeySizeAES128, iv, plainBuf, sizeof(plainBuf), encBuf, sizeof(encBuf), (size_t*)&outlen); if (kCCSuccess != status) { fprintf(stderr, "FEcipher: CCCrypt failure\n"); return -1; } printf("outlen=%d\n", outlen); status = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, 0, key, kCCKeySizeAES128, iv, encBuf, sizeof(encBuf), plainBuf, sizeof(plainBuf), (size_t*)&outlen); if (kCCSuccess != status) { fprintf(stderr, "FEcipher: CCCrypt failure\n"); return -1; } printf("outlen=%d\n", outlen); dumpbuf("dec buf", plainBuf, sizeof(plainBuf)); return 0; } Thanks, Hari
#owlstead, thanks for your response. CBC is the default - you don't need to specify anything special in the options to enable it. The same code using CCCrypt() was working before. I don't know what changed - may be a new library was installed during an update. Instead of using the convenience function CCCrypt() I'm now using the Create/Update/Final API - it works, so I have a workaround.
outlen should be size_t, not int.