Below code can hook lsm successfully on Redhat8 server, but it will cause crash on Redhat9 server. I have try to find any resource about hlist_add_head_rcu or hook way change on linux 5.1x but cannot find any useful workaround. Could you help check about why that the same way can work on linux 4.x but cannot work on linux 5.1x? If you know the reason, could you help provide some workaround or suggestions. Thanks for your help.
#include <linux/module.h>
#include <linux/kallsyms.h>
#include <linux/version.h>
#include <linux/security.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,2,0)
#include <linux/lsm_hooks.h>
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0)
#define KPROBE_LOOKUP 1
#include <linux/kprobes.h>
static struct kprobe kp = {
.symbol_name = "kallsyms_lookup_name"
};
#endif
#define SECURITY_HOOK_ADDR_NAME "security_hook_heads"
static unsigned long find_symbol_addr(const char *sym){
const char *cpsMethod = "cris test: find_symbol_addr";
unsigned long addr;
#ifdef KPROBE_LOOKUP
typedef unsigned long (*kallsyms_lookup_name_t)(const char *name);
kallsyms_lookup_name_t kallsyms_lookup_name;
register_kprobe(&kp);
kallsyms_lookup_name = (kallsyms_lookup_name_t) kp.addr;
unregister_kprobe(&kp);
#endif
addr = kallsyms_lookup_name(sym);
if (addr == 0) {
pr_err("%s: unable to find addr\n", cpsMethod);
return -EINVAL;
}
pr_info("%s: address is %lx\n", cpsMethod, addr);
return addr;
}
struct security_hook_list cris_hooks[1] = {
};
static int hook_execve_test(struct file *file, int mask)
{
pr_info("cris test: hook_execve_test\n");
return 0;
}
static struct security_hook_heads *cris_lsm_hook = NULL;
bool hook_lsm(void){
const char *cpsMethod = "cris test: hook_lsm";
int count = 0;
int i = 0;
unsigned long addr1;
addr1 = find_symbol_addr(SECURITY_HOOK_ADDR_NAME);
if (addr1 == 0)
{
pr_err("%s: [Fatal] Lookup address for security hook heads failed. Can't enable execve Hook\n", cpsMethod);
return false;
}
cris_lsm_hook = (struct security_hook_heads*)addr1;
cris_hooks[0].head = &(cris_lsm_hook->file_permission);
cris_hooks[0].hook.file_permission = hook_execve_test;
count = ARRAY_SIZE(cris_hooks);
for (i = 0; i < count; i++){
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,17,0)
list_add_rcu(&cris_hooks[i].list, cris_hooks[i].head);
#else
hlist_add_head_rcu(&cris_hooks[i].list, cris_hooks[i].head);
#endif
}
pr_info("%s: finish hook_lsm.\n", cpsMethod);
return true;
}
void unhook_lsm(void){
const char *cpsMethod = "cris test: unhook_lsm";
int count = 0;
int i = 0;
count = ARRAY_SIZE(cris_hooks);
for (i = 0; i < count; i++){
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,17,0)
list_del_rcu(&cris_hooks[i].list);
#else
hlist_del_rcu(&cris_hooks[i].list);
#endif
}
pr_info("%s: Unregister hook module\n", cpsMethod);
}
static int __init prsyms_init(void)
{
hook_lsm();
return 0;
}
static void __exit prsyms_exit(void)
{
unhook_lsm();
}
module_init(prsyms_init);
module_exit(prsyms_exit);
MODULE_LICENSE("GPL");
The version of test servers are:
Redhat8: 4.18.0-147.el8.x86_64
Redhat9: 5.14.0-70.13.1.el9_0.x86_64
And below is dump log from Redhat9 crash dump:
[ 2644.871335] cris test: find_symbol_addr: address is ffffffffb3215c60
[ 2644.871354] BUG: unable to handle page fault for address: ffffffffb3215ea0
[ 2644.871361] #PF: supervisor write access in kernel mode
[ 2644.871363] #PF: error_code(0x0003) - permissions violation
[ 2644.871365] PGD b5a15067 P4D b5a15067 PUD b5a16063 PMD 80000000b54000e1
[ 2644.871377] Oops: 0003 [#1] PREEMPT SMP PTI
[ 2644.871387] CPU: 0 PID: 2437 Comm: insmod Kdump: loaded Tainted: G S OE --------- --- 5.14.0-70.13.1.el9_0.x86_64 #1
[ 2644.871394] Hardware name: VMware, Inc. VMware7,1/440BX Desktop Reference Platform, BIOS VMW71.00V.13989454.B64.1906190538 06/19/2019
[ 2644.871396] RIP: 0010:hook_lsm.cold+0x47/0x95 [testcris]
[ 2644.871416] Code: 02 00 00 48 8d 93 40 02 00 00 48 c7 05 8f 23 00 00 83 70 72 c0 48 89 15 80 23 00 00 48 89 05 69 23 00 00 48 89 15 6a 23 00 00 <48> c7 83 40 02 00 00 40 94 72 c0 48 85 c0 74 08 48 c7 40 08 40 94
[ 2644.871418] RSP: 0018:ffffb5c00260fde0 EFLAGS: 00010246
[ 2644.871421] RAX: ffffffffb3216cf8 RBX: ffffffffb3215c60 RCX: 0000000000000000
[ 2644.871423] RDX: ffffffffb3215ea0 RSI: ffff917efbc17cc0 RDI: ffff917efbc17cc0
[ 2644.871424] RBP: ffffffffc072c000 R08: 0000000000000000 R09: ffffb5c00260fc28
[ 2644.871425] R10: ffffb5c00260fc20 R11: ffffffffb3be8228 R12: ffff917dc12226f0
[ 2644.871427] R13: ffffb5c00260fe88 R14: 0000000000000003 R15: 0000000000000000
[ 2644.871428] FS: 00007f8005409740(0000) GS:ffff917efbc00000(0000) knlGS:0000000000000000
[ 2644.871444] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 2644.871447] CR2: ffffffffb3215ea0 CR3: 000000003f536003 CR4: 00000000001706f0
[ 2644.871467] Call Trace:
[ 2644.871473] prsyms_init+0xa/0x1000 [testcris]
[ 2644.871477] do_one_initcall+0x44/0x200
[ 2644.871500] ? load_module+0xab8/0xb80
[ 2644.871503] ? kmem_cache_alloc_trace+0x45/0x420
[ 2644.871523] do_init_module+0x5c/0x270
[ 2644.871536] __do_sys_finit_module+0xae/0x110
[ 2644.871544] do_syscall_64+0x3b/0x90
[ 2644.871592] entry_SYSCALL_64_after_hwframe+0x44/0xae
Related
i started learning linux driver a few days ago and i write a simple driver.fisrt i insmod my driver ,it showed it runs well ,and normal when i rmmod. but when i insmod it again, console log showed "killed", and then i use dmesg. The kernel log showed twice stackdump which surprised me so that i don't how to debug(use printk (●'◡'●)).
Many times tried on search machine, i got nothing. so i throwed it here, needing your guys help very very desperate. i truely wanna know why it failed at second time, why stackdump happened twice and how could i fix this driver. thanks very very much!
my vm linux kernel version is : 5.13.0
driver code is here:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/printk.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/device.h>
#include <linux/export.h>
#include <linux/types.h>
#include <linux/kobject.h>
static ssize_t my_file_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, 64, "%s", __func__);
}
static ssize_t my_file_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
pr_info("going to my_file_store\n");
return count;
}
static DEVICE_ATTR(my_file, 0664, my_file_show, my_file_store);
static int my_devid = -1;
static struct class *my_class = NULL;
static struct device *my_device = NULL;
static int __init my_init(void){
pr_info("going to %s\n", __func__);
int ret = 0;
ret = alloc_chrdev_region(&my_devid, 0, 1, "my_devid");
if(ret < 0){
my_devid = -1;
pr_err("[%s,%d]alloc_chrdev_region failed\n", __func__, __LINE__);
goto FAULT;
}
pr_info("my devid %d\n", my_devid);
my_class = class_create(THIS_MODULE, "my_class");
if(my_class == NULL){
pr_err("[%s,%d]class_create failed\n", __func__, __LINE__);
goto FAULT;
}
pr_info("[%s,%d]goes here\n", __func__, __LINE__);
my_device = device_create(my_class, NULL, my_devid, "%s", "my_dev");
if(my_device == NULL){
pr_err("[%s,%d] device_create failed\n", __func__, __LINE__);
goto FAULT;
}
pr_info("[%s,%d]goes here\n", __func__, __LINE__);
ret = device_create_file(my_device, &dev_attr_my_file);
if(ret < 0){
pr_err("sysfs_create_file failed\n");
goto FAULT;
}
pr_info("go to init tail now\n");
return 0;
FAULT:
if(my_devid != -1){
unregister_chrdev_region(my_devid, "my_devid");
my_devid = -1;
}
if(my_device != NULL){
device_destroy(my_class, my_devid);
my_device = NULL;
}
if(my_class != NULL){
class_destroy(my_class);
my_class = NULL;
}
return 0;
}
static void __exit my_exit(void){
pr_info("going to %s\n", __func__);
device_remove_file(my_device, &dev_attr_my_file);
if(my_devid != -1){
unregister_chrdev_region(my_devid, "my_devid");
my_devid = -1;
}
if(my_device != NULL){
device_destroy(my_class, my_devid);
my_device = NULL;
}
if(my_class != NULL){
class_destroy(my_class);
my_class = NULL;
}
}
module_init(my_init);
module_exit(my_exit);
MODULE_AUTHOR("tid");
MODULE_LICENSE("GPL");
this is dmesg:
going to my_init
[87682.699433] my devid 247463936
[87682.700041] [my_init,47]goes here
[87682.706933] [my_init,54]goes here
[87682.706937] go to init tail now
[87704.903499] going to my_exit
[87747.424115] going to my_init
[87747.424385] my devid 262144000
[87747.424418] [my_init,47]goes here
[87747.424784] sysfs: cannot create duplicate filename '/devices/virtual/my_class'
[87747.424989] CPU: 1 PID: 462167 Comm: insmod Tainted: G OE 5.13.0-27-generic #29~20.04.1-Ubuntu
[87747.424992] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 11/12/2020
[87747.425172] Call Trace:
[87747.426055] dump_stack+0x7d/0x9c
[87747.427617] sysfs_warn_dup.cold+0x17/0x27
[87747.427889] sysfs_create_dir_ns+0xb8/0xd0
[87747.428703] kobject_add_internal+0xbd/0x2b0
[87747.429021] kobject_add+0x7e/0xb0
[87747.429023] ? kmem_cache_alloc_trace+0x37c/0x440
[87747.429671] get_device_parent.isra.0+0x179/0x1b0
[87747.429943] device_add+0xe3/0x8e0
[87747.429945] device_create_groups_vargs+0xd4/0xf0
[87747.429946] ? 0xffffffffc09b1000
[87747.429948] device_create+0x49/0x60
[87747.429950] my_init+0xf0/0x1000 [test]
[87747.430241] do_one_initcall+0x46/0x1d0
[87747.430632] ? __cond_resched+0x19/0x30
[87747.430866] ? kmem_cache_alloc_trace+0x37c/0x440
[87747.430869] do_init_module+0x62/0x260
[87747.430898] load_module+0x125d/0x1440
[87747.431183] __do_sys_finit_module+0xc2/0x120
[87747.431185] ? __do_sys_finit_module+0xc2/0x120
[87747.431186] __x64_sys_finit_module+0x1a/0x20
[87747.431188] do_syscall_64+0x61/0xb0
[87747.431260] ? __x64_sys_newfstat+0x16/0x20
[87747.431361] ? do_syscall_64+0x6e/0xb0
[87747.431363] ? __x64_sys_lseek+0x1a/0x20
[87747.431380] ? do_syscall_64+0x6e/0xb0
[87747.431382] ? exc_page_fault+0x8f/0x170
[87747.431383] ? asm_exc_page_fault+0x8/0x30
[87747.431385] entry_SYSCALL_64_after_hwframe+0x44/0xae
[87747.431386] RIP: 0033:0x7fd6b8d3789d
[87747.431388] Code: 00 c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d c3 f5 0c 00 f7 d8 64 89 01 48
[87747.431390] RSP: 002b:00007ffe09073bd8 EFLAGS: 00000246 ORIG_RAX: 0000000000000139
[87747.431405] RAX: ffffffffffffffda RBX: 0000557d4fa68760 RCX: 00007fd6b8d3789d
[87747.431405] RDX: 0000000000000000 RSI: 0000557d4db48358 RDI: 0000000000000003
[87747.431406] RBP: 0000000000000000 R08: 0000000000000000 R09: 00007fd6b8e0b260
[87747.431407] R10: 0000000000000003 R11: 0000000000000246 R12: 0000557d4db48358
[87747.431407] R13: 0000000000000000 R14: 0000557d4fa683d0 R15: 0000000000000000
[87747.431503] kobject_add_internal failed for my_class with -EEXIST, don't try to register things with the same name in the same directory.
[87747.431713] [my_init,54]goes here
[87747.431749] BUG: kernel NULL pointer dereference, address: 000000000000001f
[87747.431765] #PF: supervisor read access in kernel mode
[87747.431780] #PF: error_code(0x0000) - not-present page
[87747.431819] PGD 0 P4D 0
[87747.431821] Oops: 0000 [#1] SMP NOPTI
[87747.431823] CPU: 1 PID: 462167 Comm: insmod Tainted: G OE 5.13.0-27-generic #29~20.04.1-Ubuntu
[87747.431825] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 11/12/2020
[87747.431826] RIP: 0010:sysfs_create_file_ns+0x26/0x90
[87747.431829] Code: 9c 0f 1f 00 0f 1f 44 00 00 55 48 89 e5 41 55 41 54 53 48 83 ec 10 65 48 8b 04 25 28 00 00 00 48 89 45 e0 31 c0 48 85 ff 74 5b <48> 83 7f 30 00 48 89 fb 74 51 49 89 f4 48 85 f6 74 49 49 89 d5 48
[87747.431831] RSP: 0018:ffffa39a0406fbe0 EFLAGS: 00010282
[87747.431832] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000027
[87747.431833] RDX: 0000000000000000 RSI: ffffffffc09ae020 RDI: ffffffffffffffef
[87747.431834] RBP: ffffa39a0406fc08 R08: ffff8e77b9e589c0 R09: ffffa39a0406fa18
[87747.431835] R10: 0000000000000001 R11: 0000000000000001 R12: ffffffffc09ae020
[87747.431836] R13: ffffffffffffffef R14: ffffffffc09ae040 R15: 0000000000000000
[87747.431837] FS: 00007fd6b8bf2540(0000) GS:ffff8e77b9e40000(0000) knlGS:0000000000000000
[87747.431838] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[87747.432290] CR2: 000000000000001f CR3: 000000001f4c8005 CR4: 00000000003706e0
[87747.432721] Call Trace:
[87747.432724] device_create_file+0x42/0x80
[87747.432726] ? 0xffffffffc09b1000
[87747.432728] my_init+0x141/0x1000 [test]
[87747.432730] do_one_initcall+0x46/0x1d0
[87747.432732] ? __cond_resched+0x19/0x30
[87747.432734] ? kmem_cache_alloc_trace+0x37c/0x440
[87747.432737] do_init_module+0x62/0x260
[87747.432739] load_module+0x125d/0x1440
[87747.432741] __do_sys_finit_module+0xc2/0x120
[87747.432742] ? __do_sys_finit_module+0xc2/0x120
[87747.432743] __x64_sys_finit_module+0x1a/0x20
[87747.432745] do_syscall_64+0x61/0xb0
[87747.432747] ? __x64_sys_newfstat+0x16/0x20
[87747.432749] ? do_syscall_64+0x6e/0xb0
[87747.432750] ? __x64_sys_lseek+0x1a/0x20
[87747.432752] ? do_syscall_64+0x6e/0xb0
[87747.432754] ? exc_page_fault+0x8f/0x170
[87747.432755] ? asm_exc_page_fault+0x8/0x30
[87747.432756] entry_SYSCALL_64_after_hwframe+0x44/0xae
[87747.432758] RIP: 0033:0x7fd6b8d3789d
[87747.432759] Code: 00 c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d c3 f5 0c 00 f7 d8 64 89 01 48
[87747.432760] RSP: 002b:00007ffe09073bd8 EFLAGS: 00000246 ORIG_RAX: 0000000000000139
[87747.432762] RAX: ffffffffffffffda RBX: 0000557d4fa68760 RCX: 00007fd6b8d3789d
[87747.433030] RDX: 0000000000000000 RSI: 0000557d4db48358 RDI: 0000000000000003
[87747.433032] RBP: 0000000000000000 R08: 0000000000000000 R09: 00007fd6b8e0b260
[87747.433033] R10: 0000000000000003 R11: 0000000000000246 R12: 0000557d4db48358
[87747.433033] R13: 0000000000000000 R14: 0000557d4fa683d0 R15: 0000000000000000
[87747.433036] Modules linked in: test(OE+) vsock_loopback vmw_vsock_virtio_transport_common vmw_vsock_vmci_transport vsock nls_iso8859_1 intel_rapl_msr intel_rapl_common crct10dif_pclmul ghash_clmulni_intel aesni_intel crypto_simd cryptd rapl vmw_balloon snd_ens1371 snd_ac97_codec gameport ac97_bus snd_pcm snd_seq_midi snd_seq_midi_event snd_rawmidi joydev input_leds serio_raw snd_seq snd_seq_device snd_timer snd soundcore vmw_vmci mac_hid sch_fq_codel vmwgfx ttm drm_kms_helper cec rc_core fb_sys_fops syscopyarea sysfillrect sysimgblt msr nfsd parport_pc auth_rpcgss ppdev nfs_acl lockd lp grace parport drm sunrpc ip_tables x_tables autofs4 hid_generic ahci e1000 libahci usbhid hid mptspi mptscsih mptbase crc32_pclmul psmouse scsi_transport_spi i2c_piix4 pata_acpi [last unloaded: test]
[87747.433869] CR2: 000000000000001f
[87747.434327] ---[ end trace d7785aaa07b44309 ]---
[87747.434352] RIP: 0010:sysfs_create_file_ns+0x26/0x90
[87747.434357] Code: 9c 0f 1f 00 0f 1f 44 00 00 55 48 89 e5 41 55 41 54 53 48 83 ec 10 65 48 8b 04 25 28 00 00 00 48 89 45 e0 31 c0 48 85 ff 74 5b <48> 83 7f 30 00 48 89 fb 74 51 49 89 f4 48 85 f6 74 49 49 89 d5 48
[87747.434359] RSP: 0018:ffffa39a0406fbe0 EFLAGS: 00010282
[87747.434361] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000027
[87747.434362] RDX: 0000000000000000 RSI: ffffffffc09ae020 RDI: ffffffffffffffef
[87747.434363] RBP: ffffa39a0406fc08 R08: ffff8e77b9e589c0 R09: ffffa39a0406fa18
[87747.434363] R10: 0000000000000001 R11: 0000000000000001 R12: ffffffffc09ae020
[87747.434364] R13: ffffffffffffffef R14: ffffffffc09ae040 R15: 0000000000000000
[87747.434365] FS: 00007fd6b8bf2540(0000) GS:ffff8e77b9e40000(0000) knlGS:0000000000000000
[87747.434366] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[87747.434368] CR2: 000000000000001f CR3: 000000001f4c8005 CR4: 00000000003706e0
I would like to create an icon manually with CreateIconIndirect as follows:
HDC hDC = ::CreateCompatibleDC( nullptr );
BITMAPINFO bmiMask = {};
bmiMask.bmiHeader.biSize = sizeof( bmiMask.bmiHeader );
bmiMask.bmiHeader.biWidth = 16;
bmiMask.bmiHeader.biHeight = -16; // starts with top row
bmiMask.bmiHeader.biPlanes = 1;
bmiMask.bmiHeader.biBitCount = 32;
BYTE *byMask = nullptr;
HBITMAP hbmMask = ::CreateDIBSection( hDC, &bmiMask, DIB_RGB_COLORS,
reinterpret_cast< void** >( &byMask ),
nullptr, 0 );
BYTE bgraMask[] = { 0x00, 0x00, 0x00, 0x00 };
for( int i = 0; i < 16 * 16; i++ )
for( int j = 0; j < 4; j++ )
byMask[ i * 4 + j ] = bgraMask[ j ];
byMask[ 0 ] = 0x00; byMask[ 1 ] = 0x00; byMask[ 2 ] = 0x00; byMask[ 3 ] = 0x00;
BITMAPINFO bmiColor = {};
bmiColor.bmiHeader.biSize = sizeof( bmiColor.bmiHeader );
bmiColor.bmiHeader.biWidth = 16;
bmiColor.bmiHeader.biHeight = -16; // starts with top row
bmiColor.bmiHeader.biPlanes = 1;
bmiColor.bmiHeader.biBitCount = 32;
BYTE *byColor = nullptr;
HBITMAP hbmColor = ::CreateDIBSection( hDC, &bmiColor, DIB_RGB_COLORS,
reinterpret_cast< void** >( &byColor ),
nullptr, 0 );
BYTE bgraColor[] = { 0xff, 0xff, 0xff, 0xff };
for( int i = 0; i < 16 * 16; i++ )
for( int j = 0; j < 4; j++ )
byColor[ i * 4 + j ] = bgraColor[ j ];
byColor[ 0 ] = 0x00; byColor[ 1 ] = 0x00; byColor[ 2 ] = 0x00; byColor[ 3 ] = 0x00;
ICONINFO ii = {};
ii.fIcon = TRUE;
ii.xHotspot = ii.yHotspot = 0;
ii.hbmMask = hbmMask;
ii.hbmColor = hbmColor;
HICON hIcon = ::CreateIconIndirect( &ii );
::SendMessage( hwndDialog, WM_SETICON, ICON_SMALL,
reinterpret_cast< LPARAM >( hIcon ) );
According to MSDN ( https://learn.microsoft.com/en-us/previous-versions/dd183376(v=vs.85) ) each pixel's data consists of 4 bytes: blue, green, red, and an unused byte.
I made some experiments with the data by changing the values of byMask and byColor, then doing a screen shot and reading the exact RGB value in MS Paint. (Each time I placed Notepad directly behind the application's windows to have a constant background for eventual transparency / alpha channel effects.)
First I changed only the top left corner, while the rest of the data was 0x00 for the mask and 0xff for the color. The result: most of the icon was white (as expected) and the top left pixel had the following colors:
MR MA CR CA OR OG OB
00 00 00 ff 00 00 00
00 00 00 00 d3 e9 fe
00 00 ff 00 d3 e9 fe (a)
ff 00 00 00 d3 e9 fe
ff ff 00 00 d3 e9 fe
00 ff 00 00 d3 e9 fe
00 00 ff ff ff 00 00 (b)
ff 00 ff ff ff 00 00
ff ff ff ff ff 00 00
00 ff ff ff ff 00 00
After that I changed each pixel in both bitmaps to the same value. (And checked with MS Paint's fill tool that the picture has only one color.)
MR MA CR CA OR OG OB
00 00 00 ff 00 00 00
00 00 00 00 00 00 00
00 00 ff 00 ff 00 00 (c)
ff 00 00 00 00 00 00
ff ff 00 00 00 00 00
00 ff 00 00 00 00 00
00 00 ff ff ff 00 00 (d)
ff 00 ff ff ff 00 00 (d)
ff ff ff ff ff 00 00 (d)
00 ff ff ff ff 00 00 (d)
Abbreviations: M=mask C=Color O=Observation R=red G=green B=blue A=alpha/4.byte
I don't understand the following (letters refer to rows in the above table):
If the 4. byte is ignored, and not an alpha channel, why is pixel (a) not ff0000 like (b)?
If I change other pixels only, why does the first one change: (c) vs (a)?
Why is the result of all rows marked with (d) the same, why does the mask have no effect here?
Is there a bug in my code? Am I looking at the wrong MSDN page?
OK, I figured it. For historical reasons, there are two types of 32 bit/pixel bitmaps: those that use 3 bytes for the 3 colors, and the last one is unused (usually set to 0), and those that use the fourth byte to represent the alpha channel.
The catch is that the type is not indicated by any field but Windows takes it as an old format bitmap (without alpha) if all 4th bytes are zero, and treats it as a new format (with alpha) one if any fourth byte differs from zero. So this will result in a fully black icon:
for( int i = 0; i < 16 * 16; i++ )
for( int j = 0; j < 4; j++ )
byColor[ i * 4 + j ] = 0x00;
But if I add this line to the above, the whole icon becomes transparent*:
byColor[ 7 * 16 + 7 + 0 ] = 0x01;
* Except for the pixel in row 7 column 7, which will be only 255/256 transparent.
I'm trying to capture outgoing ethernet frames on the local host before they are sent by inserting a kprobe into __dev_queue_xmit().
However, the bytes I extract from the sk_buff structure do not match the subsequently captured packets.
I only attempted it for linear skbs up to now, because I already get unexpected results there.
For example, my kprobe reported the following information during a call to __dev_queue_xmit():
COMM PID TGID LEN DATALEN
chronyd 1058 1058 90 0
3431c4b06a8b3c7c3f2023bd08006500d0a57f040f7f0000000000000000000000000000000000006018d11a0f7f00000100000000000000000000000000000060a67f040f7f0000000000000000000000000000000000004001
COMM is the name of the process which called the function,
PID is the calling thread's id and TGID its thread group id. LEN is the value of (skb->len - skb->data_len) and DATA_LEN is skb->data_len.
Next, the program has copied LEN (in this case 90) bytes starting at skb->data.
Since DATALEN is zero, this is a linear skb. Thus, those bytes should contain exactly the frame which is about to be sent, shouldn't they?
Well, Wireshark subsequently recorded this frame:
0000 34 31 c4 b0 6a 8b 3c 7c 3f 20 23 bd 08 00 45 00
0010 00 4c 83 93 40 00 40 11 d1 a2 c0 a8 b2 18 c0 a8
0020 b2 01 c8 07 00 7b 00 38 e5 b4 23 00 06 20 00 00
0030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0050 00 00 38 bc 17 13 12 4a 4c c0
The first 14 bytes, which are forming the ethernet header, match up perfectly as expected. Everything else doesn't match up at all.
The question now is: Why do the bytes not match up?
(Yes, I am certain the frame from Wireshark is indeed the one caused by this call to __dev_queue_xmit(). This is because only background programs using the network were running at the time, so the amount of outgoing traffic was rather small. Additionally, the captured frame contains, as expected, 90 bytes. Also, this frame holds an NTP payload, which is just what you'd expect from chronyd.)
My kernel version is 5.12.6-200.fc33.x86_64.
If you want to try it out yourself or have a closer look at my program, here it is:
from bcc import BPF
from ctypes import cast, POINTER, c_char
prog = """
#include <linux/sched.h>
#include <linux/skbuff.h>
struct xmit_event {
u64 ts;
u32 pid;
u32 tgid;
u32 len;
u32 datalen;
u32 packet_buf_ptr;
char comm[TASK_COMM_LEN];
u64 head;
u64 data;
u64 tail;
u64 end;
};
BPF_PERF_OUTPUT(xmits);
#define PACKET_BUF_SIZE 32768
# define PACKET_BUFS_PER_CPU 15
struct packet_buf {
char data[PACKET_BUF_SIZE];
};
BPF_PERCPU_ARRAY(packet_buf, struct packet_buf, PACKET_BUFS_PER_CPU);
BPF_PERCPU_ARRAY(packet_buf_head, u32, 1);
int kprobe____dev_queue_xmit(struct pt_regs *ctx, struct sk_buff *skb, void *accel_priv) {
if (skb == NULL || skb->data == NULL)
return 0;
struct xmit_event data = { };
u64 both = bpf_get_current_pid_tgid();
data.pid = both;
if (data.pid == 0)
return 0;
data.tgid = both >> 32;
data.ts = bpf_ktime_get_ns();
bpf_get_current_comm(&data.comm, sizeof(data.comm));
data.len = skb->len;
// Copy packet contents
int slot = 0;
u32 *packet_buf_ptr = packet_buf_head.lookup(&slot);
if (packet_buf_ptr == NULL)
return 0;
u32 buf_head = *packet_buf_ptr;
u32 next_buf_head = (buf_head + 1) % PACKET_BUFS_PER_CPU;
packet_buf_head.update(&slot, &next_buf_head);
struct packet_buf *ringbuf = packet_buf.lookup(&buf_head);
if (ringbuf == NULL)
return 0;
u32 skb_data_len = skb->data_len;
u32 headlen = data.len - skb_data_len;
headlen &= 0xffffff; // Useless, but validator demands it because "this unsigned(!) variable could otherwise be negative"
bpf_probe_read_kernel(ringbuf->data, headlen < PACKET_BUF_SIZE ? headlen : PACKET_BUF_SIZE, skb->data);
data.packet_buf_ptr = buf_head;
data.len = headlen;
data.datalen = skb_data_len;
data.head = (u64) skb->head;
data.data = (u64) skb->data;
data.tail = (u64) skb->tail;
data.end = (u64) skb->end;
xmits.perf_submit(ctx, &data, sizeof(data));
return 0;
}
"""
global b
def xmit_received(cpu, data, size):
global b
global py_packet_buf
ev = b["xmits"].event(data)
print("%-18d %-25s %-8d %-8d %-10d %-10d %-12d %-12d %-12d %-12d" % (ev.ts, ev.comm.decode(), ev.pid, ev.tgid, ev.len, ev.datalen, ev.head, ev.data, ev.tail, ev.end))
bs = cast(py_packet_buf[ev.packet_buf_ptr][cpu].data, POINTER(c_char))[:ev.len]
c = bytes(bs)
print(c.hex())
def observe_kernel():
# load BPF program
global b
b = BPF(text=prog)
print("%-18s %-25s %-8s %-8s %-10s %-10s %-12s %-12s %-12s %-12s" % ("TS", "COMM", "PID", "TGID", "LEN", "DATALEN", "HEAD", "DATA", "TAIL", "END"))
b["xmits"].open_perf_buffer(xmit_received)
global py_packet_buf
py_packet_buf = b["packet_buf"]
try:
while True:
b.perf_buffer_poll()
except KeyboardInterrupt:
print("Kernel observer thread stopped.")
observe_kernel()
Found the issue.
I needed to replace
struct packet_buf {
char data[PACKET_BUF_SIZE];
};
with
struct packet_buf {
unsigned char data[PACKET_BUF_SIZE];
};
I, however, do not understand how signedness makes a difference when I am not performing comparisons or arithmetic operations with this data.
The following dBase code invokes a win32 API function to convert a local DST time to a system time. The first parameter set to "null" means that the function takes the current active time zone. What value do I have to put instead of "null" to specify another time zone?
The following page refers to lpTimeZoneInformation as a pointer to a TIME_ZONE_INFORMATION structure that specifies the time zone for the localtime input to this function (lpLocalTime), but is is unclear to me what kind of pointer this is.
I have tried 'Brisbane', 'E. Australia Standard Time', '10:00' and '+10:00' but none returns the expected value.
https://learn.microsoft.com/en-us/windows/win32/api/timezoneapi/nf-timezoneapi-tzspecificlocaltimetosystemtime
ITOH and HTOI are Integer TO Hex and vice-versa conversion functions
localtime and systemtime structures work, I tried to replicate that for the time_zone_information part but without success so far
As it stands, the return value is 13.20
Thanks for any help!
d=new date("31/12/2020 5:08")
offset1=getLocalTimeOffset(d)/60
function getLocalTimeOffset(d_in)
// todo typechecking of the parameter
extern clogical TzSpecificLocalTimeToSystemTime(cptr,cptr,cptr) kernel32
extern culong GetLastError(cvoid) kernel32
local systemtime,localtime,tmp
localtime = replicate(chr(0),16)
systemtime = replicate(chr(0),16)
TZI = replicate(chr(0),16)
TZIa=itoh(-600,4)
TZIb=itoh(-60,4)
TZI.setbyte(1,htoi(left(TZIa,2)))
TZI.setbyte(0,htoi(right(TZIa,2)))
TZI.setbyte(9,htoi(left(TZIb,2)))
TZI.setbyte(8,htoi(right(TZIb,2)))
tmp = itoh(d_in.year,4)
localtime.setbyte(1,htoi(left(tmp,2))) // fill the systemtime structure
localtime.setbyte(0,htoi(right(tmp,2))) // seconds and ms are of no concern
localtime.setbyte(2,d_in.month+1)
localtime.setbyte(4,d_in.day)
localtime.setbyte(6,d_in.date)
localtime.setbyte(8,d_in.hour)
localtime.setbyte(10,d_in.minute)
if TzSpecificLocalTimeToSystemTime(TZI,localtime,systemtime) = 0
tmp = getlasterror() ; ? "Error: "+tmp ; return 9999
endif
tmp = sign(d_in.date-systemtime.getbyte(6))*24*60 // consider day boundary
if (d_in.date = 1 or systemtime.getbyte(6) = 1) and (d_in.month+1 <> systemtime.getbyte(2))
tmp = -tmp // adjust for month boundaries
endif
tmp += (d_in.hour - systemtime.getbyte(8))*60
tmp += d_in.minute - systemtime.getbyte(10)
return tmp
(Too long for a comment.) The first parameter to TzSpecificLocalTimeToSystemTime must be either NULL, or otherwise point to a TIME_ZONE_INFORMATION structure, filled-in with the target timezone data from HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones per Remarks on the same page.
In OP's case, Brisbane falls under the E. Australia Standard Time key, and TZI data parses as:
typedef struct _REG_TZI_FORMAT
{
LONG Bias; // -600 A8 FD FF FF
LONG StandardBias; // 0 00 00 00 00
LONG DaylightBias; // -60 C4 FF FF FF
SYSTEMTIME StandardDate; // n/a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
SYSTEMTIME DaylightDate; // n/a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
} REG_TZI_FORMAT;
Following is the C code to fill-in a TIME_ZONE_INFORMATION structure with the same data, and successfully convert a Brisbane local time to UTC:
#include <windows.h>
#include <stdio.h>
int main()
{
TIME_ZONE_INFORMATION tzEAST = // [offset] bytes
{
-600, // LONG Bias; [0] A8 FD FF FF
{ 0 }, // WCHAR StandardName[32]; [4] 00 .. 00
{ 0 }, // SYSTEMTIME StandardDate; [68] 00 .. 00
0, // LONG StandardBias; [84] 00 00 00 00
{ 0 }, // WCHAR DaylightName[32]; [88] 00 .. 00
{ 0 }, // SYSTEMTIME DaylightDate; [152] 00 .. 00
-60 // LONG DaylightBias; [168] C4 FF FF FF
};
SYSTEMTIME stEAST = { 2021, 1, 1, 4, 12 }, stUTC = { 0 };
if(!TzSpecificLocalTimeToSystemTime(&tzEAST, &stEAST, &stUTC)) return 1;
printf("EAST %d-%02d-%02d %02d:%02d:%02d = UTC %d-%02d-%02d %02d:%02d:%02d\n",
stEAST.wYear, stEAST.wMonth, stEAST.wDay, stEAST.wHour, stEAST.wMinute, stEAST.wSecond,
stUTC.wYear, stUTC.wMonth, stUTC.wDay, stUTC.wHour, stUTC.wMinute, stUTC.wSecond);
return 0;
}
Output:
EAST 2021-01-04 12:00:00 = UTC 2021-01-04 02:00:00
[ EDIT ] Following is my guess of what the dBase code might look like. Just a guess, and nothing more than a guess, since I don't actually know dBase beyond what's been posted here.
tzBias = itoh(-600, 8)
tzDstBias = itoh( -60, 8)
tzi = replicate(chr(0), 86) // 86*2 = 172 = sizeof TIME_ZONE_INFORMATION
tzi.setbyte( 0, htoi(substring( tzBias, 6, 8))) // [ 0] LONG Bias;
tzi.setbyte( 1, htoi(substring( tzBias, 4, 6)))
tzi.setbyte( 2, htoi(substring( tzBias, 2, 4)))
tzi.setbyte( 3, htoi(substring( tzBias, 0, 2)))
tzi.setbyte(168, htoi(substring(tzDstBias, 6, 8))) // [168] LONG DaylightBias;
tzi.setbyte(169, htoi(substring(tzDstBias, 4, 6)))
tzi.setbyte(170, htoi(substring(tzDstBias, 2, 4)))
tzi.setbyte(171, htoi(substring(tzDstBias, 0, 2)))
if TzSpecificLocalTimeToSystemTime(tzi, localtime, systemtime) = 0 // ...
[ EDIT #2 courtesy OP ] The working dBase code to fill the structure is the following:
tzi.setbyte( 0, htoi(substr(tzBias, 7, 2))) // [ 0] LONG Bias
tzi.setbyte( 1, htoi(substr(tzBias, 5, 2)))
tzi.setbyte( 2, htoi(substr(tzBias, 3, 2)))
tzi.setbyte( 3, htoi(substr(tzBias, 1, 2)))
tzi.setbyte(168, htoi(substr(tzDstBias, 7,2))) // [168] LONG DaylightBias
tzi.setbyte(169, htoi(substr(tzDstBias, 5,2)))
tzi.setbyte(170, htoi(substr(tzDstBias, 3,2)))
tzi.setbyte(171, htoi(substr(tzDstBias, 1,2)))
I am doing a Linux kernel module to cleanup a process cache.
Below is the code I am using to do that.
static void clear_process_cache(struct task_struct *p)
{
struct mm_struct *mm;
struct vm_area_struct *vma;
struct page *page;
char *my_page_address;
unsigned long uaddr, paddr;
long res;
unsigned int level;
pte_t *pte;
mm = p->mm;
for (vma = mm->mmap; vma; vma = vma->vm_next) {
for(uaddr = vma->vm_start; uaddr < vma->vm_end; uaddr += PAGE_SIZE) {
down_read(&p->mm->mmap_sem);
res = get_user_pages(p, mm, uaddr, 1, 0, 1, &page, NULL);
if (res == 1) {
my_page_address = kmap(page);
paddr = (unsigned long)page_address(page);
pte = lookup_address(paddr, &level);
if (pte && (pte_val(*pte) &_PAGE_PRESENT)) {
clflush_cache_range(my_page_address, PAGE_SIZE);
}
kunmap(page);
put_page(page);
}
up_read(&p->mm->mmap_sem);
}
}
}
When the code is called intensively, the Linux kernel crashed.
I checked my code, but could NOT find why it caused kernel crash.
Would you like to help on it, or is there any other high performance way to do that ??
Here is the crash dump.
[ 391.693385] general protection fault: 0000 [#1] SMP
[ 391.694435] Modules linked in: xt_CHECKSUM iptable_mangle ipt_MASQUERADE nf_nat_masquerade_ipv4 iptable_nat nf_nat_ipv4 nf_nat nf_conntrack_ipv4 nf_defrag_ipv4 xt_conntrack nf_conntrack ipt_REJECT nf_reject_ipv4 xt_tcpudp bridge stp llc ebtable_filter ebtables ip6table_filter ip6_tables iptable_filter ip_tables x_tables vmw_vsock_vmci_transport vsock kvm_intel kvm irqbypass vmw_balloon input_leds joydev serio_raw shpchp vmw_vmci i2c_piix4 mac_hid ib_iser rdma_cm iw_cm ib_cm ib_sa ib_mad ib_core ib_addr iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi autofs4 btrfs raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx xor raid6_pq libcrc32c raid1 raid0 multipath linear crct10dif_pclmul crc32_pclmul ghash_clmulni_intel aesni_intel aes_x86_64 lrw gf128mul glue_helper vmwgfx ablk_helper
[ 391.702930] cryptd ttm drm_kms_helper syscopyarea psmouse sysfillrect pata_acpi sysimgblt mptspi fb_sys_fops mptscsih drm mptbase vmxnet3 scsi_transport_spi floppy fjes
[ 391.705034] CPU: 3 PID: 1716 Comm: java Not tainted 4.4.131 #4
[ 391.706080] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 07/28/2017
[ 391.708180] task: ffff88042607c600 ti: ffff8804292b8000 task.ti: ffff8804292b8000
[ 391.709244] RIP: 0010:[<ffffffff811a34dc>] [<ffffffff811a34dc>] put_compound_page+0x5c/0x1b0
[ 391.710358] RSP: 0000:ffff8804292bbcc8 EFLAGS: 00210202
[ 391.711439] RAX: 00d0a78b4c535441 RBX: ffffffff810dc4f9 RCX: 000507e043713000
[ 391.712523] RDX: ffff8804292bbd44 RSI: 000507e043713000 RDI: ffffffff810dc4f9
[ 391.713586] RBP: ffff8804292bbcd8 R08: ffff880002213cf0 R09: 00003ffffffff000
[ 391.714653] R10: 0000000000000080 R11: 0000000000000000 R12: 00d0a78b4c535440
[ 391.715712] R13: 0000160000000000 R14: ffff8804292bbd88 R15: ffffffff810dc4f9
[ 391.716764] FS: 00007fb138d5b700(0000) GS:ffff88042d6c0000(0000) knlGS:0000000000000000
[ 391.717829] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b
[ 391.718877] CR2: 0000000000000000 CR3: 00000000351d1000 CR4: 00000000001606f0
[ 391.719972] Stack:
[ 391.720993] ffffffff810dc4f9 ffff880000000000 ffff8804292bbcf0 ffffffff811a364d
[ 391.722055] ffff8804292bbdc8 ffff8804292bbdf8 ffffffff8102e21e ffff8804292bbd48
[ 391.723122] 0000000000000000 ffff88042607c600 ffff880429e6ac00 ffff880425e9f388
[ 391.724165] Call Trace:
[ 391.725190] [<ffffffff810dc4f9>] ? vprintk_default+0x29/0x40
[ 391.726222] [<ffffffff811a364d>] put_page+0x1d/0x50
[ 391.727259] [<ffffffff8102e21e>] clear_process_cache+0x11e/0x1f0
[ 391.728298] [<ffffffff810dc4f9>] ? vprintk_default+0x29/0x40
[ 391.729318] [<ffffffff811918d0>] ? printk+0x5a/0x76
[ 391.730328] [<ffffffff8102e93d>] do_signal+0x20d/0x770
[ 391.731310] [<ffffffff81193459>] ? unlock_page+0x69/0x70
[ 391.732297] [<ffffffff811972c0>] ? __probe_kernel_read+0x40/0x90
[ 391.733271] [<ffffffff8106d3c3>] ? bad_area+0x43/0x50
[ 391.734220] [<ffffffff810034fc>] exit_to_usermode_loop+0x8c/0xd0
[ 391.735143] [<ffffffff81003c26>] prepare_exit_to_usermode+0x26/0x30
[ 391.736062] [<ffffffff8185184e>] retint_user+0x8/0x34
[ 391.736941] Code: ff 5b 41 5c 5d c3 48 89 df e8 01 f6 ff ff 48 89 df 31 f6 e8 17 76 ff ff 5b 41 5c 5d c3 48 8b 47 20 4c 8d 60 ff a8 01 4c 0f 44 e7 <41> f6 44 24 08 01 74 08 49 8b 04 24 a8 80 74 1a 48 8b 43 20 a8
[ 391.739698] RIP [<ffffffff811a34dc>] put_compound_page+0x5c/0x1b0
[ 391.740571] RSP <ffff8804292bbcc8>