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> |
e8edc6e03 Detach sched.h fr... |
13 |
#include <linux/sched.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 54 55 56 |
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 */ char *interpreter; /* filename of interpreter */ 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 |
char iname[BINPRM_BUF_SIZE]; |
d7627467b Make do_execve() ... |
127 |
const char *iname_addr = iname; |
1da177e4c Linux-2.6.12-rc2 |
128 129 |
int retval; int fd_binary = -1; |
1da177e4c Linux-2.6.12-rc2 |
130 131 132 |
retval = -ENOEXEC; if (!enabled) |
e6084d4a0 binfmt_misc: clea... |
133 |
goto ret; |
1da177e4c Linux-2.6.12-rc2 |
134 135 136 137 138 139 140 141 |
/* to keep locking time low, we copy the interpreter string */ read_lock(&entries_lock); fmt = check_file(bprm); if (fmt) strlcpy(iname, fmt->interpreter, BINPRM_BUF_SIZE); read_unlock(&entries_lock); if (!fmt) |
e6084d4a0 binfmt_misc: clea... |
142 |
goto ret; |
1da177e4c Linux-2.6.12-rc2 |
143 |
|
51f39a1f0 syscalls: impleme... |
144 145 146 |
/* Need to be able to load the file after exec */ if (bprm->interp_flags & BINPRM_FLAGS_PATH_INACCESSIBLE) return -ENOENT; |
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] */ |
e6084d4a0 binfmt_misc: clea... |
187 |
retval = copy_strings_kernel(1, &iname_addr, 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 193 194 |
/* Update interp in case binfmt_script needs it. */ retval = bprm_change_interp(iname, bprm); if (retval < 0) |
e6084d4a0 binfmt_misc: clea... |
195 |
goto error; |
1da177e4c Linux-2.6.12-rc2 |
196 |
|
948b701a6 binfmt_misc: add ... |
197 198 199 200 201 202 203 |
if (fmt->flags & MISC_FMT_OPEN_FILE && fmt->interp_file) { interp_file = filp_clone_open(fmt->interp_file); if (!IS_ERR(interp_file)) deny_write_access(interp_file); } else { interp_file = open_exec(iname); } |
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 210 211 212 213 214 215 216 |
bprm->file = interp_file; if (fmt->flags & MISC_FMT_CREDENTIALS) { /* * 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); retval = kernel_read(bprm->file, 0, bprm->buf, BINPRM_BUF_SIZE); } else |
e6084d4a0 binfmt_misc: clea... |
217 |
retval = prepare_binprm(bprm); |
1da177e4c Linux-2.6.12-rc2 |
218 219 |
if (retval < 0) |
e6084d4a0 binfmt_misc: clea... |
220 |
goto error; |
1da177e4c Linux-2.6.12-rc2 |
221 |
|
3c456bfc4 get rid of pt_reg... |
222 |
retval = search_binary_handler(bprm); |
1da177e4c Linux-2.6.12-rc2 |
223 |
if (retval < 0) |
e6084d4a0 binfmt_misc: clea... |
224 |
goto error; |
1da177e4c Linux-2.6.12-rc2 |
225 |
|
e6084d4a0 binfmt_misc: clea... |
226 |
ret: |
1da177e4c Linux-2.6.12-rc2 |
227 |
return retval; |
e6084d4a0 binfmt_misc: clea... |
228 |
error: |
1da177e4c Linux-2.6.12-rc2 |
229 230 231 232 |
if (fd_binary > 0) sys_close(fd_binary); bprm->interp_flags = 0; bprm->interp_data = 0; |
e6084d4a0 binfmt_misc: clea... |
233 |
goto ret; |
1da177e4c Linux-2.6.12-rc2 |
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 |
} /* 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... |
257 |
s[-1] ='\0'; |
1da177e4c Linux-2.6.12-rc2 |
258 259 |
return s; } |
e6084d4a0 binfmt_misc: clea... |
260 |
static char *check_special_flags(char *sfs, Node *e) |
1da177e4c Linux-2.6.12-rc2 |
261 |
{ |
e6084d4a0 binfmt_misc: clea... |
262 |
char *p = sfs; |
1da177e4c Linux-2.6.12-rc2 |
263 264 265 266 267 |
int cont = 1; /* special flags */ while (cont) { switch (*p) { |
e6084d4a0 binfmt_misc: clea... |
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 |
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 ... |
289 290 291 292 293 294 |
case 'F': pr_debug("register: flag: F: open interpreter file now "); p++; e->flags |= MISC_FMT_OPEN_FILE; break; |
e6084d4a0 binfmt_misc: clea... |
295 296 |
default: cont = 0; |
1da177e4c Linux-2.6.12-rc2 |
297 298 299 300 301 |
} } return p; } |
e6084d4a0 binfmt_misc: clea... |
302 |
|
1da177e4c Linux-2.6.12-rc2 |
303 304 305 306 307 308 309 310 311 312 313 |
/* * 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 ... |
314 315 |
pr_debug("register: received %zu bytes ", count); |
1da177e4c Linux-2.6.12-rc2 |
316 317 |
/* some sanity checks */ err = -EINVAL; |
bbaecc088 binfmt_misc: expa... |
318 |
if ((count < 11) || (count > MAX_REGISTER_LENGTH)) |
1da177e4c Linux-2.6.12-rc2 |
319 320 321 322 |
goto out; err = -ENOMEM; memsize = sizeof(Node) + count + 8; |
f7e1ad1a1 fs/binfmt_misc.c:... |
323 |
e = kmalloc(memsize, GFP_KERNEL); |
1da177e4c Linux-2.6.12-rc2 |
324 325 326 327 328 329 330 |
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... |
331 |
goto efault; |
1da177e4c Linux-2.6.12-rc2 |
332 333 |
del = *p++; /* delimeter */ |
6b899c4e9 binfmt_misc: add ... |
334 335 336 337 |
pr_debug("register: delim: %#x {%c} ", del, del); /* Pad the buffer with the delim to simplify parsing below. */ |
e6084d4a0 binfmt_misc: clea... |
338 |
memset(buf + count, del, 8); |
1da177e4c Linux-2.6.12-rc2 |
339 |
|
6b899c4e9 binfmt_misc: add ... |
340 |
/* Parse the 'name' field. */ |
1da177e4c Linux-2.6.12-rc2 |
341 342 343 |
e->name = p; p = strchr(p, del); if (!p) |
e6084d4a0 binfmt_misc: clea... |
344 |
goto einval; |
1da177e4c Linux-2.6.12-rc2 |
345 346 347 348 349 |
*p++ = '\0'; if (!e->name[0] || !strcmp(e->name, ".") || !strcmp(e->name, "..") || strchr(e->name, '/')) |
e6084d4a0 binfmt_misc: clea... |
350 |
goto einval; |
6b899c4e9 binfmt_misc: add ... |
351 352 353 354 355 |
pr_debug("register: name: {%s} ", e->name); /* Parse the 'type' field. */ |
1da177e4c Linux-2.6.12-rc2 |
356 |
switch (*p++) { |
6b899c4e9 binfmt_misc: add ... |
357 358 359 360 361 362 363 364 365 366 367 |
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... |
368 |
goto einval; |
1da177e4c Linux-2.6.12-rc2 |
369 370 |
} if (*p++ != del) |
e6084d4a0 binfmt_misc: clea... |
371 |
goto einval; |
6b899c4e9 binfmt_misc: add ... |
372 |
|
1da177e4c Linux-2.6.12-rc2 |
373 |
if (test_bit(Magic, &e->flags)) { |
6b899c4e9 binfmt_misc: add ... |
374 375 376 377 378 |
/* Handle the 'M' (magic) format. */ char *s; /* Parse the 'offset' field. */ s = strchr(p, del); |
1da177e4c Linux-2.6.12-rc2 |
379 |
if (!s) |
e6084d4a0 binfmt_misc: clea... |
380 |
goto einval; |
1da177e4c Linux-2.6.12-rc2 |
381 382 383 |
*s++ = '\0'; e->offset = simple_strtoul(p, &p, 10); if (*p++) |
e6084d4a0 binfmt_misc: clea... |
384 |
goto einval; |
6b899c4e9 binfmt_misc: add ... |
385 386 387 388 |
pr_debug("register: offset: %#x ", e->offset); /* Parse the 'magic' field. */ |
1da177e4c Linux-2.6.12-rc2 |
389 390 391 |
e->magic = p; p = scanarg(p, del); if (!p) |
e6084d4a0 binfmt_misc: clea... |
392 |
goto einval; |
7d65cf10e unfuck binfmt_mis... |
393 |
if (!e->magic[0]) |
e6084d4a0 binfmt_misc: clea... |
394 |
goto einval; |
6b899c4e9 binfmt_misc: add ... |
395 396 397 398 399 400 |
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 |
401 402 403 |
e->mask = p; p = scanarg(p, del); if (!p) |
e6084d4a0 binfmt_misc: clea... |
404 |
goto einval; |
7d65cf10e unfuck binfmt_mis... |
405 |
if (!e->mask[0]) { |
1da177e4c Linux-2.6.12-rc2 |
406 |
e->mask = NULL; |
6b899c4e9 binfmt_misc: add ... |
407 408 409 410 411 412 413 414 415 416 417 418 419 |
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... |
420 421 422 |
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... |
423 |
goto einval; |
1da177e4c Linux-2.6.12-rc2 |
424 |
if (e->size + e->offset > BINPRM_BUF_SIZE) |
e6084d4a0 binfmt_misc: clea... |
425 |
goto einval; |
6b899c4e9 binfmt_misc: add ... |
426 427 428 429 430 431 432 433 434 |
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:... |
435 |
char *masked = kmalloc(e->size, GFP_KERNEL); |
6b899c4e9 binfmt_misc: add ... |
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 |
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 |
452 |
} else { |
6b899c4e9 binfmt_misc: add ... |
453 454 455 |
/* Handle the 'E' (extension) format. */ /* Skip the 'offset' field. */ |
1da177e4c Linux-2.6.12-rc2 |
456 457 |
p = strchr(p, del); if (!p) |
e6084d4a0 binfmt_misc: clea... |
458 |
goto einval; |
1da177e4c Linux-2.6.12-rc2 |
459 |
*p++ = '\0'; |
6b899c4e9 binfmt_misc: add ... |
460 461 |
/* Parse the 'magic' field. */ |
1da177e4c Linux-2.6.12-rc2 |
462 463 464 |
e->magic = p; p = strchr(p, del); if (!p) |
e6084d4a0 binfmt_misc: clea... |
465 |
goto einval; |
1da177e4c Linux-2.6.12-rc2 |
466 467 |
*p++ = '\0'; if (!e->magic[0] || strchr(e->magic, '/')) |
e6084d4a0 binfmt_misc: clea... |
468 |
goto einval; |
6b899c4e9 binfmt_misc: add ... |
469 470 471 472 |
pr_debug("register: extension: {%s} ", e->magic); /* Skip the 'mask' field. */ |
1da177e4c Linux-2.6.12-rc2 |
473 474 |
p = strchr(p, del); if (!p) |
e6084d4a0 binfmt_misc: clea... |
475 |
goto einval; |
1da177e4c Linux-2.6.12-rc2 |
476 477 |
*p++ = '\0'; } |
6b899c4e9 binfmt_misc: add ... |
478 479 |
/* Parse the 'interpreter' field. */ |
1da177e4c Linux-2.6.12-rc2 |
480 481 482 |
e->interpreter = p; p = strchr(p, del); if (!p) |
e6084d4a0 binfmt_misc: clea... |
483 |
goto einval; |
1da177e4c Linux-2.6.12-rc2 |
484 485 |
*p++ = '\0'; if (!e->interpreter[0]) |
e6084d4a0 binfmt_misc: clea... |
486 |
goto einval; |
6b899c4e9 binfmt_misc: add ... |
487 488 |
pr_debug("register: interpreter: {%s} ", e->interpreter); |
1da177e4c Linux-2.6.12-rc2 |
489 |
|
6b899c4e9 binfmt_misc: add ... |
490 |
/* Parse the 'flags' field. */ |
e6084d4a0 binfmt_misc: clea... |
491 |
p = check_special_flags(p, e); |
1da177e4c Linux-2.6.12-rc2 |
492 493 494 495 |
if (*p == ' ') p++; if (p != buf + count) |
e6084d4a0 binfmt_misc: clea... |
496 |
goto einval; |
1da177e4c Linux-2.6.12-rc2 |
497 498 499 500 |
return e; out: return ERR_PTR(err); |
e6084d4a0 binfmt_misc: clea... |
501 |
efault: |
1da177e4c Linux-2.6.12-rc2 |
502 503 |
kfree(e); return ERR_PTR(-EFAULT); |
e6084d4a0 binfmt_misc: clea... |
504 |
einval: |
1da177e4c Linux-2.6.12-rc2 |
505 506 507 508 509 510 511 512 513 514 515 |
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 |
516 517 518 519 |
if (count > 3) return -EINVAL; if (copy_from_user(s, buffer, count)) return -EFAULT; |
de8288b1f binfmt_misc: work... |
520 521 |
if (!count) return 0; |
e6084d4a0 binfmt_misc: clea... |
522 523 |
if (s[count - 1] == ' ') |
1da177e4c Linux-2.6.12-rc2 |
524 525 526 527 528 529 530 531 532 533 534 535 536 537 |
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:... |
538 539 |
char *dp = page; const char *status = "disabled"; |
1da177e4c Linux-2.6.12-rc2 |
540 541 542 543 544 545 546 547 548 |
if (test_bit(Enabled, &e->flags)) status = "enabled"; if (!VERBOSE_STATUS) { sprintf(page, "%s ", status); return; } |
6ceafb880 fs/binfmt_misc.c:... |
549 550 551 |
dp += sprintf(dp, "%s interpreter %s ", status, e->interpreter); |
1da177e4c Linux-2.6.12-rc2 |
552 553 |
/* print the special flags */ |
6ceafb880 fs/binfmt_misc.c:... |
554 |
dp += sprintf(dp, "flags: "); |
e6084d4a0 binfmt_misc: clea... |
555 556 557 558 559 560 |
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 ... |
561 562 |
if (e->flags & MISC_FMT_OPEN_FILE) *dp++ = 'F'; |
e6084d4a0 binfmt_misc: clea... |
563 564 |
*dp++ = ' '; |
1da177e4c Linux-2.6.12-rc2 |
565 566 567 568 569 |
if (!test_bit(Magic, &e->flags)) { sprintf(dp, "extension .%s ", e->magic); } else { |
6ceafb880 fs/binfmt_misc.c:... |
570 571 572 |
dp += sprintf(dp, "offset %i magic ", e->offset); dp = bin2hex(dp, e->magic, e->size); |
1da177e4c Linux-2.6.12-rc2 |
573 |
if (e->mask) { |
6ceafb880 fs/binfmt_misc.c:... |
574 575 576 |
dp += sprintf(dp, " mask "); dp = bin2hex(dp, e->mask, e->size); |
1da177e4c Linux-2.6.12-rc2 |
577 578 579 580 581 582 583 584 585 |
} *dp++ = ' '; *dp = '\0'; } } static struct inode *bm_get_inode(struct super_block *sb, int mode) { |
e6084d4a0 binfmt_misc: clea... |
586 |
struct inode *inode = new_inode(sb); |
1da177e4c Linux-2.6.12-rc2 |
587 588 |
if (inode) { |
85fe4025c fs: do not assign... |
589 |
inode->i_ino = get_next_ino(); |
1da177e4c Linux-2.6.12-rc2 |
590 |
inode->i_mode = mode; |
1da177e4c Linux-2.6.12-rc2 |
591 |
inode->i_atime = inode->i_mtime = inode->i_ctime = |
c2050a454 fs: Replace curre... |
592 |
current_time(inode); |
1da177e4c Linux-2.6.12-rc2 |
593 594 595 |
} return inode; } |
b57922d97 convert remaining... |
596 |
static void bm_evict_inode(struct inode *inode) |
1da177e4c Linux-2.6.12-rc2 |
597 |
{ |
dbd5768f8 vfs: Rename end_w... |
598 |
clear_inode(inode); |
8e18e2941 [PATCH] inode_die... |
599 |
kfree(inode->i_private); |
1da177e4c Linux-2.6.12-rc2 |
600 601 602 603 604 605 606 607 608 609 610 611 612 |
} static void kill_node(Node *e) { struct dentry *dentry; write_lock(&entries_lock); dentry = e->dentry; if (dentry) { list_del_init(&e->list); e->dentry = NULL; } write_unlock(&entries_lock); |
948b701a6 binfmt_misc: add ... |
613 614 615 616 |
if ((e->flags & MISC_FMT_OPEN_FILE) && e->interp_file) { filp_close(e->interp_file, NULL); e->interp_file = NULL; } |
1da177e4c Linux-2.6.12-rc2 |
617 |
if (dentry) { |
75c3cfa85 VFS: assorted wei... |
618 |
drop_nlink(d_inode(dentry)); |
1da177e4c Linux-2.6.12-rc2 |
619 620 621 622 623 624 625 626 627 |
d_drop(dentry); dput(dentry); simple_release_fs(&bm_mnt, &entry_count); } } /* /<entry> */ static ssize_t |
e6084d4a0 binfmt_misc: clea... |
628 |
bm_entry_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) |
1da177e4c Linux-2.6.12-rc2 |
629 |
{ |
496ad9aa8 new helper: file_... |
630 |
Node *e = file_inode(file)->i_private; |
1da177e4c Linux-2.6.12-rc2 |
631 632 |
ssize_t res; char *page; |
1da177e4c Linux-2.6.12-rc2 |
633 |
|
e6084d4a0 binfmt_misc: clea... |
634 635 |
page = (char *) __get_free_page(GFP_KERNEL); if (!page) |
1da177e4c Linux-2.6.12-rc2 |
636 637 638 |
return -ENOMEM; entry_status(e, page); |
1da177e4c Linux-2.6.12-rc2 |
639 |
|
6e2c10a12 binfmt_misc: use ... |
640 |
res = simple_read_from_buffer(buf, nbytes, ppos, page, strlen(page)); |
1da177e4c Linux-2.6.12-rc2 |
641 642 643 644 645 646 647 648 |
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_... |
649 |
Node *e = file_inode(file)->i_private; |
1da177e4c Linux-2.6.12-rc2 |
650 651 652 |
int res = parse_command(buffer, count); switch (res) { |
e6084d4a0 binfmt_misc: clea... |
653 654 655 656 657 658 659 660 661 662 |
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_... |
663 |
root = file_inode(file)->i_sb->s_root; |
5955102c9 wrappers for ->i_... |
664 |
inode_lock(d_inode(root)); |
1da177e4c Linux-2.6.12-rc2 |
665 |
|
e6084d4a0 binfmt_misc: clea... |
666 |
kill_node(e); |
1da177e4c Linux-2.6.12-rc2 |
667 |
|
5955102c9 wrappers for ->i_... |
668 |
inode_unlock(d_inode(root)); |
e6084d4a0 binfmt_misc: clea... |
669 670 671 |
break; default: return res; |
1da177e4c Linux-2.6.12-rc2 |
672 |
} |
e6084d4a0 binfmt_misc: clea... |
673 |
|
1da177e4c Linux-2.6.12-rc2 |
674 675 |
return count; } |
4b6f5d20b [PATCH] Make most... |
676 |
static const struct file_operations bm_entry_operations = { |
1da177e4c Linux-2.6.12-rc2 |
677 678 |
.read = bm_entry_read, .write = bm_entry_write, |
6038f373a llseek: automatic... |
679 |
.llseek = default_llseek, |
1da177e4c Linux-2.6.12-rc2 |
680 681 682 683 684 685 686 687 688 |
}; /* /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_... |
689 690 |
struct super_block *sb = file_inode(file)->i_sb; struct dentry *root = sb->s_root, *dentry; |
1da177e4c Linux-2.6.12-rc2 |
691 692 693 694 695 696 |
int err = 0; e = create_entry(buffer, count); if (IS_ERR(e)) return PTR_ERR(e); |
5955102c9 wrappers for ->i_... |
697 |
inode_lock(d_inode(root)); |
1da177e4c Linux-2.6.12-rc2 |
698 699 700 701 702 703 |
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... |
704 |
if (d_really_is_positive(dentry)) |
1da177e4c Linux-2.6.12-rc2 |
705 706 707 708 709 710 711 |
goto out2; inode = bm_get_inode(sb, S_IFREG | 0644); err = -ENOMEM; if (!inode) goto out2; |
1f5ce9e93 VFS: Unexport do_... |
712 |
err = simple_pin_fs(&bm_fs_type, &bm_mnt, &entry_count); |
1da177e4c Linux-2.6.12-rc2 |
713 714 715 716 717 |
if (err) { iput(inode); inode = NULL; goto out2; } |
948b701a6 binfmt_misc: add ... |
718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 |
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 |
733 |
e->dentry = dget(dentry); |
8e18e2941 [PATCH] inode_die... |
734 |
inode->i_private = e; |
1da177e4c Linux-2.6.12-rc2 |
735 736 737 738 739 740 741 742 743 744 745 |
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_... |
746 |
inode_unlock(d_inode(root)); |
1da177e4c Linux-2.6.12-rc2 |
747 748 749 |
if (err) { kfree(e); |
948b701a6 binfmt_misc: add ... |
750 |
return err; |
1da177e4c Linux-2.6.12-rc2 |
751 752 753 |
} return count; } |
4b6f5d20b [PATCH] Make most... |
754 |
static const struct file_operations bm_register_operations = { |
1da177e4c Linux-2.6.12-rc2 |
755 |
.write = bm_register_write, |
6038f373a llseek: automatic... |
756 |
.llseek = noop_llseek, |
1da177e4c Linux-2.6.12-rc2 |
757 758 759 760 761 762 763 |
}; /* /status */ static ssize_t bm_status_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) { |
87113e806 fs/binfmt_misc.c:... |
764 765 766 |
char *s = enabled ? "enabled " : "disabled "; |
1da177e4c Linux-2.6.12-rc2 |
767 |
|
92f4c701a use simple_read_f... |
768 |
return simple_read_from_buffer(buf, nbytes, ppos, s, strlen(s)); |
1da177e4c Linux-2.6.12-rc2 |
769 |
} |
e6084d4a0 binfmt_misc: clea... |
770 |
static ssize_t bm_status_write(struct file *file, const char __user *buffer, |
1da177e4c Linux-2.6.12-rc2 |
771 772 773 774 775 776 |
size_t count, loff_t *ppos) { int res = parse_command(buffer, count); struct dentry *root; switch (res) { |
e6084d4a0 binfmt_misc: clea... |
777 778 779 780 781 782 783 784 785 786 |
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_... |
787 |
root = file_inode(file)->i_sb->s_root; |
5955102c9 wrappers for ->i_... |
788 |
inode_lock(d_inode(root)); |
1da177e4c Linux-2.6.12-rc2 |
789 |
|
e6084d4a0 binfmt_misc: clea... |
790 791 |
while (!list_empty(&entries)) kill_node(list_entry(entries.next, Node, list)); |
1da177e4c Linux-2.6.12-rc2 |
792 |
|
5955102c9 wrappers for ->i_... |
793 |
inode_unlock(d_inode(root)); |
e6084d4a0 binfmt_misc: clea... |
794 795 796 |
break; default: return res; |
1da177e4c Linux-2.6.12-rc2 |
797 |
} |
e6084d4a0 binfmt_misc: clea... |
798 |
|
1da177e4c Linux-2.6.12-rc2 |
799 800 |
return count; } |
4b6f5d20b [PATCH] Make most... |
801 |
static const struct file_operations bm_status_operations = { |
1da177e4c Linux-2.6.12-rc2 |
802 803 |
.read = bm_status_read, .write = bm_status_write, |
6038f373a llseek: automatic... |
804 |
.llseek = default_llseek, |
1da177e4c Linux-2.6.12-rc2 |
805 806 807 |
}; /* Superblock handling */ |
ee9b6d61a [PATCH] Mark stru... |
808 |
static const struct super_operations s_ops = { |
1da177e4c Linux-2.6.12-rc2 |
809 |
.statfs = simple_statfs, |
b57922d97 convert remaining... |
810 |
.evict_inode = bm_evict_inode, |
1da177e4c Linux-2.6.12-rc2 |
811 |
}; |
e6084d4a0 binfmt_misc: clea... |
812 |
static int bm_fill_super(struct super_block *sb, void *data, int silent) |
1da177e4c Linux-2.6.12-rc2 |
813 |
{ |
e6084d4a0 binfmt_misc: clea... |
814 |
int err; |
1da177e4c Linux-2.6.12-rc2 |
815 |
static struct tree_descr bm_files[] = { |
1a1c9bb43 inode numbering: ... |
816 817 |
[2] = {"status", &bm_status_operations, S_IWUSR|S_IRUGO}, [3] = {"register", &bm_register_operations, S_IWUSR}, |
1da177e4c Linux-2.6.12-rc2 |
818 819 |
/* last one */ {""} }; |
e6084d4a0 binfmt_misc: clea... |
820 821 |
err = simple_fill_super(sb, BINFMTFS_MAGIC, bm_files); |
1da177e4c Linux-2.6.12-rc2 |
822 823 824 825 |
if (!err) sb->s_op = &s_ops; return err; } |
fc14f2fef convert get_sb_si... |
826 827 |
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 |
828 |
{ |
fc14f2fef convert get_sb_si... |
829 |
return mount_single(fs_type, flags, data, bm_fill_super); |
1da177e4c Linux-2.6.12-rc2 |
830 831 832 833 834 835 836 837 838 839 |
} 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... |
840 |
.mount = bm_mount, |
1da177e4c Linux-2.6.12-rc2 |
841 842 |
.kill_sb = kill_litter_super, }; |
7f78e0351 fs: Limit sys_mou... |
843 |
MODULE_ALIAS_FS("binfmt_misc"); |
1da177e4c Linux-2.6.12-rc2 |
844 845 846 847 |
static int __init init_misc_binfmt(void) { int err = register_filesystem(&bm_fs_type); |
8fc3dc5a3 __register_binfmt... |
848 849 |
if (!err) insert_binfmt(&misc_format); |
1da177e4c Linux-2.6.12-rc2 |
850 851 852 853 854 855 856 857 858 859 860 861 |
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"); |