From 3db254c8866de390c327d759ba615693e45aff6f Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Sat, 10 Nov 2007 02:01:51 +0000 Subject: [PATCH] apply accumulated post 1.8.0 fixes, bump version to 1.8.1 --- Makefile | 2 +- archival/unzip.c | 14 ++++++++-- loginutils/login.c | 65 ++++++++++++++++++++++++++++---------------- modutils/modprobe.c | 2 +- networking/telnetd.c | 34 +++++++++++++++-------- scripts/defconfig | 18 ++++++++++-- sysklogd/syslogd.c | 37 ++++++++++++++++++------- 7 files changed, 120 insertions(+), 52 deletions(-) diff --git a/Makefile b/Makefile index 6587d901e..b2ce6d493 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 8 -SUBLEVEL = 0 +SUBLEVEL = 1 EXTRAVERSION = NAME = Unnamed diff --git a/archival/unzip.c b/archival/unzip.c index 56a5eb625..8462822f1 100644 --- a/archival/unzip.c +++ b/archival/unzip.c @@ -41,8 +41,10 @@ enum { #endif }; +#define ZIP_HEADER_LEN 26 + typedef union { - uint8_t raw[26]; + uint8_t raw[ZIP_HEADER_LEN]; struct { uint16_t version; /* 0-1 */ uint16_t flags; /* 2-3 */ @@ -57,8 +59,14 @@ typedef union { } formatted ATTRIBUTE_PACKED; } zip_header_t; +/* Check the offset of the last element, not the length. This leniency + * allows for poor packing, whereby the overall struct may be too long, + * even though the elements are all in the right place. + */ struct BUG_zip_header_must_be_26_bytes { - char BUG_zip_header_must_be_26_bytes[sizeof(zip_header_t) == 26 ? 1 : -1]; + char BUG_zip_header_must_be_26_bytes[ + offsetof(zip_header_t, formatted.extra_len) + 2 == + ZIP_HEADER_LEN ? 1 : -1]; }; #define FIX_ENDIANNESS(zip_header) do { \ @@ -256,7 +264,7 @@ int unzip_main(int argc, char **argv) bb_error_msg_and_die("invalid zip magic %08X", magic); /* Read the file header */ - xread(src_fd, zip_header.raw, sizeof(zip_header)); + xread(src_fd, zip_header.raw, ZIP_HEADER_LEN); FIX_ENDIANNESS(zip_header); if ((zip_header.formatted.method != 0) && (zip_header.formatted.method != 8)) { bb_error_msg_and_die("unsupported method %d", zip_header.formatted.method); diff --git a/loginutils/login.c b/loginutils/login.c index bddc0f533..53d3e528b 100644 --- a/loginutils/login.c +++ b/loginutils/login.c @@ -239,9 +239,14 @@ int login_main(int argc, char **argv) char full_tty[TTYNAME_SIZE]; USE_SELINUX(security_context_t user_sid = NULL;) USE_FEATURE_UTMP(struct utmp utent;) - USE_PAM(pam_handle_t *pamh;) - USE_PAM(int pamret;) - USE_PAM(const char *failed_msg;) +#if ENABLE_PAM + int pamret; + pam_handle_t *pamh; + const char *pamuser; + const char *failed_msg; + struct passwd pwdstruct; + char pwdbuf[256]; +#endif short_tty = full_tty; username[0] = '\0'; @@ -297,18 +302,18 @@ int login_main(int argc, char **argv) #if ENABLE_PAM pamret = pam_start("login", username, &conv, &pamh); if (pamret != PAM_SUCCESS) { - failed_msg = "pam_start"; + failed_msg = "start"; goto pam_auth_failed; } /* set TTY (so things like securetty work) */ pamret = pam_set_item(pamh, PAM_TTY, short_tty); if (pamret != PAM_SUCCESS) { - failed_msg = "pam_set_item(TTY)"; + failed_msg = "set_item(TTY)"; goto pam_auth_failed; } pamret = pam_authenticate(pamh, 0); if (pamret != PAM_SUCCESS) { - failed_msg = "pam_authenticate"; + failed_msg = "authenticate"; goto pam_auth_failed; /* TODO: or just "goto auth_failed" * since user seems to enter wrong password @@ -318,28 +323,42 @@ int login_main(int argc, char **argv) /* check that the account is healthy */ pamret = pam_acct_mgmt(pamh, 0); if (pamret != PAM_SUCCESS) { - failed_msg = "account setup"; + failed_msg = "acct_mgmt"; goto pam_auth_failed; } /* read user back */ - { - const char *pamuser; - /* gcc: "dereferencing type-punned pointer breaks aliasing rules..." - * thus we cast to (void*) */ - if (pam_get_item(pamh, PAM_USER, (void*)&pamuser) != PAM_SUCCESS) { - failed_msg = "pam_get_item(USER)"; - goto pam_auth_failed; - } - safe_strncpy(username, pamuser, sizeof(username)); + pamuser = NULL; + /* gcc: "dereferencing type-punned pointer breaks aliasing rules..." + * thus we cast to (void*) */ + if (pam_get_item(pamh, PAM_USER, (void*)&pamuser) != PAM_SUCCESS) { + failed_msg = "get_item(USER)"; + goto pam_auth_failed; } - /* If we get here, the user was authenticated, and is - * granted access. */ - pw = getpwnam(username); - if (pw) - break; - goto auth_failed; + if (!pamuser || !pamuser[0]) + goto auth_failed; + safe_strncpy(username, pamuser, sizeof(username)); + /* Don't use "pw = getpwnam(username);", + * PAM is said to be capable of destroying static storage + * used by getpwnam(). We are using safe(r) function */ + pw = NULL; + getpwnam_r(username, &pwdstruct, pwdbuf, sizeof(pwdbuf), &pw); + if (!pw) + goto auth_failed; + pamret = pam_open_session(pamh, 0); + if (pamret != PAM_SUCCESS) { + failed_msg = "open_session"; + goto pam_auth_failed; + } + pamret = pam_setcred(pamh, PAM_ESTABLISH_CRED); + if (pamret != PAM_SUCCESS) { + failed_msg = "setcred"; + goto pam_auth_failed; + } + break; /* success, continue login process */ + pam_auth_failed: - bb_error_msg("%s failed: %s (%d)", failed_msg, pam_strerror(pamh, pamret), pamret); + bb_error_msg("pam_%s call failed: %s (%d)", failed_msg, + pam_strerror(pamh, pamret), pamret); safe_strncpy(username, "UNKNOWN", sizeof(username)); #else /* not PAM */ pw = getpwnam(username); diff --git a/modutils/modprobe.c b/modutils/modprobe.c index f7d193a05..dafbb4ecd 100644 --- a/modutils/modprobe.c +++ b/modutils/modprobe.c @@ -791,7 +791,7 @@ static void check_dep(char *mod, struct mod_list_t **head, struct mod_list_t **t if (*tail) (*tail)->m_next = find; find->m_prev = *tail; - /*find->m_next = NULL; - xzalloc did it */ + find->m_next = NULL; /* possibly NOT done by xzalloc! */ if (!*head) *head = find; diff --git a/networking/telnetd.c b/networking/telnetd.c index cccf03dfd..108bbf44f 100644 --- a/networking/telnetd.c +++ b/networking/telnetd.c @@ -279,6 +279,10 @@ make_new_session( /* make new session and process group */ setsid(); + /* Restore default signal handling */ + signal(SIGCHLD, SIG_DFL); + signal(SIGPIPE, SIG_DFL); + /* open the child's side of the tty. */ /* NB: setsid() disconnects from any previous ctty's. Therefore * we must open child's side of the tty AFTER setsid! */ @@ -302,14 +306,18 @@ make_new_session( /* Uses FILE-based I/O to stdout, but does fflush(stdout), * so should be safe with vfork. * I fear, though, that some users will have ridiculously big - * issue files, and they may block writing to fd 1. */ + * issue files, and they may block writing to fd 1, + * (parent is supposed to read it, but parent waits + * for vforked child to exec!) */ print_login_issue(issuefile, NULL); /* Exec shell / login / whatever */ login_argv[0] = loginpath; login_argv[1] = NULL; - execvp(loginpath, (char **)login_argv); - /* Safer with vfork, and we shouldn't send message + /* exec busybox applet (if PREFER_APPLETS=y), if that fails, + * exec external program */ + BB_EXECVP(loginpath, (char **)login_argv); + /* _exit is safer with vfork, and we shouldn't send message * to remote clients anyway */ _exit(1); /*bb_perror_msg_and_die("execv %s", loginpath);*/ } @@ -374,7 +382,7 @@ free_session(struct tsession *ts) #else /* !FEATURE_TELNETD_STANDALONE */ -/* Used in main() only, thus exits. */ +/* Used in main() only, thus "return 0" actually is exit(0). */ #define free_session(ts) return 0 #endif @@ -384,20 +392,22 @@ static void handle_sigchld(int sig) pid_t pid; struct tsession *ts; - pid = waitpid(-1, &sig, WNOHANG); - if (pid > 0) { + /* Looping: more than one child may have exited */ + while (1) { + pid = waitpid(-1, NULL, WNOHANG); + if (pid <= 0) + break; ts = sessions; while (ts) { if (ts->shell_pid == pid) { ts->shell_pid = -1; - return; + break; } ts = ts->next; } } } - int telnetd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int telnetd_main(int argc, char **argv) { @@ -430,7 +440,7 @@ int telnetd_main(int argc, char **argv) if (!(opt & OPT_FOREGROUND)) { /* DAEMON_CHDIR_ROOT was giving inconsistent * behavior with/without -F, -i */ - bb_daemonize_or_rexec(0 /*DAEMON_CHDIR_ROOT*/, argv); + bb_daemonize_or_rexec(0 /*was DAEMON_CHDIR_ROOT*/, argv); } } /* Redirect log to syslog early, if needed */ @@ -466,6 +476,8 @@ int telnetd_main(int argc, char **argv) if (opt & OPT_WATCHCHILD) signal(SIGCHLD, handle_sigchld); + else /* prevent dead children from becoming zombies */ + signal(SIGCHLD, SIG_IGN); /* This is how the buffers are used. The arrows indicate the movement @@ -497,7 +509,7 @@ int telnetd_main(int argc, char **argv) while (ts) { struct tsession *next = ts->next; /* in case we free ts. */ if (ts->shell_pid == -1) { - /* Child died ad we detected that */ + /* Child died and we detected that */ free_session(ts); } else { if (ts->size1 > 0) /* can write to pty */ @@ -514,7 +526,7 @@ int telnetd_main(int argc, char **argv) if (!IS_INETD) { FD_SET(master_fd, &rdfdset); /* This is needed because free_session() does not - * take into account master_fd when it finds new + * take master_fd into account when it finds new * maxfd among remaining fd's */ if (master_fd > maxfd) maxfd = master_fd; diff --git a/scripts/defconfig b/scripts/defconfig index 7cd17ec64..5c359a843 100644 --- a/scripts/defconfig +++ b/scripts/defconfig @@ -1,5 +1,4 @@ # -# CONFIG_HAVE_DOT_CONFIG=y # @@ -37,10 +36,9 @@ CONFIG_FEATURE_HAVE_RPC=y # # CONFIG_STATIC is not set # CONFIG_BUILD_LIBBUSYBOX is not set -# CONFIG_FEATURE_FULL_LIBBUSYBOX is not set +# CONFIG_FEATURE_INDIVIDUAL is not set # CONFIG_FEATURE_SHARED_BUSYBOX is not set CONFIG_LFS=y -# CONFIG_BUILD_AT_ONCE is not set # # Debugging Options @@ -58,7 +56,11 @@ CONFIG_INCLUDE_SUSv2=y # CONFIG_INSTALL_NO_USR is not set CONFIG_INSTALL_APPLET_SYMLINKS=y # CONFIG_INSTALL_APPLET_HARDLINKS is not set +# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set # CONFIG_INSTALL_APPLET_DONT is not set +# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set +# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set +# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set CONFIG_PREFIX="./_install" # @@ -90,6 +92,7 @@ CONFIG_IOCTL_HEX2STR_ERROR=y CONFIG_AR=y CONFIG_FEATURE_AR_LONG_FILENAMES=y CONFIG_BUNZIP2=y +CONFIG_BZIP2=y CONFIG_CPIO=y # CONFIG_DPKG is not set # CONFIG_DPKG_DEB is not set @@ -261,6 +264,7 @@ CONFIG_CHVT=y CONFIG_CLEAR=y CONFIG_DEALLOCVT=y CONFIG_DUMPKMAP=y +CONFIG_KBD_MODE=y CONFIG_LOADFONT=y CONFIG_LOADKMAP=y CONFIG_OPENVT=y @@ -465,6 +469,7 @@ CONFIG_FEATURE_MKSWAP_V0=y CONFIG_MORE=y CONFIG_FEATURE_USE_TERMIOS=y CONFIG_MOUNT=y +CONFIG_FEATURE_MOUNT_HELPERS=y CONFIG_FEATURE_MOUNT_NFS=y CONFIG_FEATURE_MOUNT_CIFS=y CONFIG_FEATURE_MOUNT_FLAGS=y @@ -549,6 +554,7 @@ CONFIG_FTPPUT=y CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS=y CONFIG_HOSTNAME=y CONFIG_HTTPD=y +CONFIG_FEATURE_HTTPD_RANGES=y CONFIG_FEATURE_HTTPD_USE_SENDFILE=y # CONFIG_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP is not set # CONFIG_FEATURE_HTTPD_SETUID is not set @@ -560,6 +566,7 @@ CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR=y CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV=y CONFIG_FEATURE_HTTPD_ENCODE_URL_STR=y CONFIG_FEATURE_HTTPD_ERROR_PAGES=y +CONFIG_FEATURE_HTTPD_PROXY=y CONFIG_IFCONFIG=y CONFIG_FEATURE_IFCONFIG_STATUS=y CONFIG_FEATURE_IFCONFIG_SLIP=y @@ -589,6 +596,7 @@ CONFIG_FEATURE_IP_ROUTE=y CONFIG_FEATURE_IP_TUNNEL=y CONFIG_FEATURE_IP_RULE=y CONFIG_FEATURE_IP_SHORT_FORMS=y +CONFIG_FEATURE_IP_RARE_PROTOCOLS=y CONFIG_IPADDR=y CONFIG_IPLINK=y CONFIG_IPROUTE=y @@ -647,9 +655,11 @@ CONFIG_KILL=y CONFIG_KILLALL=y CONFIG_KILLALL5=y CONFIG_NMETER=y +CONFIG_PGREP=y CONFIG_PIDOF=y CONFIG_FEATURE_PIDOF_SINGLE=y CONFIG_FEATURE_PIDOF_OMIT=y +CONFIG_PKILL=y CONFIG_PS=y CONFIG_FEATURE_PS_WIDE=y CONFIG_RENICE=y @@ -658,6 +668,7 @@ CONFIG_TOP=y CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE=y CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS=y # CONFIG_FEATURE_TOP_DECIMALS is not set +CONFIG_FEATURE_TOPMEM=y CONFIG_UPTIME=y CONFIG_WATCH=y @@ -743,6 +754,7 @@ CONFIG_SOFTLIMIT=y # CONFIG_SETENFORCE is not set # CONFIG_SETFILES is not set # CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set +# CONFIG_SETSEBOOL is not set # # ipsvd utilities diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c index ba46792b6..da63ced42 100644 --- a/sysklogd/syslogd.c +++ b/sysklogd/syslogd.c @@ -381,8 +381,8 @@ static void parse_fac_prio_20(int pri, char *res20) } /* len parameter is used only for "is there a timestamp?" check. - * NB: some callers cheat and supply 0 when they know - * that there is no timestamp, short-cutting the test. */ + * NB: some callers cheat and supply len==0 when they know + * that there is no timestamp, short-circuiting the test. */ static void timestamp_and_log(int pri, char *msg, int len) { char *timestamp; @@ -427,10 +427,10 @@ static void split_escape_and_log(char *tmpbuf, int len) if (*p == '<') { /* Parse the magic priority number */ pri = bb_strtou(p + 1, &p, 10); - if (*p == '>') p++; - if (pri & ~(LOG_FACMASK | LOG_PRIMASK)) { + if (*p == '>') + p++; + if (pri & ~(LOG_FACMASK | LOG_PRIMASK)) pri = (LOG_USER | LOG_NOTICE); - } } while ((c = *p++)) { @@ -526,14 +526,32 @@ static void do_syslogd(void) for (;;) { size_t sz; - + read_again: sz = safe_read(sock_fd, G.recvbuf, MAX_READ - 1); - if (sz <= 0) { - //if (sz == 0) - // continue; /* EOF from unix socket??? */ + if (sz < 0) { bb_perror_msg_and_die("read from /dev/log"); } + /* Drop trailing NULs (typically there is one NUL) */ + while (1) { + if (sz == 0) + goto read_again; + /* man 3 syslog says: "A trailing newline is added when needed". + * However, neither glibc nor uclibc do this: + * syslog(prio, "test") sends "test\0" to /dev/log, + * syslog(prio, "test\n") sends "test\n\0", + * IOW: newline is passed verbatim! + * I take it to mean that it's syslogd's job + * to make those look identical in the log files */ + if (G.recvbuf[sz-1] && G.recvbuf[sz-1] != '\n') + break; + sz--; + } + /* Maybe we need to add '\n' here, not later? + * It looks like stock syslogd does send '\n' over network, + * but we do not (see sendto below) */ + G.recvbuf[sz] = '\0'; /* make sure it *is* NUL terminated */ + /* TODO: maybe suppress duplicates? */ #if ENABLE_FEATURE_REMOTE_LOG /* We are not modifying log messages in any way before send */ @@ -549,7 +567,6 @@ static void do_syslogd(void) } } #endif - G.recvbuf[sz] = '\0'; split_escape_and_log(G.recvbuf, sz); } /* for */ } -- 2.25.1