1// SPDX-License-Identifier: GPL-2.0
2#include <errno.h>
3#include <stdio.h>
4#include <stdint.h>
5#include <stdlib.h>
6#include <unistd.h>
7#include <sys/ioctl.h>
8#include <sys/types.h>
9#include <sys/stat.h>
10#include <fcntl.h>
11#include <linux/fs.h>
12
13static int set_immutable(const char *path, int immutable)
14{
15	unsigned int flags;
16	int fd;
17	int rc;
18	int error;
19
20	fd = open(path, O_RDONLY);
21	if (fd < 0)
22		return fd;
23
24	rc = ioctl(fd, FS_IOC_GETFLAGS, &flags);
25	if (rc < 0) {
26		error = errno;
27		close(fd);
28		errno = error;
29		return rc;
30	}
31
32	if (immutable)
33		flags |= FS_IMMUTABLE_FL;
34	else
35		flags &= ~FS_IMMUTABLE_FL;
36
37	rc = ioctl(fd, FS_IOC_SETFLAGS, &flags);
38	error = errno;
39	close(fd);
40	errno = error;
41	return rc;
42}
43
44static int get_immutable(const char *path)
45{
46	unsigned int flags;
47	int fd;
48	int rc;
49	int error;
50
51	fd = open(path, O_RDONLY);
52	if (fd < 0)
53		return fd;
54
55	rc = ioctl(fd, FS_IOC_GETFLAGS, &flags);
56	if (rc < 0) {
57		error = errno;
58		close(fd);
59		errno = error;
60		return rc;
61	}
62	close(fd);
63	if (flags & FS_IMMUTABLE_FL)
64		return 1;
65	return 0;
66}
67
68int main(int argc, char **argv)
69{
70	const char *path;
71	char buf[5];
72	int fd, rc;
73
74	if (argc < 2) {
75		fprintf(stderr, "usage: %s <path>\n", argv[0]);
76		return EXIT_FAILURE;
77	}
78
79	path = argv[1];
80
81	/* attributes: EFI_VARIABLE_NON_VOLATILE |
82	 *		EFI_VARIABLE_BOOTSERVICE_ACCESS |
83	 *		EFI_VARIABLE_RUNTIME_ACCESS
84	 */
85	*(uint32_t *)buf = 0x7;
86	buf[4] = 0;
87
88	/* create a test variable */
89	fd = open(path, O_WRONLY | O_CREAT, 0600);
90	if (fd < 0) {
91		perror("open(O_WRONLY)");
92		return EXIT_FAILURE;
93	}
94
95	rc = write(fd, buf, sizeof(buf));
96	if (rc != sizeof(buf)) {
97		perror("write");
98		return EXIT_FAILURE;
99	}
100
101	close(fd);
102
103	rc = get_immutable(path);
104	if (rc < 0) {
105		perror("ioctl(FS_IOC_GETFLAGS)");
106		return EXIT_FAILURE;
107	} else if (rc) {
108		rc = set_immutable(path, 0);
109		if (rc < 0) {
110			perror("ioctl(FS_IOC_SETFLAGS)");
111			return EXIT_FAILURE;
112		}
113	}
114
115	fd = open(path, O_RDONLY);
116	if (fd < 0) {
117		perror("open");
118		return EXIT_FAILURE;
119	}
120
121	if (unlink(path) < 0) {
122		perror("unlink");
123		return EXIT_FAILURE;
124	}
125
126	rc = read(fd, buf, sizeof(buf));
127	if (rc > 0) {
128		fprintf(stderr, "reading from an unlinked variable "
129				"shouldn't be possible\n");
130		return EXIT_FAILURE;
131	}
132
133	return EXIT_SUCCESS;
134}
135