From 38f7c37983b406520e5178bdd70b4da50855bfc8 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Thu, 29 Jan 2015 13:47:54 -0800 Subject: [PATCH] modify_ldt.2: Overhaul the documentation This clarifies the behavior and documents all four functions. Signed-off-by: Andy Lutomirski Signed-off-by: Michael Kerrisk --- man2/modify_ldt.2 | 101 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 78 insertions(+), 23 deletions(-) diff --git a/man2/modify_ldt.2 b/man2/modify_ldt.2 index d12866471..f3cc94d39 100644 --- a/man2/modify_ldt.2 +++ b/man2/modify_ldt.2 @@ -1,4 +1,5 @@ .\" Copyright (c) 1995 Michael Chastain (mec@duracef.shout.net), 22 July 1995. +.\" Copyright (c) 2015 Andrew Lutomirski .\" .\" %%%LICENSE_START(GPLv2+_DOC_FULL) .\" This is free documentation; you can redistribute it and/or @@ -23,37 +24,43 @@ .\" .TH MODIFY_LDT 2 2012-07-13 "Linux" "Linux Programmer's Manual" .SH NAME -modify_ldt \- get or set ldt +modify_ldt \- get or set a per-process LDT entry .SH SYNOPSIS .nf .B #include .sp .BI "int modify_ldt(int " "func" ", void *" "ptr" ", unsigned long " "bytecount" ); .fi - +.PP .IR Note : There is no glibc wrapper for this system call; see NOTES. .SH DESCRIPTION .BR modify_ldt () -reads or writes the local descriptor table (ldt) for a process. -The ldt is a per-process memory management table used by the i386 processor. -For more information on this table, see an Intel 386 processor handbook. +reads or writes the local descriptor table (LDT) for a process. The LDT +is an array of segment descriptors that can be referenced by user code. +Linux allows processes to configure a per-process (actually per-mm) LDT. +For more information about the LDT, see the Intel Software Developer's +Manual or the AMD Architecture Programming Manual. .PP When .I func is 0, .BR modify_ldt () -reads the ldt into the memory pointed to by +reads the LDT into the memory pointed to by .IR ptr . The number of bytes read is the smaller of .I bytecount -and the actual size of the ldt. +and the actual size of the LDT, although the kernel may act as though +the LDT is padded with additional trailing zero bytes. On success, +.BR modify_ldt () +will return the number of bytes read. .PP When .I func -is 1, +is 1 or 0x11, .BR modify_ldt () -modifies one ldt entry. +modifies the LDT entry indicated by +.I ptr\->entry_number. .I ptr points to a .I user_desc @@ -61,11 +68,6 @@ structure and .I bytecount must equal the size of this structure. -.\" -.\" FIXME Should this page say something about func == 2 and func == 0x11? -.\" In Linux 2.4, func == 2 returned "the default ldt" -.\" In Linux 2.6, func == 2 is a nop, returning a zeroed out structure. -.\" Linux 2.4 and 2.6 implement an operation for func == 0x11 The .I user_desc @@ -89,12 +91,44 @@ struct user_desc { .PP In Linux 2.4 and earlier, this structure was named .IR modify_ldt_ldt_s . -.\" .PP -.\" The ldt is specific for the calling process. Any attempts to change -.\" the ldt to include the address space of another process or the kernel -.\" will result in a segmentation violation when trying to access the memory -.\" outside of the process address space. The memory protection is enforced -.\" at the paging layer. +.PP +The +.I contents +field is the segment type (data, expand-down data, non-conforming code, or +conforming code). The other fields match their descriptions in the +CPU manual, although +.BR modify_ldt () +cannot set the accessed bit. +.PP +A +.I user_desc +is considered "empty" if +.I read_exec_only +and +.I seg_not_present +are set to 1 and all of the other fields are 0. +An LDT entry can be cleared by setting it to an "empty" +.I user_desc +or, if +.I func +is 1, by setting both +.I base +and +.I limit +to 0. +.PP +A conforming code segment will be rejected if +.I +func +is 1 or if +.I seg_not_present +is 0. +.PP +When +.I func +is 2, +.BR modify_ldt () +will read zeros. This appears to be a leftover from Linux 2.4. .SH RETURN VALUE On success, .BR modify_ldt () @@ -119,19 +153,40 @@ or is 1 and .I bytecount is not equal to the size of the structure -.IR modify_ldt_ldt_s , +.IR user_desc , or .I func -is 1 and the new ldt entry has invalid values. +is 1 or 0x11 and the new ldt entry has invalid values. .TP .B ENOSYS .I func -is neither 0 nor 1. +is neither 0, 1, 2, nor 0x11. .SH CONFORMING TO This call is Linux-specific and should not be used in programs intended to be portable. +.SH BUGS +On 64-bit kernels before Linux 3.19, one of the padding bits in +.I user_desc, +if set, would prevent the descriptor from being considered empty. .SH NOTES Glibc does not provide a wrapper for this system call; call it using .BR syscall (2). +.PP +.BR modify_ldt () +should not be used for thread-local storage, as it slows down context +switches and only supports a limited number of threads. Threading libraries +should use +.BR set_thread_area (2) +or +.BR arch_prctl (2) +instead, except on extremely old kernels that do not support those system +calls. +.PP +The normal use for +.BR modify_ldt (2) +is to run legacy 16-bit or segmented 32-bit code. Not all kernels allow +16-bit segments to be installed, however. .SH SEE ALSO +.BR set_thread_area (2), +.BR arch_prctl (2), .BR vm86 (2)