Setting Immutable Flag using ioctl() in C

人走茶凉 提交于 2019-12-18 07:05:10

问题


I have attempted to make a script that creates a file and then sets it as immutable similar to the chattr +i command for linux. The script compiles (with gcc), runs and the file is created. However the file itself is not immutable and can be removed with a simple rm -f. I have attempted to stacktrace where chattr is called and I found a function called ioctl. I then used what little information I could gather and came up with what I have below. I narrowed it down from ext2_fs.h but it just doesn't seem to work. I've clearly overlooked something.

Updates to previous entry: Compiles but returns -1 on ioctl() function. Bad address shown with perror().

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/fs.h>

int main()
{
    FILE *fp;
    char shovel[16] = "I have a shovel!";
    fp = fopen("/shovel.txt", "w+");
    fwrite(shovel, sizeof(shovel[0]), sizeof(shovel)/sizeof(shovel[0]), fp);
    ioctl(fileno(fp), FS_IOC_SETFLAGS, 0x00000010);
    fclose(fp);
}

Any help appreciated.


回答1:


The main problem is that the ioctl wants a pointer to the mask, not a direct constant. You have to define a int variable, store the mask (0x10) in it and pass its address as third argument of ioctl.

Also, I'd add some hints:

  • other programs to change attributes are used to use low-level I/O directly (open, close...). Also, the file is usually opened with O_RDONLY.
  • Use FS_IMMUTABLE_FL istead the raw constant.
  • Get the current attribute mask first (FS_IOC_SETFLAGS) and mask it with the new flag, so other settings are not lost by the service.



回答2:


You are using the right ioctl command, but you're passing it the wrong arguments.

The manpage for ioctl_list(2) shows that FS_IOC_SETFLAGS expects to receive a pointer to int (an int *), yet you're passing it an integer literal (hence the Bad Address error).

The fact that you don't to any error checking whatsoever is also not helping.

The correct flag to pass to FS_IOC_SETFLAGS is a pointer holding the value EXT2_IMMUTABLE_FL, which is defined in ext2fs/ext2_fs.h (some older / different Linux distributions seem to have it under linux/ext2_fs.h), so you'll need to #include <ext2fs/etx2_fs.h>. Make sure to install e2fslibs-dev (and probably you'll need linux-headers too).

This code is working:

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <ext2fs/ext2_fs.h>

int main()
{
    FILE *fp;
    char shovel[16] = "I have a shovel!";

    if ((fp = fopen("shovel.txt", "w+")) == NULL) {
        perror("fopen(3) error");
        exit(EXIT_FAILURE);
    }

    fwrite(shovel, sizeof(shovel[0]), sizeof(shovel)/sizeof(shovel[0]), fp);

    int val = EXT2_IMMUTABLE_FL;
    if (ioctl(fileno(fp), FS_IOC_SETFLAGS, &val) < 0)
        perror("ioctl(2) error");

    fclose(fp);

    return 0;
}

Remember to run this as root.

UPDATE:

As Giuseppe Guerrini suggests in his answer, you might want to use FS_IMMUTABLE_FL instead, and you won't need to include ext2_fs.h:

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/fs.h>

int main()
{
    FILE *fp;
    char shovel[16] = "I have a shovel!";

    if ((fp = fopen("shovel.txt", "w+")) == NULL) {
        perror("fopen(3) error");
        exit(EXIT_FAILURE);
    }

    fwrite(shovel, sizeof(shovel[0]), sizeof(shovel)/sizeof(shovel[0]), fp);

    int val = FS_IMMUTABLE_FL;
    if (ioctl(fileno(fp), FS_IOC_SETFLAGS, &val) < 0)
        perror("ioctl(2) error");

    fclose(fp);

    return 0;
}


来源:https://stackoverflow.com/questions/32465756/setting-immutable-flag-using-ioctl-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!