Skip to content

Commit e414dae

Browse files
authored
Merge pull request ish-app#2387 from cgull/cgull/pty-init-fixes
2 parents 4810ae8 + b49a654 commit e414dae

9 files changed

Lines changed: 78 additions & 32 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ Open the project in Xcode, open iSH.xcconfig, and change `ROOT_BUNDLE_IDENTIFIER
4141

4242
To set up your environment, cd to the project and run `meson build` to create a build directory in `build`. Then cd to the build directory and run `ninja`.
4343

44-
To set up a self-contained Alpine linux filesystem, download the Alpine minirootfs tarball for i386 from the [Alpine website](https://alpinelinux.org/downloads/) and run `./tools/fakefsify`, with the minirootfs tarball as the first argument and the name of the output directory as the second argument. Then you can run things inside the Alpine filesystem with `./ish -f alpine /bin/login -f root`, assuming the output directory is called `alpine`. If `tools/fakefsify` doesn't exist for you in your build directory, that might be because it couldn't find libarchive on your system (see above for ways to install it.)
44+
To set up a self-contained Alpine linux filesystem, download the Alpine minirootfs tarball for i386 from the [Alpine website](https://alpinelinux.org/downloads/) and run `./tools/fakefsify`, with the minirootfs tarball as the first argument and the name of the output directory as the second argument. Then you can run things inside the Alpine filesystem with `./ish -f alpine /bin/sh`, assuming the output directory is called `alpine`. If `tools/fakefsify` doesn't exist for you in your build directory, that might be because it couldn't find libarchive on your system (see above for ways to install it.)
4545

4646
You can replace `ish` with `tools/ptraceomatic` to run the program in a real process and single step and compare the registers at each step. I use it for debugging. Requires 64-bit Linux 4.11 or later.
4747

README_KO.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ Xcode로 프로젝트를 열고, iSH.xcconfig 연 후에 `ROOT_BUNDLE_IDENTIFIER
4343

4444
환경을 세팅하기 위해서는 프로젝트 디렉토리로 이동하고 `meson build`를 커맨드 라인에 입력하세요. 그 후 빌드 된 디렉토리로 cd 후 `ninja` 커맨드를 입력해 실행하세요.
4545

46-
자체적으로 컨테이너 화 된 Alpine 리눅스 파일 시스템으로 실행하고 싶다면, [Alpine 웹사이트](https://alpinelinux.org/downloads/) 에서 i386을 위한 Alpine minirootfs(Mini Root Filesystem) tarball 을 다운로드 받고 `./tools/fakefsify`으로 실행하세요. 매개인자로 다운로드 받은 minirootfs tarball 파일을 입력하고 출력 받을 디렉토리의 이름을 두번째 인자로 입력하면 됩니다. 그 후에는 `./ish -f {출력받을 디렉토리 이름} /bin/login -f root` 명령어를 사용하여 Alpine 시스템 내에서 원하는 것을 실행할 수 있습니다. 만약 `tools/fakefsify` 가 빌드 디렉토리에 존재하지 않는다면, libarchive를 찾을 수 없어서 그런 것일 수 있습니다. 위를 참고하여 시스템에 설치하는 방법을 참고해주세요.
46+
자체적으로 컨테이너 화 된 Alpine 리눅스 파일 시스템으로 실행하고 싶다면, [Alpine 웹사이트](https://alpinelinux.org/downloads/) 에서 i386을 위한 Alpine minirootfs(Mini Root Filesystem) tarball 을 다운로드 받고 `./tools/fakefsify`으로 실행하세요. 매개인자로 다운로드 받은 minirootfs tarball 파일을 입력하고 출력 받을 디렉토리의 이름을 두번째 인자로 입력하면 됩니다. 그 후에는 `./ish -f {출력받을 디렉토리 이름} /bin/sh` 명령어를 사용하여 Alpine 시스템 내에서 원하는 것을 실행할 수 있습니다. 만약 `tools/fakefsify` 가 빌드 디렉토리에 존재하지 않는다면, libarchive를 찾을 수 없어서 그런 것일 수 있습니다. 위를 참고하여 시스템에 설치하는 방법을 참고해주세요.
4747

4848
실제 프로세스로 프로그램을 실행하고 각 단계의 레지스터를 비교하기 위해서 `ish``tools/ptraceomatic`로 바꿔 실행할 수 있습니다. 디버깅을 위해 저는 사용합니다. 64-bit Linux 4.11 이후 버전이 필요합니다.
4949

@@ -67,4 +67,4 @@ iSH에서 추가한 것 중 가장 흥미로운 것은 JIT 컴파일러 일 것
6767

6868
불행하게도 저는 어셈블리어로 대부분의 이러한 gadget을 작성했습니다. 이것은 성능적으로는 좋은 선택이었을 지 몰라도(실제로는 알 도리가 없지만), 가독성, 유지보수, 그리고 제 정신상태에 대해서는 좋지 않은 선택이 되었습니다. 컴파일러/어셈블러/링커로 인한 여러 고충은 말도 할 수 없을 정도입니다. 거의 무슨 제 코드의 가독성을 해치지 않으면 컴파일을 막는 그러한 악마가 있는 것 같았습니다. 이 코드를 작성하는 도중 제정신을 유지하기 위해서 저는 네이밍과 코드 구조론을 따른 최적의 선택을 하지 못하였습니다. `ss`, `s` 그리고 `a`와 같은 매크로 그리고 변수 명을 찾을 수 있을 것입니다. 주석 또한 찾기 힘들 것입니다.
6969

70-
그렇기에 주의 하세요: 해당 코드를 장기간 접할 경우 정신질환을 앓게되거나 GAS 매크로와 링커오류에 대한 악몽에 시달리고 또다른 부작용이 있을 수 있습니다. 암, 선천적 결함, 또는 생식기 질환을 야기한다고 질병관리청에서 인정했습니다. 암튼 그랬습니다.
70+
그렇기에 주의 하세요: 해당 코드를 장기간 접할 경우 정신질환을 앓게되거나 GAS 매크로와 링커오류에 대한 악몽에 시달리고 또다른 부작용이 있을 수 있습니다. 암, 선천적 결함, 또는 생식기 질환을 야기한다고 질병관리청에서 인정했습니다. 암튼 그랬습니다.

README_ZH.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ iSH 是一个运行在 iOS 上的 Linux shell。本项目使用了 x86 用户模
4040

4141
在项目目录中运行命令 `meson build`,之后 `build` 目录会被创建。进入到 `build` 目录并运行命令 `ninja`
4242

43-
为了建立一个自有的 Alpine linux 文件系统,请从 [Alpine 网站](https://alpinelinux.org/downloads/) 下载 `Alpine minirotfs tarball for i386` 并运行 `tools/fakefsify` 。将 minirotfs tarball 指定为第一个参数,将输出目录的名称(如`alpine`)指定为第二个参数,即 `tools/fakefsify $MinirotfsTarballFilename alpine` 然后在 Alpine 文件系统中运行 `/ish -f alpine/bin/login -f root`。如果 `build` 目录下找不到 `tools/fakefsify`,可能是系统上找不到 `libarchive` 的依赖(请参照前面的章节进行安装)。
43+
为了建立一个自有的 Alpine linux 文件系统,请从 [Alpine 网站](https://alpinelinux.org/downloads/) 下载 `Alpine minirotfs tarball for i386` 并运行 `tools/fakefsify` 。将 minirotfs tarball 指定为第一个参数,将输出目录的名称(如`alpine`)指定为第二个参数,即 `tools/fakefsify $MinirotfsTarballFilename alpine` 然后在 Alpine 文件系统中运行 `/ish -f alpine/bin/sh`。如果 `build` 目录下找不到 `tools/fakefsify`,可能是系统上找不到 `libarchive` 的依赖(请参照前面的章节进行安装)。
4444

4545
除了可以使用 `ish`,你也可以使用 `tools/ptraceomatic` 替代它,以便在某个真实进程中单步比较寄存器。我通常使用它来进行调试(需要 64 位 Linux 4.11 或更高版本)。
4646

@@ -64,4 +64,4 @@ iSH 是一个运行在 iOS 上的 Linux shell。本项目使用了 x86 用户模
6464

6565
但不幸的是,我最开始决定用汇编语言编写几乎所有的 gadgets。这可能从性能方面来说是一个好的决定(虽然我永远也无法确定),但是对可读性、可维护性和我的理智来说,这是一个可怕的决定。我承受了大量来自编译器、汇编程序以及链接器的乱七八糟的东西。那里面就像有一个魔鬼,把我的代码搞得畸形,就算没有畸形,也会编造一些愚蠢的理由说它不能够编译。为了在编写代码时保持理智,我不得不忽略代码结构和命名方面的最佳实践。你会发现宏和变量具有诸如 `ss``s``a` 等描述性的名称,并且汇编器的宏嵌套层数超乎你的想象。最重要的是,代码中几乎没有任何注释。
6666

67-
所以这是一个警告: 长期接触此代码可能会使你失去理智,对 GAS 宏和链接器错误产生噩梦,或是任何其他使人虚弱的副作用。在加利福尼亚,众所周知这样的代码会导致癌症、生产缺陷和重复伤害。
67+
所以这是一个警告: 长期接触此代码可能会使你失去理智,对 GAS 宏和链接器错误产生噩梦,或是任何其他使人虚弱的副作用。在加利福尼亚,众所周知这样的代码会导致癌症、生产缺陷和重复伤害。

fs/pty.c

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,30 @@ static int pty_master_init(struct tty *tty) {
3434
return 0;
3535
}
3636

37+
38+
static void pty_hangup(struct tty *tty) {
39+
if (tty == NULL)
40+
return;
41+
lock(&tty->lock);
42+
tty_hangup(tty);
43+
unlock(&tty->lock);
44+
}
45+
46+
static struct tty *pty_hangup_other(struct tty *tty) {
47+
struct tty *other = tty->pty.other;
48+
if (other == NULL)
49+
return NULL;
50+
pty_hangup(other);
51+
return other;
52+
}
53+
54+
static void pty_slave_cleanup(struct tty *tty) {
55+
pty_hangup_other(tty);
56+
}
57+
3758
static void pty_master_cleanup(struct tty *tty) {
38-
struct tty *slave = tty->pty.other;
59+
struct tty *slave = pty_hangup_other(tty);
3960
slave->pty.other = NULL;
40-
lock(&slave->lock);
41-
tty_hangup(slave);
42-
unlock(&slave->lock);
4361
tty_release(slave);
4462
}
4563

@@ -51,6 +69,16 @@ static int pty_slave_open(struct tty *tty) {
5169
return 0;
5270
}
5371

72+
static int pty_slave_close(struct tty *tty) {
73+
// If userland's reference count on the pty slave will go to 0,
74+
// hang up the pty master. But the session leader may have a
75+
// reference, and the pty master always has a reference.
76+
if (tty->refcount - 1 == (tty->session ? 2 : 1)) {
77+
pty_hangup_other(tty);
78+
}
79+
return 0;
80+
}
81+
5482
static int pty_master_ioctl(struct tty *tty, int cmd, void *arg) {
5583
struct tty *slave = tty->pty.other;
5684
switch (cmd) {
@@ -94,7 +122,9 @@ DEFINE_TTY_DRIVER(pty_master, &pty_master_ops, TTY_PSEUDO_MASTER_MAJOR, MAX_PTYS
94122
const struct tty_driver_ops pty_slave_ops = {
95123
.init = pty_return_eio,
96124
.open = pty_slave_open,
125+
.close = pty_slave_close,
97126
.write = pty_write,
127+
.cleanup = pty_slave_cleanup,
98128
};
99129
DEFINE_TTY_DRIVER(pty_slave, &pty_slave_ops, TTY_PSEUDO_SLAVE_MAJOR, MAX_PTYS);
100130

fs/tty.c

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -110,16 +110,7 @@ void tty_release(struct tty *tty) {
110110
cond_destroy(&tty->produced);
111111
free(tty);
112112
} else {
113-
// bit of a hack
114-
struct tty *master = NULL;
115-
if (tty->driver == &pty_slave && tty->refcount == 1)
116-
master = tty->pty.other;
117113
unlock(&tty->lock);
118-
if (master != NULL) {
119-
lock(&master->lock);
120-
tty_poll_wakeup(master, POLL_READ | POLL_HUP);
121-
unlock(&master->lock);
122-
}
123114
}
124115
}
125116

@@ -207,11 +198,14 @@ static int tty_device_open(int major, int minor, struct fd *fd) {
207198

208199
static int tty_close(struct fd *fd) {
209200
if (fd->tty != NULL) {
210-
lock(&fd->tty->fds_lock);
201+
struct tty *tty = fd->tty;
202+
lock(&tty->fds_lock);
211203
list_remove_safe(&fd->tty_other_fds);
212-
unlock(&fd->tty->fds_lock);
204+
unlock(&tty->fds_lock);
213205
lock(&ttys_lock);
214-
tty_release(fd->tty);
206+
if (tty->driver->ops->close)
207+
tty->driver->ops->close(tty);
208+
tty_release(tty);
215209
unlock(&ttys_lock);
216210
}
217211
return 0;
@@ -414,7 +408,7 @@ static bool pty_is_half_closed_master(struct tty *tty) {
414408
struct tty *slave = tty->pty.other;
415409
// only time one tty lock is nested in another
416410
lock(&slave->lock);
417-
bool half_closed = slave->ever_opened && slave->refcount == 1;
411+
bool half_closed = slave->ever_opened && (slave->refcount == 1 || slave->hung_up);
418412
unlock(&slave->lock);
419413
return half_closed;
420414
}
@@ -450,7 +444,7 @@ static ssize_t tty_read(struct fd *fd, void *buf, size_t bufsize) {
450444
struct tty *tty = fd->tty;
451445
lock(&pids_lock);
452446
lock(&tty->lock);
453-
if (tty->hung_up) {
447+
if (tty->hung_up || pty_is_half_closed_master(tty)) {
454448
unlock(&pids_lock);
455449
goto error;
456450
}
@@ -546,7 +540,7 @@ static ssize_t tty_read(struct fd *fd, void *buf, size_t bufsize) {
546540
static ssize_t tty_write(struct fd *fd, const void *buf, size_t bufsize) {
547541
struct tty *tty = fd->tty;
548542
lock(&tty->lock);
549-
if (tty->hung_up) {
543+
if (tty->hung_up || pty_is_half_closed_master(tty)) {
550544
unlock(&tty->lock);
551545
return _EIO;
552546
}
@@ -672,7 +666,7 @@ static int tiocgpgrp(struct tty *tty, pid_t_ *fg_group) {
672666
lock(&slave->lock);
673667
}
674668

675-
if (tty == slave && !tty_is_current(slave) || slave->fg_group == 0) {
669+
if (tty == slave && (!tty_is_current(slave) || slave->fg_group == 0)) {
676670
err = _ENOTTY;
677671
goto error_no_ctrl_tty;
678672
}
@@ -800,7 +794,7 @@ void tty_set_winsize(struct tty *tty, struct winsize_ winsize) {
800794

801795
void tty_hangup(struct tty *tty) {
802796
tty->hung_up = true;
803-
tty_poll_wakeup(tty, POLL_READ | POLL_WRITE | POLL_ERR | POLL_HUP);
797+
tty_input_wakeup(tty);
804798
}
805799

806800
struct dev_ops tty_dev = {

fs/tty.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ struct tty_driver {
9393
struct tty_driver_ops {
9494
int (*init)(struct tty *tty);
9595
int (*open)(struct tty *tty);
96+
int (*close)(struct tty *tty);
9697
int (*write)(struct tty *tty, const void *buf, size_t len, bool blocking);
9798
int (*ioctl)(struct tty *tty, int cmd, void *arg);
9899
void (*cleanup)(struct tty *tty);

ish-lldb.lldb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
process handle -n 0 -p 1 -s 0 SIGUSR1 SIGTTIN SIGPIPE

kernel/exit.c

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -148,12 +148,28 @@ noreturn void do_exit_group(int status) {
148148

149149
// always called from init process
150150
static void halt_system(void) {
151-
// brutally murder everything
152-
// which will leave everything in an inconsistent state. I will solve this problem later.
153-
for (int i = 2; i < MAX_PID; i++) {
154-
struct task *task = pid_get_task(i);
155-
if (task != NULL)
156-
pthread_kill(task->thread, SIGKILL);
151+
for (int state = 0; state < 3; state++) {
152+
int tasks_found = 0;
153+
for (int i = 2; i < MAX_PID; i++) {
154+
struct task *task = pid_get_task(i);
155+
if (task != NULL) {
156+
tasks_found++;
157+
switch (state) {
158+
case 0:
159+
deliver_signal(task, SIGTERM_, SIGINFO_NIL);
160+
break;
161+
case 1:
162+
deliver_signal(task, SIGKILL_, SIGINFO_NIL);
163+
break;
164+
case 2:
165+
pthread_kill(task->thread, SIGTERM);
166+
}
167+
}
168+
}
169+
if (tasks_found == 0)
170+
break;
171+
if (state != 2)
172+
sleep(1);
157173
}
158174

159175
// unmount all filesystems

kernel/log.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,10 @@ static void log_line(const char *line) {
154154
static void log_line(const char *line) {
155155
os_log_fault(OS_LOG_DEFAULT, "%s", line);
156156
}
157+
#elif LOG_HANDLER_STDERR
158+
static void log_line(const char *line) {
159+
fprintf(stderr, "%s\n", line);
160+
}
157161
#endif
158162

159163
static void default_die_handler(const char *msg) {

0 commit comments

Comments
 (0)