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