static int notsane_extended(const struct part_iter *iter) { const struct disk_dos_part_entry *dp; uint32_t end_ebr; dp = ((struct disk_dos_mbr *)iter->data)->table; if (!dp[1].ostype) return 0; if (!ost_is_nondata(dp[1].ostype)) { error("2nd EBR entry must be extended or empty.\n"); return -1; } end_ebr = dp[1].start_lba + dp[1].length; if (!dp[1].start_lba || !dp[1].length || !sane(dp[1].start_lba, dp[1].length) || end_ebr > iter->sub.dos.bebr_size) { error("Insane extended partition.\n"); return -1; } return 0; }
static int notsane_extended(const struct part_iter *iter) { const struct disk_dos_part_entry *dp; uint32_t end_ebr; dp = ((struct disk_dos_mbr *)iter->data)->table; if (!dp[1].ostype) return 0; if (!ost_is_nondata(dp[1].ostype)) { error("The 2nd EBR entry must be extended or empty."); return -1; } if (iter->flags & PIF_RELAX) return 0; end_ebr = dp[1].start_lba + dp[1].length; if (!dp[1].start_lba || !dp[1].length || !sane(dp[1].start_lba, dp[1].length) || end_ebr > iter->dos.bebr_siz) { error("Extended partition (EBR) with invalid offset and/or length."); return -1; } return 0; }
static int notsane_logical(const struct part_iter *iter) { const struct disk_dos_part_entry *dp; uint32_t end_log; dp = ((struct disk_dos_mbr *)iter->data)->table; if (!dp[0].ostype) return 0; if (ost_is_ext(dp[0].ostype)) { error("1st EBR entry must be data or empty.\n"); return -1; } end_log = dp[0].start_lba + dp[0].length; if (!dp[0].start_lba || !dp[0].length || !sane(dp[0].start_lba, dp[0].length) || end_log > iter->sub.dos.ebr_size) { error("Insane logical partition.\n"); return -1; } return 0; }
static int notsane_logical(const struct part_iter *iter) { const struct disk_dos_part_entry *dp; uint32_t end_log; dp = ((struct disk_dos_mbr *)iter->data)->table; if (!dp[0].ostype) return 0; if (ost_is_ext(dp[0].ostype)) { error("The 1st EBR entry must be data or empty."); return -1; } if (iter->flags & PIF_RELAX) return 0; end_log = dp[0].start_lba + dp[0].length; if (!dp[0].start_lba || !dp[0].length || !sane(dp[0].start_lba, dp[0].length) || end_log > iter->dos.nebr_siz) { error("Logical partition (in EBR) with invalid offset and/or length."); return -1; } return 0; }
static int notsane_gpt_hdr(const struct disk_info *di, const struct disk_gpt_header *gpth, int flags) { uint64_t gpt_loff; /* offset to GPT partition list in sectors */ uint64_t gpt_lsiz; /* size of GPT partition list in bytes */ uint64_t gpt_lcnt; /* size of GPT partition in sectors */ uint64_t gpt_sec; /* secondary gpt header */ if (!(flags & PIF_STRICT)) return 0; if (gpth->lba_alt < gpth->lba_cur) gpt_sec = gpth->lba_cur; else gpt_sec = gpth->lba_alt; gpt_loff = gpth->lba_table; gpt_lsiz = (uint64_t)gpth->part_size * gpth->part_count; gpt_lcnt = (gpt_lsiz + di->bps - 1) / di->bps; /* * disk_read_sectors allows reading of max 255 sectors, so we use * it as a sanity check base. EFI doesn't specify max (AFAIK). */ if (gpt_loff < 2 || !gpt_lsiz || gpt_lcnt > 255u || gpth->lba_first_usable > gpth->lba_last_usable || !sane(gpt_loff, gpt_lcnt) || (gpt_loff + gpt_lcnt > gpth->lba_first_usable && gpt_loff <= gpth->lba_last_usable) || gpt_loff + gpt_lcnt > gpt_sec || ((flags & PIF_STRICTER) && (gpt_sec >= di->lbacnt)) || gpth->part_size < sizeof(struct disk_gpt_part_entry)) return -1; return 0; }
static int notsane_primary(const struct part_iter *iter) { const struct disk_dos_part_entry *dp; dp = ((struct disk_dos_mbr *)iter->data)->table + iter->index0; if (!dp->ostype) return 0; if (!dp->start_lba || !dp->length || !sane(dp->start_lba, dp->length) || dp->start_lba + dp->length > iter->di.lbacnt) { error("Insane primary (MBR) partition.\n"); return -1; } return 0; }
static int notsane_primary(const struct part_iter *iter) { const struct disk_dos_part_entry *dp; dp = ((struct disk_dos_mbr *)iter->data)->table + iter->index0; if (!dp->ostype) return 0; if (iter->flags & PIF_RELAX) return 0; if (!dp->start_lba || !dp->length || !sane(dp->start_lba, dp->length) || dp->start_lba + dp->length > iter->di.lbacnt) { error("Primary partition (in MBR) with invalid offset and/or length."); return -1; } return 0; }
/** * pi_begin() - check disk, validate, and get proper iterator * @di: diskinfo struct pointer * * This function checks the disk for GPT or legacy partition table and allocates * an appropriate iterator. **/ struct part_iter *pi_begin(const struct disk_info *di, int stepall) { int setraw = 0; struct part_iter *iter = NULL; struct disk_dos_mbr *mbr = NULL; struct disk_gpt_header *gpth = NULL; struct disk_gpt_part_entry *gptl = NULL; /* Read MBR */ if (!(mbr = disk_read_sectors(di, 0, 1))) { error("Couldn't read first disk sector.\n"); goto bail; } setraw = -1; /* Check for MBR magic*/ if (mbr->sig != disk_mbr_sig_magic) { error("No MBR magic.\n"); goto bail; } /* Check for GPT protective MBR */ if (mbr->table[0].ostype == 0xEE) { if (!(gpth = disk_read_sectors(di, 1, 1))) { error("Couldn't read potential GPT header.\n"); goto bail; } } if (gpth && gpth->rev.uint32 == 0x00010000 && !memcmp(gpth->sig, disk_gpt_sig_magic, sizeof(disk_gpt_sig_magic))) { /* looks like GPT v1.0 */ uint64_t gpt_loff; /* offset to GPT partition list in sectors */ uint64_t gpt_lsiz; /* size of GPT partition list in bytes */ uint64_t gpt_lcnt; /* size of GPT partition in sectors */ #ifdef DEBUG puts("Looks like a GPT v1.0 disk."); disk_gpt_header_dump(gpth); #endif /* Verify checksum, fallback to backup, then bail if invalid */ if (gpt_check_hdr_crc(di, &gpth)) goto bail; gpt_loff = gpth->lba_table; gpt_lsiz = (uint64_t)gpth->part_size * gpth->part_count; gpt_lcnt = (gpt_lsiz + di->bps - 1) / di->bps; /* * disk_read_sectors allows reading of max 255 sectors, so we use * it as a sanity check base. EFI doesn't specify max (AFAIK). * Apart from that, some extensive sanity checks. */ if (!gpt_loff || !gpt_lsiz || gpt_lcnt > 255u || gpth->lba_first_usable > gpth->lba_last_usable || !sane(gpt_loff, gpt_lcnt) || gpt_loff + gpt_lcnt > gpth->lba_first_usable || !sane(gpth->lba_last_usable, gpt_lcnt) || gpth->lba_last_usable + gpt_lcnt >= gpth->lba_alt || gpth->lba_alt >= di->lbacnt || gpth->part_size < sizeof(struct disk_gpt_part_entry)) { error("Invalid GPT header's values.\n"); goto bail; } if (!(gptl = disk_read_sectors(di, gpt_loff, (uint8_t)gpt_lcnt))) { error("Couldn't read GPT partition list.\n"); goto bail; } /* Check array checksum(s). */ if (check_crc(gpth->table_chksum, (const uint8_t *)gptl, (unsigned int)gpt_lsiz)) { error("WARNING: GPT partition list checksum invalid, trying backup.\n"); free(gptl); /* secondary array directly precedes secondary header */ if (!(gptl = disk_read_sectors(di, gpth->lba_alt - gpt_lcnt, (uint8_t)gpt_lcnt))) { error("Couldn't read backup GPT partition list.\n"); goto bail; } if (check_crc(gpth->table_chksum, (const uint8_t *)gptl, (unsigned int)gpt_lsiz)) { error("Backup GPT partition list checksum invalid.\n"); goto bail; } } /* allocate iterator and exit */ iter = pi_new(typegpt, di, stepall, gpth, gptl); } else { /* looks like MBR */ iter = pi_new(typedos, di, stepall, mbr); } setraw = 0; bail: if (setraw) { error("WARNING: treating disk as raw.\n"); iter = pi_new(typeraw, di, stepall); } free(mbr); free(gpth); free(gptl); return iter; }
int lpd_main(int argc UNUSED_PARAM, char *argv[]) { int spooling = spooling; // for compiler char *s, *queue; char *filenames[2]; // goto spool directory if (*++argv) xchdir(*argv++); // error messages of xfuncs will be sent over network xdup2(STDOUT_FILENO, STDERR_FILENO); // nullify ctrl/data filenames memset(filenames, 0, sizeof(filenames)); // read command s = queue = xmalloc_read_stdin(); // we understand only "receive job" command if (2 != *queue) { unsupported_cmd: printf("Command %02x %s\n", (unsigned char)s[0], "is not supported"); goto err_exit; } // parse command: "2 | QUEUE_NAME | '\n'" queue++; // protect against "/../" attacks // *strchrnul(queue, '\n') = '\0'; - redundant, sane() will do if (!*sane(queue)) return EXIT_FAILURE; // queue is a directory -> chdir to it and enter spooling mode spooling = chdir(queue) + 1; // 0: cannot chdir, 1: done // we don't free(s), we might need "queue" var later while (1) { char *fname; int fd; // int is easier than ssize_t: can use xatoi_u, // and can correctly display error returns (-1) int expected_len, real_len; // signal OK safe_write(STDOUT_FILENO, "", 1); // get subcommand // valid s must be of form: "SUBCMD | LEN | space | FNAME" // N.B. we bail out on any error s = xmalloc_read_stdin(); if (!s) { // (probably) EOF char *p, *q, var[2]; // non-spooling mode or no spool helper specified if (!spooling || !*argv) return EXIT_SUCCESS; // the only non-error exit // spooling mode but we didn't see both ctrlfile & datafile if (spooling != 7) goto err_exit; // reject job // spooling mode and spool helper specified -> exec spool helper // (we exit 127 if helper cannot be executed) var[1] = '\0'; // read and delete ctrlfile q = xmalloc_xopen_read_close(filenames[0], NULL); unlink(filenames[0]); // provide datafile name // we can use leaky setenv since we are about to exec or exit xsetenv("DATAFILE", filenames[1]); // parse control file by "\n" while ((p = strchr(q, '\n')) != NULL && isalpha(*q)) { *p++ = '\0'; // q is a line of <SYM><VALUE>, // we are setting environment string <SYM>=<VALUE>. // Ignoring "l<datafile>", exporting others: if (*q != 'l') { var[0] = *q++; xsetenv(var, q); } q = p; // next line } // helper should not talk over network. // this call reopens stdio fds to "/dev/null" // (no daemonization is done) bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO | DAEMON_ONLY_SANITIZE, NULL); BB_EXECVP(*argv, argv); exit(127); } // validate input. // we understand only "control file" or "data file" cmds if (2 != s[0] && 3 != s[0]) goto unsupported_cmd; if (spooling & (1 << (s[0]-1))) { printf("Duplicated subcommand\n"); goto err_exit; } // get filename *strchrnul(s, '\n') = '\0'; fname = strchr(s, ' '); if (!fname) { // bad_fname: printf("No or bad filename\n"); goto err_exit; } *fname++ = '\0'; // // s[0]==2: ctrlfile, must start with 'c' // // s[0]==3: datafile, must start with 'd' // if (fname[0] != s[0] + ('c'-2)) // goto bad_fname; // get length expected_len = bb_strtou(s + 1, NULL, 10); if (errno || expected_len < 0) { printf("Bad length\n"); goto err_exit; } if (2 == s[0] && expected_len > 16 * 1024) { // SECURITY: // ctrlfile can't be big (we want to read it back later!) printf("File is too big\n"); goto err_exit; } // open the file if (spooling) { // spooling mode: dump both files // job in flight has mode 0200 "only writable" sane(fname); fd = open3_or_warn(fname, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0200); if (fd < 0) goto err_exit; filenames[s[0] - 2] = xstrdup(fname); } else { // non-spooling mode: // 2: control file (ignoring), 3: data file fd = -1; if (3 == s[0]) fd = xopen(queue, O_RDWR | O_APPEND); } // signal OK safe_write(STDOUT_FILENO, "", 1); // copy the file real_len = bb_copyfd_size(STDIN_FILENO, fd, expected_len); if (real_len != expected_len) { printf("Expected %d but got %d bytes\n", expected_len, real_len); goto err_exit; } // get EOF indicator, see whether it is NUL (ok) // (and don't trash s[0]!) if (safe_read(STDIN_FILENO, &s[1], 1) != 1 || s[1] != 0) { // don't send error msg to peer - it obviously // doesn't follow the protocol, so probably // it can't understand us either goto err_exit; } if (spooling) { // chmod completely downloaded file as "readable+writable" fchmod(fd, 0600); // accumulate dump state // N.B. after all files are dumped spooling should be 1+2+4==7 spooling |= (1 << (s[0]-1)); // bit 1: ctrlfile; bit 2: datafile } free(s); close(fd); // NB: can do close(-1). Who cares? // NB: don't do "signal OK" write here, it will be done // at the top of the loop } // while (1) err_exit: // don't keep corrupted files if (spooling) { #define i spooling for (i = 2; --i >= 0; ) if (filenames[i]) unlink(filenames[i]); } return EXIT_FAILURE; }
/* pi_begin() - validate and and get proper iterator for a disk described by di */ struct part_iter *pi_begin(const struct disk_info *di, int flags) { int gptprot, ret = -1; struct part_iter *iter; struct disk_dos_mbr *mbr = NULL; struct disk_gpt_header *gpth = NULL; struct disk_gpt_part_entry *gptl = NULL; /* Preallocate iterator */ if (!(iter = pi_alloc())) goto bail; /* Read MBR */ if (!(mbr = disk_read_sectors(di, 0, 1))) { error("Couldn't read the first disk sector."); goto bail; } /* Check for MBR magic */ if (mbr->sig != disk_mbr_sig_magic) { warn("No MBR magic, treating disk as raw."); /* looks like RAW */ ret = pi_ctor(iter, di, flags); goto bail; } /* Check for GPT protective MBR */ gptprot = 0; for (size_t i = 0; i < 4; i++) gptprot |= (mbr->table[i].ostype == 0xEE); if (gptprot && !(flags & PIF_PREFMBR)) { if (!(gpth = disk_read_sectors(di, 1, 1))) { error("Couldn't read potential GPT header."); goto bail; } } if (gpth && gpth->rev.uint32 == 0x00010000 && !memcmp(gpth->sig, disk_gpt_sig_magic, sizeof gpth->sig)) { /* looks like GPT v1.0 */ uint64_t gpt_loff; /* offset to GPT partition list in sectors */ uint64_t gpt_lsiz; /* size of GPT partition list in bytes */ uint64_t gpt_lcnt; /* size of GPT partition in sectors */ #ifdef DEBUG dprintf("Looks like a GPT v1.0 disk.\n"); disk_gpt_header_dump(gpth); #endif /* Verify checksum, fallback to backup, then bail if invalid */ if (gpt_check_hdr_crc(di, &gpth)) goto bail; gpt_loff = gpth->lba_table; gpt_lsiz = (uint64_t)gpth->part_size * gpth->part_count; gpt_lcnt = (gpt_lsiz + di->bps - 1) / di->bps; /* * disk_read_sectors allows reading of max 255 sectors, so we use * it as a sanity check base. EFI doesn't specify max (AFAIK). * Apart from that, some extensive sanity checks. */ if (!(flags & PIF_RELAX) && ( !gpt_loff || !gpt_lsiz || gpt_lcnt > 255u || gpth->lba_first_usable > gpth->lba_last_usable || !sane(gpt_loff, gpt_lcnt) || gpt_loff + gpt_lcnt > gpth->lba_first_usable || !sane(gpth->lba_last_usable, gpt_lcnt) || gpth->lba_last_usable + gpt_lcnt >= gpth->lba_alt || gpth->lba_alt >= di->lbacnt || gpth->part_size < sizeof *gptl)) { error("Invalid GPT header's values."); goto bail; } if (!(gptl = disk_read_sectors(di, gpt_loff, gpt_lcnt))) { error("Couldn't read GPT partition list."); goto bail; } /* Check array checksum(s). */ if (!valid_crc(gpth->table_chksum, (const uint8_t *)gptl, (unsigned int)gpt_lsiz)) { warn("Checksum of the main GPT partition list is invalid, trying backup."); free(gptl); /* secondary array directly precedes secondary header */ if (!(gptl = disk_read_sectors(di, gpth->lba_alt - gpt_lcnt, gpt_lcnt))) { error("Couldn't read backup GPT partition list."); goto bail; } if (!valid_crc(gpth->table_chksum, (const uint8_t *)gptl, gpt_lsiz)) { error("Checksum of the backup GPT partition list is invalid, giving up."); goto bail; } } /* looks like GPT */ ret = pi_gpt_ctor(iter, di, flags, gpth, gptl); } else { /* looks like MBR */ ret = pi_dos_ctor(iter, di, flags, mbr); } bail: if (ret < 0) free(iter); free(mbr); free(gpth); free(gptl); return iter; }
static void set(char *argv[], struct termios *sp) { const Tty_t *tp; register int c,off; char *cp; char *ep; while(cp = *argv++) { off = 0; if(*cp=='-') { cp++; off=1; } if(!(tp=lookup(cp)) || (off && (tp->type!=BIT) && (tp->type!=TABS))) error(ERROR_exit(1),"%s: unknown mode",cp); switch(tp->type) { case CHAR: if(off) error(ERROR_exit(1),"%s: unknown mode",cp); if(!*argv) error(ERROR_exit(1),"missing argument to %s",cp); c = gettchar(*argv++); if(c>=0) sp->c_cc[tp->mask] = c; else sp->c_cc[tp->mask] = _POSIX_VDISABLE; break; case BIT: case BITS: switch(tp->field) { case C_FLAG: if(off) sp->c_cflag &= ~tp->mask; else sp->c_cflag |= tp->mask; break; case I_FLAG: if(off) sp->c_iflag &= ~tp->mask; else sp->c_iflag |= tp->mask; break; case O_FLAG: sp->c_oflag &= ~tp->mask; sp->c_oflag |= tp->val; break; case L_FLAG: if(off) sp->c_lflag &= ~tp->mask; else sp->c_lflag |= tp->mask; break; } break; case TABS: sp->c_oflag &= ~tp->mask; if(off) sp->c_oflag |= tp->val; break; #ifdef TIOCSWINSZ case WIND: { struct winsize win; int n; if(ioctl(0,TIOCGWINSZ,&win)<0) error(ERROR_system(1),"cannot set %s",tp->name); if(!(cp= *argv)) { sfprintf(sfstdout,"%d\n",tp->mask?win.ws_col:win.ws_row); break; } argv++; n=strtol(cp,&cp,10); if(*cp) error(ERROR_system(1),"%d: invalid number of %s",argv[-1],tp->name); if(tp->mask) win.ws_col = n; else win.ws_row = n; if(ioctl(0,TIOCSWINSZ,&win)<0) error(ERROR_system(1),"cannot set %s",tp->name); break; } #endif case NUM: cp = *argv; if (!cp) { if (tp->field == C_SPEED) { if (tp = getspeed(*tp->name == 'i' ? cfgetispeed(sp) : cfgetospeed(sp))) sfprintf(sfstdout, "%s\n", tp->name); break; } error(ERROR_exit(1), "%s: missing numeric argument", tp->name); } argv++; c = (int)strtol(cp, &ep, 10); if (*ep) error(ERROR_exit(1), "%s: %s: numeric argument expected", tp->name, cp); switch (tp->field) { #if _mem_c_line_termios case C_LINE: sp->c_line = c; break; #endif case C_SPEED: if(getspeed(c)) { if (*tp->name != 'o') cfsetispeed(sp, c); if (*tp->name != 'i') cfsetospeed(sp, c); } else error(ERROR_exit(1), "%s: %s: invalid speed", tp->name, cp); break; case T_CHAR: sp->c_cc[tp->mask] = c; break; } break; case SPEED: cfsetospeed(sp, tp->mask); cfsetispeed(sp, tp->mask); break; case SIZE: sp->c_cflag &= ~CSIZE; sp->c_cflag |= tp->mask; break; case SANE: sane(sp); break; #if defined(OLCUC) && defined(IUCLC) case CASE: if(off) { sp->c_iflag |= IUCLC; sp->c_oflag |= OLCUC; } else { sp->c_iflag &= ~IUCLC; sp->c_oflag &= ~OLCUC; } break; #endif /* OLCUC && IUCLC */ } } }
static void output(struct termios *sp, int flags) { const Tty_t *tp; struct termios tty; register int delim = ' '; register int i,off,off2; char schar[2]; unsigned int ispeed = cfgetispeed(sp); unsigned int ospeed = cfgetospeed(sp); if(flags&G_FLAG) { gout(sp); return; } tty = *sp; sane(&tty); for(i=0; i < elementsof(Ttable); i++) { tp= &Ttable[i]; if(tp->flags&IG) { if(tp->flags&NL) sfputc(sfstdout,'\n'); continue; } switch(tp->type) { case BIT: case BITS: off = off2 = 1; switch(tp->field) { case C_FLAG: if(sp->c_cflag&tp->mask) off = 0; if(tty.c_cflag&tp->mask) off2 = 0; break; case I_FLAG: if(sp->c_iflag&tp->mask) off = 0; if(tty.c_iflag&tp->mask) off2 = 0; break; case O_FLAG: if((sp->c_oflag&tp->mask)==tp->val) off = 0; if(tty.c_oflag&tp->mask) off2 = 0; break; case L_FLAG: if(sp->c_lflag&tp->mask) off = 0; if(tty.c_lflag&tp->mask) off2 = 0; } if(tp->flags&NL) delim = '\n'; if(!flags && off==off2) continue; if(!off) sfprintf(sfstdout,"%s%c",tp->name,delim); else if(tp->type==BIT) sfprintf(sfstdout,"-%s%c",tp->name,delim); delim = ' '; break; case CHAR: off = sp->c_cc[tp->mask]; if(tp->flags&NL) delim = '\n'; if(!flags && off==(unsigned char)tty.c_cc[tp->mask]) continue; if(off==_POSIX_VDISABLE) sfprintf(sfstdout,"%s = <undef>;%c",tp->name,delim); else if(isprint(off&0xff)) sfprintf(sfstdout,"%s = %c;%c",tp->name,off,delim); else #if CC_NATIVE == CC_ASCII sfprintf(sfstdout,"%s = ^%c;%c",tp->name,off==0177?'?':(off^0100),delim); #else { off = ccmapc(off, CC_NATIVE, CC_ASCII); sfprintf(sfstdout,"%s = ^%c;%c",tp->name,off==0177?'?':ccmapc(off^0100,CC_ASCII,CC_NATIVE),delim); } #endif delim = ' '; break; case SIZE: if((sp->c_cflag&CSIZE)!=tp->mask) continue; if(flags || (sp->c_cflag&CSIZE) != (tty.c_cflag&CSIZE)) sfprintf(sfstdout,"%s ",tp->name); break; case SPEED: if(tp->mask==ispeed) { if(ispeed!=ospeed) schar[0]='i'; else schar[0]=0; } else if(tp->mask==ospeed) schar[0]='o'; else continue; schar[1] = 0; #ifdef TIOCSWINSZ { struct winsize win; off = ioctl(0,TIOCGWINSZ,&win); if(off>=0) sfprintf(sfstdout,"%sspeed %s baud; rows %d; columns %d;\n",schar,tp->name,win.ws_row,win.ws_col); } if(off<0) #endif sfprintf(sfstdout,"%sspeed %s baud;\n",schar,tp->name); } } if(delim=='\n') sfputc(sfstdout,'\n'); }