From b131b271a0d89b1ff04fd721530f424d0a15f0b2 Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Sun, 17 Dec 2006 17:30:01 +0000 Subject: start_stop_daemon: fix bug where any program name was "matching" processes for which readlink(/proc/N/exe) fails --- debianutils/start_stop_daemon.c | 63 +++++++++++++++++++++++------------------ libbb/read.c | 7 +++-- 2 files changed, 40 insertions(+), 30 deletions(-) diff --git a/debianutils/start_stop_daemon.c b/debianutils/start_stop_daemon.c index f52352995..399f9f5e1 100644 --- a/debianutils/start_stop_daemon.c +++ b/debianutils/start_stop_daemon.c @@ -26,7 +26,7 @@ struct pid_list { pid_t pid; }; -static struct pid_list *found = NULL; +static struct pid_list *found; static inline void push(pid_t pid) { @@ -42,13 +42,16 @@ static int pid_is_exec(pid_t pid, const char *name) { char buf[sizeof("/proc//exe") + sizeof(int)*3]; char *execbuf; + int sz; int equal; sprintf(buf, "/proc/%d/exe", pid); - execbuf = xstrdup(name); - readlink(buf, execbuf, strlen(name)+1); + sz = strlen(name) + 1; + execbuf = xzalloc(sz); + readlink(buf, execbuf, sz); - equal = ! strcmp(execbuf, name); + /* if readlink fails, execbuf still contains "" */ + equal = !strcmp(execbuf, name); if (ENABLE_FEATURE_CLEAN_UP) free(execbuf); return equal; @@ -59,7 +62,7 @@ static int pid_is_user(int pid, int uid) struct stat sb; char buf[sizeof("/proc/") + sizeof(int)*3]; - sprintf(buf, "/proc/%d", pid); + sprintf(buf, "/proc/%u", pid); if (stat(buf, &sb) != 0) return 0; return (sb.st_uid == uid); @@ -67,25 +70,24 @@ static int pid_is_user(int pid, int uid) static int pid_is_cmd(pid_t pid, const char *name) { - char buf[sizeof("/proc//stat") + sizeof(int)*3]; - FILE *f; - int c; - - sprintf(buf, "/proc/%d/stat", pid); - f = fopen(buf, "r"); - if (!f) - return 0; - while ((c = getc(f)) != EOF && c != '(') - ; - if (c != '(') { - fclose(f); - return 0; + char fname[sizeof("/proc//stat") + sizeof(int)*3]; + char *buf; + int r = 0; + + sprintf(fname, "/proc/%u/stat", pid); + buf = xmalloc_open_read_close(fname, NULL); + if (buf) { + char *p = strchr(buf, '('); + if (p) { + char *pe = strrchr(++p, ')'); + if (pe) { + *pe = '\0'; + r = !strcmp(p, name); + } + } + free(buf); } - /* this hopefully handles command names containing ')' */ - while ((c = getc(f)) != EOF && c == *name) - name++; - fclose(f); - return (c == ')' && *name == '\0'); + return r; } @@ -111,7 +113,7 @@ static void do_pidfile(void) f = fopen(pidfile, "r"); if (f) { - if (fscanf(f, "%d", &pid) == 1) + if (fscanf(f, "%u", &pid) == 1) check(pid); fclose(f); } else if (errno != ENOENT) @@ -133,7 +135,8 @@ static void do_procinit(void) foundany = 0; while ((entry = readdir(procdir)) != NULL) { - if (sscanf(entry->d_name, "%d", &pid) != 1) + pid = bb_strtou(entry->d_name, NULL, 10); + if (errno) continue; foundany++; check(pid); @@ -269,8 +272,11 @@ int start_stop_daemon_main(int argc, char **argv) argc -= optind; argv += optind; - if (userspec && sscanf(userspec, "%d", &user_id) != 1) - user_id = bb_xgetpwnam(userspec); + if (userspec) { + user_id = bb_strtou(userspec, NULL, 10); + if (errno) + user_id = bb_xgetpwnam(userspec); + } if (opt & SSD_CTX_STOP) { int i = do_stop(); @@ -301,7 +307,8 @@ int start_stop_daemon_main(int argc, char **argv) fclose(pidf); } if (chuid) { - if (sscanf(chuid, "%d", &user_id) != 1) + user_id = bb_strtou(chuid, NULL, 10); + if (errno) user_id = bb_xgetpwnam(chuid); xsetuid(user_id); } diff --git a/libbb/read.c b/libbb/read.c index b3648b4d7..50e0354ad 100644 --- a/libbb/read.c +++ b/libbb/read.c @@ -118,16 +118,19 @@ void *xmalloc_open_read_close(const char *filename, size_t *sizep) char *buf; size_t size = sizep ? *sizep : INT_MAX; int fd = xopen(filename, O_RDONLY); - off_t len = xlseek(fd, 0, SEEK_END); + /* /proc/N/stat files report len 0 here */ + /* In order to make such files readable, we add small const */ + off_t len = xlseek(fd, 0, SEEK_END) + 256; xlseek(fd, 0, SEEK_SET); if (len > size) bb_error_msg_and_die("file '%s' is too big", filename); size = len; - buf = xmalloc(size+1); + buf = xmalloc(size + 1); size = read_close(fd, buf, size); if ((ssize_t)size < 0) bb_perror_msg_and_die("'%s'", filename); + xrealloc(buf, size + 1); buf[size] = '\0'; if (sizep) *sizep = size; return buf; -- cgit v1.2.3