-
Notifications
You must be signed in to change notification settings - Fork 92
/
Copy pathcpio-strip.c
144 lines (124 loc) · 4.05 KB
/
cpio-strip.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/*
* Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: BSD-2-Clause
*/
/* Tool for removing metadata from a CPIO archive.
*
* The motivation behind this is to work towards idempotent builds. Part of the
* seL4 build system forms a CPIO archive of ELF files from the host file
* system. This archive inadvertently includes information like the i-node
* numbers and modified times of these files. This information is irrelevant at
* runtime, but causes the resulting image to not be binary identical between
* otherwise identical builds.
*
* The code that follows strips or replaces the following fields from CPIO file
* entries:
* - i-node number
* - UID
* - GID
* - modified time
*/
#define _XOPEN_SOURCE 700
/* We deliberately use seL4's CPIO library rather than libarchive or similar so
* we have the same interpretation of CPIO files as seL4. This isn't strictly
* essential, but it's nice for testing the robustness of this library.
*/
#include <cpio/cpio.h>
#include <assert.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
/* Find the pointer to a CPIO entry header from a pointer to the entry's data.
* This essentially reverses the transformation in cpio_get_entry.
*/
static void *get_header(void *data, const char *filename)
{
assert((uintptr_t)data % CPIO_ALIGNMENT == 0);
uintptr_t p = (uintptr_t)data - strlen(filename) - 1
- sizeof(struct cpio_header);
return (void *)(p - (p % CPIO_ALIGNMENT));
}
int main(int argc, char **argv)
{
if (argc != 2) {
fprintf(stderr, "Usage: %s file\n"
" Strip meta data from a CPIO file\n", argv[0]);
return -1;
}
FILE *archive = NULL;
void *p = NULL;
long len = 0;
archive = fopen(argv[1], "r+");
if (archive == NULL) {
perror("failed to open archive");
goto fail;
}
/* Determine the size of the archive, as we'll need to mmap the whole
* thing.
*/
if (fseek(archive, 0, SEEK_END) != 0) {
perror("failed to seek archive");
goto fail;
}
len = ftell(archive);
if (len == -1) {
perror("failed to read size of archive");
goto fail;
}
if (fseek(archive, 0, SEEK_SET) != 0) {
perror("failed to return to beginning of archive");
goto fail;
}
/* Mmap the file so we can operate on it with libcpio. */
p = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(archive), 0);
if (p == MAP_FAILED) {
perror("failed to mmap archive");
p = NULL;
goto fail;
}
struct cpio_info info = { .file_count = 0 };
int err = cpio_info(p, &info);
if (err != 0) {
fprintf(stderr, "failed to read CPIO info\n");
goto fail;
}
for (unsigned int i = 0; i < info.file_count; i++) {
/* Use libcpio to look up the entry. */
unsigned long size;
const char *filename;
void *data = cpio_get_entry(p, i, &filename, &size);
if (data == NULL) {
fprintf(stderr, "failed to locate entry %u\n", i);
goto fail;
}
/* Reverse the data pointer to a header pointer. */
struct cpio_header *header = get_header(data, filename);
assert((uintptr_t)header % CPIO_ALIGNMENT == 0);
/* Synthesise an i-node number. This just needs to be distinct within
* the archive. I-node numbers <=10 are reserved on certain file
* systems.
*/
unsigned int inode = 11 + i;
snprintf(header->c_ino, sizeof(header->c_ino), "%08x", inode);
/* Set the file owned by 'root'. */
memset(header->c_uid, 0, sizeof(header->c_uid));
memset(header->c_gid, 0, sizeof(header->c_gid));
/* Blank the modified time. */
memset(header->c_mtime, 0, sizeof(header->c_mtime));
}
munmap(p, len);
fclose(archive);
return 0;
fail:
if (p != NULL) {
munmap(p, len);
}
if (archive != NULL) {
fclose(archive);
}
return -1;
}