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 
13 static 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 
44 static 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 
68 int 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