start_stop_daemon: fix bug where any program name was "matching"
processes for which readlink(/proc/N/exe) fails
diff --git a/debianutils/start_stop_daemon.c b/debianutils/start_stop_daemon.c
index f523529..399f9f5 100644
--- a/debianutils/start_stop_daemon.c
+++ b/debianutils/start_stop_daemon.c
@@ -26,7 +26,7 @@
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 @@
{
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 @@
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_cmd(pid_t pid, const char *name)
{
- char buf[sizeof("/proc//stat") + sizeof(int)*3];
- FILE *f;
- int c;
+ char fname[sizeof("/proc//stat") + sizeof(int)*3];
+ char *buf;
+ int r = 0;
- 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;
+ 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 @@
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 @@
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 @@
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 @@
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 b3648b4..50e0354 100644
--- a/libbb/read.c
+++ b/libbb/read.c
@@ -118,16 +118,19 @@
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;