Skip to content

Commit f363a8f

Browse files
committed
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 <gargaviral99@gmail.com>
1 parent 38c6083 commit f363a8f

4 files changed

Lines changed: 204 additions & 61 deletions

File tree

system/nxpkg/pkg.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ int pkg_resolve_icon_source(FAR char *buffer, size_t size,
261261
FAR const struct pkg_manifest_s *manifest);
262262
int pkg_acquire_source(FAR const char *source, FAR const char *dest,
263263
FAR const char *renew_lock_path);
264+
int pkg_lock_create(FAR const char *path);
264265
void pkg_reclaim_stale_lock(FAR const char *path);
265266
int pkg_sync(FAR const char *source);
266267
int pkg_install(FAR const char *name);

system/nxpkg/pkg_install.c

Lines changed: 8 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,11 @@
2525
****************************************************************************/
2626

2727
#include <errno.h>
28-
#include <fcntl.h>
2928
#include <stdio.h>
3029
#include <stdlib.h>
3130
#include <strings.h>
3231
#include <string.h>
3332
#include <sys/stat.h>
34-
#include <time.h>
3533
#include <unistd.h>
3634

3735
#include "pkg.h"
@@ -43,7 +41,6 @@
4341
static int pkg_install_acquire_lock(FAR const char *name, FAR char *path,
4442
size_t size)
4543
{
46-
int fd;
4744
int ret;
4845

4946
ret = pkg_store_ensure_package_root(name);
@@ -58,20 +55,14 @@ static int pkg_install_acquire_lock(FAR const char *name, FAR char *path,
5855
return ret;
5956
}
6057

61-
fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0644);
62-
if (fd < 0 && errno == EEXIST)
58+
ret = pkg_lock_create(path);
59+
if (ret == -EEXIST)
6360
{
6461
pkg_reclaim_stale_lock(path);
65-
fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0644);
62+
ret = pkg_lock_create(path);
6663
}
6764

68-
if (fd < 0)
69-
{
70-
return errno == EEXIST ? -EBUSY : -errno;
71-
}
72-
73-
close(fd);
74-
return 0;
65+
return ret == -EEXIST ? -EBUSY : ret;
7566
}
7667

7768
/****************************************************************************
@@ -85,7 +76,6 @@ static int pkg_install_acquire_lock(FAR const char *name, FAR char *path,
8576

8677
static int pkg_install_acquire_installed_lock(FAR char *path, size_t size)
8778
{
88-
int fd;
8979
int ret;
9080
int tries;
9181

@@ -102,16 +92,15 @@ static int pkg_install_acquire_installed_lock(FAR char *path, size_t size)
10292

10393
for (tries = 0; tries < 100; tries++)
10494
{
105-
fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0644);
106-
if (fd >= 0)
95+
ret = pkg_lock_create(path);
96+
if (ret == 0)
10797
{
108-
close(fd);
10998
return 0;
11099
}
111100

112-
if (errno != EEXIST)
101+
if (ret != -EEXIST)
113102
{
114-
return -errno;
103+
return ret;
115104
}
116105

117106
pkg_reclaim_stale_lock(path);
@@ -337,42 +326,6 @@ static int pkg_install_write_pointers(
337326
* Public Functions
338327
****************************************************************************/
339328

340-
/****************************************************************************
341-
* Name: pkg_reclaim_stale_lock
342-
*
343-
* Description:
344-
* Remove "path" if it is old enough that it cannot belong to a still-
345-
* running holder (see PKG_LOCK_STALE_SECONDS). Best-effort: any
346-
* stat()/unlink() failure just falls through to the normal -EBUSY
347-
* result, since a lock we can't inspect should be treated as held.
348-
* Generic across every lock file this package uses (per-package
349-
* install locks, the shared installed-db lock, pkg_repo.c's sync
350-
* lock) - not install-specific despite living in this file.
351-
*
352-
****************************************************************************/
353-
354-
void pkg_reclaim_stale_lock(FAR const char *path)
355-
{
356-
struct stat st;
357-
time_t now;
358-
359-
if (stat(path, &st) < 0)
360-
{
361-
return;
362-
}
363-
364-
now = time(NULL);
365-
if (now < st.st_mtime ||
366-
(now - st.st_mtime) < PKG_LOCK_STALE_SECONDS)
367-
{
368-
return;
369-
}
370-
371-
pkg_error("reclaiming stale lock '%s' (age %ld s)",
372-
path, (long)(now - st.st_mtime));
373-
unlink(path);
374-
}
375-
376329
int pkg_install(FAR const char *name)
377330
{
378331
FAR struct pkg_index_s *index;

system/nxpkg/pkg_repo.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,6 @@ int pkg_acquire_source(FAR const char *source, FAR const char *dest,
544544

545545
static int pkg_repo_acquire_sync_lock(FAR char *path, size_t size)
546546
{
547-
int fd;
548547
int ret;
549548
int tries;
550549

@@ -561,16 +560,15 @@ static int pkg_repo_acquire_sync_lock(FAR char *path, size_t size)
561560

562561
for (tries = 0; tries < 100; tries++)
563562
{
564-
fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0644);
565-
if (fd >= 0)
563+
ret = pkg_lock_create(path);
564+
if (ret == 0)
566565
{
567-
close(fd);
568566
return 0;
569567
}
570568

571-
if (errno != EEXIST)
569+
if (ret != -EEXIST)
572570
{
573-
return -errno;
571+
return ret;
574572
}
575573

576574
pkg_reclaim_stale_lock(path);

system/nxpkg/pkg_store.c

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@
2727
#include <dirent.h>
2828
#include <errno.h>
2929
#include <fcntl.h>
30+
#include <inttypes.h>
31+
#include <pthread.h>
32+
#include <signal.h>
33+
#include <stdint.h>
3034
#include <stdlib.h>
3135
#include <stdio.h>
3236
#include <string.h>
@@ -36,10 +40,84 @@
3640

3741
#include "pkg.h"
3842

43+
/****************************************************************************
44+
* Pre-processor Definitions
45+
****************************************************************************/
46+
47+
#define PKG_LOCK_RECORD_MAGIC "NXPKG1"
48+
#define PKG_LOCK_RECORD_SIZE 64
49+
50+
/****************************************************************************
51+
* Private Data
52+
****************************************************************************/
53+
54+
static pthread_once_t g_pkg_lock_boot_once = PTHREAD_ONCE_INIT;
55+
static uint64_t g_pkg_lock_boot_id;
56+
3957
/****************************************************************************
4058
* Private Functions
4159
****************************************************************************/
4260

61+
static void pkg_lock_init_boot_id(void)
62+
{
63+
arc4random_buf(&g_pkg_lock_boot_id, sizeof(g_pkg_lock_boot_id));
64+
if (g_pkg_lock_boot_id == 0)
65+
{
66+
g_pkg_lock_boot_id = 1;
67+
}
68+
}
69+
70+
static uint64_t pkg_lock_get_boot_id(void)
71+
{
72+
if (pthread_once(&g_pkg_lock_boot_once, pkg_lock_init_boot_id) != 0)
73+
{
74+
return 1;
75+
}
76+
77+
return g_pkg_lock_boot_id;
78+
}
79+
80+
static int pkg_lock_read_owner(FAR const char *path,
81+
FAR uint64_t *boot_id,
82+
FAR pid_t *owner)
83+
{
84+
char record[PKG_LOCK_RECORD_SIZE];
85+
unsigned long long parsed_boot;
86+
long parsed_owner;
87+
ssize_t nread;
88+
int fd;
89+
int ret;
90+
91+
fd = open(path, O_RDONLY);
92+
if (fd < 0)
93+
{
94+
return -errno;
95+
}
96+
97+
nread = read(fd, record, sizeof(record) - 1);
98+
if (nread < 0)
99+
{
100+
ret = -errno;
101+
close(fd);
102+
return ret;
103+
}
104+
105+
close(fd);
106+
record[nread] = '\0';
107+
108+
ret = sscanf(record, PKG_LOCK_RECORD_MAGIC " %llx %ld",
109+
&parsed_boot, &parsed_owner);
110+
if (ret != 2 || parsed_owner <= 0 ||
111+
(long)(pid_t)parsed_owner != parsed_owner)
112+
{
113+
return -EINVAL;
114+
}
115+
116+
*boot_id = (uint64_t)parsed_boot;
117+
*owner = (pid_t)parsed_owner;
118+
return 0;
119+
}
120+
43121
static int pkg_store_format(FAR char *buffer, size_t size,
44122
FAR const char *fmt,
45123
FAR const char *name,
@@ -194,6 +272,119 @@ int pkg_store_prepare_layout(void)
194272
return pkg_store_mkdirs(PKG_TMP_PKG_DIR);
195273
}
196274

275+
int pkg_lock_create(FAR const char *path)
276+
{
277+
char record[PKG_LOCK_RECORD_SIZE];
278+
int fd;
279+
int ret;
280+
281+
fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0644);
282+
if (fd < 0)
283+
{
284+
return -errno;
285+
}
286+
287+
ret = snprintf(record, sizeof(record), PKG_LOCK_RECORD_MAGIC
288+
" %016" PRIx64 " %ld\n",
289+
pkg_lock_get_boot_id(), (long)getpid());
290+
if (ret < 0 || (size_t)ret >= sizeof(record))
291+
{
292+
ret = ret < 0 ? ret : -ENAMETOOLONG;
293+
goto errout;
294+
}
295+
296+
ret = pkg_store_write_all(fd, record, (size_t)ret);
297+
if (ret < 0)
298+
{
299+
goto errout;
300+
}
301+
302+
if (fsync(fd) < 0)
303+
{
304+
ret = -errno;
305+
goto errout;
306+
}
307+
308+
if (close(fd) < 0)
309+
{
310+
ret = -errno;
311+
unlink(path);
312+
return ret;
313+
}
314+
315+
return 0;
316+
317+
errout:
318+
close(fd);
319+
unlink(path);
320+
return ret;
321+
}
322+
323+
void pkg_reclaim_stale_lock(FAR const char *path)
324+
{
325+
struct stat st;
326+
uint64_t boot_id;
327+
pid_t owner;
328+
time_t now;
329+
int ret;
330+
331+
ret = pkg_lock_read_owner(path, &boot_id, &owner);
332+
if (ret == -EINVAL)
333+
{
334+
/* A creator may have completed open(O_EXCL) but not its first write.
335+
* Give that very small window time to close before treating the file
336+
* as a legacy timestamp-only lock.
337+
*/
338+
339+
usleep(20 * 1000);
340+
ret = pkg_lock_read_owner(path, &boot_id, &owner);
341+
}
342+
343+
if (ret == 0)
344+
{
345+
if (boot_id != pkg_lock_get_boot_id())
346+
{
347+
pkg_error("reclaiming lock from an earlier boot '%s'", path);
348+
unlink(path);
349+
return;
350+
}
351+
352+
if (kill(owner, 0) == 0 || errno == EPERM)
353+
{
354+
return;
355+
}
356+
357+
if (errno == ESRCH)
358+
{
359+
pkg_error("reclaiming lock from exited task %ld '%s'",
360+
(long)owner, path);
361+
unlink(path);
362+
}
363+
364+
return;
365+
}
366+
367+
/* Compatibility for empty lock files created by older nxpkg images.
368+
* Their only ownership information is the filesystem timestamp.
369+
*/
370+
371+
if (stat(path, &st) < 0)
372+
{
373+
return;
374+
}
375+
376+
now = time(NULL);
377+
if (now < st.st_mtime ||
378+
(now - st.st_mtime) < PKG_LOCK_STALE_SECONDS)
379+
{
380+
return;
381+
}
382+
383+
pkg_error("reclaiming legacy stale lock '%s' (age %ld s)",
384+
path, (long)(now - st.st_mtime));
385+
unlink(path);
386+
}
387+
197388
int pkg_store_ensure_package_root(FAR const char *name)
198389
{
199390
char path[PATH_MAX];

0 commit comments

Comments
 (0)