Documentation/driver-api/ioctl.rst GitHub 원문 ↗

Linux 6.18.37 · Driver API

ioctl based interfaces

Stable ioctl ABI를 위한 command encoding, timestamp, 32-bit compat, portable layout, leak 방지와 대안을 설명합니다.

Source pathDocumentation/driver-api/ioctl.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약과 해설

ioctl.rst:1-253

ioctl ABI는 배포 뒤 수정하기 어려우므로 새 command number, fixed-width member, explicit padding, monotonic timestamp와 compat handler를 처음부터 설계해야 합니다. Subsystem 공통 handler로 userspace marshalling을 한 곳에 모으고 문제 성격에 따라 netlink·sysfs·configfs 같은 대안도 우선 검토합니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 ======================
2 ioctl based interfaces
3 ======================
4
5 ioctl() is the most common way for applications to interface
6 with device drivers. It is flexible and easily extended by adding new
7 commands and can be passed through character devices, block devices as
8 well as sockets and other special file descriptors.
9
10 However, it is also very easy to get ioctl command definitions wrong,
11 and hard to fix them later without breaking existing applications,
12 so this documentation tries to help developers get it right.
13
14 Command number definitions
15 ==========================
16
17 The command number, or request number, is the second argument passed to
18 the ioctl system call. While this can be any 32-bit number that uniquely
19 identifies an action for a particular driver, there are a number of
20 conventions around defining them.
21
22 ``include/uapi/asm-generic/ioctl.h`` provides four macros for defining
23 ioctl commands that follow modern conventions: ``_IO``, ``_IOR``,
24 ``_IOW``, and ``_IOWR``. These should be used for all new commands,
25 with the correct parameters:
26
27 _IO/_IOR/_IOW/_IOWR
28 The macro name specifies how the argument will be used. It may be a
29 pointer to data to be passed into the kernel (_IOW), out of the kernel
30 (_IOR), or both (_IOWR). _IO can indicate either commands with no
31 argument or those passing an integer value instead of a pointer.
32 It is recommended to only use _IO for commands without arguments,
33 and use pointers for passing data.
34
35 type
36 An 8-bit number, often a character literal, specific to a subsystem
37 or driver, and listed in Documentation/userspace-api/ioctl/ioctl-number.rst
38
39 nr
40 An 8-bit number identifying the specific command, unique for a give
41 value of 'type'
42
43 data_type
44 The name of the data type pointed to by the argument, the command number
45 encodes the ``sizeof(data_type)`` value in a 13-bit or 14-bit integer,
46 leading to a limit of 8191 bytes for the maximum size of the argument.
47 Note: do not pass sizeof(data_type) type into _IOR/_IOW/IOWR, as that
48 will lead to encoding sizeof(sizeof(data_type)), i.e. sizeof(size_t).
49 _IO does not have a data_type parameter.
50
51
52 Interface versions
53 ==================
54
55 Some subsystems use version numbers in data structures to overload
56 commands with different interpretations of the argument.
57
58 This is generally a bad idea, since changes to existing commands tend
59 to break existing applications.
60
61 A better approach is to add a new ioctl command with a new number. The
62 old command still needs to be implemented in the kernel for compatibility,
63 but this can be a wrapper around the new implementation.
64
65 Return code
66 ===========
67
68 ioctl commands can return negative error codes as documented in errno(3);
69 these get turned into errno values in user space. On success, the return
70 code should be zero. It is also possible but not recommended to return
71 a positive 'long' value.
72
73 When the ioctl callback is called with an unknown command number, the
74 handler returns either -ENOTTY or -ENOIOCTLCMD, which also results in
75 -ENOTTY being returned from the system call. Some subsystems return
76 -ENOSYS or -EINVAL here for historic reasons, but this is wrong.
77
78 Prior to Linux 5.5, compat_ioctl handlers were required to return
79 -ENOIOCTLCMD in order to use the fallback conversion into native
80 commands. As all subsystems are now responsible for handling compat
81 mode themselves, this is no longer needed, but it may be important to
82 consider when backporting bug fixes to older kernels.
83
84 Timestamps
85 ==========
86
87 Traditionally, timestamps and timeout values are passed as ``struct
88 timespec`` or ``struct timeval``, but these are problematic because of
89 incompatible definitions of these structures in user space after the
90 move to 64-bit time_t.
91
92 The ``struct __kernel_timespec`` type can be used instead to be embedded
93 in other data structures when separate second/nanosecond values are
94 desired, or passed to user space directly. This is still not ideal though,
95 as the structure matches neither the kernel's timespec64 nor the user
96 space timespec exactly. The get_timespec64() and put_timespec64() helper
97 functions can be used to ensure that the layout remains compatible with
98 user space and the padding is treated correctly.
99
100 As it is cheap to convert seconds to nanoseconds, but the opposite
101 requires an expensive 64-bit division, a simple __u64 nanosecond value
102 can be simpler and more efficient.
103
104 Timeout values and timestamps should ideally use CLOCK_MONOTONIC time,
105 as returned by ktime_get_ns() or ktime_get_ts64(). Unlike
106 CLOCK_REALTIME, this makes the timestamps immune from jumping backwards
107 or forwards due to leap second adjustments and clock_settime() calls.
108
109 ktime_get_real_ns() can be used for CLOCK_REALTIME timestamps that
110 need to be persistent across a reboot or between multiple machines.
111
112 32-bit compat mode
113 ==================
114
115 In order to support 32-bit user space running on a 64-bit machine, each
116 subsystem or driver that implements an ioctl callback handler must also
117 implement the corresponding compat_ioctl handler.
118
119 As long as all the rules for data structures are followed, this is as
120 easy as setting the .compat_ioctl pointer to a helper function such as
121 compat_ptr_ioctl() or blkdev_compat_ptr_ioctl().
122
123 compat_ptr()
124 ------------
125
126 On the s390 architecture, 31-bit user space has ambiguous representations
127 for data pointers, with the upper bit being ignored. When running such
128 a process in compat mode, the compat_ptr() helper must be used to
129 clear the upper bit of a compat_uptr_t and turn it into a valid 64-bit
130 pointer. On other architectures, this macro only performs a cast to a
131 ``void __user *`` pointer.
132
133 In an compat_ioctl() callback, the last argument is an unsigned long,
134 which can be interpreted as either a pointer or a scalar depending on
135 the command. If it is a scalar, then compat_ptr() must not be used, to
136 ensure that the 64-bit kernel behaves the same way as a 32-bit kernel
137 for arguments with the upper bit set.
138
139 The compat_ptr_ioctl() helper can be used in place of a custom
140 compat_ioctl file operation for drivers that only take arguments that
141 are pointers to compatible data structures.
142
143 Structure layout
144 ----------------
145
146 Compatible data structures have the same layout on all architectures,
147 avoiding all problematic members:
148
149 * ``long`` and ``unsigned long`` are the size of a register, so
150 they can be either 32-bit or 64-bit wide and cannot be used in portable
151 data structures. Fixed-length replacements are ``__s32``, ``__u32``,
152 ``__s64`` and ``__u64``.
153
154 * Pointers have the same problem, in addition to requiring the
155 use of compat_ptr(). The best workaround is to use ``__u64``
156 in place of pointers, which requires a cast to ``uintptr_t`` in user
157 space, and the use of u64_to_user_ptr() in the kernel to convert
158 it back into a user pointer.
159
160 * On the x86-32 (i386) architecture, the alignment of 64-bit variables
161 is only 32-bit, but they are naturally aligned on most other
162 architectures including x86-64. This means a structure like::
163
164 struct foo {
165 __u32 a;
166 __u64 b;
167 __u32 c;
168 };
169
170 has four bytes of padding between a and b on x86-64, plus another four
171 bytes of padding at the end, but no padding on i386, and it needs a
172 compat_ioctl conversion handler to translate between the two formats.
173
174 To avoid this problem, all structures should have their members
175 naturally aligned, or explicit reserved fields added in place of the
176 implicit padding. The ``pahole`` tool can be used for checking the
177 alignment.
178
179 * On ARM OABI user space, structures are padded to multiples of 32-bit,
180 making some structs incompatible with modern EABI kernels if they
181 do not end on a 32-bit boundary.
182
183 * On the m68k architecture, struct members are not guaranteed to have an
184 alignment greater than 16-bit, which is a problem when relying on
185 implicit padding.
186
187 * Bitfields and enums generally work as one would expect them to,
188 but some properties of them are implementation-defined, so it is better
189 to avoid them completely in ioctl interfaces.
190
191 * ``char`` members can be either signed or unsigned, depending on
192 the architecture, so the __u8 and __s8 types should be used for 8-bit
193 integer values, though char arrays are clearer for fixed-length strings.
194
195 Information leaks
196 =================
197
198 Uninitialized data must not be copied back to user space, as this can
199 cause an information leak, which can be used to defeat kernel address
200 space layout randomization (KASLR), helping in an attack.
201
202 For this reason (and for compat support) it is best to avoid any
203 implicit padding in data structures. Where there is implicit padding
204 in an existing structure, kernel drivers must be careful to fully
205 initialize an instance of the structure before copying it to user
206 space. This is usually done by calling memset() before assigning to
207 individual members.
208
209 Subsystem abstractions
210 ======================
211
212 While some device drivers implement their own ioctl function, most
213 subsystems implement the same command for multiple drivers. Ideally the
214 subsystem has an .ioctl() handler that copies the arguments from and
215 to user space, passing them into subsystem specific callback functions
216 through normal kernel pointers.
217
218 This helps in various ways:
219
220 * Applications written for one driver are more likely to work for
221 another one in the same subsystem if there are no subtle differences
222 in the user space ABI.
223
224 * The complexity of user space access and data structure layout is done
225 in one place, reducing the potential for implementation bugs.
226
227 * It is more likely to be reviewed by experienced developers
228 that can spot problems in the interface when the ioctl is shared
229 between multiple drivers than when it is only used in a single driver.
230
231 Alternatives to ioctl
232 =====================
233
234 There are many cases in which ioctl is not the best solution for a
235 problem. Alternatives include:
236
237 * System calls are a better choice for a system-wide feature that
238 is not tied to a physical device or constrained by the file system
239 permissions of a character device node
240
241 * netlink is the preferred way of configuring any network related
242 objects through sockets.
243
244 * debugfs is used for ad-hoc interfaces for debugging functionality
245 that does not need to be exposed as a stable interface to applications.
246
247 * sysfs is a good way to expose the state of an in-kernel object
248 that is not tied to a file descriptor.
249
250 * configfs can be used for more complex configuration than sysfs
251
252 * A custom file system can provide extra flexibility with a simple
253 user interface but adds a lot of complexity to the implementation.
254

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

ioctl interface 개요

1-13

문서 제목은 `ioctl based interfaces`입니다. `ioctl()`은 application이 device driver와 interface하는 가장 흔한 방법입니다. New command를 추가해 유연하게 확장할 수 있고 character device, block device, socket와 다른 special file descriptor를 통해 전달할 수 있습니다.

하지만 ioctl command definition은 잘못 만들기 쉽고 existing application을 깨지 않고 나중에 고치기 어렵습니다. 이 문서는 처음부터 올바르게 정의하기 위한 지침입니다.

ioctl 특성
장점위험
새 command로 확장 가능Command encoding을 잘못 만들기 쉬움
Character·block·socket 지원Released ABI 수정이 어려움
다양한 argument 전달32-bit compat·layout·information leak 고려 필요

장점과 ABI 위험을 함께 보여 줍니다.

Command number 정의

14-50

Command 또는 request number는 ioctl system call의 두 번째 argument입니다. 특정 driver action을 unique하게 식별하는 임의의 32-bit number일 수 있지만 convention을 따라야 합니다.

`include/uapi/asm-generic/ioctl.h`는 modern convention용 `_IO`, `_IOR`, `_IOW`, `_IOWR` macro를 제공합니다. `_IOW`는 userspace에서 kernel로 data input, `_IOR`은 kernel에서 output, `_IOWR`은 양방향 pointer data를 뜻합니다. `_IO`는 argument가 없거나 pointer 대신 integer를 전달하는 command를 나타낼 수 있지만 argument 없는 command에만 쓰고 data는 pointer로 전달하는 것이 권장됩니다.

`type`은 subsystem 또는 driver별 8-bit number이며 흔히 character literal입니다. 값은 `Documentation/userspace-api/ioctl/ioctl-number.rst`에 등록합니다. `nr`은 같은 `type` 안에서 specific command를 unique하게 식별하는 8-bit number입니다.

`data_type`은 argument가 가리키는 data type 이름입니다. Command number는 `sizeof(data_type)`을 13-bit 또는 14-bit integer로 encode하므로 argument 최대 크기는 8191 bytes입니다. `_IOR`, `_IOW`, `_IOWR`에 `sizeof(data_type)` 자체를 넘기면 `sizeof(sizeof(data_type))`, 즉 `sizeof(size_t)`가 encode되므로 절대 그렇게 하면 안 됩니다. `_IO`에는 data_type parameter가 없습니다.

ioctl command macro
MacroData direction용도
_IO없음Argument 없는 command 권장
_IORKernel → userspaceRead/output pointer
_IOWUserspace → kernelWrite/input pointer
_IOWR양방향Input·output pointer

Argument data direction과 권장 용도입니다.

Command number field
Field제약
type8-bitSubsystem/driver별, registry에 등록
nr8-bit같은 type에서 unique
sizeof(data_type)13 또는 14-bit최대 8191 bytes, sizeof 표현식 전달 금지

type·nr·data_type의 폭과 제약입니다.

Interface version

51-64

일부 subsystem은 data structure version number로 같은 command argument의 해석을 overload합니다. Existing command 변경은 existing application을 깨기 쉬우므로 일반적으로 나쁜 방법입니다.

더 나은 방법은 새 number의 ioctl command를 추가하는 것입니다. Compatibility를 위해 old command도 kernel에 남겨야 하지만 new implementation을 감싸는 wrapper로 만들 수 있습니다.

ioctl ABI 확장
기존 command ABI 유지새 request number 정의새 implementation 작성Old command를 wrapper로 유지Existing application compatibility 보존

Existing command를 바꾸지 않고 새 command로 발전시킵니다.

Return code

65-83

Ioctl command는 `errno(3)`에 문서화된 negative error code를 반환할 수 있고 userspace에서는 errno 값으로 변환됩니다. Success는 0이어야 합니다. Positive `long` 반환도 가능하지만 권장하지 않습니다.

Unknown command number를 받으면 handler는 `-ENOTTY` 또는 `-ENOIOCTLCMD`를 반환하며 system call 결과는 `-ENOTTY`입니다. 역사적으로 일부 subsystem이 `-ENOSYS`나 `-EINVAL`을 반환하지만 이는 잘못입니다.

Linux 5.5 전에는 compat_ioctl handler가 native command fallback conversion을 쓰기 위해 `-ENOIOCTLCMD`를 반환해야 했습니다. 이제 각 subsystem이 compat mode를 직접 처리하므로 필요 없지만 older kernel로 bug fix를 backport할 때 고려해야 합니다.

ioctl return 규칙
상황Return
Success0
Documented failurenegative errno
Unknown command-ENOTTY 또는 handler의 -ENOIOCTLCMD → system call -ENOTTY
잘못된 역사적 관행-ENOSYS, -EINVAL
Positive value가능하지만 비권장

Success·known error·unknown command를 구분합니다.

Timestamp와 timeout

84-111

전통적으로 timestamp와 timeout은 `struct timespec` 또는 `struct timeval`로 전달했지만 64-bit `time_t` 전환 뒤 userspace definition이 호환되지 않아 문제가 됩니다.

Separate seconds/nanoseconds가 필요하면 다른 structure에 `struct __kernel_timespec`을 embed하거나 userspace에 직접 전달할 수 있습니다. 다만 kernel `timespec64`와 userspace `timespec` 어느 쪽 layout과도 정확히 같지 않습니다. `get_timespec64()`와 `put_timespec64()` helper로 userspace layout compatibility와 padding 처리를 보장해야 합니다.

Seconds를 nanoseconds로 바꾸는 것은 싸지만 반대는 expensive 64-bit division이 필요하므로 단순한 `__u64` nanosecond 값이 더 간단하고 효율적일 수 있습니다.

Timeout과 timestamp는 이상적으로 `ktime_get_ns()` 또는 `ktime_get_ts64()`가 반환하는 `CLOCK_MONOTONIC`을 써야 합니다. `CLOCK_REALTIME`과 달리 leap second adjustment나 `clock_settime()` 때문에 앞뒤로 jump하지 않습니다. Reboot 사이 또는 여러 machine 사이에 지속되어야 하는 realtime timestamp에는 `ktime_get_real_ns()`를 사용할 수 있습니다.

Timestamp representation
선택용도·주의
struct timespec/timeval64-bit time_t 이후 호환 문제
struct __kernel_timespecsec/ns field, helper로 padding 처리
__u64 nanoseconds단순·효율적, 역변환은 division 비용
CLOCK_MONOTONICTimeout·일반 timestamp 권장, clock jump 면역
CLOCK_REALTIMEReboot·machine 사이 persistent timestamp

Layout compatibility와 clock 선택을 정리했습니다.

32-bit compat mode와 compat_ptr

112-142

64-bit machine에서 32-bit userspace를 지원하려면 ioctl callback을 구현한 subsystem·driver가 corresponding `compat_ioctl` handler도 구현해야 합니다. Data structure rule을 지키면 `.compat_ioctl` pointer를 `compat_ptr_ioctl()` 또는 `blkdev_compat_ptr_ioctl()` 같은 helper로 설정하면 됩니다.

s390에서 31-bit userspace data pointer는 upper bit가 무시되는 ambiguous representation입니다. Compat mode에서는 `compat_ptr()`로 `compat_uptr_t`의 upper bit를 clear해 valid 64-bit pointer로 바꿔야 합니다. 다른 architecture에서 이 macro는 `void __user *` cast만 수행합니다.

`compat_ioctl()` callback의 마지막 argument는 `unsigned long`이고 command에 따라 pointer 또는 scalar입니다. Scalar라면 upper bit가 설정된 argument에서 64-bit kernel이 32-bit kernel과 동일하게 동작하도록 `compat_ptr()`을 사용하면 안 됩니다.

Pointer와 compatible data structure만 argument로 받는 driver는 custom compat_ioctl file operation 대신 `compat_ptr_ioctl()` helper를 사용할 수 있습니다.

Compat argument 판단
compat_ioctl unsigned long argumentCommand definition 확인Pointer인가?예: compat_ptr() 또는 compat_ptr_ioctl()아니오: scalar 그대로 처리Native handler와 동일 ABI semantics

Pointer와 scalar를 구분한 올바른 conversion입니다.

Portable structure layout

143-194

Compatible data structure는 모든 architecture에서 같은 layout이어야 하며 문제가 되는 member를 피해야 합니다. `long`과 `unsigned long`은 register 크기라 32-bit 또는 64-bit가 될 수 있으므로 portable structure에 쓰지 말고 `__s32`, `__u32`, `__s64`, `__u64`을 사용합니다.

Pointer도 폭 문제가 있고 compat_ptr가 필요합니다. Pointer 대신 `__u64`을 쓰고 userspace에서는 `uintptr_t`로 cast하며 kernel에서는 `u64_to_user_ptr()`로 user pointer로 변환하는 것이 가장 나은 workaround입니다.

x86-32에서 64-bit variable alignment는 32-bit이지만 x86-64를 포함한 대부분 architecture에서는 natural alignment입니다. 아래 structure는 x86-64에서 `a`와 `b` 사이 4-byte padding과 끝 4-byte padding이 있지만 i386에는 padding이 없어 compat conversion이 필요합니다.

struct foo {
    __u32 a;
    __u64 b;
    __u32 c;
};

문제를 피하려면 모든 member를 natural alignment에 맞추거나 implicit padding 위치에 explicit reserved field를 넣어야 합니다. `pahole`로 alignment를 확인할 수 있습니다.

ARM OABI userspace는 structure를 32-bit multiple로 pad하므로 32-bit boundary로 끝나지 않는 일부 struct는 modern EABI kernel과 호환되지 않습니다. m68k에서는 member가 16-bit보다 큰 alignment를 보장받지 못해 implicit padding 의존이 문제입니다.

Bitfield와 enum은 대개 예상대로 동작하지만 일부 property가 implementation-defined이므로 ioctl interface에서는 완전히 피하는 편이 낫습니다. `char` signedness도 architecture에 따라 달라지므로 8-bit integer에는 `__u8`, `__s8`을 쓰고 fixed-length string에는 char array가 더 명확합니다.

Portable ioctl member
문제 member문제대체
long/unsigned long32·64-bit 폭 차이__s32/__u32/__s64/__u64
Pointer폭·compat_ptr 필요__u64 + uintptr_t + u64_to_user_ptr
Implicit paddingArchitecture별 alignmentNatural ordering 또는 explicit reserved
Bitfield·enumImplementation-defined propertyFixed-width integer
char integerSignedness 차이__u8 또는 __s8

피해야 할 type과 대체 방법입니다.

Architecture layout 위험
Architecture위험
x86-32 vs x86-6464-bit member alignment·padding 차이
ARM OABIStruct size를 32-bit multiple로 padding
m68k16-bit보다 큰 member alignment 미보장

대표 compat layout 차이입니다.

Information leak 방지

195-208

Uninitialized data를 userspace로 copy하면 information leak이 발생하고 kernel address space layout randomization(KASLR)을 무력화해 attack을 도울 수 있습니다.

이 이유와 compat support 때문에 data structure의 implicit padding을 피하는 것이 좋습니다. Existing structure에 implicit padding이 있다면 userspace로 copy하기 전에 instance 전체를 초기화해야 합니다. 보통 individual member를 assign하기 전에 `memset()`을 호출합니다.

Padding leak 방지
Structure instance allocatememset()으로 전체 byte 초기화각 member assignReserved·padding도 deterministiccopy_to_userKASLR 관련 정보 노출 방지

Kernel structure를 userspace로 copy하기 전 초기화 순서입니다.

Subsystem abstraction

209-230

일부 device driver는 자체 ioctl function을 구현하지만 대부분 subsystem은 여러 driver에 같은 command를 구현합니다. 이상적으로 subsystem의 `.ioctl()` handler가 userspace argument를 copy in/out하고 normal kernel pointer로 subsystem-specific callback에 전달합니다.

이 방식은 한 driver용 application이 같은 subsystem의 다른 driver에서도 subtle userspace ABI 차이 없이 동작할 가능성을 높입니다. Userspace access와 structure layout complexity를 한 곳에서 처리해 implementation bug 가능성을 줄이고, 여러 driver가 공유하는 interface는 experienced developer에게 review될 가능성도 높습니다.

Shared subsystem ioctl
Userspace ioctlSubsystem .ioctl() handlercopy_from_user·layout validationNormal kernel structureDriver-specific callbackcopy_to_user

Userspace marshalling과 driver callback을 분리합니다.

ioctl 대안

231-253

Ioctl이 최선이 아닌 경우가 많습니다. Physical device에 묶이지 않고 character device permission에 제한되지 않는 system-wide feature에는 system call이 낫습니다. Network object configuration은 socket 기반 netlink가 선호됩니다.

Stable application interface가 필요 없는 ad-hoc debugging에는 debugfs를 씁니다. File descriptor에 묶이지 않은 in-kernel object state 노출에는 sysfs, sysfs보다 복잡한 configuration에는 configfs를 사용할 수 있습니다. Custom filesystem은 단순한 userspace interface에 extra flexibility를 주지만 implementation complexity가 매우 큽니다.

ioctl 대안 선택
대안적합한 경우
System callDevice와 무관한 system-wide feature
netlinkNetwork object configuration
debugfsStable ABI가 아닌 ad-hoc debugging
sysfsFD와 무관한 in-kernel object state
configfsSysfs보다 복잡한 configuration
Custom filesystemExtra flexibility가 필요하고 complexity를 감수할 때

Interface 성격에 맞는 kernel-userspace mechanism입니다.