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