aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Purdie <richard.purdie@linuxfoundation.org>2020-10-08 15:00:39 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2020-10-08 15:00:39 +0100
commit13cb850a6bbfa47b1768c5dc1b88ca91321bec20 (patch)
tree8fcacf6338699ec76a64ea75caf13a06eb620011
parentd8d1c38bc12c283e7d113a2dfe0691fca804b570 (diff)
downloadpseudo-13cb850a6bbfa47b1768c5dc1b88ca91321bec20.tar.gz
pseudo-13cb850a6bbfa47b1768c5dc1b88ca91321bec20.tar.bz2
pseudo-13cb850a6bbfa47b1768c5dc1b88ca91321bec20.zip
pseudo_client: Improve unlinked file descriptor tracking
Consider what happens if a program does: fd = fopen("A") link("A", "B") unlink("A") fchown(fd) Assuming we can't use the database, in order to handle this correctly, we need to change the open fd to point at B when A us unlinked. Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--ports/unix/guts/linkat.c1
-rw-r--r--pseudo_client.c65
-rw-r--r--pseudo_client.h1
3 files changed, 53 insertions, 14 deletions
diff --git a/ports/unix/guts/linkat.c b/ports/unix/guts/linkat.c
index 381f9d0..7d8dff4 100644
--- a/ports/unix/guts/linkat.c
+++ b/ports/unix/guts/linkat.c
@@ -116,6 +116,7 @@
* if the thing linked is a symlink.
*/
pseudo_client_op(OP_LINK, 0, -1, -1, newpath, &buf);
+ pseudo_client_linked_paths(oldpath, newpath);
errno = save_errno;
diff --git a/pseudo_client.c b/pseudo_client.c
index bcaf2dd..4aa3522 100644
--- a/pseudo_client.c
+++ b/pseudo_client.c
@@ -70,6 +70,8 @@ int pseudo_umask = 022;
static char **fd_paths = NULL;
static int nfds = 0;
+static char **linked_fd_paths = NULL;
+static int linked_nfds = 0;
static const char **passwd_paths = NULL;
static int npasswd_paths = 0;
#ifdef PSEUDO_PROFILING
@@ -889,32 +891,58 @@ fd_path(int fd) {
}
static void
-pseudo_client_path(int fd, const char *path) {
+pseudo_client_path_set(int fd, const char *path, char ***patharray, int *len) {
if (fd < 0)
return;
- if (fd >= nfds) {
+ if (fd >= *len) {
int i;
pseudo_debug(PDBGF_CLIENT, "expanding fds from %d to %d\n",
- nfds, fd + 1);
- fd_paths = realloc(fd_paths, (fd + 1) * sizeof(char *));
- for (i = nfds; i < fd + 1; ++i)
- fd_paths[i] = 0;
- nfds = fd + 1;
+ *len, fd + 1);
+ (*patharray) = realloc((*patharray), (fd + 1) * sizeof(char *));
+ for (i = *len; i < fd + 1; ++i)
+ (*patharray)[i] = 0;
+ *len = fd + 1;
} else {
- if (fd_paths[fd]) {
+ if ((*patharray)[fd]) {
pseudo_debug(PDBGF_CLIENT, "reopening fd %d [%s] -- didn't see close\n",
- fd, fd_paths[fd]);
+ fd, (*patharray)[fd]);
}
/* yes, it is safe to free null pointers. yay for C89 */
- free(fd_paths[fd]);
- fd_paths[fd] = 0;
+ free((*patharray)[fd]);
+ (*patharray)[fd] = 0;
}
if (path) {
- fd_paths[fd] = strdup(path);
+ (*patharray)[fd] = strdup(path);
+ }
+}
+
+static void
+pseudo_client_path(int fd, const char *path) {
+ pseudo_client_path_set(fd, path, &fd_paths, &nfds);
+}
+
+void
+pseudo_client_linked_paths(const char *oldpath, const char *newpath) {
+ int fd;
+ for (fd = 3; fd < nfds; ++fd) {
+ if (fd_paths[fd] && !strcmp(oldpath, fd_paths[fd])) {
+ pseudo_client_path_set(fd, newpath, &linked_fd_paths, &linked_nfds);
+ }
+ }
+}
+
+static void
+pseudo_client_unlinked_path(const char *path) {
+ int fd;
+ for (fd = 0; fd < linked_nfds; ++fd) {
+ if (linked_fd_paths[fd] && fd_paths[fd] && !strcmp(path, fd_paths[fd])) {
+ pseudo_client_path(fd, linked_fd_paths[fd]);
+ }
}
}
+
static void
pseudo_client_close(int fd) {
if (fd < 0 || fd >= nfds)
@@ -922,6 +950,11 @@ pseudo_client_close(int fd) {
free(fd_paths[fd]);
fd_paths[fd] = 0;
+
+ if (fd < linked_nfds) {
+ free(linked_fd_paths[fd]);
+ linked_fd_paths[fd] = 0;
+ }
}
/* spawn server */
@@ -1860,6 +1893,12 @@ pseudo_client_op(pseudo_op_t op, int access, int fd, int dirfd, const char *path
dirfd);
pseudo_client_path(dirfd, fd_path(fd));
break;
+ case OP_UNLINK:
+ case OP_DID_UNLINK:
+ if (path)
+ pseudo_client_unlinked_path(path);
+ do_request = 1;
+ break;
/* operations for which we should use the magic uid/gid */
case OP_CHMOD:
case OP_CREAT:
@@ -1882,8 +1921,6 @@ pseudo_client_op(pseudo_op_t op, int access, int fd, int dirfd, const char *path
case OP_LINK:
case OP_RENAME:
case OP_STAT:
- case OP_UNLINK:
- case OP_DID_UNLINK:
case OP_CANCEL_UNLINK:
case OP_MAY_UNLINK:
case OP_GET_XATTR:
diff --git a/pseudo_client.h b/pseudo_client.h
index 4c10fc6..d7944ce 100644
--- a/pseudo_client.h
+++ b/pseudo_client.h
@@ -9,6 +9,7 @@
extern pseudo_msg_t *pseudo_client_op(pseudo_op_t op, int access, int fd, int dirfd, const char *path, const PSEUDO_STATBUF *buf, ...);
extern int pseudo_client_ignore_path(const char *path);
extern int pseudo_client_ignore_fd(int fd);
+extern void pseudo_client_linked_paths(const char *oldpath, const char *newpath);
#if PSEUDO_STATBUF_64
#define base_lstat real_lstat64
#define base_fstat real_fstat64