forked from Minki/linux
ed8b0de5a3
"rm -rf" is bricking some peoples' laptops because of variables being used to store non-reinitializable firmware driver data that's required to POST the hardware. These are 100% bugs, and they need to be fixed, but in the mean time it shouldn't be easy to *accidentally* brick machines. We have to have delete working, and picking which variables do and don't work for deletion is quite intractable, so instead make everything immutable by default (except for a whitelist), and make tools that aren't quite so broad-spectrum unset the immutable flag. Signed-off-by: Peter Jones <pjones@redhat.com> Tested-by: Lee, Chun-Yi <jlee@suse.com> Acked-by: Matthew Garrett <mjg59@coreos.com> Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
134 lines
2.2 KiB
C
134 lines
2.2 KiB
C
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <linux/fs.h>
|
|
|
|
static int set_immutable(const char *path, int immutable)
|
|
{
|
|
unsigned int flags;
|
|
int fd;
|
|
int rc;
|
|
int error;
|
|
|
|
fd = open(path, O_RDONLY);
|
|
if (fd < 0)
|
|
return fd;
|
|
|
|
rc = ioctl(fd, FS_IOC_GETFLAGS, &flags);
|
|
if (rc < 0) {
|
|
error = errno;
|
|
close(fd);
|
|
errno = error;
|
|
return rc;
|
|
}
|
|
|
|
if (immutable)
|
|
flags |= FS_IMMUTABLE_FL;
|
|
else
|
|
flags &= ~FS_IMMUTABLE_FL;
|
|
|
|
rc = ioctl(fd, FS_IOC_SETFLAGS, &flags);
|
|
error = errno;
|
|
close(fd);
|
|
errno = error;
|
|
return rc;
|
|
}
|
|
|
|
static int get_immutable(const char *path)
|
|
{
|
|
unsigned int flags;
|
|
int fd;
|
|
int rc;
|
|
int error;
|
|
|
|
fd = open(path, O_RDONLY);
|
|
if (fd < 0)
|
|
return fd;
|
|
|
|
rc = ioctl(fd, FS_IOC_GETFLAGS, &flags);
|
|
if (rc < 0) {
|
|
error = errno;
|
|
close(fd);
|
|
errno = error;
|
|
return rc;
|
|
}
|
|
close(fd);
|
|
if (flags & FS_IMMUTABLE_FL)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
const char *path;
|
|
char buf[5];
|
|
int fd, rc;
|
|
|
|
if (argc < 2) {
|
|
fprintf(stderr, "usage: %s <path>\n", argv[0]);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
path = argv[1];
|
|
|
|
/* attributes: EFI_VARIABLE_NON_VOLATILE |
|
|
* EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
|
* EFI_VARIABLE_RUNTIME_ACCESS
|
|
*/
|
|
*(uint32_t *)buf = 0x7;
|
|
buf[4] = 0;
|
|
|
|
/* create a test variable */
|
|
fd = open(path, O_WRONLY | O_CREAT, 0600);
|
|
if (fd < 0) {
|
|
perror("open(O_WRONLY)");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
rc = write(fd, buf, sizeof(buf));
|
|
if (rc != sizeof(buf)) {
|
|
perror("write");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
close(fd);
|
|
|
|
rc = get_immutable(path);
|
|
if (rc < 0) {
|
|
perror("ioctl(FS_IOC_GETFLAGS)");
|
|
return EXIT_FAILURE;
|
|
} else if (rc) {
|
|
rc = set_immutable(path, 0);
|
|
if (rc < 0) {
|
|
perror("ioctl(FS_IOC_SETFLAGS)");
|
|
return EXIT_FAILURE;
|
|
}
|
|
}
|
|
|
|
fd = open(path, O_RDONLY);
|
|
if (fd < 0) {
|
|
perror("open");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
if (unlink(path) < 0) {
|
|
perror("unlink");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
rc = read(fd, buf, sizeof(buf));
|
|
if (rc > 0) {
|
|
fprintf(stderr, "reading from an unlinked variable "
|
|
"shouldn't be possible\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|