1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * linux/fs/readdir.c 4 * 5 * Copyright (C) 1995 Linus Torvalds 6 */ 7 8 #include <linux/stddef.h> 9 #include <linux/kernel.h> 10 #include <linux/export.h> 11 #include <linux/time.h> 12 #include <linux/mm.h> 13 #include <linux/errno.h> 14 #include <linux/stat.h> 15 #include <linux/file.h> 16 #include <linux/fs.h> 17 #include <linux/fsnotify.h> 18 #include <linux/dirent.h> 19 #include <linux/security.h> 20 #include <linux/syscalls.h> 21 #include <linux/unistd.h> 22 #include <linux/compat.h> 23 24 #include <linux/uaccess.h> 25 26 int iterate_dir(struct file *file, struct dir_context *ctx) 27 { 28 struct inode *inode = file_inode(file); 29 bool shared = false; 30 int res = -ENOTDIR; 31 if (file->f_op->iterate_shared) 32 shared = true; 33 else if (!file->f_op->iterate) 34 goto out; 35 36 res = security_file_permission(file, MAY_READ); 37 if (res) 38 goto out; 39 40 if (shared) { 41 inode_lock_shared(inode); 42 } else { 43 res = down_write_killable(&inode->i_rwsem); 44 if (res) 45 goto out; 46 } 47 48 res = -ENOENT; 49 if (!IS_DEADDIR(inode)) { 50 ctx->pos = file->f_pos; 51 if (shared) 52 res = file->f_op->iterate_shared(file, ctx); 53 else 54 res = file->f_op->iterate(file, ctx); 55 file->f_pos = ctx->pos; 56 fsnotify_access(file); 57 file_accessed(file); 58 } 59 if (shared) 60 inode_unlock_shared(inode); 61 else 62 inode_unlock(inode); 63 out: 64 return res; 65 } 66 EXPORT_SYMBOL(iterate_dir); 67 68 /* 69 * Traditional linux readdir() handling.. 70 * 71 * "count=1" is a special case, meaning that the buffer is one 72 * dirent-structure in size and that the code can't handle more 73 * anyway. Thus the special "fillonedir()" function for that 74 * case (the low-level handlers don't need to care about this). 75 */ 76 77 #ifdef __ARCH_WANT_OLD_READDIR 78 79 struct old_linux_dirent { 80 unsigned long d_ino; 81 unsigned long d_offset; 82 unsigned short d_namlen; 83 char d_name[1]; 84 }; 85 86 struct readdir_callback { 87 struct dir_context ctx; 88 struct old_linux_dirent __user * dirent; 89 int result; 90 }; 91 92 static int fillonedir(struct dir_context *ctx, const char *name, int namlen, 93 loff_t offset, u64 ino, unsigned int d_type) 94 { 95 struct readdir_callback *buf = 96 container_of(ctx, struct readdir_callback, ctx); 97 struct old_linux_dirent __user * dirent; 98 unsigned long d_ino; 99 100 if (buf->result) 101 return -EINVAL; 102 d_ino = ino; 103 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { 104 buf->result = -EOVERFLOW; 105 return -EOVERFLOW; 106 } 107 buf->result++; 108 dirent = buf->dirent; 109 if (!access_ok(VERIFY_WRITE, dirent, 110 (unsigned long)(dirent->d_name + namlen + 1) - 111 (unsigned long)dirent)) 112 goto efault; 113 if ( __put_user(d_ino, &dirent->d_ino) || 114 __put_user(offset, &dirent->d_offset) || 115 __put_user(namlen, &dirent->d_namlen) || 116 __copy_to_user(dirent->d_name, name, namlen) || 117 __put_user(0, dirent->d_name + namlen)) 118 goto efault; 119 return 0; 120 efault: 121 buf->result = -EFAULT; 122 return -EFAULT; 123 } 124 125 SYSCALL_DEFINE3(old_readdir, unsigned int, fd, 126 struct old_linux_dirent __user *, dirent, unsigned int, count) 127 { 128 int error; 129 struct fd f = fdget_pos(fd); 130 struct readdir_callback buf = { 131 .ctx.actor = fillonedir, 132 .dirent = dirent 133 }; 134 135 if (!f.file) 136 return -EBADF; 137 138 error = iterate_dir(f.file, &buf.ctx); 139 if (buf.result) 140 error = buf.result; 141 142 fdput_pos(f); 143 return error; 144 } 145 146 #endif /* __ARCH_WANT_OLD_READDIR */ 147 148 /* 149 * New, all-improved, singing, dancing, iBCS2-compliant getdents() 150 * interface. 151 */ 152 struct linux_dirent { 153 unsigned long d_ino; 154 unsigned long d_off; 155 unsigned short d_reclen; 156 char d_name[1]; 157 }; 158 159 struct getdents_callback { 160 struct dir_context ctx; 161 struct linux_dirent __user * current_dir; 162 struct linux_dirent __user * previous; 163 int count; 164 int error; 165 }; 166 167 static int filldir(struct dir_context *ctx, const char *name, int namlen, 168 loff_t offset, u64 ino, unsigned int d_type) 169 { 170 struct linux_dirent __user * dirent; 171 struct getdents_callback *buf = 172 container_of(ctx, struct getdents_callback, ctx); 173 unsigned long d_ino; 174 int reclen = ALIGN(offsetof(struct linux_dirent, d_name) + namlen + 2, 175 sizeof(long)); 176 177 buf->error = -EINVAL; /* only used if we fail.. */ 178 if (reclen > buf->count) 179 return -EINVAL; 180 d_ino = ino; 181 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { 182 buf->error = -EOVERFLOW; 183 return -EOVERFLOW; 184 } 185 dirent = buf->previous; 186 if (dirent) { 187 if (signal_pending(current)) 188 return -EINTR; 189 if (__put_user(offset, &dirent->d_off)) 190 goto efault; 191 } 192 dirent = buf->current_dir; 193 if (__put_user(d_ino, &dirent->d_ino)) 194 goto efault; 195 if (__put_user(reclen, &dirent->d_reclen)) 196 goto efault; 197 if (copy_to_user(dirent->d_name, name, namlen)) 198 goto efault; 199 if (__put_user(0, dirent->d_name + namlen)) 200 goto efault; 201 if (__put_user(d_type, (char __user *) dirent + reclen - 1)) 202 goto efault; 203 buf->previous = dirent; 204 dirent = (void __user *)dirent + reclen; 205 buf->current_dir = dirent; 206 buf->count -= reclen; 207 return 0; 208 efault: 209 buf->error = -EFAULT; 210 return -EFAULT; 211 } 212 213 SYSCALL_DEFINE3(getdents, unsigned int, fd, 214 struct linux_dirent __user *, dirent, unsigned int, count) 215 { 216 struct fd f; 217 struct linux_dirent __user * lastdirent; 218 struct getdents_callback buf = { 219 .ctx.actor = filldir, 220 .count = count, 221 .current_dir = dirent 222 }; 223 int error; 224 225 if (!access_ok(VERIFY_WRITE, dirent, count)) 226 return -EFAULT; 227 228 f = fdget_pos(fd); 229 if (!f.file) 230 return -EBADF; 231 232 error = iterate_dir(f.file, &buf.ctx); 233 if (error >= 0) 234 error = buf.error; 235 lastdirent = buf.previous; 236 if (lastdirent) { 237 if (put_user(buf.ctx.pos, &lastdirent->d_off)) 238 error = -EFAULT; 239 else 240 error = count - buf.count; 241 } 242 fdput_pos(f); 243 return error; 244 } 245 246 struct getdents_callback64 { 247 struct dir_context ctx; 248 struct linux_dirent64 __user * current_dir; 249 struct linux_dirent64 __user * previous; 250 int count; 251 int error; 252 }; 253 254 static int filldir64(struct dir_context *ctx, const char *name, int namlen, 255 loff_t offset, u64 ino, unsigned int d_type) 256 { 257 struct linux_dirent64 __user *dirent; 258 struct getdents_callback64 *buf = 259 container_of(ctx, struct getdents_callback64, ctx); 260 int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1, 261 sizeof(u64)); 262 263 buf->error = -EINVAL; /* only used if we fail.. */ 264 if (reclen > buf->count) 265 return -EINVAL; 266 dirent = buf->previous; 267 if (dirent) { 268 if (signal_pending(current)) 269 return -EINTR; 270 if (__put_user(offset, &dirent->d_off)) 271 goto efault; 272 } 273 dirent = buf->current_dir; 274 if (__put_user(ino, &dirent->d_ino)) 275 goto efault; 276 if (__put_user(0, &dirent->d_off)) 277 goto efault; 278 if (__put_user(reclen, &dirent->d_reclen)) 279 goto efault; 280 if (__put_user(d_type, &dirent->d_type)) 281 goto efault; 282 if (copy_to_user(dirent->d_name, name, namlen)) 283 goto efault; 284 if (__put_user(0, dirent->d_name + namlen)) 285 goto efault; 286 buf->previous = dirent; 287 dirent = (void __user *)dirent + reclen; 288 buf->current_dir = dirent; 289 buf->count -= reclen; 290 return 0; 291 efault: 292 buf->error = -EFAULT; 293 return -EFAULT; 294 } 295 296 SYSCALL_DEFINE3(getdents64, unsigned int, fd, 297 struct linux_dirent64 __user *, dirent, unsigned int, count) 298 { 299 struct fd f; 300 struct linux_dirent64 __user * lastdirent; 301 struct getdents_callback64 buf = { 302 .ctx.actor = filldir64, 303 .count = count, 304 .current_dir = dirent 305 }; 306 int error; 307 308 if (!access_ok(VERIFY_WRITE, dirent, count)) 309 return -EFAULT; 310 311 f = fdget_pos(fd); 312 if (!f.file) 313 return -EBADF; 314 315 error = iterate_dir(f.file, &buf.ctx); 316 if (error >= 0) 317 error = buf.error; 318 lastdirent = buf.previous; 319 if (lastdirent) { 320 typeof(lastdirent->d_off) d_off = buf.ctx.pos; 321 if (__put_user(d_off, &lastdirent->d_off)) 322 error = -EFAULT; 323 else 324 error = count - buf.count; 325 } 326 fdput_pos(f); 327 return error; 328 } 329 330 #ifdef CONFIG_COMPAT 331 struct compat_old_linux_dirent { 332 compat_ulong_t d_ino; 333 compat_ulong_t d_offset; 334 unsigned short d_namlen; 335 char d_name[1]; 336 }; 337 338 struct compat_readdir_callback { 339 struct dir_context ctx; 340 struct compat_old_linux_dirent __user *dirent; 341 int result; 342 }; 343 344 static int compat_fillonedir(struct dir_context *ctx, const char *name, 345 int namlen, loff_t offset, u64 ino, 346 unsigned int d_type) 347 { 348 struct compat_readdir_callback *buf = 349 container_of(ctx, struct compat_readdir_callback, ctx); 350 struct compat_old_linux_dirent __user *dirent; 351 compat_ulong_t d_ino; 352 353 if (buf->result) 354 return -EINVAL; 355 d_ino = ino; 356 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { 357 buf->result = -EOVERFLOW; 358 return -EOVERFLOW; 359 } 360 buf->result++; 361 dirent = buf->dirent; 362 if (!access_ok(VERIFY_WRITE, dirent, 363 (unsigned long)(dirent->d_name + namlen + 1) - 364 (unsigned long)dirent)) 365 goto efault; 366 if ( __put_user(d_ino, &dirent->d_ino) || 367 __put_user(offset, &dirent->d_offset) || 368 __put_user(namlen, &dirent->d_namlen) || 369 __copy_to_user(dirent->d_name, name, namlen) || 370 __put_user(0, dirent->d_name + namlen)) 371 goto efault; 372 return 0; 373 efault: 374 buf->result = -EFAULT; 375 return -EFAULT; 376 } 377 378 COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd, 379 struct compat_old_linux_dirent __user *, dirent, unsigned int, count) 380 { 381 int error; 382 struct fd f = fdget_pos(fd); 383 struct compat_readdir_callback buf = { 384 .ctx.actor = compat_fillonedir, 385 .dirent = dirent 386 }; 387 388 if (!f.file) 389 return -EBADF; 390 391 error = iterate_dir(f.file, &buf.ctx); 392 if (buf.result) 393 error = buf.result; 394 395 fdput_pos(f); 396 return error; 397 } 398 399 struct compat_linux_dirent { 400 compat_ulong_t d_ino; 401 compat_ulong_t d_off; 402 unsigned short d_reclen; 403 char d_name[1]; 404 }; 405 406 struct compat_getdents_callback { 407 struct dir_context ctx; 408 struct compat_linux_dirent __user *current_dir; 409 struct compat_linux_dirent __user *previous; 410 int count; 411 int error; 412 }; 413 414 static int compat_filldir(struct dir_context *ctx, const char *name, int namlen, 415 loff_t offset, u64 ino, unsigned int d_type) 416 { 417 struct compat_linux_dirent __user * dirent; 418 struct compat_getdents_callback *buf = 419 container_of(ctx, struct compat_getdents_callback, ctx); 420 compat_ulong_t d_ino; 421 int reclen = ALIGN(offsetof(struct compat_linux_dirent, d_name) + 422 namlen + 2, sizeof(compat_long_t)); 423 424 buf->error = -EINVAL; /* only used if we fail.. */ 425 if (reclen > buf->count) 426 return -EINVAL; 427 d_ino = ino; 428 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { 429 buf->error = -EOVERFLOW; 430 return -EOVERFLOW; 431 } 432 dirent = buf->previous; 433 if (dirent) { 434 if (signal_pending(current)) 435 return -EINTR; 436 if (__put_user(offset, &dirent->d_off)) 437 goto efault; 438 } 439 dirent = buf->current_dir; 440 if (__put_user(d_ino, &dirent->d_ino)) 441 goto efault; 442 if (__put_user(reclen, &dirent->d_reclen)) 443 goto efault; 444 if (copy_to_user(dirent->d_name, name, namlen)) 445 goto efault; 446 if (__put_user(0, dirent->d_name + namlen)) 447 goto efault; 448 if (__put_user(d_type, (char __user *) dirent + reclen - 1)) 449 goto efault; 450 buf->previous = dirent; 451 dirent = (void __user *)dirent + reclen; 452 buf->current_dir = dirent; 453 buf->count -= reclen; 454 return 0; 455 efault: 456 buf->error = -EFAULT; 457 return -EFAULT; 458 } 459 460 COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd, 461 struct compat_linux_dirent __user *, dirent, unsigned int, count) 462 { 463 struct fd f; 464 struct compat_linux_dirent __user * lastdirent; 465 struct compat_getdents_callback buf = { 466 .ctx.actor = compat_filldir, 467 .current_dir = dirent, 468 .count = count 469 }; 470 int error; 471 472 if (!access_ok(VERIFY_WRITE, dirent, count)) 473 return -EFAULT; 474 475 f = fdget_pos(fd); 476 if (!f.file) 477 return -EBADF; 478 479 error = iterate_dir(f.file, &buf.ctx); 480 if (error >= 0) 481 error = buf.error; 482 lastdirent = buf.previous; 483 if (lastdirent) { 484 if (put_user(buf.ctx.pos, &lastdirent->d_off)) 485 error = -EFAULT; 486 else 487 error = count - buf.count; 488 } 489 fdput_pos(f); 490 return error; 491 } 492 #endif 493