ioctl command wrong in 64 bit system from 32 bit user code - linux

I'm upgrading a device driver from a 32bit RHEL 2.6.32 to 64bit RHEL 2.6.33.9.
I have a program that talks to that driver using ioctl. It works perfectly when both the driver and the program are either 64bit or 32bit. But when the driver is 64bit, and my program is 32 bit, the ioctl command received by the driver (in compat_ioctl) does not match the values defined by the _IOR and _IOW macros.
In my driver's switch statement, the default case prints out the values of all the valid commands, which are 1-12. The 32bit ioctl command is nowhere near those values.
Can someone tell me what would cause the command from a 32bit user program to be messed up when received in a 64bit driver?
Here's some of the code: I had to type it in; the code is on a secured system without internet access, so please forgive any typos. It actually does comile and run!
// IOCTL commands from the include file - most omitted
// ...
#define PORTIO_GET_IRQ_CNT_CMD 10
#define PORTIO_CLR_IRQ_CNT_CMD 11
#define PORTIO_GET_IRQ_TIME_CMD 12
#define PORTIO_IOCTL 'k' // magic number for ioctl
// IOCTL Macros
#define PORTIO_GET_IRQ_CNT_IOCTL _IOR(PORTIO_IOCTL, PORTIO_GET_IRQ_CNT_CMD, unsigned long)
#define PORTIO_CLR_IRQ_CNT_IOCTL _IOR(PORTIO_IOCTL, PORTIO_CLR_IRQ_CNT_CMD, unsigned long)
#define PORTIO_GET_IRQ_TIME_IOCTL _IOR(PORTIO_IOCTL, PORTIO_GET_IRQ_TIME_CMD, unsigned long)
Here's the 32 bit compatible IOCTL routine, from portio.c. I've confirmed that this is being called only when my program is compiled as 32bit, and the driver is 64bit.
static long portio_compat_ioctl( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
unsigned char cmd_number;
int cmd_size=0;
//...
cmd_number = _IOC_NR( cmd );
cmd_size = _IOC_SIZE( cmd );
printk( KERN_ALERT "Portio Compat IOCTL number,size = %d,%d, cmd_number, cmd_size );
//... Switch statement and cases, based on cmd_number
}
The output looks like this:
Portio Compat IOTCL number,size = 224,3157
Of course, the code expects IOCTL numbers from 1-12, and sizes around 4 or 8. That's exactly what comes back when the code and driver are both either 64bit or 32bit.

It seems to me that your function compat_ioctl takes too many parameters. Look at other definitions in the Linux kernel:
long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
http://lxr.linux.no/#linux+v3.5.3/block/compat_ioctl.c#L654

#define PORTIO_GET_IRQ_CNT_IOCTL _IOR(PORTIO_IOCTL, PORTIO_GET_IRQ_CNT_CMD, unsigned long)
#define PORTIO_CLR_IRQ_CNT_IOCTL _IOR(PORTIO_IOCTL, PORTIO_CLR_IRQ_CNT_CMD, unsigned long)
#define PORTIO_GET_IRQ_TIME_IOCTL _IOR(PORTIO_IOCTL, PORTIO_GET_IRQ_TIME_CMD, unsigned long)
change unsigned long to unit64_t (fixed data type)
remove all pointer from ioctl macro arguments,
have :
.compat_ioctl
.unlocked_ioctl in kernel pointing to same function.

Related

`gs` missing from user_regs_struct?

I've got the following piece of code which failed to compile on i386 with "gs" missing.
I've looked at the struct definition, and it's clearly there.
Any idea what I got wrong?
Thanks!
struct user_regs_struct regs_struct;
struct iovec pt_iov = {
.iov_base = &regs,
.iov_len = sizeof(regs),
};
if (ptrace(PTRACE_GETREGSET, tid, NT_PRSTATUS, &pt_iov) == 0) {
#if defined(__x86_64__)
return regs_struct.fs;
#elif defined(__i386__)
return regs_struct.gs; <<< Got an error about "gs" not being a field of user_regs_struct
}
P.S: I know I should produce a small test case but I could not. It didn't hit this error on a standalone app. (never mind that I don't have the hardware to test it locally). All I knew was this error popped up when the code is part of a larger system, being built remotely.
That's why I was hoping maybe somebody recognized this as a "known-issue" or have some intuition as to what might be the issue.
Looks like the i386 version of user_regs_struct calls it xgs for some reason.
In sys/user.h, there's an #ifdef __x86_64__. The #else
/* These are the 32-bit x86 structures. */ side of the file has this content:
struct user_regs_struct
{
long int ebx;
long int ecx;
long int edx;
long int esi;
long int edi;
long int ebp;
long int eax;
long int xds;
long int xes;
long int xfs;
long int xgs;
long int orig_eax;
long int eip;
long int xcs;
long int eflags;
long int esp;
long int xss;
};
Perhaps that changed in some glibc version? This is on x86-64 Arch GNU/Linux, so those are plain vanilla glibc headers (taken from the Linux kernel).
ack user_regs_struct /usr/include found the right file right away. (like grep -r).
Note the top of the file says:
/* The whole purpose of this file is for GDB and GDB only. Don't read
too much into it. Don't use it for anything other than GDB unless
you know what you are doing. */
I don't know exactly why there's such a stern warning, or if they really mean for ptrace in general. If it's more than that, I'd be cautious about using it blindly if reading the header and checking the struct member names wasn't obvious to you. Maybe it's fine, maybe it's not, just saying that I wouldn't rely on code you write using it for anything critical without more research.

How to use memcpy in function that is passed a char pointer?

I'm quite new to pointers in c.
Here is a snippet of code I'm working on. I am probably not passing the pointer correctly but I can't figure out what's wrong.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
__uint16_t CCrc8();
__uint16_t process_command();
int main () {
//command format: $SET,<0-1023>*<checksum,hex>\r\n
char test_payload[] = "SET,1023*6e";
process_command(test_payload);
return 0;
}
__uint16_t process_command(char *str1) {
char local_str[20];
memcpy(local_str, str1, sizeof(str1));
printf(str1);
printf("\n");
printf(local_str);
}
This results in:
SET,1023*6e
SET,1023
I'm expecting both lines to be the same. Anything past 8 characters is left off.
The only thing I can determine is that the problem is something with sizeof(str1). Any help appreciated.
Update: I've learned sizeof(*char) is 2 on 16bit systems, 4 on 32bit systems and 8 on 64-bit systems.
So how can I use memcpy to get a local copy of str1 when I'm unsure of the size it will be?
sizeof is a compiler keyword. What you need is strlen from #include <string.h>.
The value of sizeof is determinated at compile time. For example sizeof(char[10]) just means 10. strlen on the other hand is a libc function that can determine string length dynamically.
sizeof on a pointer tells you the size of the pointer itself, not of what it points to. Since you're on a 64-bit system, pointers are 8 bytes long, so your memcpy is always copying 8 bytes. Since your string is null terminated, you should use stpncpy instead, like this:
if(stpncpy(local_str, str1, 20) == local_str + 20) {
// too long - handle it somehow
}
That will copy the string until it gets to a NUL terminator or runs out of space in the destination, and in the latter case you can handle it.

Linux socket transfer is adding extra zero padding

While I am trying to send data from Linux Client to Server over TCP I see extra zeros being added to the data. Can anyone please let me know why am I getting those additional zeroes? Please see below for the data packet format.
#define INT32 int32_t
#define UCHAR unsigned char
#define UINT8 u_int8_t
typedef struct cstruct_t {
UINT8 typ;
UINT8 l;
unsigned char buf[20];
} cksum_t;
cstruct_t cs;
INT32 fnlength;
Linux socket transfer is adding extra zero padding
No it certainly is not. You probably aren't reading it correctly. London to a brick you are ignoring the value returned by recv().
But you shouldn't be using a struct as a network protocol in the first place.
Since we dint want to add additional zeroes to make it 4-byte long as mentioned by #Soren we used
#pragma pack(push, 1)
#pragma pack(pop)
This worked perfectly for us.

In Linux device driver function, how to know the minor number or for which particular device this driver function has been invoked?

If there are three I2C devices as mentioned below and in the device driver init() function the following call register_chrdev(89, "i2c", &i2cfops) is invoked. Note, the name is "i2c" not "i2c-0"/"i2c-1"/"i2c-2". How in the i2cdriver_open or i2cdriver_ioctl function the drive will know the minor number or for which I2C device the function has been invoked?
Please refer below for more details.
crw-r--r-- 1 0 0 89, 0 Jun 12 09:15 /dev/i2c-0
crw-r--r-- 1 0 0 89, 1 Jun 12 09:15 /dev/i2c-1
crw-r--r-- 1 0 0 89, 2 Jun 12 09:15 /dev/i2c-2
Application:
int main(void)
{
int fd;
fd = open("/dev/i2c-0");
(void) ioctl(fd, ...);
return 0;
}
Driver:
static struct file_operations i2cfops;
int i2cdriver_open(struct inode * inodePtr, struct file * filePtr);
int i2cdriver_ioctl(struct inode * inodePtr, struct file * filePtr, unsigned int ui, unsigned long ul);
int driver_init(void)
{
i2cfops.open = &i2cdriver_open;
i2cfops.ioctl = &i2cdriver_ioctl;
(void) register_chrdev(89, "i2c", &i2cfops);
return 0;
}
int i2cdriver_open(struct inode * inodePtr, struct file * filePtr)
{
/*In here, how to know the minor number or for which I2C device this function has been invoked?*/
}
int i2cdriver_ioctl(struct inode * inodePtr, struct file * filePtr, unsigned int ui, unsigned long ul)
{
/*In here, how to know the minor number or for which I2C device this function has been invoked?*/
}
As a general note, whenever you're posting questions about Linux kernel/driver development, always include the kernel version you're working with. It makes it much easier to give you answers that will actually work for your kernel.
This should be able to retrieve your minor number:
/* Add this header if you don't already have it included */
#include <linux/kdev_t.h>
/* Add this macro function wherever you need the minor number */
unsigned int minor_num = MINOR(inodePtr -> i_rdev);
This page has the definition of the MINOR macro, and this page has the definition of the inode structure for reference.
When you create multiple device nodes using the same device driver, you have multiple devices with same major number but different minor numbers.
To retrieve which particular device of them is invoked, you just need to know the minor number of the device which was invoked in your file open() function.
#include <kdev_t.h>
unsigned int minor_num;
static int file_open(struct inode *inode, struct file *file){
/*The line below is to be written in your open function*/
minor_num = MINOR(inode->i_rdev);
printk(KERN_INFO "Device file opened\n");
return 0;
}
This will give you the device number using which you can perform any device-specific tasks.

Reading x86 MSR from kernel module

My main aim is to get the address values of the last 16 branches maintained by the LBR registers when a program crashes. I tried two ways till now -
1) msr-tools
This allows me to read the msr values from the command line. I make system calls to it from the C program itself and try to read the values. But the register values seem no where related to the addresses in the program itself. Most probably the registers are getting polluted from the other branches in system code. I tried turning off recording of branches in ring 0 and far jumps. But that doesn't help. Still getting unrelated values.
2) accessing through kernel module
Ok I wrote a very simple module (I've never done this before) to access the msr registers directly and possibly avoid register pollution.
Here's what I have -
#define LBR 0x1d9 //IA32_DEBUGCTL MSR
//I first set this to some non 0 value using wrmsr (msr-tools)
static void __init do_rdmsr(unsigned msr, unsigned unused2)
{
uint64_t msr_value;
__asm__ __volatile__ (" rdmsr"
: "=A" (msr_value)
: "c" (msr)
);
printk(KERN_EMERG "%lu \n",msr_value);
}
static int hello_init(void)
{
printk(KERN_EMERG "Value is ");
do_rdmsr (LBR,0);
return 0;
}
static void hello_exit(void)
{
printk(KERN_EMERG "End\n");
}
module_init(hello_init);
module_exit(hello_exit);
But the problem is that every time I use dmesg to read the output I get just
Value is 0
(I have tried for other registers - it always comes as 0)
Is there something that I am forgetting here?
Any help? Thanks
Use the following:
unsigned long long x86_get_msr(int msr)
{
unsigned long msrl = 0, msrh = 0;
/* NOTE: rdmsr is always return EDX:EAX pair value */
asm volatile ("rdmsr" : "=a"(msrl), "=d"(msrh) : "c"(msr));
return ((unsigned long long)msrh << 32) | msrl;
}
You can use Ilya Matveychikov's answer... or... OR :
#include <asm/msr.h>
int err;
unsigned int msr, cpu;
unsigned long long val;
/* rdmsr without exception handling */
val = rdmsrl(msr);
/* rdmsr with exception handling */
err = rdmsrl_safe(msr, &val);
/* rdmsr on a given CPU (instead of current one) */
err = rdmsrl_safe_on_cpu(cpu, msr, &val);
And there are many more functions, such as :
int msr_set_bit(u32 msr, u8 bit)
int msr_clear_bit(u32 msr, u8 bit)
void rdmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs)
int rdmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8])
Have a look at /lib/modules/<uname -r>/build/arch/x86/include/asm/msr.h

Resources