diff options
author | Philip Tricca <flihp@twobit.us> | 2015-06-17 15:30:56 -0700 |
---|---|---|
committer | Joe MacDonald <joe_macdonald@mentor.com> | 2015-08-08 16:43:23 -0400 |
commit | 22ade8fbe7f72bce1159fa645a246c84fe2195a2 (patch) | |
tree | 04211f85b0357290d26041c0759562aa85ce5ab4 | |
parent | b2ce05b5c18289a895f32fa30d8b47c44aa1de53 (diff) | |
download | meta-selinux-22ade8fbe7f72bce1159fa645a246c84fe2195a2.tar.gz |
e2fsprogs: Copy xattr block from source file.
Signed-off-by: Philip Tricca <flihp@twobit.us>
Signed-off-by: Joe MacDonald <joe_macdonald@mentor.com>
-rw-r--r-- | recipes-devtools/e2fsprogs/e2fsprogs/misc-xattr-create-xattr-block.patch | 341 | ||||
-rw-r--r-- | recipes-devtools/e2fsprogs/e2fsprogs_1.42.9.bbappend | 1 |
2 files changed, 342 insertions, 0 deletions
diff --git a/recipes-devtools/e2fsprogs/e2fsprogs/misc-xattr-create-xattr-block.patch b/recipes-devtools/e2fsprogs/e2fsprogs/misc-xattr-create-xattr-block.patch new file mode 100644 index 0000000..5955b44 --- /dev/null +++ b/recipes-devtools/e2fsprogs/e2fsprogs/misc-xattr-create-xattr-block.patch | |||
@@ -0,0 +1,341 @@ | |||
1 | To build the xattr disk block we process the output from listxattr and | ||
2 | lgetxattr from the source file system object. This data is formated in a disk | ||
3 | block according to the format specified in the kernel ext2 file system driver. | ||
4 | See the comment block at the beginning of fs/ext2/xattr.c for details. | ||
5 | |||
6 | Currently we only process attributes with the 'security.' prefix as our use | ||
7 | case is SELinux labels and IMA. Additional prefixes can likely be supported with | ||
8 | minimal effort but none have been tested. | ||
9 | |||
10 | Once the xattr block has been created it is written to disk. The xattr block is | ||
11 | associated with the appropriate file system object through the i_file_acl inode | ||
12 | member and the inode is updated on disk. | ||
13 | |||
14 | Signed-off-by: Philip Tricca <flihp@twobit.us> | ||
15 | |||
16 | Index: e2fsprogs-1.42.9/misc/xattr.c | ||
17 | =================================================================== | ||
18 | --- e2fsprogs-1.42.9.orig/misc/xattr.c | ||
19 | +++ e2fsprogs-1.42.9/misc/xattr.c | ||
20 | @@ -1,6 +1,23 @@ | ||
21 | #include "xattr.h" | ||
22 | |||
23 | +#include <attr/xattr.h> | ||
24 | +#include <ctype.h> | ||
25 | +#include <errno.h> | ||
26 | +#include <ext2fs/ext2_ext_attr.h> | ||
27 | +#include <linux/xattr.h> | ||
28 | +#include <stdint.h> | ||
29 | #include <stdio.h> | ||
30 | +#include <stdlib.h> | ||
31 | +#include <string.h> | ||
32 | +#include <sys/stat.h> | ||
33 | +#include <sys/types.h> | ||
34 | +#include <unistd.h> | ||
35 | + | ||
36 | +#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) | ||
37 | +#define HEADER(ptr) ((struct ext2_ext_attr_header *)(ptr)) | ||
38 | +#define ENTRY(ptr) ((struct ext2_ext_attr_entry *)(ptr)) | ||
39 | +#define FIRST_ENTRY(ptr) ENTRY(HEADER(ptr) + 1) | ||
40 | +#define VALUE(hdr, ent) (((char*)hdr) + (ent->e_value_offs)) | ||
41 | |||
42 | #ifdef XATTR_DEBUG | ||
43 | #define XATTR_STDERR(fmt, args...) fprintf (stderr, fmt, ##args) | ||
44 | @@ -8,6 +25,28 @@ | ||
45 | #define XATTR_STDERR(fmt, args...) do {} while (0) | ||
46 | #endif | ||
47 | |||
48 | +/* structure for mapping xattr name prefix data */ | ||
49 | +typedef struct xattr_prefix { | ||
50 | + int index; | ||
51 | + char *name; | ||
52 | + size_t length; | ||
53 | +} xattr_prefix_t; | ||
54 | + | ||
55 | +xattr_prefix_t xattr_prefixes [] = { | ||
56 | +/* Only interested in security prefix. Can support others though. | ||
57 | + { | ||
58 | + .index = EXT2_XATTR_INDEX_USER, | ||
59 | + .name = XATTR_USER_PREFIX, | ||
60 | + .length = XATTR_USER_PREFIX_LEN, | ||
61 | + }, | ||
62 | +*/ | ||
63 | + { | ||
64 | + .index = EXT2_XATTR_INDEX_SECURITY, | ||
65 | + .name = XATTR_SECURITY_PREFIX, | ||
66 | + .length = XATTR_SECURITY_PREFIX_LEN, | ||
67 | + }, | ||
68 | + { 0 }, | ||
69 | +}; | ||
70 | |||
71 | /* Free remaining resources after all files have been processed. */ | ||
72 | void | ||
73 | @@ -16,6 +55,211 @@ xattr_cleanup () | ||
74 | XATTR_STDERR ("Cleaning up resources from xattrs.\n"); | ||
75 | } | ||
76 | |||
77 | +/* Get value for named xattr from file at path. | ||
78 | + * Returns pointer to allocated block for value and length in length param. | ||
79 | + * If no value, return NULL pointer and length of 0. | ||
80 | + * On error return NULL pointer and length set to -1. | ||
81 | + */ | ||
82 | +static char* | ||
83 | +xattr_get_value (const char *path, const char *name, ssize_t *length) | ||
84 | +{ | ||
85 | + char *value = NULL; | ||
86 | + | ||
87 | + *length = lgetxattr (path, name, NULL, 0); | ||
88 | + if (*length == -1) { | ||
89 | + com_err (__func__, errno, "lgetattr"); | ||
90 | + goto out; | ||
91 | + } | ||
92 | + if (*length == 0) { | ||
93 | + fprintf (stderr, "xattr %s has value length 0\n", name); | ||
94 | + goto out; | ||
95 | + } | ||
96 | + value = calloc (1, *length); | ||
97 | + if (value == NULL) { | ||
98 | + com_err (__func__, errno, "calloc"); | ||
99 | + goto out; | ||
100 | + } | ||
101 | + *length = lgetxattr (path, name, value, *length); | ||
102 | + if (*length == -1) { | ||
103 | + com_err (__func__, errno, "lgetattr"); | ||
104 | + goto value_err; | ||
105 | + } | ||
106 | +out: | ||
107 | + return value; | ||
108 | + | ||
109 | +value_err: | ||
110 | + if (value) | ||
111 | + free (value); | ||
112 | + return NULL; | ||
113 | +} | ||
114 | + | ||
115 | +/* Get all attribute names for file at path. Return pointer to allocated memory | ||
116 | + * block holding all names and the length through parameter size. | ||
117 | + * If no xattrs: return NULL and set size to 0 | ||
118 | + * If error: return NULL and set size to -1 | ||
119 | + */ | ||
120 | +static char* | ||
121 | +xattr_get_names (const char *path, ssize_t *size) | ||
122 | +{ | ||
123 | + char *names = NULL; | ||
124 | + | ||
125 | + *size = llistxattr (path, NULL, 0); | ||
126 | + if (*size == -1) { | ||
127 | + com_err (__func__, errno, "llistxattr"); | ||
128 | + goto out; | ||
129 | + } | ||
130 | + if (*size == 0) { | ||
131 | + /* no xattrs */ | ||
132 | + goto out; | ||
133 | + } | ||
134 | + names = calloc (1, *size); | ||
135 | + if (names == NULL) { | ||
136 | + com_err (__func__, errno, "calloc"); | ||
137 | + goto out; | ||
138 | + } | ||
139 | + *size = llistxattr (path, names, *size); | ||
140 | + if (*size == -1) { | ||
141 | + com_err (__func__, errno, "llistxattr"); | ||
142 | + goto cleanup; | ||
143 | + } | ||
144 | + if (*size == 0) { | ||
145 | + fprintf (stdout, "Conflicting data, no xattrs for file: %s\n", path); | ||
146 | + goto cleanup; | ||
147 | + } | ||
148 | +out: | ||
149 | + return names; | ||
150 | + | ||
151 | +cleanup: | ||
152 | + if (names) | ||
153 | + free (names); | ||
154 | + return NULL; | ||
155 | +} | ||
156 | + | ||
157 | +/* return pointer to next string in xattr name block, don't go beyond length | ||
158 | + */ | ||
159 | +static inline char* | ||
160 | +next_name (char *name, size_t length) | ||
161 | +{ | ||
162 | + int i = 0; | ||
163 | + | ||
164 | + for (i = 0; i < length; ++i) | ||
165 | + if (name [i] == '\0') { | ||
166 | + ++i; | ||
167 | + break; | ||
168 | + } | ||
169 | + | ||
170 | + return name + i; | ||
171 | +} | ||
172 | + | ||
173 | +/* Find entry in xattr_table with matching prefix. */ | ||
174 | +static const xattr_prefix_t* | ||
175 | +xattr_find_prefix (char *name, size_t length) | ||
176 | +{ | ||
177 | + int i = 0; | ||
178 | + | ||
179 | + XATTR_STDERR ("find_attr_data: searching for prefix from xattr name: %s\n", name); | ||
180 | + for (i = 0; xattr_prefixes[i].index != 0; ++i) { | ||
181 | + if (!strncmp (name, xattr_prefixes[i].name, MIN (length, xattr_prefixes[i].length))) { | ||
182 | + XATTR_STDERR ("found match in table with index: %d\n", xattr_prefixes[i].index); | ||
183 | + return &xattr_prefixes[i]; | ||
184 | + } | ||
185 | + } | ||
186 | + return NULL; | ||
187 | +} | ||
188 | + | ||
189 | +/* Query file at path for attributes. build up structure the file system | ||
190 | + * expects of an extended attribute disk block (header parameter). | ||
191 | + * | ||
192 | + * The main loop walks through the xattr names one at a time. It gets the value | ||
193 | + * for each named xattr and copies the data into the xattr block pointed to by | ||
194 | + * the header parameter. To do this the loop also tracks the location of the | ||
195 | + * associated entry and value. Values start at the end of the buffer and grow | ||
196 | + * back towards the header while the entries start immediately after the header | ||
197 | + * and grow towards the end of the block. | ||
198 | + * | ||
199 | + * See the comment block at the beginning of the xattr.c file in the ext2 file | ||
200 | + * system code in the kernel: fs/ext2/xattr.c | ||
201 | + * Assume the xattr block pointed to by header parameter is initialized to 0s. | ||
202 | + */ | ||
203 | +static int | ||
204 | +xattr_build_block (const char *path, | ||
205 | + struct ext2_ext_attr_header **header, | ||
206 | + size_t header_length) | ||
207 | +{ | ||
208 | + struct ext2_ext_attr_entry *entry = NULL; | ||
209 | + char *names = NULL, *value = NULL, *name_curr = NULL; | ||
210 | + ssize_t names_length = 0, value_length = 0; | ||
211 | + size_t name_length = 0, value_index = 0, len_rem = 0; | ||
212 | + const xattr_prefix_t *prefix = NULL; | ||
213 | + int ret = 0; | ||
214 | + | ||
215 | + XATTR_STDERR ("xattr_build_block for file: %s\n", path); | ||
216 | + *header = NULL; | ||
217 | + names = xattr_get_names (path, &names_length); | ||
218 | + if (names == NULL) { | ||
219 | + // no xattrs for file @ path or error | ||
220 | + ret = names_length; | ||
221 | + goto out; | ||
222 | + } | ||
223 | + *header = calloc (1, header_length); | ||
224 | + if (*header == NULL) { | ||
225 | + com_err (__func__, errno, "calloc"); | ||
226 | + goto out; | ||
227 | + } | ||
228 | + (*header)->h_magic = EXT2_EXT_ATTR_MAGIC; | ||
229 | + (*header)->h_blocks = 1; | ||
230 | + /* Values start at end of buffer. NOTE: It must be moved before a value can | ||
231 | + * be stored. | ||
232 | + */ | ||
233 | + value_index = header_length; | ||
234 | + for (name_curr = names, entry = FIRST_ENTRY(*header), len_rem = names_length; | ||
235 | + name_curr < names + names_length; | ||
236 | + len_rem = names_length - (name_curr - names), | ||
237 | + name_curr = next_name (name_curr, len_rem), | ||
238 | + entry = EXT2_EXT_ATTR_NEXT(entry)) | ||
239 | + { | ||
240 | + XATTR_STDERR ("xattr_build_block: processing xattr with name %s\n", name_curr); | ||
241 | + name_length = strnlen (name_curr, len_rem); | ||
242 | + prefix = xattr_find_prefix (name_curr, name_length); | ||
243 | + if (!prefix) { | ||
244 | + fprintf (stderr, "Don't currently handle xattr: %s\n", name_curr); | ||
245 | + continue; | ||
246 | + } | ||
247 | + value = xattr_get_value (path, name_curr, &value_length); | ||
248 | + if (value == NULL) { | ||
249 | + // no xattr value or error | ||
250 | + fprintf (stderr, "failed to get value, skipping\n"); | ||
251 | + goto next; | ||
252 | + } | ||
253 | + /* setup offsets and lengths for name and value */ | ||
254 | + entry->e_name_len = name_length - prefix->length; | ||
255 | + entry->e_name_index = prefix->index; | ||
256 | + /* Can't know these till we know the length of the value. */ | ||
257 | + entry->e_value_offs = value_index -= EXT2_EXT_ATTR_SIZE(value_length); | ||
258 | + entry->e_value_size = value_length; | ||
259 | + /* Check to be sure entry name and value don't overlap before copy. */ | ||
260 | + if (EXT2_EXT_ATTR_NAME(entry) + entry->e_name_len > VALUE(*header, entry)) { | ||
261 | + fprintf (stderr, "xattr entry name and value overlap! Too much xattr data."); | ||
262 | + ret = -1; | ||
263 | + goto out; | ||
264 | + } | ||
265 | + /* copy name and value data then calculate the hash */ | ||
266 | + memcpy (EXT2_EXT_ATTR_NAME(entry), | ||
267 | + name_curr + prefix->length, | ||
268 | + entry->e_name_len); | ||
269 | + memcpy (VALUE(*header, entry), value, entry->e_value_size); | ||
270 | + entry->e_hash = ext2fs_ext_attr_hash_entry (entry, VALUE(*header, entry)); | ||
271 | +next: | ||
272 | + if (value) | ||
273 | + free (value); | ||
274 | + } | ||
275 | + XATTR_STDERR ("xattr_build_block: done building xattr buffer\n"); | ||
276 | +out: | ||
277 | + if (names) | ||
278 | + free (names); | ||
279 | + return ret; | ||
280 | +} | ||
281 | + | ||
282 | /* This is the entry point to the xattr module. This function copies the xattrs | ||
283 | * from the file at 'path' to the file system object at 'ino'. | ||
284 | * | ||
285 | @@ -28,7 +272,56 @@ errcode_t | ||
286 | set_inode_xattr (ext2_filsys fs, ext2_ino_t ino, const char *path) | ||
287 | { | ||
288 | errcode_t ret = 0; | ||
289 | + char *buf = NULL; | ||
290 | + struct ext2_inode inode = { 0 }; | ||
291 | + blk_t block = 0; | ||
292 | + struct ext2_ext_attr_header *header = NULL; | ||
293 | + uint32_t newcount = 0; | ||
294 | |||
295 | XATTR_STDERR ("Copying xattrs from %s to inode 0x%x.\n", path, ino); | ||
296 | + /* Populate the xattr block for the file at path */ | ||
297 | + if (ret = xattr_build_block (path, &header, fs->blocksize)) { | ||
298 | + goto out; | ||
299 | + } | ||
300 | + if (header == NULL) { | ||
301 | + XATTR_STDERR ("set_inode_xattrs: no xattrs for %s\n", path); | ||
302 | + goto out; | ||
303 | + } | ||
304 | + if (ret = ext2fs_read_inode (fs, ino, &inode)) { | ||
305 | + com_err(__func__, ret, "ext2fs_read_inode"); | ||
306 | + goto out; | ||
307 | + } | ||
308 | + if (ret = ext2fs_alloc_block (fs, 0, NULL, &block)) { | ||
309 | + com_err(__func__, ret, "ext2fs_alloc_block: returned %d", ret); | ||
310 | + goto out; | ||
311 | + } | ||
312 | + ext2fs_mark_block_bitmap2 (fs->block_map, block); | ||
313 | + XATTR_STDERR ("writing xattr block 0x%x to disk:\n", block); | ||
314 | + if (ret = ext2fs_write_ext_attr (fs, block, header)) { | ||
315 | + com_err(__func__, ret, "ext2fs_write_ext_attr: returned %d", ret); | ||
316 | + goto out; | ||
317 | + } | ||
318 | + /* point inode for current file to xattr block, update block count and | ||
319 | + * write inode to disk | ||
320 | + */ | ||
321 | + inode.i_file_acl = block; | ||
322 | + if (ret = ext2fs_adjust_ea_refcount2(fs, | ||
323 | + block, | ||
324 | + (char*)header, | ||
325 | + 1, | ||
326 | + &newcount)) | ||
327 | + { | ||
328 | + com_err(__func__, ret, "ext2fs_adjust_ea_refcount"); | ||
329 | + goto out; | ||
330 | + } | ||
331 | + if (ret = ext2fs_iblk_add_blocks (fs, &inode, 1)) { | ||
332 | + com_err(__func__, ret, "ext2fs_iblk_add_blocks failed"); | ||
333 | + goto out; | ||
334 | + } | ||
335 | + if (ret = ext2fs_write_inode (fs, ino, &inode)) | ||
336 | + com_err(__func__, ret, "ext2fs_write_inode: returned %d", ret); | ||
337 | +out: | ||
338 | + if (header) | ||
339 | + free (header); | ||
340 | return ret; | ||
341 | } | ||
diff --git a/recipes-devtools/e2fsprogs/e2fsprogs_1.42.9.bbappend b/recipes-devtools/e2fsprogs/e2fsprogs_1.42.9.bbappend index a4576b1..edc94d8 100644 --- a/recipes-devtools/e2fsprogs/e2fsprogs_1.42.9.bbappend +++ b/recipes-devtools/e2fsprogs/e2fsprogs_1.42.9.bbappend | |||
@@ -4,4 +4,5 @@ SRC_URI += " \ | |||
4 | file://misc-xattr-add-xattr-module-stub.patch \ | 4 | file://misc-xattr-add-xattr-module-stub.patch \ |
5 | file://mke2fs.c-create_inode.c-copy-xattrs.patch \ | 5 | file://mke2fs.c-create_inode.c-copy-xattrs.patch \ |
6 | file://lib-ext2fs-ext2_ext_attr.h-add-xattr-index.patch \ | 6 | file://lib-ext2fs-ext2_ext_attr.h-add-xattr-index.patch \ |
7 | file://misc-xattr-create-xattr-block.patch \ | ||
7 | " | 8 | " |