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