ãµã¨ openSUSE 13.1 ã install ãã¦ã¿ããlsb_release ã® Description 㨠/etc/os-release ã® PRETTY_NAME ã¯ä¸è´ãã¦ããããã ã
% lsb_release -a LSB Version: n/a Distributor ID: openSUSE project Description: openSUSE 13.1 (Bottle) (x86_64) Release: 13.1 Codename: Bottle % cat /etc/os-release NAME=openSUSE VERSION="13.1 (Bottle)" VERSION_ID="13.1" PRETTY_NAME="openSUSE 13.1 (Bottle) (x86_64)" ID=opensuse ANSI_COLOR="0;32" CPE_NAME="cpe:/o:opensuse:opensuse:13.1" BUG_REPORT_URL="https://bugs.opensuse.org" HOME_URL="https://opensuse.org/" ID_LIKE="suse"
ãªãããµã¼ã (ããã¹ãç°å¢) ãã¤ã³ã¹ãã¼ã«ããã®ã ããlsb_release ã¯ãªãã£ãã®ã§ãzypper install lsb-release ã¨ã㦠lsb-release ããã±ã¼ã¸ãã¤ã³ã¹ãã¼ã«ããã
ã¾ãã/etc/SuSE-release 㨠/etc/SUSE-brand ã¨ãããã®ããã£ãã
% cat /etc/SuSE-release openSUSE 13.1 (x86_64) VERSION = 13.1 CODENAME = Bottle # /etc/SuSE-release is deprecated and will be removed in the future, use /etc/os-release instead % cat /etc/SUSE-brand openSUSE VERSION = 13.1
Ruby 㧠system, spawn ã¡ã½ãããªã©ã³ãã³ããèµ·åããã¨ããã« vfork ã·ã¹ãã ã³ã¼ã«ã使ã£ã¦ã¿ãã (ç¾å¨ã® trunk ã«å ¥ã£ã¦ãããæ¶ãããªããã° Ruby 2.2 ã«å ¥ãã)
vfork ã¨ããã®ã¯å±éºã ããã©éã fork ã·ã¹ãã ã³ã¼ã«ã§ããã
Unix ã«ãããã³ãã³ãã®èµ·åã¯ãã¾ã親ããã»ã¹ã fork ã§ããã»ã¹ãè¤è£½ãããããã£ã¦ã§ããåããã»ã¹ã execve ã§ããã»ã¹ãå¥ã®ããã°ã©ã ã«å ¥ãæ¿ããã
ããã§ãããã¦ã㯠fork ãã¦ããã« execve ããã®ã§ãæéãããã¦ããã»ã¹ã®ã¡ã¢ãªãã³ãã¼ãããããã«ããã«æ¨ã¦ããã¨ããåä½ãç¡é§ã§é ããã¨ããã®ãå¤ä»£ã® Unix ã§ã¯åé¡ã ã£ããããªã
ãã㧠BSD ã®ã²ã¨ããåããã»ã¹ã execve ããã¾ã§ã¯è¦ªã®ã¡ã¢ãªããã®ã¾ã¾ä½¿ãã°ãããããªããã¨èãã¦ããããåä½ãè¡ã vfork ãä½ã£ãã ããã¯ç¡é§ãªåä½ããªããªãã®ã§å®éã«éããªã£ãã ãªãã親åãåãã¡ã¢ãªã§åæã«åä½ããã¨ã¾ã¨ãã«åããªãã®ãæãããªã®ã§ãåããã»ã¹ã execve ãã (ããã㯠_exit ãªã©ã§çµäºãã) ã¾ã§è¦ªããã»ã¹ã¯åæ¢ããã
ã¨ã¯ãããåããã»ã¹ãã¡ã¢ãªãæ¸ãæããçµæã親ããã»ã¹ããè¦ããã¨ããã¡ãã£ã¨ããããªãã¨è¨ããããªããããªåä½ã§ãvfork ããããããªããã¨ã¯åãããåãã£ã¦ããã ã ããä»®æ³ã¡ã¢ãªã§ copy-on-write ãå®ç¾ãã¦ãããããã³ãã¼ãããã®ããã«è¦ããããã©ãå®éã«ã¯ã³ãã¼ãã¦ããªãã®ã§éããã¨ããåä½ã fork ã§å®ç¾ããã vfork ãæ¨ã¦ããã¨ãã話ã§ã¯ãã£ãããã ã
ããã¦æãçµã¡ãç¾ä»£ã§ã¯ fork ã copy-on-write ã«ããã®ã¯æ®éã§ãéããªã£ãã ã ãã vfork ã¯å¿ãã¾ããããã¨ããã®ãæ®éã®èªèã ããã
ããããä»®æ³ã¡ã¢ãªã§ copy-on-write ã¨ã¯ãããåããã»ã¹ã®ã¡ã¢ãªããããããµãã«è¨å®ããªãã¨ãããªãã®ã§ã親ããã»ã¹ãã¡ã¢ãªã使ãã°ä½¿ãã»ã© fork ãé ããªãã¨ããå¾åã¯å¤ãã£ã¦ããªãã vfork ã«ãã®å¾åã¯ãªã (ãããã¯ä½ã) ã®ã§ã親ããã»ã¹ã大ãããªãã°ãã®ãã¡ vfork ã®ã»ããæ確ã«éããªãã ããã
追è¨: ãåããã»ã¹ã®ã¡ã¢ãªããããããµãã«è¨å®ãã¨ããã®ã¯ããã£ã¨ã¡ããã¨è¿°ã¹ãã¨ã copy-on-write 㪠fork ã§ã¯ã親ããã»ã¹ã¨åããã»ã¹ãã¡ã¢ãªãread onlyã§å ±æããããã«ãã¼ã¸ãã¼ãã«ãè¨å®ããããããã«ã¯ãã¼ã¸ã®æ°ã« (ã¤ã¾ã使ç¨ã¡ã¢ãªéã«) æ¯ä¾ããæéãããããã¨ããæå³ã§ããã ãªãããã®ç¶æ ã§ã¯ãã©ã¡ããã®ããã»ã¹ã§æ¸ãè¾¼ã¿ãããããã³ã«ãã¼ã¸ãã©ã«ããèµ·ãããå¿ è¦ãªãæ°ãããã¼ã¸ã確ä¿ãã¦ã³ãã¼ãã¦æ¸ãè¾¼ã¿å¯è½ã«ãã¦ãæ¸ãè¾¼ã¿ãç¶è¡ãã (copy-on-write)ã ããããåããã»ã¹ã exec ããå¾ã§ãã親ããã»ã¹ã®ãã¼ã¸ãã¼ãã«ããã®ã¾ã¾ã«ãªã£ã¦ããã¨ã親ããã»ã¹ãread onlyãªãã¼ã¸ã«æ¸ãè¾¼ããã³ã« (ã³ãã¼ã¯èµ·ããªããã®ã®) ãã¼ã¸ãã©ã«ãã¯èµ·ãããããããªãã ããã¯ã親ããã»ã¹ãé ããããããªæ°ãããã ãã®åä½ã«ã¤ãã¦ã¯ãNetBSD ããã¥ã¡ã³ãã¼ã·ã§ã³: ãªãä¼çµ±ç㪠vfork()ãå®è£ ããã®ããã«èª¬æãããã
ããã²ã¨ã¤ã®åé¡ã¯ã¡ã¢ãªã®ãªã¼ãã¼ã³ããã (å©ç¨ã§ãããããå¤ãã®ã¡ã¢ãªãããã»ã¹ã«å²ãå½ã¦ããã¨) ã許ãã¦ããªãå ´åã«ã 巨大ãªããã»ã¹ã® fork ã失æããã¡ã«ãªãã¨ãããã¨ã§ããã fork ããã¨è¦ªããã»ã¹ã¨åãéã®ã¡ã¢ãªãåããã»ã¹ã«å²ãå½ã¦ãããã®ã§ãå¿ è¦ãªã¡ã¢ãªã¯ 2åã«ãªãã 極端ãªå ´åã¨ãã¦ãå©ç¨ã§ããã¡ã¢ãªã®ååããã大ããªããã»ã¹ã¯ fork ã§ããªããã¨ã«ãªãã vfork ã§ããã°ãåããã»ã¹ã¯è¦ªããã»ã¹ã®ã¡ã¢ãªããã®ã¾ã¾å©ç¨ããã®ã§ããã®åé¡ã¯çºçããªãã
ã¨ããããã§ãvfork ã使ã£ã¦ã¿ãããã ããã¾ãç¾å®çãªã¡ã¢ãªéã§éããªãã®ããã¨ããçåã解決ããããã«æ¸¬å®ãã¦ã¿ããç¾å®çãªã¡ã¢ãªéã§éããªããªããªãããã¾ãé åã¯ãªãã
以ä¸ã®ããã«ãã¦æ¸¬å®ãã¦ã¿ãã
% uname -mrsv Linux 3.14-2-amd64 #1 SMP Debian 3.14.15-2 (2014-08-09) x86_64 % ./miniruby -Ilib -rbenchmark -e ' str = "a" * 1000; 23.times { mem = File.read("/proc/self/status")[/^VmSize:\s*(\S+)/, 1] str << str time = Benchmark.realtime { system("true") } puts "#{mem} #{time}" }'
ã§ããããããã¦ã¿ãã
çµæã¨ãã¦ã¯ãvfork ã®ã»ããããããã¾ã«éããruby (miniruby) ãèµ·åãããããã®ã¡ã¢ãªé (21MB å¼·) ã§ãã§ã«æ°åã®é度ãåºã¦ãããã¡ã¢ãªã大ãããªãã«ã¤ãã¦å·®ã¯åºãããããã»ã¹ã 4GB ãããã«ãªãã¾ã§æ¸¬ã£ã¦ããããããã§ã¯ 200å以ä¸ã«ãªã£ã¦ããã
ã¨ããããã§ãé度ãèããã¨ãã² vfork ã使ãããã
ããããvfork ã¯å±éºã§ãããããããããã®ã¯ CERT ã® Secure Coding ã§ã POS33-C. Do not use vfork() ã¨æ確ã«ã使ããªãã¨æ¸ããã¦ãããã¨ã ããã(JPCERT ã«ããå訳)
ãã®å±éºæ§ã確信ãæã£ã¦é¿ããããããã¨ããã®ãåé¡ã§ããã
fork ã«å¯¾ãã vfork ã®éãã¯ä»¥ä¸ã® 2ç¹ã§ããã
ã¡ã¢ãªã®å ±æã§åé¡ãèµ·ããªãããã«ãã¡ã¢ãªã®ä½¿ãæ¹ã以ä¸ã®ããã«å¶éããã
親ããã»ã¹ã§å¶éãå®ãã®ã¯é£ãããªããããããåããã»ã¹ã«ã¤ãã¦ã¯ç°¡åã§ã¯ãªãã
ãããã«ããå¶éãå®ããªãã£ãå ´åã«ã¯ãåããã»ã¹ã親ããã»ã¹ã«å½±é¿ãåã¼ãããããã¯ãã®éãèµ·ããå¾ãããã®ã¨ããåããã»ã¹ã¨è¦ªããã»ã¹ã®æ¨©éãç°ãªãã¨ã»ãã¥ãªãã£åé¡ (権éææ ¼) ã«çºå±ãããããããªããvfork ããç´å¾ã¯è¦ªåã®æ¨©éã¯åããªã®ã§ããã®å¾ã§ã©ã¡ããã setuid ãªã©ã§æ¨©éãå¤åãããå ´åãåé¡ã§ããããã®ãããsetuid ãªã©ãå¯è½ãªããã»ã¹ (root ã®ããã»ã¹ããsetuid/setgid ãããã³ãã³ãããèµ·åãããããã»ã¹) ã§ã¯ vfork ã使ããªããã¨ã«ããã
å ·ä½çã«ãåããã»ã¹ã§ã¹ã¿ãã¯ä»¥å¤ã®ã¡ã¢ãªãå¤æ´ããã³ã¼ããåããã¨ãé²ããã¨ã«ã¤ãã¦ã¯ä»¥ä¸ã®ããã«èãã¦ã¿ãã
ä»ã«ãæå³ãããã³ã¼ããåãå¯è½æ§ã¯ããã ããããRTLD ã¨ã? async-signal-safe ãªé¢æ°ãã¹ã¬ããã©ã¤ãã©ãªã wrap ãã¦ãããããããªãã®ãå¿é ã
調ã¹ãã¨ãvfork ãå®éã«ä½¿ã話ã¯ããã¤ãè¦ã¤ããã libc 㧠posix_spawn ãå®è£ ããæã«ä½¿ããã¨ããã®ãå¤ãã
glibc ã® posix_spawn ã®å®è£ sysdeps/posix/spawni.c vfork ã (POSIX_SPAWN_USEVFORK ãæå®ããªãã¦ã) æå¹ã«ãªãã®ã¯ä»¥ä¸ã®æ¡ä»¶ãæãç«ã£ãã¨ã
(flags & (POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER | POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_RESETIDS)) == 0 && file_actions == NULL
追è¨
ãã£ãããªã®ã§ãã£ã¨ç´°ãããã¼ã¿ãã¨ã£ã¦ã¿ãã
% ./miniruby -Ilib -rbenchmark -e ' str = "a" * 1000; while str.length < 5_000_000_000 mem = File.read("/proc/self/status")[/^VmSize:\s*(\S+)/, 1] str << str[0, str.length/100] time = Benchmark.realtime { system("true") } puts "#{mem},#{time}" end'
Mac OS X ã® posix_spawn ã«ã¯ POSIX_SPAWN_CLOEXEC_DEFAULT ã¨ãããã©ã°ã使ãã¦ãæå®ããªãã£ã fd ããã㶠close ãããã¨ãã§ããããã ãããã¯è¯ãæ¹åã ãªãã
ãã£ãããªã®ã§ posix-spawn gem ã測ã£ã¦æ¯è¼ãã¦ã¿ããã
#!/bin/sh echo func,mem,time ./ruby.fork -rbenchmark -e ' str = "a" * 1000; while str.length < 5_000_000_000 mem = File.read("/proc/self/status")[/^VmSize:\s*(\S+)/, 1] str << str[0, str.length/100] time = Benchmark.realtime { system("true") } puts "fork,#{mem},#{time}" end' ./ruby.vfork -rbenchmark -e ' str = "a" * 1000; while str.length < 5_000_000_000 mem = File.read("/proc/self/status")[/^VmSize:\s*(\S+)/, 1] str << str[0, str.length/100] time = Benchmark.realtime { system("true") } puts "vfork,#{mem},#{time}" end' ./ruby.vfork -rposix-spawn -rbenchmark -e ' str = "a" * 1000; while str.length < 5_000_000_000 mem = File.read("/proc/self/status")[/^VmSize:\s*(\S+)/, 1] str << str[0, str.length/100] time = Benchmark.realtime { POSIX::Spawn.system("true") } puts "posix-spawn,#{mem},#{time}" end'
ãã ããposix-spawn ã«æ¯ã¹ã¦ vfork ã¯ã¡ãã£ã¨é ããªããposix_spawn ã®ä¸èº«ã¯ vfork ãªã®ã§ä½è¨ãªä½æ¥ããã¦ããã¨ãããã¨ãªãã ãã©ããªãã ãããsignal ã®è¨å®ã¨ããfd ã® close-on-exec ã®è¨å®ã¨ãããã®ãããã ãããã
vfork ããç¶æ 㧠setuid ããã¨ãæ¬å½ã«å±éºã ããããã¡ãã£ã¨è©¦ãã¦ã¿ããã
% t.c #define _GNU_SOURCE #include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <wait.h> int main(int argc, char *argv[]) { pid_t pid, pid2; uid_t ruid, euid, suid; int ret; int status; fprintf(stderr, "parent pid=%ld\n", (long)getpid()); ret = getresuid(&ruid, &euid, &suid); if (ret == -1) { perror("getresuid"); exit(EXIT_FAILURE); } fprintf(stderr, "parent ruid=%ld euid=%ld suid=%ld\n", (long)ruid, (long)euid, (long)suid); pid = vfork(); if (pid == -1) { perror("vfork"); exit(EXIT_FAILURE); } if (pid == 0) { /* child */ fprintf(stderr, "child pid=%ld\n", (long)getpid()); ret = setuid(1000); if (ret == -1) { perror("setuid"); exit(EXIT_FAILURE); } ret = getresuid(&ruid, &euid, &suid); if (ret == -1) { perror("getresuid"); exit(EXIT_FAILURE); } fprintf(stderr, "child ruid=%ld euid=%ld suid=%ld\n", (long)ruid, (long)euid, (long)suid); sleep(10); _exit(EXIT_SUCCESS); } /* parent */ fprintf(stderr, "parent\n"); pid2 = waitpid(pid, &status, WUNTRACED|WCONTINUED); if (pid2 == -1) { perror("waitpid"); exit(EXIT_FAILURE); } if (WIFEXITED(status)) fprintf(stderr, "pid %ld exit %ld\n", (long)pid2, WEXITSTATUS(status)); else if (WIFSIGNALED(status)) fprintf(stderr, "pid %ld signal %ld\n", (long)pid2, WTERMSIG(status)); else fprintf(stderr, "pid %ld unexpected %ld\n", (long)pid2, (long)status); return EXIT_SUCCESS; } % gcc t.c % sudo ./a.out parent pid=8623 parent ruid=0 euid=0 suid=0 child pid=8624 child ruid=1000 euid=1000 suid=1000
ã§ãä»ã®ç«¯æ«ãã gdb 㧠attach ãã¦ã¿ãã
(gdb) attach 8624 Attaching to program: /tmp/a/a.out, process 8624 ptrace: Operation not permitted.
ããã«ã¼ãã«ãç¦æ¢ãã¦ããã¦ããããã ã
ptrace ã®ããã¥ã¢ã«ã® EPERM ã®é ã«æ¸ãã¦ãã該å½ããããªæ¡ä»¶ã¯ set-user-ID/set-group-ID programs ã¨ããã¨ããããªããruid=euid=suid ã«ãã¦ããã®ã§ãããã3ã¤ä»¥å¤ã«ãªã«ãè¨é²ãã¦ããã®ã ãããã
kill ã§ã·ã°ãã«ãéããã¨ã¯ã§ããã
ã¾ããvfork ã§ãªããfork ã§ãåãæåã«ãªããã¾ããã¡ã¢ãªãè¦ãããã ãã§ãå±ãªããã
vfork ããã¨ãã親ããã»ã¹ã®ä»ã®ã¹ã¬ãã (vfork ãå¼ã³åºãã以å¤ã®ã¹ã¬ãã) ã¯æ¢ã¾ãã®ã ãããã(ãã¨ãããããã¡ã¢ãªã¯å ±æãããã ããã)
% cat t.c #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <pthread.h> static volatile char *global = "vfork doesn't share memory."; void printn(int prefix, int n) { char buf[4]; buf[0] = prefix; buf[1] = '0' + n; buf[2] = '\n'; buf[3] = '\0'; write(1, buf, sizeof(buf)); } void *thread_func(void *arg) { int i; for (i = 0; i < 6; i++) { printn('t', i); sleep(1); } return NULL; } int main(int argc, char *argv[]) { int ret; pthread_t th; pid_t pid; int status; int j; ret = pthread_create(&th, NULL, thread_func, NULL); if (ret != 0) { errno = ret; perror("pthread_create"); exit(EXIT_FAILURE); } pid = vfork(); if (pid == -1) { perror("vfork"); exit(EXIT_FAILURE); } if (pid == 0) { /* child */ int i; global = "vfork share memory."; for (i = 0; i < 3; i++) { sleep(1); printn('c', i); } _exit(0); } for (j = 0; j < 3; j++) { printn('p', j); sleep(1); } pid = wait(&status); if (pid == -1) { perror("wait"); exit(EXIT_FAILURE); } ret = pthread_join(th, NULL); if (ret != 0) { errno = ret; perror("pthread_join"); exit(EXIT_FAILURE); } printf("%s\n", global); return EXIT_SUCCESS; } % gcc -Wall t.c -lpthread % ./a.out t0 c0 t1 t2 c1 t3 c2 p0 t4 p1 t5 p2 vfork share memory. % uname -srvm Linux 3.14-2-amd64 #1 SMP Debian 3.14.15-2 (2014-08-09) x86_64
åããã»ã¹ã§æ¸ãæããã°ãã¼ãã«å¤æ°ã親ããã»ã¹ã«åæ ããã¦ããã®ã§è¦ªããã»ã¹ã¨åããã»ã¹ã§ã¡ã¢ãªã¯å ±æããã¦ãããå ±æãã¦ããã®ã§è¦ªããã»ã¹ã® vfork ãå¼ã³åºããã¹ã¬ãã p[0-2] ã¨åããã»ã¹ c[0-2] ã¯å½ç¶åæã«ã¯å®è¡ãããªãã¦ãåããã»ã¹ãçµãã£ãå¾ã«è¦ªããã»ã¹ãåãã¦ããã親ããã»ã¹ã§åãã¦ããä»ã®ã¹ã¬ãã t[0-5] 㯠vfork ä¸ã«ãåãã¦ããã
ãã®èª¿åã§ããã¤ã調ã¹ã¦ã¿ãã
ã¡ã¢ãªãå ±æãã親ããã»ã¹ã®ä»ã®ã¹ã¬ãããåä½ãã¤ã¥ãã:
ã¡ã¢ãªãå ±æãã親ããã»ã¹å ¨ä½ãåæ¢ãã:
ã¡ã¢ãªãå ±æããã親ããã»ã¹å ¨ä½ãåæ¢ãã:
ã¡ã¢ãªãå ±æããã親ããã»ã¹ã¯åä½ãç¶ãã (fork ç¸å½ã®åä½):
ããããããããèããã¨ããã¯ãæ¹åã¨ãã¦ã¯ vfork ãã posix_spawn ã®ã»ãããããªããã¨æããèªå㧠vfork ã使ãã¨ãåããã»ã¹ã§ã®ã¡ã¢ãªã®æ¸ãå¤ããã¹ã¿ãã¯ã ãã«å®ç§ã«å¶éã§ãããã©ãã確信ãæã¦ãªãã確信ãæã¦ãªãããå±ãªãæãã®å ´å (ç§ã®å¤æã¨ãã¦ã¯ setuid å¯è½ãªå ´å) ã¯ä½¿ããªãããã«ãªã£ã¡ãããã
æ¬æ¥ã®ã¾ã¤ãã¨ããã®çºè¡¨ (åºèª¿è¬æ¼) ããã¿ã«ãªããããã¨è°è«ããçµæãé常ã«ç°¡ååããéç解æãªãç°¡åã«å®è£ ã§ãããã¨ãããã£ãã®ã§å®è£ ãã¦ã¿ãã
% cat static-check.rb class C def m xxxx end end def_methods = {} call_methods = {} ObjectSpace.each_object {|o| methods = [] methods.concat o.instance_methods.map {|msym| o.instance_method(msym) } if Module === o methods.concat o.methods.map {|msym| o.method(msym) } methods.each {|m| def_methods[m.name] = true asm = RubyVM::InstructionSequence.disasm(m) next if !asm asm.scan(/mid:([a-zA-Z0-9]+)/) { call_methods[$1] = true } } } a = call_methods.keys - def_methods.keys if !a.empty? p a.sort end % ruby --disable-gems static-check.rb ["synchronize", "xxxx"]
ããã«ãããå®ç¾©ããã¦ããªãããã©å¼ã³åºããåå¨ãããxxxx ã¨ããã¡ã½ãããçºè¦ã§ãã¦ããããã¾ã¾ã§ã¯å®è¡ã xxxx ã¨ããã¡ã½ããå¼ã³åºãã«å°éããªãããããã®ãããªãã®ãçºè¦ãããã¨ã¯ã§ããªãã£ãã®ã ããããã§ã¯ãããå®è¡ããã«çºè¦ãã¦ããã
話ã¯ç°¡åã§ããã¹ã¦ã®ã¡ã½ããå®ç¾©ã®ã¡ã½ããåããªã¹ãã¢ãããããã¹ã¦ã®ã¡ã½ããå¼ã³åºãã®ã¡ã½ããåããªã¹ãã¢ããããå¾è ã ãã«åå¨ããã¡ã½ããåã表示ãã¦ããã ãã§ããã(å®è£ ãä¸å®å ¨ã§ããã®ã¯ããã£ã¦ããã®ã§æ°ã«ãã¦ããªã)
飲ã¿ä¼ã®ä¸ã§å®è£ ããã®ã ããã¡ããã©ããã«ããã¾ã¤ãã¨ãããããã ãããªã©ã«è¦ãã¦ãããããªè©±ãåºãã
åç´ãª typo ã®çºè¦ãªãããã§ãããªãå¹ãã ããã¨ããå®æçã«å®è¡ãã¦ååã®å¢æ¸ãç£è¦ããã°ã©ããã¨ãããã¤ããããåé¡ã ãã©ãRails ã¿ãããªã®ã¯ãªã¯ã¨ã¹ããåä»å§ããåã§ããã°ããã¨ããrequire ã®çµããã§ããã°ããã¨ãããã¨ãInstructionSequence#to_a ã使ããã ããã¨ãã
shellshock ã§æåã«ãªã£ããã·ã§ã«é¢æ°ãåå«ã®ããã»ã¹ã« export ããã¨ãã bash ã®æ©è½ã¯ãã©ãã ksh88 ã«ç±æ¥ãããããªæ°ãããã
ksh88 ã®ããã¥ã¢ã« ã«ã¯ typeset ã§ã-f (é¢æ°) 㨠-x (export) ãçµã¿åãããããã¨è¨è¿°ããã¦ããã
ksh88 ã¯ãã¾ãçãæ®ã£ã¦ããªãã®ã ããAIX 7.1 ã«ã¾ã ãã£ãã®ã§è©¦ãã¦ã¿ãã試è¡é¯èª¤ã®çµæã以ä¸ã®ããã«ããã¨åããã¨ã確èªã§ããã
-bash-4.2$ ksh $ echo bar > bin/foo # foo ã¨ããååã®ãã¡ã¤ã«ã§ shell procedure ãä½ããä¸èº«ã¯ bar ãå¼ã³åºã $ chmod 755 bin/foo # shell procedure ã¯å®è¡å¯è½ã§ãªãã¨ãããªãã®ã§å®è¡å¯è½ã«ãã $ which foo # which 㧠foo ãè¦ã¤ãã /home/akr/bin/foo $ foo # ãã㧠foo ãå¼ã³åºã㨠bar ãè¦ã¤ãããªãã¨ããã¨ã©ã¼ foo: bar: not found . $ bar () { echo baz; } # bar ãé¢æ°ã¨ãã¦å®ç¾©ãã $ foo # ãã㧠foo ãå¼ã³åºãã¦ã bar ã¯è¦ã¤ãããªã foo: bar: not found . $ typeset -fx bar # bar ã export ããããã«è¨å®ãã $ foo # foo ãå¼ã³åºã㨠bar ãå¼ã³åºããã baz $
試ãã¦ããã£ãã®ã ãããã㯠bash ã®ããã«ç°å¢å¤æ°ãä»ããæ©è½ã§ã¯ãªãããã ãä¾ãã°ãksh -c bar ã¨ããããfoo ã®å é ã« #!/bin/ksh ãã¤ãã㨠bar ã®å®ç¾©ã¯ä¼ãããªãã
truss ããã¨ä»¥ä¸ã®ããã«ãªãã
-bash-4.2$ truss -f ksh -c 'bar () { echo baz; }; typeset -fx bar; foo' ... 12124234: 51511337: execve("/home/akr/bin/foo", 0x200119B8, 0x20011EB8) Err#8 ENOEXEC 12124234: 51511337: kopen("/home/akr/bin/foo", O_RDONLY) = 3 ... baz 12124234: 51511337: kwrite(1, " b a z\n", 4) = 4 ...
ã¤ã¾ããksh 㯠foo ã execve ãããã¨ãã¦å¤±æãããããããªãã®ã§ foo ãèªåã§èªãã§å¦çã㦠(bar ãå¼ãã§) baz ãåºåãããã¨ããæµãã§ããã
execve ãã¦ãªãã®ã§å¼ã³åºãå ã®æ å ±ãå©ç¨å¯è½ã§ãtypeset ã«ãã export ã¨ãã¼ã¯ããã¦ãã bar ãè¦ã¤ãã¦ä½¿ãã®ã§ãããã
ã¨ããããã§ããã ksh88 ã使ããã¦ãã¦ãã(ç°å¢å¤æ°ã¯é¢ä¿ãªãã®ã§) shellshock ã®ãããªè©±ã«ã¯ãªããªãã ããã
ã¡ãªã¿ã«ãksh93 ã§ã¯åããªãã(ksh93 ã®ããã¥ã¢ã«ã§ããtypeset 㧠-f 㨠-x ãçµã¿åãããæã®åä½ã®è¨è¿°ã¯æ¶ãã¦ããã)
-bash-4.2$ ksh93 -c 'bar () { echo baz; }; typeset -fx bar; foo' foo: line 1: bar: not found
ãªããpdksh ã®ããã¥ã¢ã« ã«ã¯ typeset -fx ã¯å¹æããªããã¨ãæ¸ãã¦ããã
[latest]