wok rev 17415
linux: hardlink on fifos, sockets, char & block devices and symlinks in initramfs
author | Pascal Bellard <pascal.bellard@slitaz.org> |
---|---|
date | Tue Dec 02 19:00:19 2014 +0100 (2014-12-02) |
parents | f12aae0b9697 |
children | 2c6ef61a6d6a |
files | linux/receipt linux/stuff/linux-hardlinks.u |
line diff
1.1 --- a/linux/receipt Mon Dec 01 10:38:15 2014 +0100 1.2 +++ b/linux/receipt Tue Dec 02 19:00:19 2014 +0100 1.3 @@ -224,6 +224,7 @@ 1.4 $PACKAGE-subroot.u 1.5 $PACKAGE-CVE-2013-2929.u 1.6 $PACKAGE-romfs.u 1.7 +$PACKAGE-hardlinks.u 1.8 aufs3-base.patch 1.9 aufs3-standalone.patch 1.10 aufs3-loopback.patch
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/linux/stuff/linux-hardlinks.u Tue Dec 02 19:00:19 2014 +0100 2.3 @@ -0,0 +1,241 @@ 2.4 +Fix hardlink on fifos, sockets, char & block devices and symlinks 2.5 +--- linux-3.2.53/init/initramfs.c 2.6 ++++ linux-3.2.53/init/initramfs.c 2.7 +@@ -20,10 +20,24 @@ 2.8 + 2.9 + #define N_ALIGN(len) ((((len) + 1) & ~3) + 2) 2.10 + 2.11 ++static __initdata unsigned long ino, major, minor, nlink; 2.12 ++static __initdata time_t mtime; 2.13 ++static __initdata mode_t mode; 2.14 ++static __initdata unsigned long body_len, name_len; 2.15 ++static __initdata uid_t uid; 2.16 ++static __initdata gid_t gid; 2.17 ++static __initdata unsigned rdev; 2.18 ++ 2.19 ++struct names { 2.20 ++ struct names *next; 2.21 ++ char name[1]; 2.22 ++}; 2.23 ++ 2.24 + static __initdata struct hash { 2.25 +- int ino, minor, major; 2.26 ++ int ino, nlink, minor, major; 2.27 + mode_t mode; 2.28 + struct hash *next; 2.29 ++ struct names *next_name; 2.30 + char name[N_ALIGN(PATH_MAX)]; 2.31 + } *head[32]; 2.32 + 2.33 +@@ -34,8 +48,7 @@ 2.34 + return tmp & 31; 2.35 + } 2.36 + 2.37 +-static char __init *find_link(int major, int minor, int ino, 2.38 +- mode_t mode, char *name) 2.39 ++static struct hash __init *find_link(char *name) 2.40 + { 2.41 + struct hash **p, *q; 2.42 + for (p = head + hash(major, minor, ino); *p; p = &(*p)->next) { 2.43 +@@ -47,7 +60,16 @@ 2.44 + continue; 2.45 + if (((*p)->mode ^ mode) & S_IFMT) 2.46 + continue; 2.47 +- return (*p)->name; 2.48 ++ if (--(*p)->nlink) { 2.49 ++ struct names **n; 2.50 ++ for (n = &(*p)->next_name; *n; n = &(*n)->next); 2.51 ++ *n = kmalloc(sizeof(struct names) + strlen(name), GFP_KERNEL); 2.52 ++ if (!*n) 2.53 ++ panic("can't allocate link name entry"); 2.54 ++ strcpy((*n)->name, name); 2.55 ++ (*n)->next = NULL; 2.56 ++ } 2.57 ++ return *p; 2.58 + } 2.59 + q = kmalloc(sizeof(struct hash), GFP_KERNEL); 2.60 + if (!q) 2.61 +@@ -55,11 +77,13 @@ 2.62 + q->major = major; 2.63 + q->minor = minor; 2.64 + q->ino = ino; 2.65 ++ q->nlink = nlink; 2.66 + q->mode = mode; 2.67 + strcpy(q->name, name); 2.68 ++ q->next_name = NULL; 2.69 + q->next = NULL; 2.70 + *p = q; 2.71 +- return NULL; 2.72 ++ return q; 2.73 + } 2.74 + 2.75 + static void __init free_hash(void) 2.76 +@@ -115,17 +139,8 @@ 2.77 + } 2.78 + } 2.79 + 2.80 +-static __initdata time_t mtime; 2.81 +- 2.82 + /* cpio header parsing */ 2.83 + 2.84 +-static __initdata unsigned long ino, major, minor, nlink; 2.85 +-static __initdata mode_t mode; 2.86 +-static __initdata unsigned long body_len, name_len; 2.87 +-static __initdata uid_t uid; 2.88 +-static __initdata gid_t gid; 2.89 +-static __initdata unsigned rdev; 2.90 +- 2.91 + static void __init parse_header(char *s) 2.92 + { 2.93 + unsigned long parsed[12]; 2.94 +@@ -193,7 +208,7 @@ 2.95 + } 2.96 + } 2.97 + 2.98 +-static __initdata char *header_buf, *symlink_buf, *name_buf; 2.99 ++static __initdata char *header_buf, *name_buf; 2.100 + 2.101 + static int __init do_start(void) 2.102 + { 2.103 +@@ -231,17 +246,9 @@ 2.104 + state = SkipIt; 2.105 + if (name_len <= 0 || name_len > PATH_MAX) 2.106 + return 0; 2.107 +- if (S_ISLNK(mode)) { 2.108 +- if (body_len > PATH_MAX) 2.109 +- return 0; 2.110 +- collect = collected = symlink_buf; 2.111 +- remains = N_ALIGN(name_len) + body_len; 2.112 +- next_state = GotSymlink; 2.113 +- state = Collect; 2.114 ++ if (S_ISLNK(mode) && (body_len > PATH_MAX)) 2.115 + return 0; 2.116 +- } 2.117 +- if (S_ISREG(mode) || !body_len) 2.118 +- read_into(name_buf, N_ALIGN(name_len), GotName); 2.119 ++ read_into(name_buf, N_ALIGN(name_len), GotName); 2.120 + return 0; 2.121 + } 2.122 + 2.123 +@@ -269,13 +276,34 @@ 2.124 + static int __init maybe_link(void) 2.125 + { 2.126 + if (nlink >= 2) { 2.127 +- char *old = find_link(major, minor, ino, mode, collected); 2.128 +- if (old) 2.129 +- return (sys_link(old, collected) < 0) ? -1 : 1; 2.130 ++ struct hash *p = find_link(collected); 2.131 ++ if (p->nlink >= 2) 2.132 ++ return 1; 2.133 + } 2.134 + return 0; 2.135 + } 2.136 + 2.137 ++static void __init walk_names(struct names *p, char *name) 2.138 ++{ 2.139 ++ if (!p) 2.140 ++ return; 2.141 ++ walk_names(p->next, name); 2.142 ++ sys_link(name, p->name); 2.143 ++ kfree(p); 2.144 ++} 2.145 ++ 2.146 ++static void __init make_links(char *name) 2.147 ++{ 2.148 ++ if (nlink >= 2) { 2.149 ++ struct hash *p = find_link(name); 2.150 ++ if (!p->nlink) { 2.151 ++ walk_names(p->next_name, name); 2.152 ++ sys_link(name, p->name); 2.153 ++ p->next_name = NULL; 2.154 ++ } 2.155 ++ } 2.156 ++} 2.157 ++ 2.158 + static void __init clean_path(char *path, mode_t mode) 2.159 + { 2.160 + struct stat st; 2.161 +@@ -300,11 +328,8 @@ 2.162 + } 2.163 + clean_path(collected, mode); 2.164 + if (S_ISREG(mode)) { 2.165 +- int ml = maybe_link(); 2.166 +- if (ml >= 0) { 2.167 +- int openflags = O_WRONLY|O_CREAT; 2.168 +- if (ml != 1) 2.169 +- openflags |= O_TRUNC; 2.170 ++ if (maybe_link() == 0) { 2.171 ++ int openflags = O_WRONLY|O_CREAT|O_TRUNC; 2.172 + wfd = sys_open(collected, openflags, mode); 2.173 + 2.174 + if (wfd >= 0) { 2.175 +@@ -316,6 +341,11 @@ 2.176 + state = CopyFile; 2.177 + } 2.178 + } 2.179 ++ } else if (S_ISLNK(mode)) { 2.180 ++ if (maybe_link() == 0) { 2.181 ++ vcollected = kstrdup(collected, GFP_KERNEL); 2.182 ++ state = GotSymlink; 2.183 ++ } 2.184 + } else if (S_ISDIR(mode)) { 2.185 + sys_mkdir(collected, mode); 2.186 + sys_chown(collected, uid, gid); 2.187 +@@ -328,6 +358,7 @@ 2.188 + sys_chown(collected, uid, gid); 2.189 + sys_chmod(collected, mode); 2.190 + do_utime(collected, mtime); 2.191 ++ make_links(collected); 2.192 + } 2.193 + } 2.194 + return 0; 2.195 +@@ -339,6 +370,7 @@ 2.196 + sys_write(wfd, victim, body_len); 2.197 + sys_close(wfd); 2.198 + do_utime(vcollected, mtime); 2.199 ++ make_links(vcollected); 2.200 + kfree(vcollected); 2.201 + eat(body_len); 2.202 + state = SkipIt; 2.203 +@@ -353,13 +385,15 @@ 2.204 + 2.205 + static int __init do_symlink(void) 2.206 + { 2.207 +- collected[N_ALIGN(name_len) + body_len] = '\0'; 2.208 +- clean_path(collected, 0); 2.209 +- sys_symlink(collected + N_ALIGN(name_len), collected); 2.210 +- sys_lchown(collected, uid, gid); 2.211 +- do_utime(collected, mtime); 2.212 ++ victim[body_len] = '\0'; 2.213 ++ clean_path(vcollected, 0); 2.214 ++ sys_symlink(victim, vcollected); 2.215 ++ sys_lchown(vcollected, uid, gid); 2.216 ++ do_utime(vcollected, mtime); 2.217 ++ make_links(vcollected); 2.218 ++ kfree(vcollected); 2.219 ++ eat(body_len); 2.220 + state = SkipIt; 2.221 +- next_state = Reset; 2.222 + return 0; 2.223 + } 2.224 + 2.225 +@@ -466,10 +500,9 @@ 2.226 + int early_free_initrd = (buf == (char *) initrd_start); 2.227 + 2.228 + header_buf = kmalloc(110, GFP_KERNEL); 2.229 +- symlink_buf = kmalloc(PATH_MAX + N_ALIGN(PATH_MAX) + 1, GFP_KERNEL); 2.230 + name_buf = kmalloc(N_ALIGN(PATH_MAX), GFP_KERNEL); 2.231 + 2.232 +- if (!header_buf || !symlink_buf || !name_buf) 2.233 ++ if (!header_buf || !name_buf) 2.234 + panic("can't allocate buffers"); 2.235 + 2.236 + state = Start; 2.237 +@@ -524,7 +557,6 @@ 2.238 + } 2.239 + dir_utime(); 2.240 + kfree(name_buf); 2.241 +- kfree(symlink_buf); 2.242 + kfree(header_buf); 2.243 + return message; 2.244 + }