Compare commits

..
6 Commits
47 .. 49
Author SHA1 Message Date
Patrick McCarty b802948209 Release v49
- List tarball contents prior to extraction to improve robustness
- Plug some memory leaks
- Print errors to stderr instead of stdout

Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2019-05-24 13:04:07 -07:00
Auke Kok 4495b923a9 Redo tar extraction - try and make this safe(r).
Instead of extracting to a tmp folder, just tar `tf` it first. This
keeps extracting to the proper locations trivial, at the cost of
decompression the content twice.
2019-05-10 11:08:06 -07:00
Auke Kok 8f7289f028 Test result of tar extraction before trusting the result.
We extract the tarball to a temporary file, before actually allowing
gdb to use this file. This allows us to make sure that gdb doesn't
see the file if it is corrupt. Only if tar exceeds, we rename() the
temp result into the actual needed file. If tar fails, we throw away
the file.
2019-05-07 16:19:36 -07:00
Auke Kok dc376d5e8b Update to v48 2019-01-15 12:47:32 -08:00
Auke Kok c831ecb902 Use select() to time out, and exit.
With socket activation, we can now select() and time out before accept()
and exit, releasing all resource we used back to the system.

The default timeout is set for 10 minutes. If no more connections
arrive, the daemon exits.

Socket activation is done through the clr_debug_daemon.socket unit, which
the clr_debug_fuse service requires, so this should be extra robust when
starting up.

The daemon ignores stat() requests for trash that gnome sends when it
sees the fuse system mounted, and returns the underlying stat() for
the root node instead of a remote value, because there is no value
in fetching this info over curl.
2019-01-09 12:58:42 -08:00
Auke Kok 0978d429b2 Clean up some of the socket activation stuff. 2019-01-08 12:37:56 -08:00
5 changed files with 118 additions and 57 deletions
+2 -1
View File
@@ -1,6 +1,7 @@
[Unit] [Unit]
Description=Clear Linux debuginfo fuse monitor Description=Clear Linux debuginfo fuse monitor
After=clr_debug_daemon.service After=clr_debug_daemon.socket
Requires=clr_debug_daemon.socket
DefaultDependencies=no DefaultDependencies=no
[Service] [Service]
+3 -1
View File
@@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script. # Process this file with autoconf to produce a configure script.
AC_PREREQ([2.66]) AC_PREREQ([2.66])
AC_INIT(clr-debug-info, 47, arjan@linux.intel.com) AC_INIT(clr-debug-info, 49, arjan@linux.intel.com)
AM_INIT_AUTOMAKE([foreign -Wall -W subdir-objects]) AM_INIT_AUTOMAKE([foreign -Wall -W subdir-objects])
AM_SILENT_RULES([yes]) AM_SILENT_RULES([yes])
AC_PROG_CC AC_PROG_CC
@@ -15,6 +15,8 @@ PKG_CHECK_MODULES([SYSTEMD], [systemd])
PKG_CHECK_MODULES([LIBSYSTEMD], [libsystemd]) PKG_CHECK_MODULES([LIBSYSTEMD], [libsystemd])
LT_INIT LT_INIT
AC_DEFINE([SOCKET_PATH], ["/run/clr-debug-info"], [path to communication socket])
dir="" dir=""
AC_ARG_WITH([systemdsystemunitdir], AS_HELP_STRING([--with-systemdsystemunitdir=DIR], AC_ARG_WITH([systemdsystemunitdir], AS_HELP_STRING([--with-systemdsystemunitdir=DIR],
[path to systemd system service dir @<:@default=/usr/lib/systemd/system@:>@]), [dir=${withval}], [path to systemd system service dir @<:@default=/usr/lib/systemd/system@:>@]), [dir=${withval}],
+6 -4
View File
@@ -36,6 +36,8 @@
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#include "config.h"
/* 0.75 seconds timeout */ /* 0.75 seconds timeout */
#define TIMEOUT 75000 #define TIMEOUT 75000
#define TIMEOUT2 1500 #define TIMEOUT2 1500
@@ -58,7 +60,7 @@ void try_to_get(const char *path, int pid, time_t timestamp)
int shorttime = 0; int shorttime = 0;
__nc_unused__ size_t wr = -1; __nc_unused__ size_t wr = -1;
// printf("Trying to aquire %s\n", path); // printf("Trying to aquire %s\n", path);
sockfd = socket(AF_UNIX, SOCK_STREAM, 0); sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sockfd < 0) { if (sockfd < 0) {
@@ -66,13 +68,13 @@ void try_to_get(const char *path, int pid, time_t timestamp)
} }
sun.sun_family = AF_UNIX; sun.sun_family = AF_UNIX;
strcpy(sun.sun_path, "/run/clr-debug-info"); strcpy(sun.sun_path, SOCKET_PATH);
ret = connect(sockfd, ret = connect(sockfd,
(struct sockaddr *)&sun, (struct sockaddr *)&sun,
offsetof(struct sockaddr_un, sun_path) + strlen("/run/clr-debug-info") + 1); offsetof(struct sockaddr_un, sun_path) + strlen(SOCKET_PATH) + 1);
if (ret < 0) { if (ret < 0) {
printf("Cannot connect %s\n", strerror(errno)); printf("Cannot connect to %s: %s\n", SOCKET_PATH, strerror(errno));
close(sockfd); close(sockfd);
return; return;
} }
+10
View File
@@ -75,6 +75,16 @@ static int xmp_getattr(const char *path, struct stat *stbuf)
memset(stbuf, 0, sizeof(struct stat)); memset(stbuf, 0, sizeof(struct stat));
res = lstat(newpath, stbuf); res = lstat(newpath, stbuf);
/*
* filter out things that never should get fetched
* this prevents us from asking curl to fetch us useless things
*/
if (strncmp(path, "/.Trash", strlen("/.Trash")) == 0) {
return -ENOENT;
} else if (strcmp(path, "/") == 0) {
return 0;
}
/* /*
* get the file. if the st_mtime is set, this is just an async refresh, otherwise it's * get the file. if the st_mtime is set, this is just an async refresh, otherwise it's
* a synchronous request. * a synchronous request.
+97 -51
View File
@@ -2,7 +2,7 @@
* Clear Linux -- automatic debug information installation * Clear Linux -- automatic debug information installation
* *
* Copyright (C) 2013 Arjan van de Ven * Copyright (C) 2013 Arjan van de Ven
* Curl portions borrowed from the Fenrus Update code * Curl portions borrowed from the Fenrus Update code
* which in part is (C) 2012 Intel Corporation * which in part is (C) 2012 Intel Corporation
* Copyright (C) 2014 Intel Corporation * Copyright (C) 2014 Intel Corporation
* *
@@ -32,6 +32,7 @@
#include <malloc.h> #include <malloc.h>
#include <pthread.h> #include <pthread.h>
#include <pwd.h> #include <pwd.h>
#include <libgen.h>
#include <signal.h> #include <signal.h>
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
@@ -57,6 +58,8 @@
#include <stdatomic.h> #include <stdatomic.h>
#endif #endif
#define TIMEOUT 600 /* 10 minutes */
static pthread_mutex_t dupes_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t dupes_mutex = PTHREAD_MUTEX_INITIALIZER;
char *urls[2] = { "https://cdn.download.clearlinux.org/debuginfo/", char *urls[2] = { "https://cdn.download.clearlinux.org/debuginfo/",
@@ -168,10 +171,9 @@ static int curl_get_file(const char *url, const char *prefix, time_t timestamp)
long ret; long ret;
long changed; long changed;
int fd; int fd;
char filename[PATH_MAX]; autofree(char) *filename = NULL;
CURL *curl = NULL; CURL *curl = NULL;
FILE *file; FILE *file;
struct stat statbuf;
if (avoid_dupes(url)) { if (avoid_dupes(url)) {
return 300; return 300;
@@ -182,12 +184,15 @@ static int curl_get_file(const char *url, const char *prefix, time_t timestamp)
return 301; return 301;
} }
strcpy(filename, "/tmp/clr-debug-info-XXXXXX"); // fprintf(stderr, "Fetching %s, prefix %s, path %s\n", url, prefix, path);
if (asprintf(&filename, "/tmp/clr-debug-info-XXXXXX") < 0) {
curl_easy_cleanup(curl);
return 418;
}
fd = mkstemp(filename); fd = mkstemp(filename);
if (fd < 0) { if (fd < 0) {
curl_easy_cleanup(curl); curl_easy_cleanup(curl);
return 500; return 418;
} }
file = fdopen(fd, "w"); file = fdopen(fd, "w");
@@ -225,7 +230,7 @@ static int curl_get_file(const char *url, const char *prefix, time_t timestamp)
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &ret); curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &ret);
fflush(file); fflush(file);
// printf("HTTP return code is %i\n", ret); // printf("HTTP return code is %i\n", ret);
/* HTTP 304 is returned if (a) the cached debuginfo has the same /* HTTP 304 is returned if (a) the cached debuginfo has the same
* timestamp or is newer than that on the server and (b) we haven't * timestamp or is newer than that on the server and (b) we haven't
@@ -238,6 +243,9 @@ static int curl_get_file(const char *url, const char *prefix, time_t timestamp)
} }
if (ret == 200) { if (ret == 200) {
autofree(char) *command = NULL;
struct stat statbuf;
/* get timestamp, if any */ /* get timestamp, if any */
curl_easy_getinfo(curl, CURLINFO_FILETIME, &changed); curl_easy_getinfo(curl, CURLINFO_FILETIME, &changed);
if (changed >= 0) { if (changed >= 0) {
@@ -249,22 +257,45 @@ static int curl_get_file(const char *url, const char *prefix, time_t timestamp)
futimens(fd, times); futimens(fd, times);
} }
autofree(char) *command = NULL;
// printf("Filename is %s\n", filename);
memset(&statbuf, 0, sizeof(statbuf)); memset(&statbuf, 0, sizeof(statbuf));
stat(filename, &statbuf); stat(filename, &statbuf);
if (statbuf.st_size > 0 && if (statbuf.st_size <= 0) {
asprintf(&command, ret = 418;
"tar -C /var/cache/debuginfo/%s --no-same-owner " goto out;
"--no-same-permissions -xf %s", }
/* test extraction first */
if (asprintf(&command, "tar -C /var/cache/debuginfo/%s --no-same-owner "
"--no-same-permissions -tf %s",
prefix, prefix,
filename) >= 0) { filename) < 0) {
if (system(command) != 0) { ret = 418;
fputs("Warning: tar extraction failed\n", stderr); goto out;
} }
if (system(command) != 0) {
ret = 418;
fprintf(stderr, "Error: tar validation failed\n");
goto out;
}
free(command); /* reuse */
if (asprintf(&command, "tar -C /var/cache/debuginfo/%s --no-same-owner "
"--no-same-permissions -xf %s",
prefix,
filename) < 0) {
ret = 418;
goto out;
}
if (system(command) != 0) {
ret = 418;
fprintf(stderr, "Error: tar extraction failed\n");
goto out;
} }
} }
out:
unlink(filename); unlink(filename);
curl_easy_cleanup(curl); curl_easy_cleanup(curl);
fclose(file); fclose(file);
@@ -338,7 +369,7 @@ static void *server_thread(void *arg)
goto thread_end; goto thread_end;
} }
// printf("Getting url %s %i:%06i\n", url, before.tv_sec, before.tv_usec); // printf("Getting url %s %i:%06i\n", url, before.tv_sec, before.tv_usec);
ret = curl_get_file(url, prefix, timestamp); ret = curl_get_file(url, prefix, timestamp);
switch (ret) { switch (ret) {
@@ -349,7 +380,7 @@ static void *server_thread(void *arg)
// ignore these error codes // ignore these error codes
break; break;
default: default:
printf("Request for %s resulted in error %i\n", url, ret); fprintf(stderr, "Request for %s resulted in error %i\n", url, ret);
break; break;
} }
@@ -431,54 +462,71 @@ int main(__nc_unused__ int argc, __nc_unused__ char **argv)
signal(SIGPIPE, SIG_IGN); signal(SIGPIPE, SIG_IGN);
if (sd_listen_fds(0) == 1) { if (sd_listen_fds(0) == 1) {
/* systemd socket activation */ /* systemd socket activation */
printf("Received socket from systemd socket activation\n"); sockfd = SD_LISTEN_FDS_START + 0;
sockfd = SD_LISTEN_FDS_START + 0; } else if (sd_listen_fds(0) > 1) {
} else if (sd_listen_fds(0) > 1) { fprintf(stderr, "Too many file descriptors received.\n");
printf("Too many file descriptors received.\n"); exit(EXIT_FAILURE);
exit(1); } else {
} else { sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
sockfd = socket(AF_UNIX, SOCK_STREAM, 0); if (sockfd < 0) {
if (sockfd < 0) { exit(EXIT_FAILURE);
return EXIT_FAILURE; }
}
sun.sun_family = AF_UNIX; sun.sun_family = AF_UNIX;
strcpy(sun.sun_path, "/run/clr-debug-info"); strcpy(sun.sun_path, SOCKET_PATH);
ret = bind(sockfd, ret = bind(sockfd,
(struct sockaddr *)&sun, (struct sockaddr *)&sun,
offsetof(struct sockaddr_un, sun_path) + strlen("/run/clr-debug-info") + 1); offsetof(struct sockaddr_un, sun_path) + strlen(SOCKET_PATH) + 1);
if (ret < 0) { if (ret < 0) {
printf("Failed to bind:%s \n", strerror(errno)); fprintf(stderr, "Failed to bind:%s \n", strerror(errno));
return EXIT_FAILURE; exit(EXIT_FAILURE);
} }
if (listen(sockfd, 16) < 0) { if (listen(sockfd, 16) < 0) {
printf("Failed to listen:%s \n", strerror(errno)); fprintf(stderr, "Failed to listen:%s \n", strerror(errno));
return EXIT_FAILURE; exit(EXIT_FAILURE);
} }
} }
if (setgid(dbg_group)) { if (setgid(dbg_group)) {
fprintf(stderr, "Unable to drop privileges setgid %s\n", strerror(errno)); fprintf(stderr, "Unable to drop privileges setgid %s\n", strerror(errno));
return EXIT_FAILURE; exit(EXIT_FAILURE);
} }
if (setgroups(1, &dbg_group)) { if (setgroups(1, &dbg_group)) {
fprintf(stderr, "Unable to drop privileges setgroups %s\n", strerror(errno)); fprintf(stderr, "Unable to drop privileges setgroups %s\n", strerror(errno));
return EXIT_FAILURE; exit(EXIT_FAILURE);
} }
if (setuid(dbg_user)) { if (setuid(dbg_user)) {
fprintf(stderr, "Unable to drop privileges setuid %s\n", strerror(errno)); fprintf(stderr, "Unable to drop privileges setuid %s\n", strerror(errno));
return EXIT_FAILURE; exit(EXIT_FAILURE);
} }
while (1) { while (1) {
fd_set rfds;
struct timeval tv;
int ret;
int clientsock; int clientsock;
pthread_t thread; pthread_t thread;
malloc_trim(0); malloc_trim(0);
/* use select() to timeout and exit gracefully */
FD_ZERO(&rfds);
FD_SET(sockfd, &rfds);
tv.tv_sec = TIMEOUT;
tv.tv_usec = 0;
ret = select(sockfd + 1, &rfds, NULL, NULL, &tv);
if (ret == -1) {
perror("select()");
exit(EXIT_FAILURE);
} else if (ret == 0) {
break;
}
clientsock = accept(sockfd, NULL, NULL); clientsock = accept(sockfd, NULL, NULL);
/* Too many connections, wait for the next loop/retry */ /* Too many connections, wait for the next loop/retry */
@@ -503,6 +551,4 @@ int main(__nc_unused__ int argc, __nc_unused__ char **argv)
if (hash) { if (hash) {
nc_hashmap_free(hash); nc_hashmap_free(hash);
} }
close(sockfd);
} }