wok view linux-uml/stuff/linux-hardlinks.u @ rev 18710

grub2: CVE-2015-8370 fix (again)
author Pascal Bellard <pascal.bellard@slitaz.org>
date Wed Dec 16 18:01:12 2015 +0100 (2015-12-16)
parents
children
line source
1 Fix hardlink on fifos, sockets, char & block devices and symlinks
2 --- linux-3.2.53/init/initramfs.c
3 +++ linux-3.2.53/init/initramfs.c
4 @@ -20,10 +20,24 @@
6 #define N_ALIGN(len) ((((len) + 1) & ~3) + 2)
8 +static __initdata unsigned long ino, major, minor, nlink;
9 +static __initdata time_t mtime;
10 +static __initdata mode_t mode;
11 +static __initdata unsigned long body_len, name_len;
12 +static __initdata uid_t uid;
13 +static __initdata gid_t gid;
14 +static __initdata unsigned rdev;
15 +
16 +struct names {
17 + struct names *next;
18 + char name[1];
19 +};
20 +
21 static __initdata struct hash {
22 - int ino, minor, major;
23 + int ino, nlink, minor, major;
24 mode_t mode;
25 struct hash *next;
26 + struct names *next_name;
27 char name[N_ALIGN(PATH_MAX)];
28 } *head[32];
30 @@ -34,8 +48,7 @@
31 return tmp & 31;
32 }
34 -static char __init *find_link(int major, int minor, int ino,
35 - mode_t mode, char *name)
36 +static struct hash __init *find_link(char *name)
37 {
38 struct hash **p, *q;
39 for (p = head + hash(major, minor, ino); *p; p = &(*p)->next) {
40 @@ -47,7 +60,16 @@
41 continue;
42 if (((*p)->mode ^ mode) & S_IFMT)
43 continue;
44 - return (*p)->name;
45 + if (--(*p)->nlink) {
46 + struct names **n;
47 + for (n = &(*p)->next_name; *n; n = &(*n)->next);
48 + *n = kmalloc(sizeof(struct names) + strlen(name), GFP_KERNEL);
49 + if (!*n)
50 + panic("can't allocate link name entry");
51 + strcpy((*n)->name, name);
52 + (*n)->next = NULL;
53 + }
54 + return *p;
55 }
56 q = kmalloc(sizeof(struct hash), GFP_KERNEL);
57 if (!q)
58 @@ -55,11 +77,13 @@
59 q->major = major;
60 q->minor = minor;
61 q->ino = ino;
62 + q->nlink = nlink;
63 q->mode = mode;
64 strcpy(q->name, name);
65 + q->next_name = NULL;
66 q->next = NULL;
67 *p = q;
68 - return NULL;
69 + return q;
70 }
72 static void __init free_hash(void)
73 @@ -115,17 +139,8 @@
74 }
75 }
77 -static __initdata time_t mtime;
78 -
79 /* cpio header parsing */
81 -static __initdata unsigned long ino, major, minor, nlink;
82 -static __initdata mode_t mode;
83 -static __initdata unsigned long body_len, name_len;
84 -static __initdata uid_t uid;
85 -static __initdata gid_t gid;
86 -static __initdata unsigned rdev;
87 -
88 static void __init parse_header(char *s)
89 {
90 unsigned long parsed[12];
91 @@ -193,7 +208,7 @@
92 }
93 }
95 -static __initdata char *header_buf, *symlink_buf, *name_buf;
96 +static __initdata char *header_buf, *name_buf;
98 static int __init do_start(void)
99 {
100 @@ -231,17 +246,9 @@
101 state = SkipIt;
102 if (name_len <= 0 || name_len > PATH_MAX)
103 return 0;
104 - if (S_ISLNK(mode)) {
105 - if (body_len > PATH_MAX)
106 - return 0;
107 - collect = collected = symlink_buf;
108 - remains = N_ALIGN(name_len) + body_len;
109 - next_state = GotSymlink;
110 - state = Collect;
111 + if (S_ISLNK(mode) && (body_len > PATH_MAX))
112 return 0;
113 - }
114 - if (S_ISREG(mode) || !body_len)
115 - read_into(name_buf, N_ALIGN(name_len), GotName);
116 + read_into(name_buf, N_ALIGN(name_len), GotName);
117 return 0;
118 }
120 @@ -269,13 +276,34 @@
121 static int __init maybe_link(void)
122 {
123 if (nlink >= 2) {
124 - char *old = find_link(major, minor, ino, mode, collected);
125 - if (old)
126 - return (sys_link(old, collected) < 0) ? -1 : 1;
127 + struct hash *p = find_link(collected);
128 + if (p->nlink >= 2)
129 + return 1;
130 }
131 return 0;
132 }
134 +static void __init walk_names(struct names *p, char *name)
135 +{
136 + if (!p)
137 + return;
138 + walk_names(p->next, name);
139 + sys_link(name, p->name);
140 + kfree(p);
141 +}
142 +
143 +static void __init make_links(char *name)
144 +{
145 + if (nlink >= 2) {
146 + struct hash *p = find_link(name);
147 + if (!p->nlink) {
148 + walk_names(p->next_name, name);
149 + sys_link(name, p->name);
150 + p->next_name = NULL;
151 + }
152 + }
153 +}
154 +
155 static void __init clean_path(char *path, mode_t mode)
156 {
157 struct stat st;
158 @@ -300,11 +328,8 @@
159 }
160 clean_path(collected, mode);
161 if (S_ISREG(mode)) {
162 - int ml = maybe_link();
163 - if (ml >= 0) {
164 - int openflags = O_WRONLY|O_CREAT;
165 - if (ml != 1)
166 - openflags |= O_TRUNC;
167 + if (maybe_link() == 0) {
168 + int openflags = O_WRONLY|O_CREAT|O_TRUNC;
169 wfd = sys_open(collected, openflags, mode);
171 if (wfd >= 0) {
172 @@ -316,6 +341,11 @@
173 state = CopyFile;
174 }
175 }
176 + } else if (S_ISLNK(mode)) {
177 + if (maybe_link() == 0) {
178 + vcollected = kstrdup(collected, GFP_KERNEL);
179 + state = GotSymlink;
180 + }
181 } else if (S_ISDIR(mode)) {
182 sys_mkdir(collected, mode);
183 sys_chown(collected, uid, gid);
184 @@ -328,6 +358,7 @@
185 sys_chown(collected, uid, gid);
186 sys_chmod(collected, mode);
187 do_utime(collected, mtime);
188 + make_links(collected);
189 }
190 }
191 return 0;
192 @@ -339,6 +370,7 @@
193 sys_write(wfd, victim, body_len);
194 sys_close(wfd);
195 do_utime(vcollected, mtime);
196 + make_links(vcollected);
197 kfree(vcollected);
198 eat(body_len);
199 state = SkipIt;
200 @@ -353,13 +385,18 @@
202 static int __init do_symlink(void)
203 {
204 - collected[N_ALIGN(name_len) + body_len] = '\0';
205 - clean_path(collected, 0);
206 - sys_symlink(collected + N_ALIGN(name_len), collected);
207 - sys_lchown(collected, uid, gid);
208 - do_utime(collected, mtime);
209 + char c = victim[body_len];
210 +
211 + victim[body_len] = '\0';
212 + clean_path(vcollected, 0);
213 + sys_symlink(victim, vcollected);
214 + victim[body_len] = c;
215 + sys_lchown(vcollected, uid, gid);
216 + do_utime(vcollected, mtime);
217 + make_links(vcollected);
218 + kfree(vcollected);
219 + eat(body_len);
220 state = SkipIt;
221 - next_state = Reset;
222 return 0;
223 }
225 @@ -419,10 +456,9 @@
226 static __initdata char msg_buf[64];
228 header_buf = kmalloc(110, GFP_KERNEL);
229 - symlink_buf = kmalloc(PATH_MAX + N_ALIGN(PATH_MAX) + 1, GFP_KERNEL);
230 name_buf = kmalloc(N_ALIGN(PATH_MAX), GFP_KERNEL);
232 - if (!header_buf || !symlink_buf || !name_buf)
233 + if (!header_buf || !name_buf)
234 panic("can't allocate buffers");
236 state = Start;
237 @@ -467,7 +503,6 @@
238 }
239 dir_utime();
240 kfree(name_buf);
241 - kfree(symlink_buf);
242 kfree(header_buf);
243 return message;
244 }