@@ -55,16 +55,32 @@ static int validate_service_name(const char *name)
5555 return 0 ;
5656}
5757
58+ static int build_shm_name (char * dst , size_t dst_len ,
59+ const char * service_name ,
60+ uint64_t session_id )
61+ {
62+ if (validate_service_name (service_name ) < 0 )
63+ return -2 ; /* invalid service name */
64+
65+ int n = snprintf (dst , dst_len , "%s-%016llx.ipcshm" ,
66+ service_name , (unsigned long long )session_id );
67+ if (n < 0 || (size_t )n >= dst_len )
68+ return -1 ;
69+ return 0 ;
70+ }
71+
5872/* Build per-session SHM file path: {run_dir}/{service_name}-{session_id:016x}.ipcshm */
5973static int build_shm_path (char * dst , size_t dst_len ,
6074 const char * run_dir , const char * service_name ,
6175 uint64_t session_id )
6276{
63- if (validate_service_name (service_name ) < 0 )
64- return -2 ; /* invalid service name */
77+ char shm_name [256 ];
78+ int name_rc = build_shm_name (shm_name , sizeof (shm_name ), service_name ,
79+ session_id );
80+ if (name_rc < 0 )
81+ return name_rc ;
6582
66- int n = snprintf (dst , dst_len , "%s/%s-%016llx.ipcshm" ,
67- run_dir , service_name , (unsigned long long )session_id );
83+ int n = snprintf (dst , dst_len , "%s/%s" , run_dir , shm_name );
6884 if (n < 0 || (size_t )n >= dst_len )
6985 return -1 ;
7086 return 0 ;
@@ -153,28 +169,28 @@ static inline uint32_t *shm_u32_ptr(void *base, int offset)
153169 * -1 = doesn't exist
154170 * -2 = exists but undersized / invalid (treated as stale, unlinked)
155171 */
156- static int unlink_same_file (const char * path , const struct stat * expected ,
172+ static int unlink_same_file (int dir_fd , const char * name , const struct stat * expected ,
157173 bool allow_stale_unlink )
158174{
159175 if (!allow_stale_unlink )
160176 return -1 ;
161177
162178 struct stat current ;
163- if (lstat ( path , & current ) != 0 )
179+ if (fstatat ( dir_fd , name , & current , AT_SYMLINK_NOFOLLOW ) != 0 )
164180 return (errno == ENOENT ) ? 0 : -1 ;
165181
166182 if (current .st_dev != expected -> st_dev || current .st_ino != expected -> st_ino )
167183 return -1 ;
168184
169- /* Stale recovery only unlinks same-inode files in a private run directory. */
170- // codeql[cpp/toctou-race-condition]
171- if (unlink (path ) == 0 || errno == ENOENT )
185+ /* Stale recovery only unlinks same-inode entries in a private run directory. */
186+ if (unlinkat (dir_fd , name , 0 ) == 0 || errno == ENOENT )
172187 return 0 ;
173188
174189 return -1 ;
175190}
176191
177- static int check_shm_stale (const char * path , bool allow_stale_unlink )
192+ static int check_shm_stale (const char * path , int dir_fd , const char * name ,
193+ bool allow_stale_unlink )
178194{
179195#ifdef O_NOFOLLOW
180196 int fd = open (path , O_RDONLY | O_NOFOLLOW );
@@ -203,21 +219,21 @@ static int check_shm_stale(const char *path, bool allow_stale_unlink)
203219 /* Must be at least header-sized to inspect. */
204220 if (st .st_size < (off_t )NIPC_SHM_HEADER_LEN ) {
205221 close (fd );
206- return (unlink_same_file (path , & st , allow_stale_unlink ) == 0 ) ? -2 : 1 ;
222+ return (unlink_same_file (dir_fd , name , & st , allow_stale_unlink ) == 0 ) ? -2 : 1 ;
207223 }
208224
209225 void * map = mmap (NULL , NIPC_SHM_HEADER_LEN , PROT_READ , MAP_SHARED , fd , 0 );
210226 close (fd );
211227 if (map == MAP_FAILED ) {
212- return (unlink_same_file (path , & st , allow_stale_unlink ) == 0 ) ? -2 : 1 ;
228+ return (unlink_same_file (dir_fd , name , & st , allow_stale_unlink ) == 0 ) ? -2 : 1 ;
213229 }
214230
215231 const nipc_shm_region_header_t * hdr = (const nipc_shm_region_header_t * )map ;
216232
217233 /* Validate magic first. */
218234 if (hdr -> magic != NIPC_SHM_REGION_MAGIC ) {
219235 munmap (map , NIPC_SHM_HEADER_LEN );
220- return (unlink_same_file (path , & st , allow_stale_unlink ) == 0 ) ? -2 : 1 ;
236+ return (unlink_same_file (dir_fd , name , & st , allow_stale_unlink ) == 0 ) ? -2 : 1 ;
221237 }
222238
223239 int32_t owner = hdr -> owner_pid ;
@@ -229,7 +245,7 @@ static int check_shm_stale(const char *path, bool allow_stale_unlink)
229245 }
230246
231247 /* Dead owner or zero generation (uninitialized/legacy) — stale */
232- return (unlink_same_file (path , & st , allow_stale_unlink ) == 0 ) ? 0 : 1 ;
248+ return (unlink_same_file (dir_fd , name , & st , allow_stale_unlink ) == 0 ) ? 0 : 1 ;
233249}
234250
235251/* ------------------------------------------------------------------ */
@@ -258,6 +274,14 @@ nipc_shm_error_t nipc_shm_server_create(const char *run_dir,
258274 if (path_rc < 0 )
259275 return NIPC_SHM_ERR_PATH_TOO_LONG ;
260276
277+ char shm_name [256 ];
278+ int name_rc = build_shm_name (shm_name , sizeof (shm_name ), service_name ,
279+ session_id );
280+ if (name_rc == -2 )
281+ return NIPC_SHM_ERR_BAD_PARAM ;
282+ if (name_rc < 0 )
283+ return NIPC_SHM_ERR_PATH_TOO_LONG ;
284+
261285 /* Round capacities up to alignment. */
262286 req_capacity = align64 (req_capacity );
263287 resp_capacity = align64 (resp_capacity );
@@ -277,7 +301,15 @@ nipc_shm_error_t nipc_shm_server_create(const char *run_dir,
277301 /* If O_EXCL failed because file exists, do stale recovery and retry. */
278302 if (fd < 0 && errno == EEXIST ) {
279303 bool allow_stale_unlink = run_dir_allows_stale_unlink (run_dir );
280- int stale = check_shm_stale (path , allow_stale_unlink );
304+ int dir_fd = allow_stale_unlink
305+ ? open (run_dir , O_RDONLY | O_DIRECTORY | O_CLOEXEC )
306+ : -1 ;
307+ if (dir_fd < 0 )
308+ allow_stale_unlink = false;
309+
310+ int stale = check_shm_stale (path , dir_fd , shm_name , allow_stale_unlink );
311+ if (dir_fd >= 0 )
312+ close (dir_fd );
281313 if (stale == 1 )
282314 return NIPC_SHM_ERR_ADDR_IN_USE ;
283315 /* Stale file was unlinked, retry create */
@@ -797,7 +829,8 @@ void nipc_shm_cleanup_stale(const char *run_dir, const char *service_name)
797829 if (!dir )
798830 return ;
799831
800- bool allow_stale_unlink = run_dir_allows_stale_unlink (run_dir );
832+ int dir_fd = dirfd (dir );
833+ bool allow_stale_unlink = dir_fd >= 0 && run_dir_allows_stale_unlink (run_dir );
801834
802835 struct dirent * ent ;
803836 while ((ent = readdir (dir )) != NULL ) {
@@ -819,7 +852,7 @@ void nipc_shm_cleanup_stale(const char *run_dir, const char *service_name)
819852
820853 /* check_shm_stale unlinks stale files and returns:
821854 * 0 = stale (unlinked), +1 = live, -1 = gone, -2 = invalid (unlinked) */
822- check_shm_stale (path , allow_stale_unlink );
855+ check_shm_stale (path , dir_fd , ent -> d_name , allow_stale_unlink );
823856 }
824857
825858 closedir (dir );
0 commit comments