Blame view
fs/binfmt_misc.c
17.3 KB
09c434b8a treewide: Add SPD... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
1da177e4c Linux-2.6.12-rc2 |
2 |
/* |
e6084d4a0 binfmt_misc: clea... |
3 |
* binfmt_misc.c |
1da177e4c Linux-2.6.12-rc2 |
4 |
* |
e6084d4a0 binfmt_misc: clea... |
5 |
* Copyright (C) 1997 Richard Günther |
1da177e4c Linux-2.6.12-rc2 |
6 |
* |
e6084d4a0 binfmt_misc: clea... |
7 |
* binfmt_misc detects binaries via a magic or filename extension and invokes |
34962fb80 docs: Fix more br... |
8 |
* a specified wrapper. See Documentation/admin-guide/binfmt-misc.rst for more details. |
1da177e4c Linux-2.6.12-rc2 |
9 |
*/ |
6b899c4e9 binfmt_misc: add ... |
10 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
6ceafb880 fs/binfmt_misc.c:... |
11 |
#include <linux/kernel.h> |
1da177e4c Linux-2.6.12-rc2 |
12 13 |
#include <linux/module.h> #include <linux/init.h> |
589ee6284 sched/headers: Pr... |
14 |
#include <linux/sched/mm.h> |
b502bd115 magic.h: move som... |
15 |
#include <linux/magic.h> |
1da177e4c Linux-2.6.12-rc2 |
16 17 18 |
#include <linux/binfmts.h> #include <linux/slab.h> #include <linux/ctype.h> |
8d82e180b binfmt_misc: reus... |
19 |
#include <linux/string_helpers.h> |
1da177e4c Linux-2.6.12-rc2 |
20 21 22 23 |
#include <linux/file.h> #include <linux/pagemap.h> #include <linux/namei.h> #include <linux/mount.h> |
bc99a664e vfs: Convert binf... |
24 |
#include <linux/fs_context.h> |
1da177e4c Linux-2.6.12-rc2 |
25 |
#include <linux/syscalls.h> |
6e2c10a12 binfmt_misc: use ... |
26 |
#include <linux/fs.h> |
6b899c4e9 binfmt_misc: add ... |
27 |
#include <linux/uaccess.h> |
1da177e4c Linux-2.6.12-rc2 |
28 |
|
948b701a6 binfmt_misc: add ... |
29 |
#include "internal.h" |
6b899c4e9 binfmt_misc: add ... |
30 31 32 33 34 |
#ifdef DEBUG # define USE_DEBUG 1 #else # define USE_DEBUG 0 #endif |
1da177e4c Linux-2.6.12-rc2 |
35 36 37 38 39 40 41 42 43 |
enum { VERBOSE_STATUS = 1 /* make it zero to save 400 bytes kernel memory */ }; static LIST_HEAD(entries); static int enabled = 1; enum {Enabled, Magic}; |
e6084d4a0 binfmt_misc: clea... |
44 45 46 |
#define MISC_FMT_PRESERVE_ARGV0 (1 << 31) #define MISC_FMT_OPEN_BINARY (1 << 30) #define MISC_FMT_CREDENTIALS (1 << 29) |
948b701a6 binfmt_misc: add ... |
47 |
#define MISC_FMT_OPEN_FILE (1 << 28) |
1da177e4c Linux-2.6.12-rc2 |
48 49 50 51 52 53 54 55 |
typedef struct { struct list_head list; unsigned long flags; /* type, status, etc. */ int offset; /* offset of magic */ int size; /* size of magic/mask */ char *magic; /* magic or filename extension */ char *mask; /* mask, NULL for exact match */ |
50097f749 exec: binfmt_misc... |
56 |
const char *interpreter; /* filename of interpreter */ |
1da177e4c Linux-2.6.12-rc2 |
57 58 |
char *name; struct dentry *dentry; |
948b701a6 binfmt_misc: add ... |
59 |
struct file *interp_file; |
1da177e4c Linux-2.6.12-rc2 |
60 61 62 |
} Node; static DEFINE_RWLOCK(entries_lock); |
1f5ce9e93 VFS: Unexport do_... |
63 |
static struct file_system_type bm_fs_type; |
1da177e4c Linux-2.6.12-rc2 |
64 65 |
static struct vfsmount *bm_mnt; static int entry_count; |
bbaecc088 binfmt_misc: expa... |
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
/* * Max length of the register string. Determined by: * - 7 delimiters * - name: ~50 bytes * - type: 1 byte * - offset: 3 bytes (has to be smaller than BINPRM_BUF_SIZE) * - magic: 128 bytes (512 in escaped form) * - mask: 128 bytes (512 in escaped form) * - interp: ~50 bytes * - flags: 5 bytes * Round that up a bit, and then back off to hold the internal data * (like struct Node). */ #define MAX_REGISTER_LENGTH 1920 /* |
1da177e4c Linux-2.6.12-rc2 |
82 83 84 85 86 87 88 89 |
* Check if we support the binfmt * if we do, return the node, else NULL * locking is done in load_misc_binary */ static Node *check_file(struct linux_binprm *bprm) { char *p = strrchr(bprm->interp, '.'); struct list_head *l; |
6b899c4e9 binfmt_misc: add ... |
90 |
/* Walk all the registered handlers. */ |
1da177e4c Linux-2.6.12-rc2 |
91 92 93 94 |
list_for_each(l, &entries) { Node *e = list_entry(l, Node, list); char *s; int j; |
6b899c4e9 binfmt_misc: add ... |
95 |
/* Make sure this one is currently enabled. */ |
1da177e4c Linux-2.6.12-rc2 |
96 97 |
if (!test_bit(Enabled, &e->flags)) continue; |
6b899c4e9 binfmt_misc: add ... |
98 |
/* Do matching based on extension if applicable. */ |
1da177e4c Linux-2.6.12-rc2 |
99 100 101 102 103 |
if (!test_bit(Magic, &e->flags)) { if (p && !strcmp(e->magic, p + 1)) return e; continue; } |
6b899c4e9 binfmt_misc: add ... |
104 |
/* Do matching based on magic & mask. */ |
1da177e4c Linux-2.6.12-rc2 |
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
s = bprm->buf + e->offset; if (e->mask) { for (j = 0; j < e->size; j++) if ((*s++ ^ e->magic[j]) & e->mask[j]) break; } else { for (j = 0; j < e->size; j++) if ((*s++ ^ e->magic[j])) break; } if (j == e->size) return e; } return NULL; } /* * the loader itself */ |
71613c3b8 get rid of pt_reg... |
124 |
static int load_misc_binary(struct linux_binprm *bprm) |
1da177e4c Linux-2.6.12-rc2 |
125 126 |
{ Node *fmt; |
e6084d4a0 binfmt_misc: clea... |
127 |
struct file *interp_file = NULL; |
1da177e4c Linux-2.6.12-rc2 |
128 |
int retval; |
1da177e4c Linux-2.6.12-rc2 |
129 130 131 |
retval = -ENOEXEC; if (!enabled) |
43a4f2619 exec: binfmt_misc... |
132 |
return retval; |
1da177e4c Linux-2.6.12-rc2 |
133 134 135 136 |
/* to keep locking time low, we copy the interpreter string */ read_lock(&entries_lock); fmt = check_file(bprm); |
50097f749 exec: binfmt_misc... |
137 |
if (fmt) |
43a4f2619 exec: binfmt_misc... |
138 |
dget(fmt->dentry); |
1da177e4c Linux-2.6.12-rc2 |
139 140 |
read_unlock(&entries_lock); if (!fmt) |
43a4f2619 exec: binfmt_misc... |
141 |
return retval; |
1da177e4c Linux-2.6.12-rc2 |
142 |
|
51f39a1f0 syscalls: impleme... |
143 |
/* Need to be able to load the file after exec */ |
43a4f2619 exec: binfmt_misc... |
144 |
retval = -ENOENT; |
51f39a1f0 syscalls: impleme... |
145 |
if (bprm->interp_flags & BINPRM_FLAGS_PATH_INACCESSIBLE) |
43a4f2619 exec: binfmt_misc... |
146 |
goto ret; |
51f39a1f0 syscalls: impleme... |
147 |
|
1da177e4c Linux-2.6.12-rc2 |
148 |
if (!(fmt->flags & MISC_FMT_PRESERVE_ARGV0)) { |
b6a2fea39 mm: variable leng... |
149 150 |
retval = remove_arg_zero(bprm); if (retval) |
e6084d4a0 binfmt_misc: clea... |
151 |
goto ret; |
1da177e4c Linux-2.6.12-rc2 |
152 |
} |
bc2bf338d exec: Remove recu... |
153 |
if (fmt->flags & MISC_FMT_OPEN_BINARY) |
b8a61c9e7 exec: Generic exe... |
154 |
bprm->have_execfd = 1; |
1da177e4c Linux-2.6.12-rc2 |
155 |
|
1da177e4c Linux-2.6.12-rc2 |
156 |
/* make argv[1] be the path to the binary */ |
986db2d14 exec: simplify th... |
157 |
retval = copy_string_kernel(bprm->interp, bprm); |
1da177e4c Linux-2.6.12-rc2 |
158 |
if (retval < 0) |
b8a61c9e7 exec: Generic exe... |
159 |
goto ret; |
1da177e4c Linux-2.6.12-rc2 |
160 161 162 |
bprm->argc++; /* add the interp as argv[0] */ |
986db2d14 exec: simplify th... |
163 |
retval = copy_string_kernel(fmt->interpreter, bprm); |
1da177e4c Linux-2.6.12-rc2 |
164 |
if (retval < 0) |
b8a61c9e7 exec: Generic exe... |
165 |
goto ret; |
e6084d4a0 binfmt_misc: clea... |
166 |
bprm->argc++; |
1da177e4c Linux-2.6.12-rc2 |
167 |
|
b66c59840 exec: do not leav... |
168 |
/* Update interp in case binfmt_script needs it. */ |
50097f749 exec: binfmt_misc... |
169 |
retval = bprm_change_interp(fmt->interpreter, bprm); |
b66c59840 exec: do not leav... |
170 |
if (retval < 0) |
b8a61c9e7 exec: Generic exe... |
171 |
goto ret; |
1da177e4c Linux-2.6.12-rc2 |
172 |
|
eb23aa031 exec: binfmt_misc... |
173 |
if (fmt->flags & MISC_FMT_OPEN_FILE) { |
19f391eb0 turn filp_clone_o... |
174 |
interp_file = file_clone_open(fmt->interp_file); |
948b701a6 binfmt_misc: add ... |
175 176 177 |
if (!IS_ERR(interp_file)) deny_write_access(interp_file); } else { |
50097f749 exec: binfmt_misc... |
178 |
interp_file = open_exec(fmt->interpreter); |
948b701a6 binfmt_misc: add ... |
179 |
} |
e6084d4a0 binfmt_misc: clea... |
180 181 |
retval = PTR_ERR(interp_file); if (IS_ERR(interp_file)) |
b8a61c9e7 exec: Generic exe... |
182 |
goto ret; |
1da177e4c Linux-2.6.12-rc2 |
183 |
|
bc2bf338d exec: Remove recu... |
184 |
bprm->interpreter = interp_file; |
a16b3357b exec: Allow load_... |
185 |
if (fmt->flags & MISC_FMT_CREDENTIALS) |
56305aa9b exec: Compute fil... |
186 |
bprm->execfd_creds = 1; |
1da177e4c Linux-2.6.12-rc2 |
187 |
|
bc2bf338d exec: Remove recu... |
188 |
retval = 0; |
e6084d4a0 binfmt_misc: clea... |
189 |
ret: |
43a4f2619 exec: binfmt_misc... |
190 |
dput(fmt->dentry); |
1da177e4c Linux-2.6.12-rc2 |
191 |
return retval; |
1da177e4c Linux-2.6.12-rc2 |
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
} /* Command parsers */ /* * parses and copies one argument enclosed in del from *sp to *dp, * recognising the \x special. * returns pointer to the copied argument or NULL in case of an * error (and sets err) or null argument length. */ static char *scanarg(char *s, char del) { char c; while ((c = *s++) != del) { if (c == '\\' && *s == 'x') { s++; if (!isxdigit(*s++)) return NULL; if (!isxdigit(*s++)) return NULL; } } |
7d65cf10e unfuck binfmt_mis... |
215 |
s[-1] ='\0'; |
1da177e4c Linux-2.6.12-rc2 |
216 217 |
return s; } |
e6084d4a0 binfmt_misc: clea... |
218 |
static char *check_special_flags(char *sfs, Node *e) |
1da177e4c Linux-2.6.12-rc2 |
219 |
{ |
e6084d4a0 binfmt_misc: clea... |
220 |
char *p = sfs; |
1da177e4c Linux-2.6.12-rc2 |
221 222 223 224 225 |
int cont = 1; /* special flags */ while (cont) { switch (*p) { |
e6084d4a0 binfmt_misc: clea... |
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
case 'P': pr_debug("register: flag: P (preserve argv0) "); p++; e->flags |= MISC_FMT_PRESERVE_ARGV0; break; case 'O': pr_debug("register: flag: O (open binary) "); p++; e->flags |= MISC_FMT_OPEN_BINARY; break; case 'C': pr_debug("register: flag: C (preserve creds) "); p++; /* this flags also implies the open-binary flag */ e->flags |= (MISC_FMT_CREDENTIALS | MISC_FMT_OPEN_BINARY); break; |
948b701a6 binfmt_misc: add ... |
247 248 249 250 251 252 |
case 'F': pr_debug("register: flag: F: open interpreter file now "); p++; e->flags |= MISC_FMT_OPEN_FILE; break; |
e6084d4a0 binfmt_misc: clea... |
253 254 |
default: cont = 0; |
1da177e4c Linux-2.6.12-rc2 |
255 256 257 258 259 |
} } return p; } |
e6084d4a0 binfmt_misc: clea... |
260 |
|
1da177e4c Linux-2.6.12-rc2 |
261 262 263 264 265 266 267 268 269 270 271 |
/* * This registers a new binary format, it recognises the syntax * ':name:type:offset:magic:mask:interpreter:flags' * where the ':' is the IFS, that can be chosen with the first char */ static Node *create_entry(const char __user *buffer, size_t count) { Node *e; int memsize, err; char *buf, *p; char del; |
6b899c4e9 binfmt_misc: add ... |
272 273 |
pr_debug("register: received %zu bytes ", count); |
1da177e4c Linux-2.6.12-rc2 |
274 275 |
/* some sanity checks */ err = -EINVAL; |
bbaecc088 binfmt_misc: expa... |
276 |
if ((count < 11) || (count > MAX_REGISTER_LENGTH)) |
1da177e4c Linux-2.6.12-rc2 |
277 278 279 280 |
goto out; err = -ENOMEM; memsize = sizeof(Node) + count + 8; |
f7e1ad1a1 fs/binfmt_misc.c:... |
281 |
e = kmalloc(memsize, GFP_KERNEL); |
1da177e4c Linux-2.6.12-rc2 |
282 283 284 285 286 287 288 |
if (!e) goto out; p = buf = (char *)e + sizeof(Node); memset(e, 0, sizeof(Node)); if (copy_from_user(buf, buffer, count)) |
e6084d4a0 binfmt_misc: clea... |
289 |
goto efault; |
1da177e4c Linux-2.6.12-rc2 |
290 291 |
del = *p++; /* delimeter */ |
6b899c4e9 binfmt_misc: add ... |
292 293 294 295 |
pr_debug("register: delim: %#x {%c} ", del, del); /* Pad the buffer with the delim to simplify parsing below. */ |
e6084d4a0 binfmt_misc: clea... |
296 |
memset(buf + count, del, 8); |
1da177e4c Linux-2.6.12-rc2 |
297 |
|
6b899c4e9 binfmt_misc: add ... |
298 |
/* Parse the 'name' field. */ |
1da177e4c Linux-2.6.12-rc2 |
299 300 301 |
e->name = p; p = strchr(p, del); if (!p) |
e6084d4a0 binfmt_misc: clea... |
302 |
goto einval; |
1da177e4c Linux-2.6.12-rc2 |
303 304 305 306 307 |
*p++ = '\0'; if (!e->name[0] || !strcmp(e->name, ".") || !strcmp(e->name, "..") || strchr(e->name, '/')) |
e6084d4a0 binfmt_misc: clea... |
308 |
goto einval; |
6b899c4e9 binfmt_misc: add ... |
309 310 311 312 313 |
pr_debug("register: name: {%s} ", e->name); /* Parse the 'type' field. */ |
1da177e4c Linux-2.6.12-rc2 |
314 |
switch (*p++) { |
6b899c4e9 binfmt_misc: add ... |
315 316 317 318 319 320 321 322 323 324 325 |
case 'E': pr_debug("register: type: E (extension) "); e->flags = 1 << Enabled; break; case 'M': pr_debug("register: type: M (magic) "); e->flags = (1 << Enabled) | (1 << Magic); break; default: |
e6084d4a0 binfmt_misc: clea... |
326 |
goto einval; |
1da177e4c Linux-2.6.12-rc2 |
327 328 |
} if (*p++ != del) |
e6084d4a0 binfmt_misc: clea... |
329 |
goto einval; |
6b899c4e9 binfmt_misc: add ... |
330 |
|
1da177e4c Linux-2.6.12-rc2 |
331 |
if (test_bit(Magic, &e->flags)) { |
6b899c4e9 binfmt_misc: add ... |
332 333 334 335 336 |
/* Handle the 'M' (magic) format. */ char *s; /* Parse the 'offset' field. */ s = strchr(p, del); |
1da177e4c Linux-2.6.12-rc2 |
337 |
if (!s) |
e6084d4a0 binfmt_misc: clea... |
338 |
goto einval; |
5cc41e099 fs/binfmt_misc.c:... |
339 340 341 342 343 344 345 |
*s = '\0'; if (p != s) { int r = kstrtoint(p, 10, &e->offset); if (r != 0 || e->offset < 0) goto einval; } p = s; |
1da177e4c Linux-2.6.12-rc2 |
346 |
if (*p++) |
e6084d4a0 binfmt_misc: clea... |
347 |
goto einval; |
6b899c4e9 binfmt_misc: add ... |
348 349 350 351 |
pr_debug("register: offset: %#x ", e->offset); /* Parse the 'magic' field. */ |
1da177e4c Linux-2.6.12-rc2 |
352 353 354 |
e->magic = p; p = scanarg(p, del); if (!p) |
e6084d4a0 binfmt_misc: clea... |
355 |
goto einval; |
7d65cf10e unfuck binfmt_mis... |
356 |
if (!e->magic[0]) |
e6084d4a0 binfmt_misc: clea... |
357 |
goto einval; |
6b899c4e9 binfmt_misc: add ... |
358 359 360 361 362 363 |
if (USE_DEBUG) print_hex_dump_bytes( KBUILD_MODNAME ": register: magic[raw]: ", DUMP_PREFIX_NONE, e->magic, p - e->magic); /* Parse the 'mask' field. */ |
1da177e4c Linux-2.6.12-rc2 |
364 365 366 |
e->mask = p; p = scanarg(p, del); if (!p) |
e6084d4a0 binfmt_misc: clea... |
367 |
goto einval; |
7d65cf10e unfuck binfmt_mis... |
368 |
if (!e->mask[0]) { |
1da177e4c Linux-2.6.12-rc2 |
369 |
e->mask = NULL; |
6b899c4e9 binfmt_misc: add ... |
370 371 372 373 374 375 376 377 378 379 380 381 382 |
pr_debug("register: mask[raw]: none "); } else if (USE_DEBUG) print_hex_dump_bytes( KBUILD_MODNAME ": register: mask[raw]: ", DUMP_PREFIX_NONE, e->mask, p - e->mask); /* * Decode the magic & mask fields. * Note: while we might have accepted embedded NUL bytes from * above, the unescape helpers here will stop at the first one * it encounters. */ |
8d82e180b binfmt_misc: reus... |
383 384 385 |
e->size = string_unescape_inplace(e->magic, UNESCAPE_HEX); if (e->mask && string_unescape_inplace(e->mask, UNESCAPE_HEX) != e->size) |
e6084d4a0 binfmt_misc: clea... |
386 |
goto einval; |
5cc41e099 fs/binfmt_misc.c:... |
387 388 |
if (e->size > BINPRM_BUF_SIZE || BINPRM_BUF_SIZE - e->size < e->offset) |
e6084d4a0 binfmt_misc: clea... |
389 |
goto einval; |
6b899c4e9 binfmt_misc: add ... |
390 391 392 393 394 395 396 397 398 |
pr_debug("register: magic/mask length: %i ", e->size); if (USE_DEBUG) { print_hex_dump_bytes( KBUILD_MODNAME ": register: magic[decoded]: ", DUMP_PREFIX_NONE, e->magic, e->size); if (e->mask) { int i; |
f7e1ad1a1 fs/binfmt_misc.c:... |
399 |
char *masked = kmalloc(e->size, GFP_KERNEL); |
6b899c4e9 binfmt_misc: add ... |
400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 |
print_hex_dump_bytes( KBUILD_MODNAME ": register: mask[decoded]: ", DUMP_PREFIX_NONE, e->mask, e->size); if (masked) { for (i = 0; i < e->size; ++i) masked[i] = e->magic[i] & e->mask[i]; print_hex_dump_bytes( KBUILD_MODNAME ": register: magic[masked]: ", DUMP_PREFIX_NONE, masked, e->size); kfree(masked); } } } |
1da177e4c Linux-2.6.12-rc2 |
416 |
} else { |
6b899c4e9 binfmt_misc: add ... |
417 418 419 |
/* Handle the 'E' (extension) format. */ /* Skip the 'offset' field. */ |
1da177e4c Linux-2.6.12-rc2 |
420 421 |
p = strchr(p, del); if (!p) |
e6084d4a0 binfmt_misc: clea... |
422 |
goto einval; |
1da177e4c Linux-2.6.12-rc2 |
423 |
*p++ = '\0'; |
6b899c4e9 binfmt_misc: add ... |
424 425 |
/* Parse the 'magic' field. */ |
1da177e4c Linux-2.6.12-rc2 |
426 427 428 |
e->magic = p; p = strchr(p, del); if (!p) |
e6084d4a0 binfmt_misc: clea... |
429 |
goto einval; |
1da177e4c Linux-2.6.12-rc2 |
430 431 |
*p++ = '\0'; if (!e->magic[0] || strchr(e->magic, '/')) |
e6084d4a0 binfmt_misc: clea... |
432 |
goto einval; |
6b899c4e9 binfmt_misc: add ... |
433 434 435 436 |
pr_debug("register: extension: {%s} ", e->magic); /* Skip the 'mask' field. */ |
1da177e4c Linux-2.6.12-rc2 |
437 438 |
p = strchr(p, del); if (!p) |
e6084d4a0 binfmt_misc: clea... |
439 |
goto einval; |
1da177e4c Linux-2.6.12-rc2 |
440 441 |
*p++ = '\0'; } |
6b899c4e9 binfmt_misc: add ... |
442 443 |
/* Parse the 'interpreter' field. */ |
1da177e4c Linux-2.6.12-rc2 |
444 445 446 |
e->interpreter = p; p = strchr(p, del); if (!p) |
e6084d4a0 binfmt_misc: clea... |
447 |
goto einval; |
1da177e4c Linux-2.6.12-rc2 |
448 449 |
*p++ = '\0'; if (!e->interpreter[0]) |
e6084d4a0 binfmt_misc: clea... |
450 |
goto einval; |
6b899c4e9 binfmt_misc: add ... |
451 452 |
pr_debug("register: interpreter: {%s} ", e->interpreter); |
1da177e4c Linux-2.6.12-rc2 |
453 |
|
6b899c4e9 binfmt_misc: add ... |
454 |
/* Parse the 'flags' field. */ |
e6084d4a0 binfmt_misc: clea... |
455 |
p = check_special_flags(p, e); |
1da177e4c Linux-2.6.12-rc2 |
456 457 458 459 |
if (*p == ' ') p++; if (p != buf + count) |
e6084d4a0 binfmt_misc: clea... |
460 |
goto einval; |
1da177e4c Linux-2.6.12-rc2 |
461 462 463 464 |
return e; out: return ERR_PTR(err); |
e6084d4a0 binfmt_misc: clea... |
465 |
efault: |
1da177e4c Linux-2.6.12-rc2 |
466 467 |
kfree(e); return ERR_PTR(-EFAULT); |
e6084d4a0 binfmt_misc: clea... |
468 |
einval: |
1da177e4c Linux-2.6.12-rc2 |
469 470 471 472 473 474 475 476 477 478 479 |
kfree(e); return ERR_PTR(-EINVAL); } /* * Set status of entry/binfmt_misc: * '1' enables, '0' disables and '-1' clears entry/binfmt_misc */ static int parse_command(const char __user *buffer, size_t count) { char s[4]; |
1da177e4c Linux-2.6.12-rc2 |
480 481 482 483 |
if (count > 3) return -EINVAL; if (copy_from_user(s, buffer, count)) return -EFAULT; |
de8288b1f binfmt_misc: work... |
484 485 |
if (!count) return 0; |
e6084d4a0 binfmt_misc: clea... |
486 487 |
if (s[count - 1] == ' ') |
1da177e4c Linux-2.6.12-rc2 |
488 489 490 491 492 493 494 495 496 497 498 499 500 501 |
count--; if (count == 1 && s[0] == '0') return 1; if (count == 1 && s[0] == '1') return 2; if (count == 2 && s[0] == '-' && s[1] == '1') return 3; return -EINVAL; } /* generic stuff */ static void entry_status(Node *e, char *page) { |
6ceafb880 fs/binfmt_misc.c:... |
502 503 |
char *dp = page; const char *status = "disabled"; |
1da177e4c Linux-2.6.12-rc2 |
504 505 506 507 508 509 510 511 512 |
if (test_bit(Enabled, &e->flags)) status = "enabled"; if (!VERBOSE_STATUS) { sprintf(page, "%s ", status); return; } |
6ceafb880 fs/binfmt_misc.c:... |
513 514 515 |
dp += sprintf(dp, "%s interpreter %s ", status, e->interpreter); |
1da177e4c Linux-2.6.12-rc2 |
516 517 |
/* print the special flags */ |
6ceafb880 fs/binfmt_misc.c:... |
518 |
dp += sprintf(dp, "flags: "); |
e6084d4a0 binfmt_misc: clea... |
519 520 521 522 523 524 |
if (e->flags & MISC_FMT_PRESERVE_ARGV0) *dp++ = 'P'; if (e->flags & MISC_FMT_OPEN_BINARY) *dp++ = 'O'; if (e->flags & MISC_FMT_CREDENTIALS) *dp++ = 'C'; |
948b701a6 binfmt_misc: add ... |
525 526 |
if (e->flags & MISC_FMT_OPEN_FILE) *dp++ = 'F'; |
e6084d4a0 binfmt_misc: clea... |
527 528 |
*dp++ = ' '; |
1da177e4c Linux-2.6.12-rc2 |
529 530 531 532 533 |
if (!test_bit(Magic, &e->flags)) { sprintf(dp, "extension .%s ", e->magic); } else { |
6ceafb880 fs/binfmt_misc.c:... |
534 535 536 |
dp += sprintf(dp, "offset %i magic ", e->offset); dp = bin2hex(dp, e->magic, e->size); |
1da177e4c Linux-2.6.12-rc2 |
537 |
if (e->mask) { |
6ceafb880 fs/binfmt_misc.c:... |
538 539 540 |
dp += sprintf(dp, " mask "); dp = bin2hex(dp, e->mask, e->size); |
1da177e4c Linux-2.6.12-rc2 |
541 542 543 544 545 546 547 548 549 |
} *dp++ = ' '; *dp = '\0'; } } static struct inode *bm_get_inode(struct super_block *sb, int mode) { |
e6084d4a0 binfmt_misc: clea... |
550 |
struct inode *inode = new_inode(sb); |
1da177e4c Linux-2.6.12-rc2 |
551 552 |
if (inode) { |
85fe4025c fs: do not assign... |
553 |
inode->i_ino = get_next_ino(); |
1da177e4c Linux-2.6.12-rc2 |
554 |
inode->i_mode = mode; |
1da177e4c Linux-2.6.12-rc2 |
555 |
inode->i_atime = inode->i_mtime = inode->i_ctime = |
c2050a454 fs: Replace curre... |
556 |
current_time(inode); |
1da177e4c Linux-2.6.12-rc2 |
557 558 559 |
} return inode; } |
b57922d97 convert remaining... |
560 |
static void bm_evict_inode(struct inode *inode) |
1da177e4c Linux-2.6.12-rc2 |
561 |
{ |
83f918274 exec: binfmt_misc... |
562 |
Node *e = inode->i_private; |
7e8660060 fs/binfmt_misc.c:... |
563 |
if (e && e->flags & MISC_FMT_OPEN_FILE) |
83f918274 exec: binfmt_misc... |
564 |
filp_close(e->interp_file, NULL); |
dbd5768f8 vfs: Rename end_w... |
565 |
clear_inode(inode); |
83f918274 exec: binfmt_misc... |
566 |
kfree(e); |
1da177e4c Linux-2.6.12-rc2 |
567 568 569 570 571 572 573 |
} static void kill_node(Node *e) { struct dentry *dentry; write_lock(&entries_lock); |
baba1b297 exec: binfmt_misc... |
574 |
list_del_init(&e->list); |
1da177e4c Linux-2.6.12-rc2 |
575 |
write_unlock(&entries_lock); |
baba1b297 exec: binfmt_misc... |
576 577 578 579 580 |
dentry = e->dentry; drop_nlink(d_inode(dentry)); d_drop(dentry); dput(dentry); simple_release_fs(&bm_mnt, &entry_count); |
1da177e4c Linux-2.6.12-rc2 |
581 582 583 584 585 |
} /* /<entry> */ static ssize_t |
e6084d4a0 binfmt_misc: clea... |
586 |
bm_entry_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) |
1da177e4c Linux-2.6.12-rc2 |
587 |
{ |
496ad9aa8 new helper: file_... |
588 |
Node *e = file_inode(file)->i_private; |
1da177e4c Linux-2.6.12-rc2 |
589 590 |
ssize_t res; char *page; |
1da177e4c Linux-2.6.12-rc2 |
591 |
|
e6084d4a0 binfmt_misc: clea... |
592 593 |
page = (char *) __get_free_page(GFP_KERNEL); if (!page) |
1da177e4c Linux-2.6.12-rc2 |
594 595 596 |
return -ENOMEM; entry_status(e, page); |
1da177e4c Linux-2.6.12-rc2 |
597 |
|
6e2c10a12 binfmt_misc: use ... |
598 |
res = simple_read_from_buffer(buf, nbytes, ppos, page, strlen(page)); |
1da177e4c Linux-2.6.12-rc2 |
599 600 601 602 603 604 605 606 |
free_page((unsigned long) page); return res; } static ssize_t bm_entry_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { struct dentry *root; |
496ad9aa8 new helper: file_... |
607 |
Node *e = file_inode(file)->i_private; |
1da177e4c Linux-2.6.12-rc2 |
608 609 610 |
int res = parse_command(buffer, count); switch (res) { |
e6084d4a0 binfmt_misc: clea... |
611 612 613 614 615 616 617 618 619 620 |
case 1: /* Disable this handler. */ clear_bit(Enabled, &e->flags); break; case 2: /* Enable this handler. */ set_bit(Enabled, &e->flags); break; case 3: /* Delete this handler. */ |
ea7d4c046 binfmt_misc: ->s_... |
621 |
root = file_inode(file)->i_sb->s_root; |
5955102c9 wrappers for ->i_... |
622 |
inode_lock(d_inode(root)); |
1da177e4c Linux-2.6.12-rc2 |
623 |
|
baba1b297 exec: binfmt_misc... |
624 625 |
if (!list_empty(&e->list)) kill_node(e); |
1da177e4c Linux-2.6.12-rc2 |
626 |
|
5955102c9 wrappers for ->i_... |
627 |
inode_unlock(d_inode(root)); |
e6084d4a0 binfmt_misc: clea... |
628 629 630 |
break; default: return res; |
1da177e4c Linux-2.6.12-rc2 |
631 |
} |
e6084d4a0 binfmt_misc: clea... |
632 |
|
1da177e4c Linux-2.6.12-rc2 |
633 634 |
return count; } |
4b6f5d20b [PATCH] Make most... |
635 |
static const struct file_operations bm_entry_operations = { |
1da177e4c Linux-2.6.12-rc2 |
636 637 |
.read = bm_entry_read, .write = bm_entry_write, |
6038f373a llseek: automatic... |
638 |
.llseek = default_llseek, |
1da177e4c Linux-2.6.12-rc2 |
639 640 641 642 643 644 645 646 647 |
}; /* /register */ static ssize_t bm_register_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { Node *e; struct inode *inode; |
ea7d4c046 binfmt_misc: ->s_... |
648 649 |
struct super_block *sb = file_inode(file)->i_sb; struct dentry *root = sb->s_root, *dentry; |
1da177e4c Linux-2.6.12-rc2 |
650 651 652 653 654 655 |
int err = 0; e = create_entry(buffer, count); if (IS_ERR(e)) return PTR_ERR(e); |
5955102c9 wrappers for ->i_... |
656 |
inode_lock(d_inode(root)); |
1da177e4c Linux-2.6.12-rc2 |
657 658 659 660 661 662 |
dentry = lookup_one_len(e->name, root, strlen(e->name)); err = PTR_ERR(dentry); if (IS_ERR(dentry)) goto out; err = -EEXIST; |
75c3cfa85 VFS: assorted wei... |
663 |
if (d_really_is_positive(dentry)) |
1da177e4c Linux-2.6.12-rc2 |
664 665 666 667 668 669 670 |
goto out2; inode = bm_get_inode(sb, S_IFREG | 0644); err = -ENOMEM; if (!inode) goto out2; |
1f5ce9e93 VFS: Unexport do_... |
671 |
err = simple_pin_fs(&bm_fs_type, &bm_mnt, &entry_count); |
1da177e4c Linux-2.6.12-rc2 |
672 673 674 675 676 |
if (err) { iput(inode); inode = NULL; goto out2; } |
948b701a6 binfmt_misc: add ... |
677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 |
if (e->flags & MISC_FMT_OPEN_FILE) { struct file *f; f = open_exec(e->interpreter); if (IS_ERR(f)) { err = PTR_ERR(f); pr_notice("register: failed to install interpreter file %s ", e->interpreter); simple_release_fs(&bm_mnt, &entry_count); iput(inode); inode = NULL; goto out2; } e->interp_file = f; } |
1da177e4c Linux-2.6.12-rc2 |
692 |
e->dentry = dget(dentry); |
8e18e2941 [PATCH] inode_die... |
693 |
inode->i_private = e; |
1da177e4c Linux-2.6.12-rc2 |
694 695 696 697 698 699 700 701 702 703 704 |
inode->i_fop = &bm_entry_operations; d_instantiate(dentry, inode); write_lock(&entries_lock); list_add(&e->list, &entries); write_unlock(&entries_lock); err = 0; out2: dput(dentry); out: |
5955102c9 wrappers for ->i_... |
705 |
inode_unlock(d_inode(root)); |
1da177e4c Linux-2.6.12-rc2 |
706 707 708 |
if (err) { kfree(e); |
948b701a6 binfmt_misc: add ... |
709 |
return err; |
1da177e4c Linux-2.6.12-rc2 |
710 711 712 |
} return count; } |
4b6f5d20b [PATCH] Make most... |
713 |
static const struct file_operations bm_register_operations = { |
1da177e4c Linux-2.6.12-rc2 |
714 |
.write = bm_register_write, |
6038f373a llseek: automatic... |
715 |
.llseek = noop_llseek, |
1da177e4c Linux-2.6.12-rc2 |
716 717 718 719 720 721 722 |
}; /* /status */ static ssize_t bm_status_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) { |
87113e806 fs/binfmt_misc.c:... |
723 724 725 |
char *s = enabled ? "enabled " : "disabled "; |
1da177e4c Linux-2.6.12-rc2 |
726 |
|
92f4c701a use simple_read_f... |
727 |
return simple_read_from_buffer(buf, nbytes, ppos, s, strlen(s)); |
1da177e4c Linux-2.6.12-rc2 |
728 |
} |
e6084d4a0 binfmt_misc: clea... |
729 |
static ssize_t bm_status_write(struct file *file, const char __user *buffer, |
1da177e4c Linux-2.6.12-rc2 |
730 731 732 733 734 735 |
size_t count, loff_t *ppos) { int res = parse_command(buffer, count); struct dentry *root; switch (res) { |
e6084d4a0 binfmt_misc: clea... |
736 737 738 739 740 741 742 743 744 745 |
case 1: /* Disable all handlers. */ enabled = 0; break; case 2: /* Enable all handlers. */ enabled = 1; break; case 3: /* Delete all handlers. */ |
ea7d4c046 binfmt_misc: ->s_... |
746 |
root = file_inode(file)->i_sb->s_root; |
5955102c9 wrappers for ->i_... |
747 |
inode_lock(d_inode(root)); |
1da177e4c Linux-2.6.12-rc2 |
748 |
|
e6084d4a0 binfmt_misc: clea... |
749 |
while (!list_empty(&entries)) |
baba1b297 exec: binfmt_misc... |
750 |
kill_node(list_first_entry(&entries, Node, list)); |
1da177e4c Linux-2.6.12-rc2 |
751 |
|
5955102c9 wrappers for ->i_... |
752 |
inode_unlock(d_inode(root)); |
e6084d4a0 binfmt_misc: clea... |
753 754 755 |
break; default: return res; |
1da177e4c Linux-2.6.12-rc2 |
756 |
} |
e6084d4a0 binfmt_misc: clea... |
757 |
|
1da177e4c Linux-2.6.12-rc2 |
758 759 |
return count; } |
4b6f5d20b [PATCH] Make most... |
760 |
static const struct file_operations bm_status_operations = { |
1da177e4c Linux-2.6.12-rc2 |
761 762 |
.read = bm_status_read, .write = bm_status_write, |
6038f373a llseek: automatic... |
763 |
.llseek = default_llseek, |
1da177e4c Linux-2.6.12-rc2 |
764 765 766 |
}; /* Superblock handling */ |
ee9b6d61a [PATCH] Mark stru... |
767 |
static const struct super_operations s_ops = { |
1da177e4c Linux-2.6.12-rc2 |
768 |
.statfs = simple_statfs, |
b57922d97 convert remaining... |
769 |
.evict_inode = bm_evict_inode, |
1da177e4c Linux-2.6.12-rc2 |
770 |
}; |
bc99a664e vfs: Convert binf... |
771 |
static int bm_fill_super(struct super_block *sb, struct fs_context *fc) |
1da177e4c Linux-2.6.12-rc2 |
772 |
{ |
e6084d4a0 binfmt_misc: clea... |
773 |
int err; |
cda37124f fs: constify tree... |
774 |
static const struct tree_descr bm_files[] = { |
1a1c9bb43 inode numbering: ... |
775 776 |
[2] = {"status", &bm_status_operations, S_IWUSR|S_IRUGO}, [3] = {"register", &bm_register_operations, S_IWUSR}, |
1da177e4c Linux-2.6.12-rc2 |
777 778 |
/* last one */ {""} }; |
e6084d4a0 binfmt_misc: clea... |
779 780 |
err = simple_fill_super(sb, BINFMTFS_MAGIC, bm_files); |
1da177e4c Linux-2.6.12-rc2 |
781 782 783 784 |
if (!err) sb->s_op = &s_ops; return err; } |
bc99a664e vfs: Convert binf... |
785 |
static int bm_get_tree(struct fs_context *fc) |
1da177e4c Linux-2.6.12-rc2 |
786 |
{ |
bc99a664e vfs: Convert binf... |
787 788 789 790 791 792 793 794 795 796 797 |
return get_tree_single(fc, bm_fill_super); } static const struct fs_context_operations bm_context_ops = { .get_tree = bm_get_tree, }; static int bm_init_fs_context(struct fs_context *fc) { fc->ops = &bm_context_ops; return 0; |
1da177e4c Linux-2.6.12-rc2 |
798 799 800 801 802 803 804 805 806 807 |
} static struct linux_binfmt misc_format = { .module = THIS_MODULE, .load_binary = load_misc_binary, }; static struct file_system_type bm_fs_type = { .owner = THIS_MODULE, .name = "binfmt_misc", |
bc99a664e vfs: Convert binf... |
808 |
.init_fs_context = bm_init_fs_context, |
1da177e4c Linux-2.6.12-rc2 |
809 810 |
.kill_sb = kill_litter_super, }; |
7f78e0351 fs: Limit sys_mou... |
811 |
MODULE_ALIAS_FS("binfmt_misc"); |
1da177e4c Linux-2.6.12-rc2 |
812 813 814 815 |
static int __init init_misc_binfmt(void) { int err = register_filesystem(&bm_fs_type); |
8fc3dc5a3 __register_binfmt... |
816 817 |
if (!err) insert_binfmt(&misc_format); |
1da177e4c Linux-2.6.12-rc2 |
818 819 820 821 822 823 824 825 826 827 828 829 |
return err; } static void __exit exit_misc_binfmt(void) { unregister_binfmt(&misc_format); unregister_filesystem(&bm_fs_type); } core_initcall(init_misc_binfmt); module_exit(exit_misc_binfmt); MODULE_LICENSE("GPL"); |