3
votes

Using C and operating from within kernel space, is it possible to read the i_flags data directly from an inode and see the entire unsigned long value as opposed to the value/settings of only the supported flags?

I am using kernel 3.10.0 on Centos 7 on top of Oracle's VirtualBox.

I apologize if this question doesn't make sense, I am rather new to this and am trying to educate myself on how things work. I've been struggling with this for some time and have read so many different things that I am becoming more confused.

Simply put, I am trying to read the i_flags field into a variable and then check the status of the individual bits (perhaps by using test_bit?) regardless of whether or not they represent flags that are supported or implemented in the kernel or elsewhere. My thinking is, this data might be available from the raw 32 bit data in the i_flags field?

Should I be able to read x number of bytes from the inode starting at a given location? Or is there a more simple "read" method that I am just not seeing? Can this even be done?

Any pointers would be greatly appreciated.

Rog

Additional info -

Here is the code I use to reference the i_flags -

printk(KERN_INFO "inode value = %lu\n", file_inode(file)->i_flags); 

I'm unclear if this is the equivalent to the suggested format below -

unsigned int flags = inode_pointer->i_flags

My version prints a 0 although the "e" flag is on by default. Shouldn't there be a value other than 0 indicating the "e" flag is on?

If I use chattr to add the "a" and "i" flags, it now returns 12 in the i_flags field which makes sense. However if I add the "d" flag, I still see 12.

If I am getting the raw value from the inode field (i_flags), shouldn't turning on the "d" bit cause a change in this value?

Thank

Rog

More information -

Here is what I did to test values.

rls is a copy of /usr/bin/ls. The following commands show adding "i" and "a" to /usr/bin/rls. Then, lsattr confirms those flags are set.

sudo chattr +ia /usr/bin/rls

lsattr /usr/bin/rls ----ia-------e--

Running "rls" causes the output of the aforementioned printk statement to get logged to /var/log/messages. The flag value is 12 because both i and a are set.

rls

Jun 29 14:46:15 localhost kernel: open_exec inode value lu = 12

Then add the "d" flag.

sudo chattr +d /usr/bin/rls

And run lsattr against rls to see the flag showing the "d" flag is set

lsattr /usr/bin/rls

----iad------e--

Running "rls" again, the value of flags remains 12

rls

Jun 29 14:53:21 localhost kernel: open_exec inode value lu = 12

Shouldn't i_flag be something different with the addition of the "d" flag?

Thanks,

Rog

1
Can you show the code that corresponds to the statement "If I use chattr to add the "a" and "i" flags, it now returns 12 in the i_flags field which makes sense. However if I add the "d" flag, I still see 12."missimer

1 Answers

0
votes

If I understand correctly you have the memory address of an struct inode and you want to be able to read the i_flag field in its entirety instead of using the bitwise operations to test against a specific flag.

If that is the case then you can just do:

 unsigned int flags = inode_pointer->i_flags

i_flags is just an unsigned int (at least in 3.10.0) and you can access it as you would any other unsigned int. Since we treat it as a flag normal operations such as multiplication aren't typically performed on it but that is by convention and must be enforced by the programmers. The compiler doesn't know nor care whether an unsigned int is being used as a group of flags (as in the case of i_flags, where each bit holds some meaning or whether it is being used as an integer where it represents a single number.

Update

I believe (but to be honest I'm not 100% sure) the issue is that some of the chattr attributes do not map to i_flag bit values. You can find the bitmasks used with i_flag here. For example chattr's a corresponds to S_APPEND which has a value of 4 which coincides with what you are seeing but I cannot find something that would correspond to d in the list of i_flag bitmasks.