From f363a8f4448c15a8b7bb5ff9f5f65be562dbf786 Mon Sep 17 00:00:00 2001 From: aviralgarg05 Date: Thu, 23 Jul 2026 23:08:07 +0530 Subject: [PATCH] system/nxpkg: Protect live locks from filesystem clock skew. Record a per-boot token and owner PID in every package, installed-database, and synchronization lock. A contender now keeps a lock held while its recorded owner task is alive, regardless of unreliable FAT modification timestamps. Reclaim locks from exited owners or earlier boots immediately, while retaining timestamp-based migration handling for legacy empty lock files. This prevents a just-created live lock from being mistaken for a decades-old stale file on targets whose mounted filesystem clock does not match CLOCK_REALTIME. Assisted-by: OpenAI Codex:gpt-5.6-sol Signed-off-by: aviralgarg05 --- system/nxpkg/pkg.h | 1 + system/nxpkg/pkg_install.c | 63 ++---------- system/nxpkg/pkg_repo.c | 10 +- system/nxpkg/pkg_store.c | 191 +++++++++++++++++++++++++++++++++++++ 4 files changed, 204 insertions(+), 61 deletions(-) diff --git a/system/nxpkg/pkg.h b/system/nxpkg/pkg.h index 28c8c19a8..8c1f6850a 100644 --- a/system/nxpkg/pkg.h +++ b/system/nxpkg/pkg.h @@ -261,6 +261,7 @@ int pkg_resolve_icon_source(FAR char *buffer, size_t size, FAR const struct pkg_manifest_s *manifest); int pkg_acquire_source(FAR const char *source, FAR const char *dest, FAR const char *renew_lock_path); +int pkg_lock_create(FAR const char *path); void pkg_reclaim_stale_lock(FAR const char *path); int pkg_sync(FAR const char *source); int pkg_install(FAR const char *name); diff --git a/system/nxpkg/pkg_install.c b/system/nxpkg/pkg_install.c index cef908c51..7b326cfe8 100644 --- a/system/nxpkg/pkg_install.c +++ b/system/nxpkg/pkg_install.c @@ -25,13 +25,11 @@ ****************************************************************************/ #include -#include #include #include #include #include #include -#include #include #include "pkg.h" @@ -43,7 +41,6 @@ static int pkg_install_acquire_lock(FAR const char *name, FAR char *path, size_t size) { - int fd; int ret; ret = pkg_store_ensure_package_root(name); @@ -58,20 +55,14 @@ static int pkg_install_acquire_lock(FAR const char *name, FAR char *path, return ret; } - fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0644); - if (fd < 0 && errno == EEXIST) + ret = pkg_lock_create(path); + if (ret == -EEXIST) { pkg_reclaim_stale_lock(path); - fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0644); + ret = pkg_lock_create(path); } - if (fd < 0) - { - return errno == EEXIST ? -EBUSY : -errno; - } - - close(fd); - return 0; + return ret == -EEXIST ? -EBUSY : ret; } /**************************************************************************** @@ -85,7 +76,6 @@ static int pkg_install_acquire_lock(FAR const char *name, FAR char *path, static int pkg_install_acquire_installed_lock(FAR char *path, size_t size) { - int fd; int ret; int tries; @@ -102,16 +92,15 @@ static int pkg_install_acquire_installed_lock(FAR char *path, size_t size) for (tries = 0; tries < 100; tries++) { - fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0644); - if (fd >= 0) + ret = pkg_lock_create(path); + if (ret == 0) { - close(fd); return 0; } - if (errno != EEXIST) + if (ret != -EEXIST) { - return -errno; + return ret; } pkg_reclaim_stale_lock(path); @@ -337,42 +326,6 @@ out: * Public Functions ****************************************************************************/ -/**************************************************************************** - * Name: pkg_reclaim_stale_lock - * - * Description: - * Remove "path" if it is old enough that it cannot belong to a still- - * running holder (see PKG_LOCK_STALE_SECONDS). Best-effort: any - * stat()/unlink() failure just falls through to the normal -EBUSY - * result, since a lock we can't inspect should be treated as held. - * Generic across every lock file this package uses (per-package - * install locks, the shared installed-db lock, pkg_repo.c's sync - * lock) - not install-specific despite living in this file. - * - ****************************************************************************/ - -void pkg_reclaim_stale_lock(FAR const char *path) -{ - struct stat st; - time_t now; - - if (stat(path, &st) < 0) - { - return; - } - - now = time(NULL); - if (now < st.st_mtime || - (now - st.st_mtime) < PKG_LOCK_STALE_SECONDS) - { - return; - } - - pkg_error("reclaiming stale lock '%s' (age %ld s)", - path, (long)(now - st.st_mtime)); - unlink(path); -} - int pkg_install(FAR const char *name) { FAR struct pkg_index_s *index; diff --git a/system/nxpkg/pkg_repo.c b/system/nxpkg/pkg_repo.c index 3cd201e8e..2a4e0ef27 100644 --- a/system/nxpkg/pkg_repo.c +++ b/system/nxpkg/pkg_repo.c @@ -544,7 +544,6 @@ int pkg_acquire_source(FAR const char *source, FAR const char *dest, static int pkg_repo_acquire_sync_lock(FAR char *path, size_t size) { - int fd; int ret; int tries; @@ -561,16 +560,15 @@ static int pkg_repo_acquire_sync_lock(FAR char *path, size_t size) for (tries = 0; tries < 100; tries++) { - fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0644); - if (fd >= 0) + ret = pkg_lock_create(path); + if (ret == 0) { - close(fd); return 0; } - if (errno != EEXIST) + if (ret != -EEXIST) { - return -errno; + return ret; } pkg_reclaim_stale_lock(path); diff --git a/system/nxpkg/pkg_store.c b/system/nxpkg/pkg_store.c index 562c0e3df..c73b7b583 100644 --- a/system/nxpkg/pkg_store.c +++ b/system/nxpkg/pkg_store.c @@ -27,6 +27,10 @@ #include #include #include +#include +#include +#include +#include #include #include #include @@ -36,10 +40,84 @@ #include "pkg.h" +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define PKG_LOCK_RECORD_MAGIC "NXPKG1" +#define PKG_LOCK_RECORD_SIZE 64 + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static pthread_once_t g_pkg_lock_boot_once = PTHREAD_ONCE_INIT; +static uint64_t g_pkg_lock_boot_id; + /**************************************************************************** * Private Functions ****************************************************************************/ +static void pkg_lock_init_boot_id(void) +{ + arc4random_buf(&g_pkg_lock_boot_id, sizeof(g_pkg_lock_boot_id)); + if (g_pkg_lock_boot_id == 0) + { + g_pkg_lock_boot_id = 1; + } +} + +static uint64_t pkg_lock_get_boot_id(void) +{ + if (pthread_once(&g_pkg_lock_boot_once, pkg_lock_init_boot_id) != 0) + { + return 1; + } + + return g_pkg_lock_boot_id; +} + +static int pkg_lock_read_owner(FAR const char *path, + FAR uint64_t *boot_id, + FAR pid_t *owner) +{ + char record[PKG_LOCK_RECORD_SIZE]; + unsigned long long parsed_boot; + long parsed_owner; + ssize_t nread; + int fd; + int ret; + + fd = open(path, O_RDONLY); + if (fd < 0) + { + return -errno; + } + + nread = read(fd, record, sizeof(record) - 1); + if (nread < 0) + { + ret = -errno; + close(fd); + return ret; + } + + close(fd); + record[nread] = '\0'; + + ret = sscanf(record, PKG_LOCK_RECORD_MAGIC " %llx %ld", + &parsed_boot, &parsed_owner); + if (ret != 2 || parsed_owner <= 0 || + (long)(pid_t)parsed_owner != parsed_owner) + { + return -EINVAL; + } + + *boot_id = (uint64_t)parsed_boot; + *owner = (pid_t)parsed_owner; + return 0; +} + static int pkg_store_format(FAR char *buffer, size_t size, FAR const char *fmt, FAR const char *name, @@ -194,6 +272,119 @@ int pkg_store_prepare_layout(void) return pkg_store_mkdirs(PKG_TMP_PKG_DIR); } +int pkg_lock_create(FAR const char *path) +{ + char record[PKG_LOCK_RECORD_SIZE]; + int fd; + int ret; + + fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0644); + if (fd < 0) + { + return -errno; + } + + ret = snprintf(record, sizeof(record), PKG_LOCK_RECORD_MAGIC + " %016" PRIx64 " %ld\n", + pkg_lock_get_boot_id(), (long)getpid()); + if (ret < 0 || (size_t)ret >= sizeof(record)) + { + ret = ret < 0 ? ret : -ENAMETOOLONG; + goto errout; + } + + ret = pkg_store_write_all(fd, record, (size_t)ret); + if (ret < 0) + { + goto errout; + } + + if (fsync(fd) < 0) + { + ret = -errno; + goto errout; + } + + if (close(fd) < 0) + { + ret = -errno; + unlink(path); + return ret; + } + + return 0; + +errout: + close(fd); + unlink(path); + return ret; +} + +void pkg_reclaim_stale_lock(FAR const char *path) +{ + struct stat st; + uint64_t boot_id; + pid_t owner; + time_t now; + int ret; + + ret = pkg_lock_read_owner(path, &boot_id, &owner); + if (ret == -EINVAL) + { + /* A creator may have completed open(O_EXCL) but not its first write. + * Give that very small window time to close before treating the file + * as a legacy timestamp-only lock. + */ + + usleep(20 * 1000); + ret = pkg_lock_read_owner(path, &boot_id, &owner); + } + + if (ret == 0) + { + if (boot_id != pkg_lock_get_boot_id()) + { + pkg_error("reclaiming lock from an earlier boot '%s'", path); + unlink(path); + return; + } + + if (kill(owner, 0) == 0 || errno == EPERM) + { + return; + } + + if (errno == ESRCH) + { + pkg_error("reclaiming lock from exited task %ld '%s'", + (long)owner, path); + unlink(path); + } + + return; + } + + /* Compatibility for empty lock files created by older nxpkg images. + * Their only ownership information is the filesystem timestamp. + */ + + if (stat(path, &st) < 0) + { + return; + } + + now = time(NULL); + if (now < st.st_mtime || + (now - st.st_mtime) < PKG_LOCK_STALE_SECONDS) + { + return; + } + + pkg_error("reclaiming legacy stale lock '%s' (age %ld s)", + path, (long)(now - st.st_mtime)); + unlink(path); +} + int pkg_store_ensure_package_root(FAR const char *name) { char path[PATH_MAX];