Package: schroot Version: 1.3.1-1 Severity: minor User: ubuntu-de...@lists.ubuntu.com Usertags: origin-ubuntu lucid
Hi! I seem to have run into a weird glitch when using the "command-prefix" option of schroot. Namely, schroot is backgrounded by my shell on exit because it receives SIGTTOU when attempting to reset the termios on CTTY_FILENO: $ schroot -u root -c lucid cloning (with CLONE_NEWPID) for child parent waiting running child (lucid)r...@system:/tmp# exit parent done, exiting 0 [1]+ Stopped schroot -u root -c lucid $ echo $? 150 $ fg schroot -u root -c lucid $ echo $? 0 This happens for me because I've been playing with the CLONE_NEW* flags, and it seems that CLONE_NEWPID seems to trigger the tty layer into sending SIGTTOU when it attempts to reset the termios. I can, for some reason, trigger this without anything very heavy-weight by calling "bash -i" from a simple wrapper, but that just illustrates the problem -- I'm not sure why it's happening under schroot only with CLONE_NEWPID. Attached is - "minimal.c" shows the signal arriving in a simple environment. - "runalt.c" which I use with command-prefix like this: # works: #command-prefix=/scratch/src/newpid/altrun,fork #command-prefix=/scratch/src/newpid/altrun,clone command-prefix=/scratch/src/newpid/altrun,clone-newnet # breaks: #command-prefix=/scratch/src/newpid/altrun,clone-newpid I'm at a loss. "minimal.c" behaves the same on older kernels, so I'm assuming this isn't a kernel bug. Maybe bash is doing something weird when it finds itself running as PID 1? Thanks, -Kees -- Kees Cook @debian.org
// Copyright (C) 2010, Kees Cook <k...@ubuntu.com> // License: GPLv3 #define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <termios.h> #include <unistd.h> #include <stdint.h> #include <string.h> #include <signal.h> #include <stdint.h> #include <stddef.h> #include <inttypes.h> void catch_ttou(int sig) { printf("Caught SIGTTOU!\n"); /* need to ignore or we will catch this until our parent backgrounds us */ signal(SIGTTOU,SIG_IGN); } int main(int argc, char * argv[]) { struct termios saved_termios; struct termios after_termios; signal(SIGTTOU,catch_ttou); if (tcgetattr(STDIN_FILENO, &saved_termios) < 0) { perror("tcgetattr"); return -1; } printf("spawning termios fiddler...\n"); system("/bin/bash -i -c /bin/true"); printf("reset termios ...\n"); if (tcsetattr(STDIN_FILENO, TCSANOW, &saved_termios) < 0) { perror("tcsetattr"); return -1; } return 0; }
// Copyright (C) 2010, Kees Cook <k...@ubuntu.com> // License: GPLv3 #define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <stdint.h> #include <string.h> #include <stdint.h> #include <stddef.h> #include <inttypes.h> #include <sched.h> #include <signal.h> int child(void *ptr) { char **argv = ptr; printf("running child\n"); execv(*argv,argv); perror("execv"); return -1; } int main(int argc, char * argv[]) { int status; uint8_t stack[4096]; int flags = SIGCHLD; if (argc<3) { fprintf(stderr,"Usage: %s [fork|clone|clone-newpid|clone-newnet] cmd arg arg...\n", argv[0]); return -1; } if (strcmp(argv[1],"clone-newpid")==0) { flags |= CLONE_NEWPID; } if (strcmp(argv[1],"clone-newnet")==0) { flags |= CLONE_NEWNET; } if (strcmp(argv[1],"fork")==0) { printf("forking for child\n"); switch (fork()) { case -1: perror("fork"); return -1; case 0: exit(child(argv+2)); default: break; } } else { printf("cloning %sfor child\n", ((flags & CLONE_NEWPID) == CLONE_NEWPID) ? "(with CLONE_NEWPID) " : ( ((flags & CLONE_NEWNET) == CLONE_NEWNET) ? "(with CLONE_NEWNET) " : "")); if (clone(child, stack+sizeof(stack), flags, argv+2)<0) { perror("clone"); return -1; } } printf("parent waiting\n"); waitpid(-1, &status, __WALL); printf("parent done, exiting %d\n", WEXITSTATUS(status)); return WEXITSTATUS(status); }